From 923d2a145e9090658fba5e922f99340f0f94347b Mon Sep 17 00:00:00 2001 From: Niranjan Jayakar Date: Thu, 26 Mar 2020 13:32:17 +0000 Subject: [PATCH 01/53] fix(stepfunctions-tasks): batch job - can not use task input as array size (#7008) Also, clean up some error messaging to be direct, terse and show the user input. fixes #6922 --- .../lib/run-batch-job.ts | 43 ++++++-------- .../test/run-batch-job.test.ts | 58 +++++++++++++++++-- 2 files changed, 70 insertions(+), 31 deletions(-) diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/run-batch-job.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/run-batch-job.ts index 67868f402f44f..7c8b2e14af2a4 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/run-batch-job.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/run-batch-job.ts @@ -2,7 +2,7 @@ import * as batch from '@aws-cdk/aws-batch'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as sfn from '@aws-cdk/aws-stepfunctions'; -import { Duration, Stack } from '@aws-cdk/core'; +import { Duration, Stack, withResolved } from '@aws-cdk/core'; import { getResourceArn } from './resource-arn-suffix'; /** @@ -191,38 +191,31 @@ export class RunBatchJob implements sfn.IStepFunctionsTask { } // validate arraySize limits - if ( - props.arraySize !== undefined && - (props.arraySize < 2 || props.arraySize > 10000) - ) { - throw new Error( - `Invalid value of arraySize. The array size can be between 2 and 10,000.` - ); - } + withResolved(props.arraySize, (arraySize) => { + if (arraySize !== undefined && (arraySize < 2 || arraySize > 10_000)) { + throw new Error(`arraySize must be between 2 and 10,000. Received ${arraySize}.`); + } + }); // validate dependency size if (props.dependsOn && props.dependsOn.length > 20) { - throw new Error( - `Invalid number of dependencies. A job can depend upon a maximum of 20 jobs.` - ); + throw new Error(`dependencies must be 20 or less. Received ${props.dependsOn.length}.`); } // validate attempts - if ( - props.attempts !== undefined && - (props.attempts < 1 || props.attempts > 10) - ) { - throw new Error( - `Invalid value of attempts. You may specify between 1 and 10 attempts.` - ); - } + withResolved(props.attempts, (attempts) => { + if (attempts !== undefined && (attempts < 1 || attempts > 10)) { + throw new Error(`attempts must be between 1 and 10. Received ${attempts}.`); + } + }); // validate timeout - if (props.timeout && props.timeout.toSeconds() < 60) { - throw new Error( - `Invalid value of timrout. The minimum value for the timeout is 60 seconds.` - ); - } + // tslint:disable-next-line:no-unused-expression + props.timeout !== undefined && withResolved(props.timeout.toSeconds(), (timeout) => { + if (timeout < 60) { + throw new Error(`timeout must be greater than 60 seconds. Received ${timeout} seconds.`); + } + }); // This is reuqired since environment variables must not start with AWS_BATCH; // this naming convention is reserved for variables that are set by the AWS Batch service. diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/run-batch-job.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/run-batch-job.test.ts index 1e6adba6038a7..afe6f4a11cef6 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/run-batch-job.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/run-batch-job.test.ts @@ -131,6 +131,52 @@ test('Task with all the parameters', () => { }); }); +test('supports tokens', () => { + // WHEN + const task = new sfn.Task(stack, 'Task', { + task: new tasks.RunBatchJob({ + jobDefinition: batchJobDefinition, + jobName: sfn.Data.stringAt('$.jobName'), + jobQueue: batchJobQueue, + arraySize: sfn.Data.numberAt('$.arraySize'), + timeout: cdk.Duration.seconds(sfn.Data.numberAt('$.timeout')), + attempts: sfn.Data.numberAt('$.attempts'), + }) + }); + + // THEN + expect(stack.resolve(task.toStateJson())).toEqual({ + Type: 'Task', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition' + }, + ':states:::batch:submitJob.sync' + ] + ] + }, + End: true, + Parameters: { + 'JobDefinition': { Ref: 'JobDefinition24FFE3ED' }, + 'JobName.$': '$.jobName', + 'JobQueue': { Ref: 'JobQueueEE3AD499' }, + 'ArrayProperties': { + 'Size.$': '$.arraySize' + }, + 'RetryStrategy': { + 'Attempts.$': '$.attempts' + }, + 'Timeout': { + 'AttemptDurationSeconds.$': '$.timeout' + } + } + }); +}); + test('Task throws if WAIT_FOR_TASK_TOKEN is supplied as service integration pattern', () => { expect(() => { new sfn.Task(stack, 'Task', { @@ -174,7 +220,7 @@ test('Task throws if arraySize is out of limits 2-10000', () => { }) }); }).toThrow( - /Invalid value of arraySize. The array size can be between 2 and 10,000./i + /arraySize must be between 2 and 10,000/ ); expect(() => { @@ -187,7 +233,7 @@ test('Task throws if arraySize is out of limits 2-10000', () => { }) }); }).toThrow( - /Invalid value of arraySize. The array size can be between 2 and 10,000./i + /arraySize must be between 2 and 10,000/ ); }); @@ -205,7 +251,7 @@ test('Task throws if dependencies exceeds 20', () => { }) }); }).toThrow( - /Invalid number of dependencies. A job can depend upon a maximum of 20 jobs./i + /dependencies must be 20 or less/ ); }); @@ -220,7 +266,7 @@ test('Task throws if attempts is out of limits 1-10', () => { }) }); }).toThrow( - /Invalid value of attempts. You may specify between 1 and 10 attempts./i + /attempts must be between 1 and 10/ ); expect(() => { @@ -233,7 +279,7 @@ test('Task throws if attempts is out of limits 1-10', () => { }) }); }).toThrow( - /Invalid value of attempts. You may specify between 1 and 10 attempts./i + /attempts must be between 1 and 10/ ); }); @@ -248,6 +294,6 @@ test('Task throws if timeout is less than 60 sec', () => { }) }); }).toThrow( - /Invalid value of timrout. The minimum value for the timeout is 60 seconds./i + /timeout must be greater than 60 seconds/ ); }); From 22a560dd4a49d74a9ff217c27c77a7e03d7b38de Mon Sep 17 00:00:00 2001 From: Niranjan Jayakar Date: Thu, 26 Mar 2020 14:23:54 +0000 Subject: [PATCH 02/53] feat(core): `Size` unit representing digital information quantity (#6940) Several construct libraries, specifically compute and storage types, allow configuring their resources with digital information. This type allows for this to be better modeled in the CDK app. A few places this could be used - - https://github.com/aws/aws-cdk/blob/4501b8ba566ac776042fc97435d4db96fc421e0b/packages/%40aws-cdk/aws-lambda/lib/function.ts#L75-L83 - https://github.com/aws/aws-cdk/blob/4501b8ba566ac776042fc97435d4db96fc421e0b/packages/%40aws-cdk/aws-rds/lib/instance.ts#L625-L630 - https://github.com/aws/aws-cdk/blob/1085a27d6d57621b47f415a3e2a11166702e8709/packages/%40aws-cdk/aws-autoscaling/lib/volume.ts#L89-L96 --- packages/@aws-cdk/core/README.md | 24 ++++ packages/@aws-cdk/core/lib/duration.ts | 2 +- packages/@aws-cdk/core/lib/index.ts | 1 + packages/@aws-cdk/core/lib/size.ts | 140 +++++++++++++++++++++++ packages/@aws-cdk/core/test/test.size.ts | 103 +++++++++++++++++ 5 files changed, 269 insertions(+), 1 deletion(-) create mode 100644 packages/@aws-cdk/core/lib/size.ts create mode 100644 packages/@aws-cdk/core/test/test.size.ts diff --git a/packages/@aws-cdk/core/README.md b/packages/@aws-cdk/core/README.md index a6ea67e9ae9a0..a336ffef2fc80 100644 --- a/packages/@aws-cdk/core/README.md +++ b/packages/@aws-cdk/core/README.md @@ -35,6 +35,30 @@ Duration.days(7) // 7 days Duration.parse('PT5M') // 5 minutes ``` +## Size (Digital Information Quantity) + +To make specification of digital storage quantities unambiguous, a class called +`Size` is available. + +An instance of `Size` is initialized through one of its static factory methods: + +```ts +Size.kibibytes(200) // 200 KiB +Size.mebibytes(5) // 5 MiB +Size.gibibytes(40) // 40 GiB +Size.tebibytes(200) // 200 TiB +Size.pebibytes(3) // 3 PiB +``` + +Instances of `Size` created with one of the units can be converted into others. +By default, conversion to a higher unit will fail if the conversion does not produce +a whole number. This can be overridden by unsetting `integral` property. + +```ts +Size.mebibytes(2).toKibibytes() // yields 2048 +Size.kibibytes(2050).toMebibyte({ integral: false }) // yields 2 +``` + ## Secrets To help avoid accidental storage of secrets as plain text, we use the `SecretValue` type to diff --git a/packages/@aws-cdk/core/lib/duration.ts b/packages/@aws-cdk/core/lib/duration.ts index 69152a27b5d28..826033d99402c 100644 --- a/packages/@aws-cdk/core/lib/duration.ts +++ b/packages/@aws-cdk/core/lib/duration.ts @@ -244,7 +244,7 @@ export class Duration { */ export interface TimeConversionOptions { /** - * If `true`, conversions into a larger time unit (e.g. `Seconds` to `Mintues`) will fail if the result is not an + * If `true`, conversions into a larger time unit (e.g. `Seconds` to `Minutes`) will fail if the result is not an * integer. * * @default true diff --git a/packages/@aws-cdk/core/lib/index.ts b/packages/@aws-cdk/core/lib/index.ts index 1fd26c2652b2d..828d9eca25057 100644 --- a/packages/@aws-cdk/core/lib/index.ts +++ b/packages/@aws-cdk/core/lib/index.ts @@ -27,6 +27,7 @@ export * from './cfn-tag'; export * from './removal-policy'; export * from './arn'; export * from './duration'; +export * from './size'; export * from './stack-trace'; export * from './app'; diff --git a/packages/@aws-cdk/core/lib/size.ts b/packages/@aws-cdk/core/lib/size.ts new file mode 100644 index 0000000000000..ec18845ddaa4c --- /dev/null +++ b/packages/@aws-cdk/core/lib/size.ts @@ -0,0 +1,140 @@ +import { Token } from "./token"; + +/** + * Represents the amount of digital storage. + * + * The amount can be specified either as a literal value (e.g: `10`) which + * cannot be negative, or as an unresolved number token. + * + * When the amount is passed as a token, unit conversion is not possible. + */ +export class Size { + /** + * Create a Storage representing an amount kibibytes. + * 1 KiB = 1024 bytes + */ + public static kibibytes(amount: number): Size { + return new Size(amount, StorageUnit.Kibibytes); + } + + /** + * Create a Storage representing an amount mebibytes. + * 1 MiB = 1024 KiB + */ + public static mebibytes(amount: number): Size { + return new Size(amount, StorageUnit.Mebibytes); + } + + /** + * Create a Storage representing an amount mebibytes. + * 1 GiB = 1024 MiB + */ + public static gibibytes(amount: number): Size { + return new Size(amount, StorageUnit.Gibibytes); + } + + /** + * Create a Storage representing an amount tebibytes. + * 1 TiB = 1024 GiB + */ + public static tebibytes(amount: number): Size { + return new Size(amount, StorageUnit.Tebibytes); + } + + /** + * Create a Storage representing an amount pebibytes. + * 1 PiB = 1024 TiB + */ + public static pebibyte(amount: number): Size { + return new Size(amount, StorageUnit.Pebibytes); + } + + private readonly amount: number; + private readonly unit: StorageUnit; + + private constructor(amount: number, unit: StorageUnit) { + if (!Token.isUnresolved(amount) && amount < 0) { + throw new Error(`Storage amounts cannot be negative. Received: ${amount}`); + } + this.amount = amount; + this.unit = unit; + } + + /** + * Return this storage as a total number of kibibytes. + */ + public toKibibytes(opts: StorageConversionOptions = {}): number { + return convert(this.amount, this.unit, StorageUnit.Kibibytes, opts); + } + + /** + * Return this storage as a total number of mebibytes. + */ + public toMebibytes(opts: StorageConversionOptions = {}): number { + return convert(this.amount, this.unit, StorageUnit.Mebibytes, opts); + } + + /** + * Return this storage as a total number of gibibytes. + */ + public toGibibytes(opts: StorageConversionOptions = {}): number { + return convert(this.amount, this.unit, StorageUnit.Gibibytes, opts); + } + + /** + * Return this storage as a total number of tebibytes. + */ + public toTebibytes(opts: StorageConversionOptions = {}): number { + return convert(this.amount, this.unit, StorageUnit.Tebibytes, opts); + } + + /** + * Return this storage as a total number of pebibytes. + */ + public toPebibytes(opts: StorageConversionOptions = {}): number { + return convert(this.amount, this.unit, StorageUnit.Pebibytes, opts); + } +} + +/** + * Options for how to convert time to a different unit. + */ +export interface StorageConversionOptions { + /** + * If `true`, conversions into a larger storage units (e.g. `Kibibytes` to `Mebibytes`) will fail if the result is not + * an integer. + * @default true + */ + readonly integral?: boolean; +} + +class StorageUnit { + public static readonly Kibibytes = new StorageUnit('kibibytes', 1); + public static readonly Mebibytes = new StorageUnit('mebibytes', 1024); + public static readonly Gibibytes = new StorageUnit('gibibytes', 1024 * 1024); + public static readonly Tebibytes = new StorageUnit('tebibytes', 1024 * 1024 * 1024); + public static readonly Pebibytes = new StorageUnit('pebibytes', 1024 * 1024 * 1024 * 1024); + + private constructor(public readonly label: string, public readonly inKibiBytes: number) { + // MAX_SAFE_INTEGER is 2^53, so by representing storage in kibibytes, + // the highest storage we can represent is 8 exbibytes. + } + + public toString() { + return this.label; + } +} + +function convert(amount: number, fromUnit: StorageUnit, toUnit: StorageUnit, { integral = true }: StorageConversionOptions) { + if (fromUnit.inKibiBytes === toUnit.inKibiBytes) { return amount; } + if (Token.isUnresolved(amount)) { + throw new Error(`Unable to perform time unit conversion on un-resolved token ${amount}.`); + } + + const multiplier = fromUnit.inKibiBytes / toUnit.inKibiBytes; + const value = amount * multiplier; + if (!Number.isInteger(value) && integral) { + throw new Error(`'${amount} ${fromUnit}' cannot be converted into a whole number of ${toUnit}.`); + } + return value; +} diff --git a/packages/@aws-cdk/core/test/test.size.ts b/packages/@aws-cdk/core/test/test.size.ts new file mode 100644 index 0000000000000..b1eb953543230 --- /dev/null +++ b/packages/@aws-cdk/core/test/test.size.ts @@ -0,0 +1,103 @@ +import { Test } from 'nodeunit'; +import { Size, Stack, Token } from '../lib'; + +export = { + 'negative amount'(test: Test) { + test.throws(() => Size.kibibytes(-1), /negative/); + + test.done(); + }, + + 'unresolved amount'(test: Test) { + const stack = new Stack(); + const lazySize = Size.kibibytes(Token.asNumber({ resolve: () => 1337 })); + test.equals(stack.resolve(lazySize.toKibibytes()), 1337); + test.throws( + () => stack.resolve(lazySize.toMebibytes()), + /Unable to perform time unit conversion on un-resolved token/ + ); + + test.done(); + }, + + 'Size in kibibytes'(test: Test) { + const size = Size.kibibytes(4_294_967_296); + + test.equal(size.toKibibytes(), 4_294_967_296); + test.equal(size.toMebibytes(), 4_194_304); + test.equal(size.toGibibytes(), 4_096); + test.equal(size.toTebibytes(), 4); + test.throws(() => size.toPebibytes(), /'4294967296 kibibytes' cannot be converted into a whole number/); + floatEqual(test, size.toPebibytes({ integral: false }), 4_294_967_296 / (1024 * 1024 * 1024 * 1024)); + + test.equal(Size.kibibytes(4 * 1024 * 1024).toGibibytes(), 4); + + test.done(); + }, + + 'Size in mebibytes'(test: Test) { + const size = Size.mebibytes(4_194_304); + + test.equal(size.toKibibytes(), 4_294_967_296); + test.equal(size.toMebibytes(), 4_194_304); + test.equal(size.toGibibytes(), 4_096); + test.equal(size.toTebibytes(), 4); + test.throws(() => size.toPebibytes(), /'4194304 mebibytes' cannot be converted into a whole number/); + floatEqual(test, size.toPebibytes({ integral: false }), 4_194_304 / (1024 * 1024 * 1024)); + + test.equal(Size.mebibytes(4 * 1024).toGibibytes(), 4); + + test.done(); + }, + + 'Size in gibibyte'(test: Test) { + const size = Size.gibibytes(5); + + test.equal(size.toKibibytes(), 5_242_880); + test.equal(size.toMebibytes(), 5_120); + test.equal(size.toGibibytes(), 5); + test.throws(() => size.toTebibytes(), /'5 gibibytes' cannot be converted into a whole number/); + floatEqual(test, size.toTebibytes({ integral: false }), 5 / 1024); + test.throws(() => size.toPebibytes(), /'5 gibibytes' cannot be converted into a whole number/); + floatEqual(test, size.toPebibytes({ integral: false }), 5 / (1024 * 1024)); + + test.equal(Size.gibibytes(4096).toTebibytes(), 4); + + test.done(); + }, + + 'Size in tebibyte'(test: Test) { + const size = Size.tebibytes(5); + + test.equal(size.toKibibytes(), 5_368_709_120); + test.equal(size.toMebibytes(), 5_242_880); + test.equal(size.toGibibytes(), 5_120); + test.equal(size.toTebibytes(), 5); + test.throws(() => size.toPebibytes(), /'5 tebibytes' cannot be converted into a whole number/); + floatEqual(test, size.toPebibytes({ integral: false }), 5 / 1024); + + test.equal(Size.tebibytes(4096).toPebibytes(), 4); + + test.done(); + }, + + 'Size in pebibyte'(test: Test) { + const size = Size.pebibyte(5); + + test.equal(size.toKibibytes(), 5_497_558_138_880); + test.equal(size.toMebibytes(), 5_368_709_120); + test.equal(size.toGibibytes(), 5_242_880); + test.equal(size.toTebibytes(), 5_120); + test.equal(size.toPebibytes(), 5); + + test.done(); + }, +}; + +function floatEqual(test: Test, actual: number, expected: number) { + test.ok( + // Floats are subject to rounding errors up to Number.ESPILON + actual >= expected - Number.EPSILON && actual <= expected + Number.EPSILON, + `${actual} == ${expected}`, + ); +} From afd70453de70e8e54bfd941404efda74d594e0e6 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Thu, 26 Mar 2020 16:35:15 +0100 Subject: [PATCH 03/53] fix(cli): can't use credential providers for stacks with assets (#7022) * fix(cli): can't use credential providers for stacks with assets Stacks with assets were broken for environments that completely used credential providers (and no other sources of AWS credentials). Not because the wrong credentials were being used (as you would expect it to be broken). Instead, an error was being thrown because the "current" account lookup was incorrectly forwarding to the "default" account lookup (fix: we know what the current account is. Just return that instead). What's worse, this value wasn't even being used! It was being looked up so that if something was wrong finding the target bucket, we could format a nice error message containing the account id. Even happy paths were failing due to the premature lookup though (fix: only look up when we actually need the value). Fixes #7005. * Properly look up partition so this also works in aws-cn Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- packages/aws-cdk/lib/api/aws-auth/sdk.ts | 6 +++++ packages/aws-cdk/lib/util/asset-publishing.ts | 23 ++++++++++++---- packages/aws-cdk/test/assets.test.ts | 26 +++++++++++++++++++ .../cdk-assets/lib/private/handlers/files.ts | 8 +++--- packages/cdk-assets/test/files.test.ts | 11 ++++++++ 5 files changed, 66 insertions(+), 8 deletions(-) diff --git a/packages/aws-cdk/lib/api/aws-auth/sdk.ts b/packages/aws-cdk/lib/api/aws-auth/sdk.ts index cd178d735acec..98933e33e9fa9 100644 --- a/packages/aws-cdk/lib/api/aws-auth/sdk.ts +++ b/packages/aws-cdk/lib/api/aws-auth/sdk.ts @@ -14,6 +14,8 @@ export interface ISDK { route53(): AWS.Route53; ecr(): AWS.ECR; + + sts(): AWS.STS; } /** @@ -66,4 +68,8 @@ export class SDK implements ISDK { public ecr(): AWS.ECR { return new AWS.ECR(this.config); } + + public sts(): AWS.STS { + return new AWS.STS(this.config); + } } \ No newline at end of file diff --git a/packages/aws-cdk/lib/util/asset-publishing.ts b/packages/aws-cdk/lib/util/asset-publishing.ts index 604e52cd528a3..e90c53d899851 100644 --- a/packages/aws-cdk/lib/util/asset-publishing.ts +++ b/packages/aws-cdk/lib/util/asset-publishing.ts @@ -8,6 +8,13 @@ import { debug, error, print } from '../logging'; * Use cdk-assets to publish all assets in the given manifest. */ export async function publishAssets(manifest: cdk_assets.AssetManifest, sdk: SdkProvider, targetEnv: cxapi.Environment) { + // This shouldn't really happen (it's a programming error), but we don't have + // the types here to guide us. Do an runtime validation to be super super sure. + if (targetEnv.account === undefined || targetEnv.account === cxapi.UNKNOWN_ACCOUNT + || targetEnv.region === undefined || targetEnv.account === cxapi.UNKNOWN_REGION) { + throw new Error(`Asset publishing requires resolved account and region, got ${JSON.stringify(targetEnv)}`); + } + const publisher = new cdk_assets.AssetPublishing(manifest, { aws: new PublishingAws(sdk, targetEnv), progressListener: new PublishingProgressListener(), @@ -33,15 +40,21 @@ class PublishingAws implements cdk_assets.IAws { } public async discoverDefaultRegion(): Promise { - return this.aws.defaultRegion; + return this.targetEnv.region; } public async discoverCurrentAccount(): Promise { - const account = await this.aws.defaultAccount(); - if (!account) { - throw new Error('AWS credentials are required to upload assets. Please configure environment variables or ~/.aws/credentials.'); + // Discover the current partition given current credentials. We already + // have the target environment, but it doesn't contain the partition yet. + // + // Until it does, we need to do a lookup here. + const sts = (await this.sdk({})).sts(); + const response = await sts.getCallerIdentity().promise(); + if (!response.Arn) { + throw new Error(`Unexpected STS response: ${JSON.stringify(response)}`); } - return account; + const partition = response.Arn!.split(':')[1]; + return { accountId: this.targetEnv.account, partition }; } public async s3Client(options: cdk_assets.ClientOptions): Promise { diff --git a/packages/aws-cdk/test/assets.test.ts b/packages/aws-cdk/test/assets.test.ts index af6a7d25883a6..985df6cdba210 100644 --- a/packages/aws-cdk/test/assets.test.ts +++ b/packages/aws-cdk/test/assets.test.ts @@ -1,8 +1,11 @@ import { AssetMetadataEntry } from '@aws-cdk/cx-api'; +import { AssetManifest } from 'cdk-assets'; import { ToolkitInfo } from '../lib'; import { addMetadataAssetsToManifest } from '../lib/assets'; import { AssetManifestBuilder } from '../lib/util/asset-manifest-builder'; +import { publishAssets } from '../lib/util/asset-publishing'; import { testStack } from './util'; +import { MockSDK } from './util/mock-sdk'; let toolkit: ToolkitInfo; let assets: AssetManifestBuilder; @@ -218,6 +221,29 @@ describe('docker assets', () => { }); }); +test('publishing does not fail if there is no "default" account', () => { + // GIVEN + const manifest = new AssetManifest('.', { + version: '0', + files: { + assetId: { + source: { path: __filename }, + destinations: { + theDestination: { + bucketName: '${AWS::AccountId}-bucket', + objectKey: 'key', + }, + } + }, + }, + }); + const provider = new MockSDK(); + provider.defaultAccount = jest.fn(() => Promise.resolve(undefined)); + + // WHEN + publishAssets(manifest, provider, { account: '12345678', region: 'aa-south-1', name: 'main' }); +}); + function stackWithAssets(assetEntries: AssetMetadataEntry[]) { return testStack({ stackName: 'SomeStack', diff --git a/packages/cdk-assets/lib/private/handlers/files.ts b/packages/cdk-assets/lib/private/handlers/files.ts index 8b5b894ee3fd4..300c463601c50 100644 --- a/packages/cdk-assets/lib/private/handlers/files.ts +++ b/packages/cdk-assets/lib/private/handlers/files.ts @@ -25,14 +25,16 @@ export class FileAssetHandler implements IAssetHandler { const s3 = await this.host.aws.s3Client(destination); this.host.emitMessage(EventType.CHECK, `Check ${s3Url}`); - const account = await this.host.aws.discoverCurrentAccount(); + // A thunk for describing the current account. Used when we need to format an error + // message, not in the success case. + const account = async () => (await this.host.aws.discoverCurrentAccount())?.accountId; switch (await bucketOwnership(s3, destination.bucketName)) { case BucketOwnership.MINE: break; case BucketOwnership.DOES_NOT_EXIST: - throw new Error(`No bucket named '${destination.bucketName}'. Is account ${account} bootstrapped?`); + throw new Error(`No bucket named '${destination.bucketName}'. Is account ${await account()} bootstrapped?`); case BucketOwnership.SOMEONE_ELSES_OR_NO_ACCESS: - throw new Error(`Bucket named '${destination.bucketName}' exists, but not in account ${account}. Wrong account?`); + throw new Error(`Bucket named '${destination.bucketName}' exists, but not in account ${await account()}. Wrong account?`); } if (await objectExists(s3, destination.bucketName, destination.objectKey)) { diff --git a/packages/cdk-assets/test/files.test.ts b/packages/cdk-assets/test/files.test.ts index 8b444d6b9260f..6c5e9c131e8f7 100644 --- a/packages/cdk-assets/test/files.test.ts +++ b/packages/cdk-assets/test/files.test.ts @@ -92,6 +92,17 @@ test('upload file if new', async () => { // We'll just have to assume the contents are correct }); +test('successful run does not need to query account ID', async () => { + const pub = new AssetPublishing(AssetManifest.fromPath('/simple/cdk.out'), { aws }); + + aws.mockS3.headObject = mockedApiFailure('NotFound', 'File does not exist'); + aws.mockS3.upload = mockUpload('FILE_CONTENTS'); + + await pub.publish(); + + expect(aws.discoverCurrentAccount).not.toHaveBeenCalled(); +}); + test('correctly identify asset path if path is absolute', async () => { const pub = new AssetPublishing(AssetManifest.fromPath('/abs/cdk.out'), { aws }); From ca19dc454d18ec1ea1b48230610fa2405e28ab0f Mon Sep 17 00:00:00 2001 From: Niranjan Jayakar Date: Thu, 26 Mar 2020 16:32:07 +0000 Subject: [PATCH 04/53] chore: revert mergify behaviour (#7025) A [previous commit][1] changed the behaviour of mergify to not dismiss PR reviews marked 'changes requested', and let the PR authors dismiss the review when they're ready. It was not considered that dismiss PR reviews is an privileged action available only to admins of the repo. Quoting [Github documentation][2], "repository administrators or people with write access can dismiss a review". Reverting this change to its previous behaviour. [1]: https://github.com/aws/aws-cdk/commit/9ad04485021a3132dd2bb97475fb4f945df7df3a [2]: https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/dismissing-a-pull-request-review --- .mergify.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.mergify.yml b/.mergify.yml index 1aeba69346865..f9c1230893663 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -56,17 +56,11 @@ pull_request_rules: - status-success~=AWS CodeBuild us-east-1 - status-success=Semantic Pull Request - status-success=mandatory-changes - - name: when changes are requested - actions: - comment: - message: Once all the requested changes have been addressed, and the PR is ready for another review, remember to [dismiss the review](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/dismissing-a-pull-request-review). - conditions: - - "#changes-requested-reviews-by>=1" - name: remove stale reviews actions: dismiss_reviews: approved: true - changes_requested: false + changes_requested: true conditions: - author!=dependabot[bot] - author!=dependabot-preview[bot] From 53efde5b991c135d6a0a3bdc8e894e8cfad92a07 Mon Sep 17 00:00:00 2001 From: Niranjan Jayakar Date: Thu, 26 Mar 2020 19:51:49 +0000 Subject: [PATCH 05/53] chore(core): improved rounding options to Size (#7027) * Following up to fix up with comments - https://github.com/aws/aws-cdk/pull/6940#discussion_r398570513 * Fixing up a missed rename from the previuos change. Rename `StorageConversionOptions` to `SizeConversionOptions`. Given that we have not released these changes yet, this should not be a breaking change. --- packages/@aws-cdk/core/lib/size.ts | 49 +++++++++++++++++------- packages/@aws-cdk/core/test/test.size.ts | 29 +++++++++++--- 2 files changed, 58 insertions(+), 20 deletions(-) diff --git a/packages/@aws-cdk/core/lib/size.ts b/packages/@aws-cdk/core/lib/size.ts index ec18845ddaa4c..5c87e4f670290 100644 --- a/packages/@aws-cdk/core/lib/size.ts +++ b/packages/@aws-cdk/core/lib/size.ts @@ -63,49 +63,61 @@ export class Size { /** * Return this storage as a total number of kibibytes. */ - public toKibibytes(opts: StorageConversionOptions = {}): number { + public toKibibytes(opts: SizeConversionOptions = {}): number { return convert(this.amount, this.unit, StorageUnit.Kibibytes, opts); } /** * Return this storage as a total number of mebibytes. */ - public toMebibytes(opts: StorageConversionOptions = {}): number { + public toMebibytes(opts: SizeConversionOptions = {}): number { return convert(this.amount, this.unit, StorageUnit.Mebibytes, opts); } /** * Return this storage as a total number of gibibytes. */ - public toGibibytes(opts: StorageConversionOptions = {}): number { + public toGibibytes(opts: SizeConversionOptions = {}): number { return convert(this.amount, this.unit, StorageUnit.Gibibytes, opts); } /** * Return this storage as a total number of tebibytes. */ - public toTebibytes(opts: StorageConversionOptions = {}): number { + public toTebibytes(opts: SizeConversionOptions = {}): number { return convert(this.amount, this.unit, StorageUnit.Tebibytes, opts); } /** * Return this storage as a total number of pebibytes. */ - public toPebibytes(opts: StorageConversionOptions = {}): number { + public toPebibytes(opts: SizeConversionOptions = {}): number { return convert(this.amount, this.unit, StorageUnit.Pebibytes, opts); } } +/** + * Rouding behaviour when converting between units of `Size`. + */ +export enum SizeRoundingBehavior { + /** Fail the conversion if the result is not an integer. */ + FAIL, + /** If the result is not an integer, round it to the closest integer less than the result */ + FLOOR, + /** Don't round. Return even if the result is a fraction. */ + NONE, + +} + /** * Options for how to convert time to a different unit. */ -export interface StorageConversionOptions { +export interface SizeConversionOptions { /** - * If `true`, conversions into a larger storage units (e.g. `Kibibytes` to `Mebibytes`) will fail if the result is not - * an integer. - * @default true + * How conversions should behave when it encounters a non-integer result + * @default SizeRoundingBehavior.FAIL */ - readonly integral?: boolean; + readonly rounding?: SizeRoundingBehavior; } class StorageUnit { @@ -125,7 +137,8 @@ class StorageUnit { } } -function convert(amount: number, fromUnit: StorageUnit, toUnit: StorageUnit, { integral = true }: StorageConversionOptions) { +function convert(amount: number, fromUnit: StorageUnit, toUnit: StorageUnit, options: SizeConversionOptions = {}) { + const rounding = options.rounding ?? SizeRoundingBehavior.FAIL; if (fromUnit.inKibiBytes === toUnit.inKibiBytes) { return amount; } if (Token.isUnresolved(amount)) { throw new Error(`Unable to perform time unit conversion on un-resolved token ${amount}.`); @@ -133,8 +146,16 @@ function convert(amount: number, fromUnit: StorageUnit, toUnit: StorageUnit, { i const multiplier = fromUnit.inKibiBytes / toUnit.inKibiBytes; const value = amount * multiplier; - if (!Number.isInteger(value) && integral) { - throw new Error(`'${amount} ${fromUnit}' cannot be converted into a whole number of ${toUnit}.`); + switch (rounding) { + case SizeRoundingBehavior.NONE: + return value; + case SizeRoundingBehavior.FLOOR: + return Math.floor(value); + default: + case SizeRoundingBehavior.FAIL: + if (!Number.isInteger(value)) { + throw new Error(`'${amount} ${fromUnit}' cannot be converted into a whole number of ${toUnit}.`); + } + return value; } - return value; } diff --git a/packages/@aws-cdk/core/test/test.size.ts b/packages/@aws-cdk/core/test/test.size.ts index b1eb953543230..9bbf2135b3b13 100644 --- a/packages/@aws-cdk/core/test/test.size.ts +++ b/packages/@aws-cdk/core/test/test.size.ts @@ -1,5 +1,5 @@ import { Test } from 'nodeunit'; -import { Size, Stack, Token } from '../lib'; +import { Size, SizeRoundingBehavior, Stack, Token } from '../lib'; export = { 'negative amount'(test: Test) { @@ -28,7 +28,7 @@ export = { test.equal(size.toGibibytes(), 4_096); test.equal(size.toTebibytes(), 4); test.throws(() => size.toPebibytes(), /'4294967296 kibibytes' cannot be converted into a whole number/); - floatEqual(test, size.toPebibytes({ integral: false }), 4_294_967_296 / (1024 * 1024 * 1024 * 1024)); + floatEqual(test, size.toPebibytes({ rounding: SizeRoundingBehavior.NONE }), 4_294_967_296 / (1024 * 1024 * 1024 * 1024)); test.equal(Size.kibibytes(4 * 1024 * 1024).toGibibytes(), 4); @@ -43,7 +43,7 @@ export = { test.equal(size.toGibibytes(), 4_096); test.equal(size.toTebibytes(), 4); test.throws(() => size.toPebibytes(), /'4194304 mebibytes' cannot be converted into a whole number/); - floatEqual(test, size.toPebibytes({ integral: false }), 4_194_304 / (1024 * 1024 * 1024)); + floatEqual(test, size.toPebibytes({ rounding: SizeRoundingBehavior.NONE }), 4_194_304 / (1024 * 1024 * 1024)); test.equal(Size.mebibytes(4 * 1024).toGibibytes(), 4); @@ -57,9 +57,9 @@ export = { test.equal(size.toMebibytes(), 5_120); test.equal(size.toGibibytes(), 5); test.throws(() => size.toTebibytes(), /'5 gibibytes' cannot be converted into a whole number/); - floatEqual(test, size.toTebibytes({ integral: false }), 5 / 1024); + floatEqual(test, size.toTebibytes({ rounding: SizeRoundingBehavior.NONE }), 5 / 1024); test.throws(() => size.toPebibytes(), /'5 gibibytes' cannot be converted into a whole number/); - floatEqual(test, size.toPebibytes({ integral: false }), 5 / (1024 * 1024)); + floatEqual(test, size.toPebibytes({ rounding: SizeRoundingBehavior.NONE }), 5 / (1024 * 1024)); test.equal(Size.gibibytes(4096).toTebibytes(), 4); @@ -74,7 +74,7 @@ export = { test.equal(size.toGibibytes(), 5_120); test.equal(size.toTebibytes(), 5); test.throws(() => size.toPebibytes(), /'5 tebibytes' cannot be converted into a whole number/); - floatEqual(test, size.toPebibytes({ integral: false }), 5 / 1024); + floatEqual(test, size.toPebibytes({ rounding: SizeRoundingBehavior.NONE }), 5 / 1024); test.equal(Size.tebibytes(4096).toPebibytes(), 4); @@ -92,6 +92,23 @@ export = { test.done(); }, + + 'rounding behavior'(test: Test) { + const size = Size.mebibytes(5_200); + + test.throws(() => size.toGibibytes(), /cannot be converted into a whole number/); + test.throws(() => size.toGibibytes({ rounding: SizeRoundingBehavior.FAIL }), /cannot be converted into a whole number/); + + test.equals(size.toGibibytes({ rounding: SizeRoundingBehavior.FLOOR }), 5); + test.equals(size.toTebibytes({ rounding: SizeRoundingBehavior.FLOOR }), 0); + floatEqual(test, size.toKibibytes({ rounding: SizeRoundingBehavior.FLOOR }), 5_324_800); + + test.equals(size.toGibibytes({ rounding: SizeRoundingBehavior.NONE}), 5.078125); + test.equals(size.toTebibytes({ rounding: SizeRoundingBehavior.NONE}), 5200 / (1024 * 1024)); + test.equals(size.toKibibytes({ rounding: SizeRoundingBehavior.NONE}), 5_324_800); + + test.done(); + } }; function floatEqual(test: Test, actual: number, expected: number) { From 1186227b01e73cb05425549aeac88630c9a5ff58 Mon Sep 17 00:00:00 2001 From: Shiv Lakshminarayan Date: Fri, 27 Mar 2020 01:49:06 -0700 Subject: [PATCH 06/53] fix(kinesis): retention period does not use Duration type (#7037) fix(kinesis): retention period does not use Duration type Rationale: Consistency with how time intervals are defined across the construct library. Also fixed previously broken validation on retention period and updated tests. Closes #7036 BREAKING CHANGE: `retentionPeriodHours` is now `retentionPeriod` and of type `Duration` --- packages/@aws-cdk/aws-kinesis/lib/stream.ts | 12 ++++---- .../@aws-cdk/aws-kinesis/test/test.stream.ts | 30 ++++++++----------- 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/packages/@aws-cdk/aws-kinesis/lib/stream.ts b/packages/@aws-cdk/aws-kinesis/lib/stream.ts index a60deba2c5d13..09cc92e05e722 100644 --- a/packages/@aws-cdk/aws-kinesis/lib/stream.ts +++ b/packages/@aws-cdk/aws-kinesis/lib/stream.ts @@ -1,6 +1,6 @@ import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; -import { Construct, IResource, Resource, Stack } from '@aws-cdk/core'; +import { Construct, Duration, IResource, Resource, Stack } from '@aws-cdk/core'; import { CfnStream } from './kinesis.generated'; /** @@ -185,9 +185,9 @@ export interface StreamProps { /** * The number of hours for the data records that are stored in shards to remain accessible. - * @default 24 + * @default Duration.hours(24) */ - readonly retentionPeriodHours?: number; + readonly retentionPeriod?: Duration; /** * The number of shards for the stream. @@ -261,9 +261,9 @@ export class Stream extends StreamBase { }); const shardCount = props.shardCount || 1; - const retentionPeriodHours = props.retentionPeriodHours || 24; - if (retentionPeriodHours < 24 && retentionPeriodHours > 168) { - throw new Error("retentionPeriodHours must be between 24 and 168 hours"); + const retentionPeriodHours = props.retentionPeriod?.toHours() ?? 24; + if (retentionPeriodHours < 24 || retentionPeriodHours > 168) { + throw new Error(`retentionPeriod must be between 24 and 168 hours. Received ${retentionPeriodHours}`); } const { streamEncryption, encryptionKey } = this.parseEncryption(props); diff --git a/packages/@aws-cdk/aws-kinesis/test/test.stream.ts b/packages/@aws-cdk/aws-kinesis/test/test.stream.ts index 6cf2b7cb1638e..40c37a49296ea 100644 --- a/packages/@aws-cdk/aws-kinesis/test/test.stream.ts +++ b/packages/@aws-cdk/aws-kinesis/test/test.stream.ts @@ -1,7 +1,7 @@ import { expect } from '@aws-cdk/assert'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; -import { App, Stack } from '@aws-cdk/core'; +import { App, Duration, Stack } from '@aws-cdk/core'; import { Test } from 'nodeunit'; import { Stream, StreamEncryption } from '../lib'; @@ -64,8 +64,8 @@ export = { "uses explicit retention period"(test: Test) { const stack = new Stack(); - new Stream(stack, 'MyStream', { - retentionPeriodHours: 168 + new Stream(stack, "MyStream", { + retentionPeriod: Duration.hours(168) }); expect(stack).toMatch({ @@ -83,23 +83,17 @@ export = { test.done(); }, "retention period must be between 24 and 168 hours"(test: Test) { - test.throws({ - block: () => { - new Stream(new Stack(), 'MyStream', { - retentionPeriodHours: 169 - }); - }, - message: "retentionPeriodHours must be between 24 and 168 hours" - }); + test.throws(() => { + new Stream(new Stack(), 'MyStream', { + retentionPeriod: Duration.hours(169) + }); + }, /retentionPeriod must be between 24 and 168 hours. Received 169/); - test.throws({ - block: () => { + test.throws(() => { new Stream(new Stack(), 'MyStream', { - retentionPeriodHours: 23 - }); - }, - message: "retentionPeriodHours must be between 24 and 168 hours" - }); + retentionPeriod: Duration.hours(23) + }); + }, /retentionPeriod must be between 24 and 168 hours. Received 23/); test.done(); }, From 855af6a1444a4bb3edae9c08f4653f1a1370cf0f Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Fri, 27 Mar 2020 11:22:32 +0100 Subject: [PATCH 07/53] chore: fix test by adding 'await' and setting up mocks (#7028) The test was passing previously, but that's because I forgot the 'await'. Oops. --- packages/aws-cdk/test/assets.test.ts | 24 +++++++++++++++++++----- packages/aws-cdk/test/util/mock-sdk.ts | 20 ++++++++++++++++++++ 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/packages/aws-cdk/test/assets.test.ts b/packages/aws-cdk/test/assets.test.ts index 985df6cdba210..764abd184eca2 100644 --- a/packages/aws-cdk/test/assets.test.ts +++ b/packages/aws-cdk/test/assets.test.ts @@ -5,7 +5,7 @@ import { addMetadataAssetsToManifest } from '../lib/assets'; import { AssetManifestBuilder } from '../lib/util/asset-manifest-builder'; import { publishAssets } from '../lib/util/asset-publishing'; import { testStack } from './util'; -import { MockSDK } from './util/mock-sdk'; +import { errorWithCode, MockSDK } from './util/mock-sdk'; let toolkit: ToolkitInfo; let assets: AssetManifestBuilder; @@ -221,7 +221,7 @@ describe('docker assets', () => { }); }); -test('publishing does not fail if there is no "default" account', () => { +test('publishing does not fail if there is no "default" account', async () => { // GIVEN const manifest = new AssetManifest('.', { version: '0', @@ -230,7 +230,7 @@ test('publishing does not fail if there is no "default" account', () => { source: { path: __filename }, destinations: { theDestination: { - bucketName: '${AWS::AccountId}-bucket', + bucketName: '${AWS::AccountId}-${AWS::Partition}-bucket', objectKey: 'key', }, } @@ -239,9 +239,23 @@ test('publishing does not fail if there is no "default" account', () => { }); const provider = new MockSDK(); provider.defaultAccount = jest.fn(() => Promise.resolve(undefined)); + provider.stubSTS({ + // Necessary to potentially replace partition + getCallerIdentity() { return { Account: 'UNUSED', Arn: 'arn:aws-aa:1234:stuff', UserId: 'userId' }; } + }); + provider.stubS3({ + getBucketLocation() { return { LocationConstraint: 'abc' }; }, + headObject(options) { + if (options.Bucket !== '12345678-aws-aa-bucket') { + throw new Error(`Unexpected bucket name: ${options.Bucket}`); + } + throw errorWithCode('NotFound', 'Does not exist eh'); + }, + upload: (() => undefined) as any, + }); // WHEN - publishAssets(manifest, provider, { account: '12345678', region: 'aa-south-1', name: 'main' }); + await publishAssets(manifest, provider, { account: '12345678', region: 'aa-south-1', name: 'main' }); }); function stackWithAssets(assetEntries: AssetMetadataEntry[]) { @@ -263,4 +277,4 @@ function mockFn any>(fn: F): jest.Mock throw new Error(`Not a mock function: ${fn}`); } return fn; -} \ No newline at end of file +} diff --git a/packages/aws-cdk/test/util/mock-sdk.ts b/packages/aws-cdk/test/util/mock-sdk.ts index c11fdf307c7f6..b4dac6cc6cf35 100644 --- a/packages/aws-cdk/test/util/mock-sdk.ts +++ b/packages/aws-cdk/test/util/mock-sdk.ts @@ -42,6 +42,20 @@ export class MockSDK extends SdkProvider { public stubEcr(stubs: SyncHandlerSubsetOf) { (this.sdk as any).ecr = jest.fn().mockReturnValue(partialAwsService(stubs)); } + + /** + * Replace the S3 client with the given object + */ + public stubS3(stubs: SyncHandlerSubsetOf) { + (this.sdk as any).s3 = jest.fn().mockReturnValue(partialAwsService(stubs)); + } + + /** + * Replace the STS client with the given object + */ + public stubSTS(stubs: SyncHandlerSubsetOf) { + (this.sdk as any).sts = jest.fn().mockReturnValue(partialAwsService(stubs)); + } } /** @@ -128,3 +142,9 @@ export function mockToolkitInfo() { environment: { name: 'env', account: '1234', region: 'abc' } }); } + +export function errorWithCode(code: string, message: string) { + const ret = new Error(message); + (ret as any).code = code; + return ret; +} From aa60f8901257bcf7de4db0d8207661ce70d6c42a Mon Sep 17 00:00:00 2001 From: Erik Snoek Date: Fri, 27 Mar 2020 17:40:58 +0100 Subject: [PATCH 08/53] feat(rds): aurora - iam role to import and export data from s3 (#6611) closes #6610 --- packages/@aws-cdk/aws-rds/README.md | 27 + packages/@aws-cdk/aws-rds/lib/cluster.ts | 130 +++- packages/@aws-cdk/aws-rds/lib/instance.ts | 83 +- .../@aws-cdk/aws-rds/lib/parameter-group.ts | 32 +- .../@aws-cdk/aws-rds/lib/private/version.ts | 21 + packages/@aws-cdk/aws-rds/lib/props.ts | 58 +- packages/@aws-cdk/aws-rds/package.json | 2 + .../test/integ.cluster-s3.expected.json | 715 ++++++++++++++++++ .../@aws-cdk/aws-rds/test/integ.cluster-s3.ts | 35 + .../@aws-cdk/aws-rds/test/integ.cluster.ts | 1 + .../aws-rds/test/private/test.version.ts | 38 + .../@aws-cdk/aws-rds/test/test.cluster.ts | 509 ++++++++++++- .../aws-rds/test/test.parameter-group.ts | 28 + packages/@aws-cdk/aws-rds/test/test.props.ts | 111 +++ 14 files changed, 1768 insertions(+), 22 deletions(-) create mode 100644 packages/@aws-cdk/aws-rds/lib/private/version.ts create mode 100644 packages/@aws-cdk/aws-rds/test/integ.cluster-s3.expected.json create mode 100644 packages/@aws-cdk/aws-rds/test/integ.cluster-s3.ts create mode 100644 packages/@aws-cdk/aws-rds/test/private/test.version.ts create mode 100644 packages/@aws-cdk/aws-rds/test/test.props.ts diff --git a/packages/@aws-cdk/aws-rds/README.md b/packages/@aws-cdk/aws-rds/README.md index cfa53cc0a4abc..10ec97869b1d3 100644 --- a/packages/@aws-cdk/aws-rds/README.md +++ b/packages/@aws-cdk/aws-rds/README.md @@ -167,3 +167,30 @@ const dbConnections = instance.metricDatabaseConnections(); // The average amount of time taken per disk I/O operation (average over 1 minute) const readLatency = instance.metric('ReadLatency', { statistic: 'Average', periodSec: 60 }); ``` + +### Enabling S3 integration to a cluster (non-serverless Aurora only) + +Data in S3 buckets can be imported to and exported from Aurora databases using SQL queries. To enable this +functionality, set the `s3ImportBuckets` and `s3ExportBuckets` properties for import and export respectively. When +configured, the CDK automatically creates and configures IAM roles as required. +Additionally, the `s3ImportRole` and `s3ExportRole` properties can be used to set this role directly. + +For Aurora MySQL, read more about [loading data from +S3](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Integrating.LoadFromS3.html) and [saving +data into S3](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Integrating.SaveIntoS3.html). + +For Aurora PostgreSQL, read more about [loading data from +S3](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.Migrating.html) and [saving +data into S3](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/postgresql-s3-export.html). + +The following snippet sets up a database cluster with different S3 buckets where the data is imported and exported - + +```ts +const importBucket = new s3.Bucket(this, 'importbucket'); +const exportBucket = new s3.Bucket(this, 'exportbucket'); +new DatabaseCluster(this, 'dbcluster', { + // ... + s3ImportBuckets: [ importBucket ], + s3ExportBuckets: [ exportBucket ] +}); +``` diff --git a/packages/@aws-cdk/aws-rds/lib/cluster.ts b/packages/@aws-cdk/aws-rds/lib/cluster.ts index 3cb4fd321e05c..3a3bdde0b0fdb 100644 --- a/packages/@aws-cdk/aws-rds/lib/cluster.ts +++ b/packages/@aws-cdk/aws-rds/lib/cluster.ts @@ -1,12 +1,13 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import { IRole, ManagedPolicy, Role, ServicePrincipal } from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; +import * as s3 from '@aws-cdk/aws-s3'; import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; import { Construct, Duration, RemovalPolicy, Resource, Token } from '@aws-cdk/core'; import { DatabaseClusterAttributes, IDatabaseCluster } from './cluster-ref'; import { DatabaseSecret } from './database-secret'; import { Endpoint } from './endpoint'; -import { IParameterGroup } from './parameter-group'; +import { ClusterParameterGroup, IParameterGroup } from './parameter-group'; import { BackupProps, DatabaseClusterEngine, InstanceProps, Login, RotationMultiUserOptions } from './props'; import { CfnDBCluster, CfnDBInstance, CfnDBSubnetGroup } from './rds.generated'; @@ -141,6 +142,68 @@ export interface DatabaseClusterProps { * @default - A role is automatically created for you */ readonly monitoringRole?: IRole; + + /** + * Role that will be associated with this DB cluster to enable S3 import. + * This feature is only supported by the Aurora database engine. + * + * This property must not be used if `s3ImportBuckets` is used. + * + * For MySQL: + * @see https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Integrating.LoadFromS3.html + * + * For PostgreSQL: + * @see https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.Migrating.html + * + * @default - New role is created if `s3ImportBuckets` is set, no role is defined otherwise + */ + readonly s3ImportRole?: IRole; + + /** + * S3 buckets that you want to load data from. This feature is only supported by the Aurora database engine. + * + * This property must not be used if `s3ImportRole` is used. + * + * For MySQL: + * @see https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Integrating.LoadFromS3.html + * + * For PostgreSQL: + * @see https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.Migrating.html + * + * @default - None + */ + readonly s3ImportBuckets?: s3.IBucket[]; + + /** + * Role that will be associated with this DB cluster to enable S3 export. + * This feature is only supported by the Aurora database engine. + * + * This property must not be used if `s3ExportBuckets` is used. + * + * For MySQL: + * @see https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Integrating.SaveIntoS3.html + * + * For PostgreSQL: + * @see https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/postgresql-s3-export.html + * + * @default - New role is created if `s3ExportBuckets` is set, no role is defined otherwise + */ + readonly s3ExportRole?: IRole; + + /** + * S3 buckets that you want to load data into. This feature is only supported by the Aurora database engine. + * + * This property must not be used if `s3ExportRole` is used. + * + * For MySQL: + * @see https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Integrating.SaveIntoS3.html + * + * For PostgreSQL: + * @see https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/postgresql-s3-export.html + * + * @default - None + */ + readonly s3ExportBuckets?: s3.IBucket[]; } /** @@ -308,6 +371,68 @@ export class DatabaseCluster extends DatabaseClusterBase { this.singleUserRotationApplication = props.engine.singleUserRotationApplication; this.multiUserRotationApplication = props.engine.multiUserRotationApplication; + let s3ImportRole = props.s3ImportRole; + if (props.s3ImportBuckets && props.s3ImportBuckets.length > 0) { + if (props.s3ImportRole) { + throw new Error(`Only one of s3ImportRole or s3ImportBuckets must be specified, not both.`); + } + + s3ImportRole = new Role(this, "S3ImportRole", { + assumedBy: new ServicePrincipal("rds.amazonaws.com") + }); + for (const bucket of props.s3ImportBuckets) { + bucket.grantRead(s3ImportRole); + } + } + + let s3ExportRole = props.s3ExportRole; + if (props.s3ExportBuckets && props.s3ExportBuckets.length > 0) { + if (props.s3ExportRole) { + throw new Error(`Only one of s3ExportRole or s3ExportBuckets must be specified, not both.`); + } + + s3ExportRole = new Role(this, "S3ExportRole", { + assumedBy: new ServicePrincipal("rds.amazonaws.com"), + }); + for (const bucket of props.s3ExportBuckets) { + bucket.grantReadWrite(s3ExportRole); + } + } + + let clusterParameterGroup = props.parameterGroup; + const clusterAssociatedRoles: CfnDBCluster.DBClusterRoleProperty[] = []; + if (s3ImportRole || s3ExportRole) { + if (s3ImportRole) { + clusterAssociatedRoles.push({ roleArn: s3ImportRole.roleArn }); + } + if (s3ExportRole) { + clusterAssociatedRoles.push({ roleArn: s3ExportRole.roleArn }); + } + + // MySQL requires the associated roles to be specified as cluster parameters as well, PostgreSQL does not + if (props.engine === DatabaseClusterEngine.AURORA || props.engine === DatabaseClusterEngine.AURORA_MYSQL) { + if (!clusterParameterGroup) { + const parameterGroupFamily = props.engine.parameterGroupFamily(props.engineVersion); + if (!parameterGroupFamily) { + throw new Error(`No parameter group family found for database engine ${props.engine.name} with version ${props.engineVersion}.` + + 'Failed to set the correct cluster parameters for s3 import and export roles.'); + } + clusterParameterGroup = new ClusterParameterGroup(this, "ClusterParameterGroup", { + family: parameterGroupFamily, + }); + } + + if (clusterParameterGroup instanceof ClusterParameterGroup) { // ignore imported ClusterParameterGroup + if (s3ImportRole) { + clusterParameterGroup.addParameter('aurora_load_from_s3_role', s3ImportRole.roleArn); + } + if (s3ExportRole) { + clusterParameterGroup.addParameter('aurora_select_into_s3_role', s3ExportRole.roleArn); + } + } + } + } + const cluster = new CfnDBCluster(this, 'Resource', { // Basic engine: props.engine.name, @@ -316,7 +441,8 @@ export class DatabaseCluster extends DatabaseClusterBase { dbSubnetGroupName: subnetGroup.ref, vpcSecurityGroupIds: [this.securityGroupId], port: props.port, - dbClusterParameterGroupName: props.parameterGroup && props.parameterGroup.parameterGroupName, + dbClusterParameterGroupName: clusterParameterGroup && clusterParameterGroup.parameterGroupName, + associatedRoles: clusterAssociatedRoles.length > 0 ? clusterAssociatedRoles : undefined, // Admin masterUsername: secret ? secret.secretValueFromJson('username').toString() : props.masterUser.username, masterUserPassword: secret diff --git a/packages/@aws-cdk/aws-rds/lib/instance.ts b/packages/@aws-cdk/aws-rds/lib/instance.ts index 7971d5bdd55ad..0961c2e8cdf9d 100644 --- a/packages/@aws-cdk/aws-rds/lib/instance.ts +++ b/packages/@aws-cdk/aws-rds/lib/instance.ts @@ -154,17 +154,78 @@ export abstract class DatabaseInstanceBase extends Resource implements IDatabase */ export class DatabaseInstanceEngine extends DatabaseClusterEngine { /* tslint:disable max-line-length */ - public static readonly MARIADB = new DatabaseInstanceEngine('mariadb', secretsmanager.SecretRotationApplication.MARIADB_ROTATION_SINGLE_USER, secretsmanager.SecretRotationApplication.MARIADB_ROTATION_MULTI_USER); - public static readonly MYSQL = new DatabaseInstanceEngine('mysql', secretsmanager.SecretRotationApplication.MYSQL_ROTATION_SINGLE_USER, secretsmanager.SecretRotationApplication.MYSQL_ROTATION_MULTI_USER); - public static readonly ORACLE_EE = new DatabaseInstanceEngine('oracle-ee', secretsmanager.SecretRotationApplication.ORACLE_ROTATION_SINGLE_USER, secretsmanager.SecretRotationApplication.ORACLE_ROTATION_MULTI_USER); - public static readonly ORACLE_SE2 = new DatabaseInstanceEngine('oracle-se2', secretsmanager.SecretRotationApplication.ORACLE_ROTATION_SINGLE_USER, secretsmanager.SecretRotationApplication.ORACLE_ROTATION_MULTI_USER); - public static readonly ORACLE_SE1 = new DatabaseInstanceEngine('oracle-se1', secretsmanager.SecretRotationApplication.ORACLE_ROTATION_SINGLE_USER, secretsmanager.SecretRotationApplication.ORACLE_ROTATION_MULTI_USER); - public static readonly ORACLE_SE = new DatabaseInstanceEngine('oracle-se', secretsmanager.SecretRotationApplication.ORACLE_ROTATION_SINGLE_USER, secretsmanager.SecretRotationApplication.ORACLE_ROTATION_MULTI_USER); - public static readonly POSTGRES = new DatabaseInstanceEngine('postgres', secretsmanager.SecretRotationApplication.POSTGRES_ROTATION_SINGLE_USER, secretsmanager.SecretRotationApplication.POSTGRES_ROTATION_MULTI_USER); - public static readonly SQL_SERVER_EE = new DatabaseInstanceEngine('sqlserver-ee', secretsmanager.SecretRotationApplication.SQLSERVER_ROTATION_SINGLE_USER, secretsmanager.SecretRotationApplication.SQLSERVER_ROTATION_MULTI_USER); - public static readonly SQL_SERVER_SE = new DatabaseInstanceEngine('sqlserver-se', secretsmanager.SecretRotationApplication.SQLSERVER_ROTATION_SINGLE_USER, secretsmanager.SecretRotationApplication.SQLSERVER_ROTATION_MULTI_USER); - public static readonly SQL_SERVER_EX = new DatabaseInstanceEngine('sqlserver-ex', secretsmanager.SecretRotationApplication.SQLSERVER_ROTATION_SINGLE_USER, secretsmanager.SecretRotationApplication.SQLSERVER_ROTATION_MULTI_USER); - public static readonly SQL_SERVER_WEB = new DatabaseInstanceEngine('sqlserver-web', secretsmanager.SecretRotationApplication.SQLSERVER_ROTATION_SINGLE_USER, secretsmanager.SecretRotationApplication.SQLSERVER_ROTATION_MULTI_USER); + public static readonly MARIADB = new DatabaseInstanceEngine('mariadb', secretsmanager.SecretRotationApplication.MARIADB_ROTATION_SINGLE_USER, secretsmanager.SecretRotationApplication.MARIADB_ROTATION_MULTI_USER, [ + { engineMajorVersion: '10.0', parameterGroupFamily: 'mariadb10.0' }, + { engineMajorVersion: '10.1', parameterGroupFamily: 'mariadb10.1' }, + { engineMajorVersion: '10.2', parameterGroupFamily: 'mariadb10.2' }, + { engineMajorVersion: '10.3', parameterGroupFamily: 'mariadb10.3' } + ]); + + public static readonly MYSQL = new DatabaseInstanceEngine('mysql', secretsmanager.SecretRotationApplication.MYSQL_ROTATION_SINGLE_USER, secretsmanager.SecretRotationApplication.MYSQL_ROTATION_MULTI_USER, [ + { engineMajorVersion: '5.6', parameterGroupFamily: 'mysql5.6' }, + { engineMajorVersion: '5.7', parameterGroupFamily: 'mysql5.7' }, + { engineMajorVersion: '8.0', parameterGroupFamily: 'mysql8.0' } + ]); + + public static readonly ORACLE_EE = new DatabaseInstanceEngine('oracle-ee', secretsmanager.SecretRotationApplication.ORACLE_ROTATION_SINGLE_USER, secretsmanager.SecretRotationApplication.ORACLE_ROTATION_MULTI_USER, [ + { engineMajorVersion: '11.2', parameterGroupFamily: 'oracle-ee-11.2' }, + { engineMajorVersion: '12.1', parameterGroupFamily: 'oracle-ee-12.1' }, + { engineMajorVersion: '12.2', parameterGroupFamily: 'oracle-ee-12.2' }, + { engineMajorVersion: '18', parameterGroupFamily: 'oracle-ee-18' }, + { engineMajorVersion: '19', parameterGroupFamily: 'oracle-ee-19' } + ]); + + public static readonly ORACLE_SE2 = new DatabaseInstanceEngine('oracle-se2', secretsmanager.SecretRotationApplication.ORACLE_ROTATION_SINGLE_USER, secretsmanager.SecretRotationApplication.ORACLE_ROTATION_MULTI_USER, [ + { engineMajorVersion: '12.1', parameterGroupFamily: 'oracle-se2-12.1' }, + { engineMajorVersion: '12.2', parameterGroupFamily: 'oracle-se2-12.2' }, + { engineMajorVersion: '18', parameterGroupFamily: 'oracle-se2-18' }, + { engineMajorVersion: '19', parameterGroupFamily: 'oracle-se2-19' } + ]); + + public static readonly ORACLE_SE1 = new DatabaseInstanceEngine('oracle-se1', secretsmanager.SecretRotationApplication.ORACLE_ROTATION_SINGLE_USER, secretsmanager.SecretRotationApplication.ORACLE_ROTATION_MULTI_USER, [ + { engineMajorVersion: '11.2', parameterGroupFamily: 'oracle-se1-11.2' } + ]); + + public static readonly ORACLE_SE = new DatabaseInstanceEngine('oracle-se', secretsmanager.SecretRotationApplication.ORACLE_ROTATION_SINGLE_USER, secretsmanager.SecretRotationApplication.ORACLE_ROTATION_MULTI_USER, [ + { engineMajorVersion: '11.2', parameterGroupFamily: 'oracle-se-11.2' } + ]); + + public static readonly POSTGRES = new DatabaseInstanceEngine('postgres', secretsmanager.SecretRotationApplication.POSTGRES_ROTATION_SINGLE_USER, secretsmanager.SecretRotationApplication.POSTGRES_ROTATION_MULTI_USER, [ + { engineMajorVersion: '9.3', parameterGroupFamily: 'postgres9.3' }, + { engineMajorVersion: '9.4', parameterGroupFamily: 'postgres9.4' }, + { engineMajorVersion: '9.5', parameterGroupFamily: 'postgres9.5' }, + { engineMajorVersion: '9.6', parameterGroupFamily: 'postgres9.6' }, + { engineMajorVersion: '10', parameterGroupFamily: 'postgres10' }, + { engineMajorVersion: '11', parameterGroupFamily: 'postgres11' }, + ]); + + public static readonly SQL_SERVER_EE = new DatabaseInstanceEngine('sqlserver-ee', secretsmanager.SecretRotationApplication.SQLSERVER_ROTATION_SINGLE_USER, secretsmanager.SecretRotationApplication.SQLSERVER_ROTATION_MULTI_USER, [ + { engineMajorVersion: '11', parameterGroupFamily: 'sqlserver-ee-11.0' }, + { engineMajorVersion: '12', parameterGroupFamily: 'sqlserver-ee-12.0' }, + { engineMajorVersion: '13', parameterGroupFamily: 'sqlserver-ee-13.0' }, + { engineMajorVersion: '14', parameterGroupFamily: 'sqlserver-ee-14.0' } + ]); + + public static readonly SQL_SERVER_SE = new DatabaseInstanceEngine('sqlserver-se', secretsmanager.SecretRotationApplication.SQLSERVER_ROTATION_SINGLE_USER, secretsmanager.SecretRotationApplication.SQLSERVER_ROTATION_MULTI_USER, [ + { engineMajorVersion: '11', parameterGroupFamily: 'sqlserver-se-11.0' }, + { engineMajorVersion: '12', parameterGroupFamily: 'sqlserver-se-12.0' }, + { engineMajorVersion: '13', parameterGroupFamily: 'sqlserver-se-13.0' }, + { engineMajorVersion: '14', parameterGroupFamily: 'sqlserver-se-14.0' } + ]); + + public static readonly SQL_SERVER_EX = new DatabaseInstanceEngine('sqlserver-ex', secretsmanager.SecretRotationApplication.SQLSERVER_ROTATION_SINGLE_USER, secretsmanager.SecretRotationApplication.SQLSERVER_ROTATION_MULTI_USER, [ + { engineMajorVersion: '11', parameterGroupFamily: 'sqlserver-ex-11.0' }, + { engineMajorVersion: '12', parameterGroupFamily: 'sqlserver-ex-12.0' }, + { engineMajorVersion: '13', parameterGroupFamily: 'sqlserver-ex-13.0' }, + { engineMajorVersion: '14', parameterGroupFamily: 'sqlserver-ex-14.0' } + ]); + + public static readonly SQL_SERVER_WEB = new DatabaseInstanceEngine('sqlserver-web', secretsmanager.SecretRotationApplication.SQLSERVER_ROTATION_SINGLE_USER, secretsmanager.SecretRotationApplication.SQLSERVER_ROTATION_MULTI_USER, [ + { engineMajorVersion: '11', parameterGroupFamily: 'sqlserver-web-11.0' }, + { engineMajorVersion: '12', parameterGroupFamily: 'sqlserver-web-12.0' }, + { engineMajorVersion: '13', parameterGroupFamily: 'sqlserver-web-13.0' }, + { engineMajorVersion: '14', parameterGroupFamily: 'sqlserver-web-14.0' } + ]); /* tslint:enable max-line-length */ /** To make it a compile-time error to pass a DatabaseClusterEngine where a DatabaseInstanceEngine is expected. */ diff --git a/packages/@aws-cdk/aws-rds/lib/parameter-group.ts b/packages/@aws-cdk/aws-rds/lib/parameter-group.ts index eb52911caf723..ee7b13fa04e98 100644 --- a/packages/@aws-cdk/aws-rds/lib/parameter-group.ts +++ b/packages/@aws-cdk/aws-rds/lib/parameter-group.ts @@ -1,4 +1,4 @@ -import { Construct, IResource, Resource } from '@aws-cdk/core'; +import { Construct, IResource, Lazy, Resource } from '@aws-cdk/core'; import { CfnDBClusterParameterGroup, CfnDBParameterGroup } from './rds.generated'; /** @@ -31,6 +31,24 @@ abstract class ParameterGroupBase extends Resource implements IParameterGroup { * The name of the parameter group */ public abstract readonly parameterGroupName: string; + + /** + * Parameters of the parameter group + */ + protected parameters?: { [key: string]: string } = {}; + + /** + * Add a parameter to this parameter group + * + * @param key The key of the parameter to be added + * @param value The value of the parameter to be added + */ + public addParameter(key: string, value: string) { + if (!this.parameters) { + this.parameters = {}; + } + this.parameters[key] = value; + } } /** @@ -51,8 +69,10 @@ export interface ParameterGroupProps { /** * The parameters in this parameter group + * + * @default - None */ - readonly parameters: { [key: string]: string }; + readonly parameters?: { [key: string]: string }; } /** @@ -69,10 +89,12 @@ export class ParameterGroup extends ParameterGroupBase { constructor(scope: Construct, id: string, props: ParameterGroupProps) { super(scope, id); + this.parameters = props.parameters ? props.parameters : {}; + const resource = new CfnDBParameterGroup(this, 'Resource', { description: props.description || `Parameter group for ${props.family}`, family: props.family, - parameters: props.parameters, + parameters: Lazy.anyValue({ produce: () => this.parameters }) }); this.parameterGroupName = resource.ref; @@ -100,10 +122,12 @@ export class ClusterParameterGroup extends ParameterGroupBase { constructor(scope: Construct, id: string, props: ClusterParameterGroupProps) { super(scope, id); + this.parameters = props.parameters ? props.parameters : {}; + const resource = new CfnDBClusterParameterGroup(this, 'Resource', { description: props.description || `Cluster parameter group for ${props.family}`, family: props.family, - parameters: props.parameters, + parameters: Lazy.anyValue({ produce: () => this.parameters }), }); this.parameterGroupName = resource.ref; diff --git a/packages/@aws-cdk/aws-rds/lib/private/version.ts b/packages/@aws-cdk/aws-rds/lib/private/version.ts new file mode 100644 index 0000000000000..9e7ce227c2b5c --- /dev/null +++ b/packages/@aws-cdk/aws-rds/lib/private/version.ts @@ -0,0 +1,21 @@ +/** + * Compare two version strings. Fails if the comparison has to tiebreak with non-numbers. + * @returns 0 if both are same, 1 if 'a' is later version than 'b' and -1 if 'b' is later version than 'a' + */ +export function compare(a: string, b: string) { + const aParts = a.split('.'); + const bParts = b.split('.'); + for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) { + if (i === aParts.length) { return -1; } + if (i === bParts.length) { return 1; } + + if (!aParts[i] || !bParts[i] || isNaN(aParts[i] as any) || isNaN(bParts[i] as any)) { + throw new Error(`Can only compare version strings with numbers. Received [${a}] and [${b}].`); + } + const partCompare = parseInt(aParts[i], 10) - parseInt(bParts[i], 10); + + if (partCompare < 0) { return -1; } + if (partCompare > 0) { return 1; } + } + return 0; +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-rds/lib/props.ts b/packages/@aws-cdk/aws-rds/lib/props.ts index c0971bdef82ca..10596ea18df2f 100644 --- a/packages/@aws-cdk/aws-rds/lib/props.ts +++ b/packages/@aws-cdk/aws-rds/lib/props.ts @@ -3,6 +3,22 @@ import * as kms from '@aws-cdk/aws-kms'; import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; import { Duration, SecretValue } from '@aws-cdk/core'; import { IParameterGroup } from './parameter-group'; +import { compare } from './private/version'; + +/** + * Engine major version and parameter group family pairs. + */ +export interface ParameterGroupFamily { + /** + * The engine major version name + */ + readonly engineMajorVersion: string; + + /** + * The parameter group family name + */ + readonly parameterGroupFamily: string +} /** * A database cluster engine. Provides mapping to the serverless application @@ -10,9 +26,19 @@ import { IParameterGroup } from './parameter-group'; */ export class DatabaseClusterEngine { /* tslint:disable max-line-length */ - public static readonly AURORA = new DatabaseClusterEngine('aurora', secretsmanager.SecretRotationApplication.MYSQL_ROTATION_SINGLE_USER, secretsmanager.SecretRotationApplication.MYSQL_ROTATION_MULTI_USER); - public static readonly AURORA_MYSQL = new DatabaseClusterEngine('aurora-mysql', secretsmanager.SecretRotationApplication.MYSQL_ROTATION_SINGLE_USER, secretsmanager.SecretRotationApplication.MYSQL_ROTATION_MULTI_USER); - public static readonly AURORA_POSTGRESQL = new DatabaseClusterEngine('aurora-postgresql', secretsmanager.SecretRotationApplication.POSTGRES_ROTATION_SINGLE_USER, secretsmanager.SecretRotationApplication.POSTGRES_ROTATION_MULTI_USER); + public static readonly AURORA = new DatabaseClusterEngine('aurora', secretsmanager.SecretRotationApplication.MYSQL_ROTATION_SINGLE_USER, secretsmanager.SecretRotationApplication.MYSQL_ROTATION_MULTI_USER, [ + { engineMajorVersion: '5.6', parameterGroupFamily: 'aurora5.6' } + ]); + + public static readonly AURORA_MYSQL = new DatabaseClusterEngine('aurora-mysql', secretsmanager.SecretRotationApplication.MYSQL_ROTATION_SINGLE_USER, secretsmanager.SecretRotationApplication.MYSQL_ROTATION_MULTI_USER, [ + { engineMajorVersion: '5.7', parameterGroupFamily: 'aurora-mysql5.7' } + ]); + + public static readonly AURORA_POSTGRESQL = new DatabaseClusterEngine('aurora-postgresql', secretsmanager.SecretRotationApplication.POSTGRES_ROTATION_SINGLE_USER, secretsmanager.SecretRotationApplication.POSTGRES_ROTATION_MULTI_USER, [ + { engineMajorVersion: '9.6', parameterGroupFamily: 'aurora-postgresql9.6'}, + { engineMajorVersion: '10', parameterGroupFamily: 'aurora-postgresql10' }, + { engineMajorVersion: '11', parameterGroupFamily: 'aurora-postgresql11'} + ]); /* tslint:enable max-line-length */ /** @@ -30,11 +56,35 @@ export class DatabaseClusterEngine { */ public readonly multiUserRotationApplication: secretsmanager.SecretRotationApplication; + private readonly parameterGroupFamilies?: ParameterGroupFamily[]; + // tslint:disable-next-line max-line-length - constructor(name: string, singleUserRotationApplication: secretsmanager.SecretRotationApplication, multiUserRotationApplication: secretsmanager.SecretRotationApplication) { + constructor(name: string, singleUserRotationApplication: secretsmanager.SecretRotationApplication, multiUserRotationApplication: secretsmanager.SecretRotationApplication, parameterGroupFamilies?: ParameterGroupFamily[]) { this.name = name; this.singleUserRotationApplication = singleUserRotationApplication; this.multiUserRotationApplication = multiUserRotationApplication; + this.parameterGroupFamilies = parameterGroupFamilies; + } + + /** + * Get the latest parameter group family for this engine. Latest is determined using semver on the engine major version. + * When `engineVersion` is specified, return the parameter group family corresponding to that engine version. + * Return undefined if no parameter group family is defined for this engine or for the requested `engineVersion`. + */ + public parameterGroupFamily(engineVersion?: string): string | undefined { + if (this.parameterGroupFamilies === undefined) { return undefined; } + if (engineVersion) { + const family = this.parameterGroupFamilies.find(x => engineVersion.startsWith(x.engineMajorVersion)); + if (family) { + return family.parameterGroupFamily; + } + } else if (this.parameterGroupFamilies.length > 0) { + const sorted = this.parameterGroupFamilies.slice().sort((a, b) => { + return compare(a.engineMajorVersion, b.engineMajorVersion); + }).reverse(); + return sorted[0].parameterGroupFamily; + } + return undefined; } } diff --git a/packages/@aws-cdk/aws-rds/package.json b/packages/@aws-cdk/aws-rds/package.json index 755cef821b7a9..437cf21488c1b 100644 --- a/packages/@aws-cdk/aws-rds/package.json +++ b/packages/@aws-cdk/aws-rds/package.json @@ -79,6 +79,7 @@ "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", + "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^2.0.0" @@ -94,6 +95,7 @@ "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/core": "0.0.0", + "@aws-cdk/aws-s3": "0.0.0", "constructs": "^2.0.0" }, "engines": { diff --git a/packages/@aws-cdk/aws-rds/test/integ.cluster-s3.expected.json b/packages/@aws-cdk/aws-rds/test/integ.cluster-s3.expected.json new file mode 100644 index 0000000000000..56c9031c5c032 --- /dev/null +++ b/packages/@aws-cdk/aws-rds/test/integ.cluster-s3.expected.json @@ -0,0 +1,715 @@ +{ + "Resources": { + "VPCB9E5F0B4": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-s3-integ/VPC" + } + ] + } + }, + "VPCPublicSubnet1SubnetB4246D30": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-s3-integ/VPC/PublicSubnet1" + }, + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + } + ] + } + }, + "VPCPublicSubnet1RouteTableFEE4B781": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-s3-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1RouteTableAssociation0B0896DC": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + } + } + }, + "VPCPublicSubnet1DefaultRoute91CEF279": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet1EIP6AD938E8": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-s3-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1NATGatewayE0556630": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet1EIP6AD938E8", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-s3-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet2Subnet74179F39": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-s3-integ/VPC/PublicSubnet2" + }, + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + } + ] + } + }, + "VPCPublicSubnet2RouteTable6F1A15F1": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-s3-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2RouteTableAssociation5A808732": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + } + } + }, + "VPCPublicSubnet2DefaultRouteB7481BBA": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet2EIP4947BC00": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-s3-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2NATGateway3C070193": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet2EIP4947BC00", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-s3-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPrivateSubnet1Subnet8BCA10E0": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-s3-integ/VPC/PrivateSubnet1" + }, + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + } + ] + } + }, + "VPCPrivateSubnet1RouteTableBE8A6027": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-s3-integ/VPC/PrivateSubnet1" + } + ] + } + }, + "VPCPrivateSubnet1RouteTableAssociation347902D1": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + } + } + }, + "VPCPrivateSubnet1DefaultRouteAE1D6490": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet1NATGatewayE0556630" + } + } + }, + "VPCPrivateSubnet2SubnetCFCDAA7A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.192.0/18", + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-s3-integ/VPC/PrivateSubnet2" + }, + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + } + ] + } + }, + "VPCPrivateSubnet2RouteTable0A19E10E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-s3-integ/VPC/PrivateSubnet2" + } + ] + } + }, + "VPCPrivateSubnet2RouteTableAssociation0C73D413": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + } + } + }, + "VPCPrivateSubnet2DefaultRouteF4F5CFD2": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet2NATGateway3C070193" + } + } + }, + "VPCIGWB7E252D3": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-s3-integ/VPC" + } + ] + } + }, + "VPCVPCGW99B986DC": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "VPCB9E5F0B4" + }, + "InternetGatewayId": { + "Ref": "VPCIGWB7E252D3" + } + } + }, + "DbSecurity381C2C15": { + "Type": "AWS::KMS::Key", + "Properties": { + "KeyPolicy": { + "Statement": [ + { + "Action": [ + "kms:Create*", + "kms:Describe*", + "kms:Enable*", + "kms:List*", + "kms:Put*", + "kms:Update*", + "kms:Revoke*", + "kms:Disable*", + "kms:Get*", + "kms:Delete*", + "kms:ScheduleKeyDeletion", + "kms:CancelKeyDeletion", + "kms:GenerateDataKey", + "kms:TagResource", + "kms:UntagResource" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "ImportBucketBAF3A8E9": { + "Type": "AWS::S3::Bucket", + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "ExportBucket4E99310E": { + "Type": "AWS::S3::Bucket", + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "DatabaseSubnets56F17B9A": { + "Type": "AWS::RDS::DBSubnetGroup", + "Properties": { + "DBSubnetGroupDescription": "Subnets for Database database", + "SubnetIds": [ + { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, + { + "Ref": "VPCPublicSubnet2Subnet74179F39" + } + ] + } + }, + "DatabaseSecurityGroup5C91FDCB": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "RDS security group", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "DatabaseSecurityGroupfrom00000IndirectPortF24F2E03": { + "Type": "AWS::EC2::SecurityGroupIngress", + "Properties": { + "IpProtocol": "tcp", + "CidrIp": "0.0.0.0/0", + "Description": "Open to the world", + "FromPort": { + "Fn::GetAtt": [ + "DatabaseB269D8BB", + "Endpoint.Port" + ] + }, + "GroupId": { + "Fn::GetAtt": [ + "DatabaseSecurityGroup5C91FDCB", + "GroupId" + ] + }, + "ToPort": { + "Fn::GetAtt": [ + "DatabaseB269D8BB", + "Endpoint.Port" + ] + } + } + }, + "DatabaseS3ImportRole377BC9C0": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "rds.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "DatabaseS3ImportRoleDefaultPolicyA60A7342": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:GetObject*", + "s3:GetBucket*", + "s3:List*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "ImportBucketBAF3A8E9", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "ImportBucketBAF3A8E9", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "DatabaseS3ImportRoleDefaultPolicyA60A7342", + "Roles": [ + { + "Ref": "DatabaseS3ImportRole377BC9C0" + } + ] + } + }, + "DatabaseS3ExportRole9E328562": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "rds.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "DatabaseS3ExportRoleDefaultPolicy8FEADB68": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:GetObject*", + "s3:GetBucket*", + "s3:List*", + "s3:DeleteObject*", + "s3:PutObject*", + "s3:Abort*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "ExportBucket4E99310E", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "ExportBucket4E99310E", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "DatabaseS3ExportRoleDefaultPolicy8FEADB68", + "Roles": [ + { + "Ref": "DatabaseS3ExportRole9E328562" + } + ] + } + }, + "DatabaseClusterParameterGroupF2A52087": { + "Type": "AWS::RDS::DBClusterParameterGroup", + "Properties": { + "Description": "Cluster parameter group for aurora5.6", + "Family": "aurora5.6", + "Parameters": { + "aurora_load_from_s3_role": { + "Fn::GetAtt": [ + "DatabaseS3ImportRole377BC9C0", + "Arn" + ] + }, + "aurora_select_into_s3_role": { + "Fn::GetAtt": [ + "DatabaseS3ExportRole9E328562", + "Arn" + ] + } + } + } + }, + "DatabaseB269D8BB": { + "Type": "AWS::RDS::DBCluster", + "Properties": { + "Engine": "aurora", + "AssociatedRoles": [ + { + "RoleArn": { + "Fn::GetAtt": [ + "DatabaseS3ImportRole377BC9C0", + "Arn" + ] + } + }, + { + "RoleArn": { + "Fn::GetAtt": [ + "DatabaseS3ExportRole9E328562", + "Arn" + ] + } + } + ], + "DBClusterParameterGroupName": { + "Ref": "DatabaseClusterParameterGroupF2A52087" + }, + "DBSubnetGroupName": { + "Ref": "DatabaseSubnets56F17B9A" + }, + "KmsKeyId": { + "Fn::GetAtt": [ + "DbSecurity381C2C15", + "Arn" + ] + }, + "MasterUsername": "admin", + "MasterUserPassword": "7959866cacc02c2d243ecfe177464fe6", + "StorageEncrypted": true, + "VpcSecurityGroupIds": [ + { + "Fn::GetAtt": [ + "DatabaseSecurityGroup5C91FDCB", + "GroupId" + ] + } + ] + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "DatabaseInstance1844F58FD": { + "Type": "AWS::RDS::DBInstance", + "Properties": { + "DBInstanceClass": "db.t3.small", + "DBClusterIdentifier": { + "Ref": "DatabaseB269D8BB" + }, + "DBSubnetGroupName": { + "Ref": "DatabaseSubnets56F17B9A" + }, + "Engine": "aurora", + "PubliclyAccessible": true + }, + "DependsOn": [ + "VPCPublicSubnet1DefaultRoute91CEF279", + "VPCPublicSubnet2DefaultRouteB7481BBA" + ], + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "DatabaseInstance2AA380DEE": { + "Type": "AWS::RDS::DBInstance", + "Properties": { + "DBInstanceClass": "db.t3.small", + "DBClusterIdentifier": { + "Ref": "DatabaseB269D8BB" + }, + "DBSubnetGroupName": { + "Ref": "DatabaseSubnets56F17B9A" + }, + "Engine": "aurora", + "PubliclyAccessible": true + }, + "DependsOn": [ + "VPCPublicSubnet1DefaultRoute91CEF279", + "VPCPublicSubnet2DefaultRouteB7481BBA" + ], + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-rds/test/integ.cluster-s3.ts b/packages/@aws-cdk/aws-rds/test/integ.cluster-s3.ts new file mode 100644 index 0000000000000..f2ca46d7d9c90 --- /dev/null +++ b/packages/@aws-cdk/aws-rds/test/integ.cluster-s3.ts @@ -0,0 +1,35 @@ +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as kms from '@aws-cdk/aws-kms'; +import * as s3 from '@aws-cdk/aws-s3'; +import * as cdk from '@aws-cdk/core'; +import { DatabaseCluster, DatabaseClusterEngine } from '../lib'; + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'aws-cdk-rds-s3-integ'); + +const vpc = new ec2.Vpc(stack, 'VPC', { maxAzs: 2 }); + +const kmsKey = new kms.Key(stack, 'DbSecurity'); + +const importBucket = new s3.Bucket(stack, 'ImportBucket'); +const exportBucket = new s3.Bucket(stack, 'ExportBucket'); + +const cluster = new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA, + masterUser: { + username: 'admin', + password: cdk.SecretValue.plainText('7959866cacc02c2d243ecfe177464fe6'), + }, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE3, ec2.InstanceSize.SMALL), + vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC }, + vpc + }, + kmsKey, + s3ImportBuckets: [importBucket], + s3ExportBuckets: [exportBucket] +}); + +cluster.connections.allowDefaultPortFromAnyIpv4('Open to the world'); + +app.synth(); diff --git a/packages/@aws-cdk/aws-rds/test/integ.cluster.ts b/packages/@aws-cdk/aws-rds/test/integ.cluster.ts index 9e733ade94239..ac30f02e574ba 100644 --- a/packages/@aws-cdk/aws-rds/test/integ.cluster.ts +++ b/packages/@aws-cdk/aws-rds/test/integ.cluster.ts @@ -18,6 +18,7 @@ const params = new ClusterParameterGroup(stack, 'Params', { }); const kmsKey = new kms.Key(stack, 'DbSecurity'); + const cluster = new DatabaseCluster(stack, 'Database', { engine: DatabaseClusterEngine.AURORA, masterUser: { diff --git a/packages/@aws-cdk/aws-rds/test/private/test.version.ts b/packages/@aws-cdk/aws-rds/test/private/test.version.ts new file mode 100644 index 0000000000000..2977d702bd5cb --- /dev/null +++ b/packages/@aws-cdk/aws-rds/test/private/test.version.ts @@ -0,0 +1,38 @@ +import { Test } from 'nodeunit'; +import { compare } from '../../lib/private/version'; + +export = { + 'compare - same versions'(test: Test) { + test.equals(compare('1', '1'), 0); + test.equals(compare('1.0', '1.0'), 0); + test.done(); + }, + + 'compare - a < b'(test: Test) { + test.equals(compare('1', '2'), -1); + test.equals(compare('1.0', '1.2'), -1); + test.equals(compare('1.3', '4'), -1); + test.equals(compare('1', '1.2'), -1); + test.equals(compare('1.0', '2.0'), -1); + test.equals(compare('4', '10'), -1); + test.done(); + }, + + 'compare - a > b'(test: Test) { + test.equals(compare('2', '1'), 1); + test.equals(compare('1.2', '1.0'), 1); + test.equals(compare('1.2', '1'), 1); + test.equals(compare('4', '1.2'), 1); + test.equals(compare('2.0', '1.0'), 1); + test.equals(compare('10', '4'), 1); + test.done(); + }, + + 'compare - NaN'(test: Test) { + test.throws(() => compare('1', ''), /only compare version strings with numbers/); + test.throws(() => compare('', '1'), /only compare version strings with numbers/); + test.throws(() => compare('', ''), /only compare version strings with numbers/); + test.throws(() => compare('4x', '1.0'), /only compare version strings with numbers/); + test.done(); + }, +}; \ No newline at end of file diff --git a/packages/@aws-cdk/aws-rds/test/test.cluster.ts b/packages/@aws-cdk/aws-rds/test/test.cluster.ts index 95fad9cf384ed..0d317b72730dc 100644 --- a/packages/@aws-cdk/aws-rds/test/test.cluster.ts +++ b/packages/@aws-cdk/aws-rds/test/test.cluster.ts @@ -2,6 +2,7 @@ import { expect, haveResource, ResourcePart } from '@aws-cdk/assert'; import * as ec2 from '@aws-cdk/aws-ec2'; import { ManagedPolicy, Role, ServicePrincipal } from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; +import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; import { ClusterParameterGroup, DatabaseCluster, DatabaseClusterEngine, ParameterGroup } from '../lib'; @@ -495,7 +496,7 @@ export = { test.done(); }, - 'throws when trying to add single user rotation multiple timet'(test: Test) { + 'throws when trying to add single user rotation multiple times'(test: Test) { // GIVEN const stack = new cdk.Stack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -516,6 +517,512 @@ export = { test.done(); }, + + 'create a cluster with s3 import role'(test: Test) { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, "VPC"); + + const associatedRole = new Role(stack, 'AssociatedRole', { + assumedBy: new ServicePrincipal('rds.amazonaws.com'), + }); + + // WHEN + new DatabaseCluster(stack, "Database", { + engine: DatabaseClusterEngine.AURORA, + instances: 1, + masterUser: { + username: "admin" + }, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc + }, + s3ImportRole: associatedRole + }); + + // THEN + expect(stack).to(haveResource("AWS::RDS::DBCluster", { + AssociatedRoles: [{ + RoleArn: { + "Fn::GetAtt": [ + "AssociatedRole824CFCD3", + "Arn" + ] + } + }] + })); + + expect(stack).to(haveResource("AWS::RDS::DBClusterParameterGroup", { + Family: 'aurora5.6', + Parameters: { + aurora_load_from_s3_role: { + "Fn::GetAtt": [ + "AssociatedRole824CFCD3", + "Arn" + ] + } + } + })); + + test.done(); + }, + + 'create a cluster with s3 import buckets'(test: Test) { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, "VPC"); + + const bucket = new s3.Bucket(stack, 'Bucket'); + + // WHEN + new DatabaseCluster(stack, "Database", { + engine: DatabaseClusterEngine.AURORA, + instances: 1, + masterUser: { + username: "admin" + }, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc + }, + s3ImportBuckets: [bucket] + }); + + // THEN + expect(stack).to(haveResource("AWS::RDS::DBCluster", { + AssociatedRoles: [{ + RoleArn: { + "Fn::GetAtt": [ + "DatabaseS3ImportRole377BC9C0", + "Arn" + ] + } + }] + })); + + expect(stack).to(haveResource("AWS::RDS::DBClusterParameterGroup", { + Family: 'aurora5.6', + Parameters: { + aurora_load_from_s3_role: { + "Fn::GetAtt": [ + "DatabaseS3ImportRole377BC9C0", + "Arn" + ] + } + } + })); + + expect(stack).to(haveResource("AWS::IAM::Policy", { + PolicyDocument: { + Statement: [ + { + Action: [ + "s3:GetObject*", + "s3:GetBucket*", + "s3:List*" + ], + Effect: "Allow", + Resource: [ + { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + Version: "2012-10-17" + } + })); + + test.done(); + }, + + 'create a cluster with s3 export role'(test: Test) { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, "VPC"); + + const associatedRole = new Role(stack, 'AssociatedRole', { + assumedBy: new ServicePrincipal('rds.amazonaws.com'), + }); + + // WHEN + new DatabaseCluster(stack, "Database", { + engine: DatabaseClusterEngine.AURORA, + instances: 1, + masterUser: { + username: "admin" + }, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc + }, + s3ExportRole: associatedRole + }); + + // THEN + expect(stack).to(haveResource("AWS::RDS::DBCluster", { + AssociatedRoles: [{ + RoleArn: { + "Fn::GetAtt": [ + "AssociatedRole824CFCD3", + "Arn" + ] + } + }] + })); + + expect(stack).to(haveResource("AWS::RDS::DBClusterParameterGroup", { + Family: 'aurora5.6', + Parameters: { + aurora_select_into_s3_role: { + "Fn::GetAtt": [ + "AssociatedRole824CFCD3", + "Arn" + ] + } + } + })); + + test.done(); + }, + + 'create a cluster with s3 export buckets'(test: Test) { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, "VPC"); + + const bucket = new s3.Bucket(stack, 'Bucket'); + + // WHEN + new DatabaseCluster(stack, "Database", { + engine: DatabaseClusterEngine.AURORA, + instances: 1, + masterUser: { + username: "admin" + }, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc + }, + s3ExportBuckets: [bucket] + }); + + // THEN + expect(stack).to(haveResource("AWS::RDS::DBCluster", { + AssociatedRoles: [{ + RoleArn: { + "Fn::GetAtt": [ + "DatabaseS3ExportRole9E328562", + "Arn" + ] + } + }] + })); + + expect(stack).to(haveResource("AWS::RDS::DBClusterParameterGroup", { + Family: 'aurora5.6', + Parameters: { + aurora_select_into_s3_role: { + "Fn::GetAtt": [ + "DatabaseS3ExportRole9E328562", + "Arn" + ] + } + } + })); + + expect(stack).to(haveResource("AWS::IAM::Policy", { + PolicyDocument: { + Statement: [ + { + Action: [ + "s3:GetObject*", + "s3:GetBucket*", + "s3:List*", + "s3:DeleteObject*", + "s3:PutObject*", + "s3:Abort*" + ], + Effect: "Allow", + Resource: [ + { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + Version: "2012-10-17" + } + })); + + test.done(); + }, + + 'create a cluster with s3 import and export buckets'(test: Test) { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, "VPC"); + + const importBucket = new s3.Bucket(stack, 'ImportBucket'); + const exportBucket = new s3.Bucket(stack, 'ExportBucket'); + + // WHEN + new DatabaseCluster(stack, "Database", { + engine: DatabaseClusterEngine.AURORA, + instances: 1, + masterUser: { + username: "admin" + }, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc + }, + s3ImportBuckets: [importBucket], + s3ExportBuckets: [exportBucket] + }); + + // THEN + expect(stack).to(haveResource("AWS::RDS::DBCluster", { + AssociatedRoles: [{ + RoleArn: { + "Fn::GetAtt": [ + "DatabaseS3ImportRole377BC9C0", + "Arn" + ] + } + }, + { + RoleArn: { + "Fn::GetAtt": [ + "DatabaseS3ExportRole9E328562", + "Arn" + ] + } + }] + })); + + expect(stack).to(haveResource("AWS::RDS::DBClusterParameterGroup", { + Family: 'aurora5.6', + Parameters: { + aurora_load_from_s3_role: { + "Fn::GetAtt": [ + "DatabaseS3ImportRole377BC9C0", + "Arn" + ] + }, + aurora_select_into_s3_role: { + "Fn::GetAtt": [ + "DatabaseS3ExportRole9E328562", + "Arn" + ] + } + } + })); + + test.done(); + }, + + 'create a cluster with s3 import and export buckets and custom parameter group'(test: Test) { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, "VPC"); + + const parameterGroup = new ClusterParameterGroup(stack, 'ParameterGroup', { + family: 'family', + parameters: { + key: 'value' + } + }); + + const importBucket = new s3.Bucket(stack, 'ImportBucket'); + const exportBucket = new s3.Bucket(stack, 'ExportBucket'); + + // WHEN + new DatabaseCluster(stack, "Database", { + engine: DatabaseClusterEngine.AURORA, + instances: 1, + masterUser: { + username: "admin" + }, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc + }, + parameterGroup, + s3ImportBuckets: [importBucket], + s3ExportBuckets: [exportBucket] + }); + + // THEN + expect(stack).to(haveResource("AWS::RDS::DBCluster", { + AssociatedRoles: [{ + RoleArn: { + "Fn::GetAtt": [ + "DatabaseS3ImportRole377BC9C0", + "Arn" + ] + } + }, + { + RoleArn: { + "Fn::GetAtt": [ + "DatabaseS3ExportRole9E328562", + "Arn" + ] + } + }] + })); + + expect(stack).to(haveResource("AWS::RDS::DBClusterParameterGroup", { + Family: 'family', + Parameters: { + key: 'value', + aurora_load_from_s3_role: { + "Fn::GetAtt": [ + "DatabaseS3ImportRole377BC9C0", + "Arn" + ] + }, + aurora_select_into_s3_role: { + "Fn::GetAtt": [ + "DatabaseS3ExportRole9E328562", + "Arn" + ] + } + } + })); + + test.done(); + }, + + 'PostgreSQL cluster with s3 export buckets does not generate custom parameter group'(test: Test) { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, "VPC"); + + const bucket = new s3.Bucket(stack, 'Bucket'); + + // WHEN + new DatabaseCluster(stack, "Database", { + engine: DatabaseClusterEngine.AURORA_POSTGRESQL, + instances: 1, + masterUser: { + username: "admin" + }, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc + }, + s3ExportBuckets: [bucket] + }); + + // THEN + expect(stack).to(haveResource("AWS::RDS::DBCluster", { + AssociatedRoles: [{ + RoleArn: { + "Fn::GetAtt": [ + "DatabaseS3ExportRole9E328562", + "Arn" + ] + } + }] + })); + + expect(stack).notTo(haveResource("AWS::RDS::DBClusterParameterGroup")); + + test.done(); + }, + + 'throws when s3ExportRole and s3ExportBuckets properties are both specified'(test: Test) { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, "VPC"); + + const exportRole = new Role(stack, 'ExportRole', { + assumedBy: new ServicePrincipal('rds.amazonaws.com'), + }); + const exportBucket = new s3.Bucket(stack, 'ExportBucket'); + + // THEN + test.throws(() => new DatabaseCluster(stack, "Database", { + engine: DatabaseClusterEngine.AURORA, + instances: 1, + masterUser: { + username: "admin" + }, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc + }, + s3ExportRole: exportRole, + s3ExportBuckets: [exportBucket], + })); + + test.done(); + }, + + 'throws when s3ImportRole and s3ImportBuckets properties are both specified'(test: Test) { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, "VPC"); + + const importRole = new Role(stack, 'ImportRole', { + assumedBy: new ServicePrincipal('rds.amazonaws.com'), + }); + const importBucket = new s3.Bucket(stack, 'ImportBucket'); + + // THEN + test.throws(() => new DatabaseCluster(stack, "Database", { + engine: DatabaseClusterEngine.AURORA, + instances: 1, + masterUser: { + username: "admin" + }, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc + }, + s3ImportRole: importRole, + s3ImportBuckets: [importBucket], + })); + + test.done(); + }, }; function testStack() { diff --git a/packages/@aws-cdk/aws-rds/test/test.parameter-group.ts b/packages/@aws-cdk/aws-rds/test/test.parameter-group.ts index c6a8b27af3392..077d93507a6c7 100644 --- a/packages/@aws-cdk/aws-rds/test/test.parameter-group.ts +++ b/packages/@aws-cdk/aws-rds/test/test.parameter-group.ts @@ -51,6 +51,34 @@ export = { } })); + test.done(); + }, + + 'Add an additional parameter to an existing parameter group'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const clusterParameterGroup = new ClusterParameterGroup(stack, 'Params', { + family: 'hello', + description: 'desc', + parameters: { + key1: 'value1' + } + }); + + clusterParameterGroup.addParameter('key2', 'value2'); + + // THEN + expect(stack).to(haveResource('AWS::RDS::DBClusterParameterGroup', { + Description: 'desc', + Family: 'hello', + Parameters: { + key1: 'value1', + key2: 'value2' + } + })); + test.done(); } }; diff --git a/packages/@aws-cdk/aws-rds/test/test.props.ts b/packages/@aws-cdk/aws-rds/test/test.props.ts new file mode 100644 index 0000000000000..bb395411ef09d --- /dev/null +++ b/packages/@aws-cdk/aws-rds/test/test.props.ts @@ -0,0 +1,111 @@ +import { SecretRotationApplication } from '@aws-cdk/aws-secretsmanager'; +import { Test } from 'nodeunit'; +import { DatabaseClusterEngine } from '../lib'; + +export = { + 'cluster parameter group correctly determined for AURORA'(test: Test) { + // GIVEN + const engine = DatabaseClusterEngine.AURORA; + + // WHEN + const family = engine.parameterGroupFamily(); + + // THEN + test.equals(family, 'aurora5.6'); + + test.done(); + }, + + 'cluster parameter group correctly determined for AURORA_MYSQL'(test: Test) { + // GIVEN + const engine = DatabaseClusterEngine.AURORA_MYSQL; + + // WHEN + const family = engine.parameterGroupFamily(); + + // THEN + test.equals(family, 'aurora-mysql5.7'); + + test.done(); + }, + + 'cluster parameter group correctly determined for AURORA_POSTGRESQL'(test: Test) { + // GIVEN + const engine = DatabaseClusterEngine.AURORA_POSTGRESQL; + + // WHEN + const family = engine.parameterGroupFamily(); + + // THEN + test.equals(family, 'aurora-postgresql11'); + + test.done(); + }, + + 'cluster parameter group correctly determined for AURORA and given version'(test: Test) { + // GIVEN + const engine = DatabaseClusterEngine.AURORA; + + // WHEN + const family = engine.parameterGroupFamily('5.6.mysql_aurora.1.22.2'); + + // THEN + test.equals(family, 'aurora5.6'); + + test.done(); + }, + + 'cluster parameter group correctly determined for AURORA_MYSQL and given version'(test: Test) { + // GIVEN + const engine = DatabaseClusterEngine.AURORA_MYSQL; + + // WHEN + const family = engine.parameterGroupFamily('5.7.mysql_aurora.2.07.1'); + + // THEN + test.equals(family, 'aurora-mysql5.7'); + + test.done(); + }, + + 'cluster parameter group correctly determined for AURORA_POSTGRESQL and given version'(test: Test) { + // GIVEN + const engine = DatabaseClusterEngine.AURORA_POSTGRESQL; + + // WHEN + const family = engine.parameterGroupFamily('11.6'); + + // THEN + test.equals(family, 'aurora-postgresql11'); + + test.done(); + }, + + 'parameter group family'(test: Test) { + // WHEN + const engine1 = new DatabaseClusterEngine( + 'no-parameter-group-family', + SecretRotationApplication.POSTGRES_ROTATION_SINGLE_USER, + SecretRotationApplication.POSTGRES_ROTATION_SINGLE_USER); + const engine2 = new DatabaseClusterEngine( + 'aurora-postgresql', + SecretRotationApplication.POSTGRES_ROTATION_SINGLE_USER, + SecretRotationApplication.POSTGRES_ROTATION_SINGLE_USER, + [ + { engineMajorVersion: '1.0', parameterGroupFamily: 'family-1'}, + { engineMajorVersion: '2.0', parameterGroupFamily: 'family-2' }, + ]); + + // THEN + test.equals(engine1.parameterGroupFamily(), undefined); + test.equals(engine1.parameterGroupFamily('1'), undefined); + + test.equals(engine2.parameterGroupFamily('3'), undefined); + test.equals(engine2.parameterGroupFamily('1'), undefined); + test.equals(engine2.parameterGroupFamily('1.1'), undefined); + test.equals(engine2.parameterGroupFamily('1.0'), 'family-1'); + test.equals(engine2.parameterGroupFamily('2.0.2'), 'family-2'); + + test.done(); + } +}; From 450b7a8169dd1171990cfe85b23df02959ce7f59 Mon Sep 17 00:00:00 2001 From: Ben Limmer Date: Fri, 27 Mar 2020 11:44:12 -0600 Subject: [PATCH 09/53] docs(apigateway): add documentation for stage default method throttling (#6900) It took me a good deal of time to understand how to configure default method throttling for my deployment stage. Because of the special '/*/*' path, I thought that an explicit example in the documentation could help others secure their apigateway endpoints with default method throttles, especially since the default throttles are quite high (5,000 rate limit / 10,000 burst limit). Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- packages/@aws-cdk/aws-apigateway/README.md | 35 ++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/packages/@aws-cdk/aws-apigateway/README.md b/packages/@aws-cdk/aws-apigateway/README.md index f7ac9755270c1..34d414c0f9f36 100644 --- a/packages/@aws-cdk/aws-apigateway/README.md +++ b/packages/@aws-cdk/aws-apigateway/README.md @@ -546,6 +546,41 @@ const api = new apigateway.RestApi(this, 'books', { }) ``` +You can use the `methodOptions` property to configure +[default method throttling](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-request-throttling.html#apigateway-api-level-throttling-in-usage-plan) +for a stage. The following snippet configures the a stage that accepts +100 requests per minute, allowing burst up to 200 requests per minute. + +```ts +const api = new apigateway.RestApi(this, 'books'); +const deployment = new apigateway.Deployment(this, 'my-deployment', { api }); +const stage = new apigateway.Stage(this, 'my-stage', { + deployment, + methodOptions: { + '/*/*': { // This special path applies to all resource paths and all HTTP methods + throttlingRateLimit: 100, + throttlingBurstLimit: 200 + } + } +}); +``` + +Configuring `methodOptions` on the `deployOptions` of `RestApi` will set the +throttling behaviors on the default stage that is automatically created. + +```ts +const api = new apigateway.RestApi(this, 'books', { + deployOptions: { + methodOptions: { + '/*/*': { // This special path applies to all resource paths and all HTTP methods + throttlingRateLimit: 100, + throttlingBurstLimit: 1000 + } + } + } +}); +``` + #### Deeper dive: invalidation of deployments API Gateway deployments are an immutable snapshot of the API. This means that we From e52097a49024a43610c6a07cbb0bf861c5bb9a0a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 27 Mar 2020 19:25:57 +0000 Subject: [PATCH 10/53] chore(deps): bump aws-sdk from 2.646.0 to 2.648.0 (#7045) Bumps [aws-sdk](https://github.com/aws/aws-sdk-js) from 2.646.0 to 2.648.0. - [Release notes](https://github.com/aws/aws-sdk-js/releases) - [Changelog](https://github.com/aws/aws-sdk-js/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-js/compare/v2.646.0...v2.648.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- packages/@aws-cdk/aws-cloudfront/package.json | 2 +- packages/@aws-cdk/aws-cloudtrail/package.json | 2 +- packages/@aws-cdk/aws-codebuild/package.json | 2 +- packages/@aws-cdk/aws-codecommit/package.json | 2 +- packages/@aws-cdk/aws-dynamodb/package.json | 2 +- packages/@aws-cdk/aws-eks/package.json | 2 +- packages/@aws-cdk/aws-events-targets/package.json | 2 +- packages/@aws-cdk/aws-lambda/package.json | 2 +- packages/@aws-cdk/aws-route53/package.json | 2 +- packages/@aws-cdk/aws-sqs/package.json | 2 +- packages/@aws-cdk/custom-resources/package.json | 2 +- packages/aws-cdk/package.json | 2 +- packages/cdk-assets/package.json | 2 +- yarn.lock | 8 ++++---- 14 files changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/@aws-cdk/aws-cloudfront/package.json b/packages/@aws-cdk/aws-cloudfront/package.json index 14cb9792e35b7..7a4239c504273 100644 --- a/packages/@aws-cdk/aws-cloudfront/package.json +++ b/packages/@aws-cdk/aws-cloudfront/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.646.0", + "aws-sdk": "^2.648.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudtrail/package.json b/packages/@aws-cdk/aws-cloudtrail/package.json index 227f6c7f27e6a..a28db00fc3e55 100644 --- a/packages/@aws-cdk/aws-cloudtrail/package.json +++ b/packages/@aws-cdk/aws-cloudtrail/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.646.0", + "aws-sdk": "^2.648.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-codebuild/package.json b/packages/@aws-cdk/aws-codebuild/package.json index 53f4b09f78cb9..ae6a3331e5a1b 100644 --- a/packages/@aws-cdk/aws-codebuild/package.json +++ b/packages/@aws-cdk/aws-codebuild/package.json @@ -70,7 +70,7 @@ "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.646.0", + "aws-sdk": "^2.648.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-codecommit/package.json b/packages/@aws-cdk/aws-codecommit/package.json index c524bccd5f896..c9dbf7c021c96 100644 --- a/packages/@aws-cdk/aws-codecommit/package.json +++ b/packages/@aws-cdk/aws-codecommit/package.json @@ -70,7 +70,7 @@ "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.646.0", + "aws-sdk": "^2.648.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-dynamodb/package.json b/packages/@aws-cdk/aws-dynamodb/package.json index 809095334e8ca..e7aec094f6238 100644 --- a/packages/@aws-cdk/aws-dynamodb/package.json +++ b/packages/@aws-cdk/aws-dynamodb/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.646.0", + "aws-sdk": "^2.648.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-eks/package.json b/packages/@aws-cdk/aws-eks/package.json index de62c9ef6e63d..4924f02579a7e 100644 --- a/packages/@aws-cdk/aws-eks/package.json +++ b/packages/@aws-cdk/aws-eks/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.646.0", + "aws-sdk": "^2.648.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-events-targets/package.json b/packages/@aws-cdk/aws-events-targets/package.json index 650320cf8a53a..f39e7a40bb7c2 100644 --- a/packages/@aws-cdk/aws-events-targets/package.json +++ b/packages/@aws-cdk/aws-events-targets/package.json @@ -86,7 +86,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-codecommit": "0.0.0", - "aws-sdk": "^2.646.0", + "aws-sdk": "^2.648.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-lambda/package.json b/packages/@aws-cdk/aws-lambda/package.json index aedbce223546d..25b0362367c1c 100644 --- a/packages/@aws-cdk/aws-lambda/package.json +++ b/packages/@aws-cdk/aws-lambda/package.json @@ -71,7 +71,7 @@ "@types/lodash": "^4.14.149", "@types/nodeunit": "^0.0.30", "@types/sinon": "^7.5.2", - "aws-sdk": "^2.646.0", + "aws-sdk": "^2.648.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-route53/package.json b/packages/@aws-cdk/aws-route53/package.json index 38564485a65ec..ee7a45fff725d 100644 --- a/packages/@aws-cdk/aws-route53/package.json +++ b/packages/@aws-cdk/aws-route53/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.646.0", + "aws-sdk": "^2.648.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-sqs/package.json b/packages/@aws-cdk/aws-sqs/package.json index ab66eb40f7405..77951dd6858c0 100644 --- a/packages/@aws-cdk/aws-sqs/package.json +++ b/packages/@aws-cdk/aws-sqs/package.json @@ -65,7 +65,7 @@ "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.646.0", + "aws-sdk": "^2.648.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/custom-resources/package.json b/packages/@aws-cdk/custom-resources/package.json index fd67b285373dd..f5567a07d8fd6 100644 --- a/packages/@aws-cdk/custom-resources/package.json +++ b/packages/@aws-cdk/custom-resources/package.json @@ -73,7 +73,7 @@ "@types/aws-lambda": "^8.10.39", "@types/fs-extra": "^8.1.0", "@types/sinon": "^7.5.2", - "aws-sdk": "^2.646.0", + "aws-sdk": "^2.648.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index 2192d9e0de991..24ab9cde20186 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -69,7 +69,7 @@ "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/region-info": "0.0.0", "archiver": "^3.1.1", - "aws-sdk": "^2.646.0", + "aws-sdk": "^2.648.0", "camelcase": "^5.3.1", "cdk-assets": "0.0.0", "colors": "^1.4.0", diff --git a/packages/cdk-assets/package.json b/packages/cdk-assets/package.json index b240b86dde671..5d38fbb4f8714 100644 --- a/packages/cdk-assets/package.json +++ b/packages/cdk-assets/package.json @@ -44,7 +44,7 @@ "dependencies": { "@aws-cdk/cdk-assets-schema": "0.0.0", "archiver": "^3.1.1", - "aws-sdk": "^2.646.0", + "aws-sdk": "^2.648.0", "glob": "^7.1.6", "yargs": "^15.3.1" }, diff --git a/yarn.lock b/yarn.lock index 6b23bae5f39d0..427c1bccf3e97 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2619,10 +2619,10 @@ aws-sdk-mock@^5.1.0: sinon "^9.0.1" traverse "^0.6.6" -aws-sdk@^2.637.0, aws-sdk@^2.646.0: - version "2.646.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.646.0.tgz#a5334912e09c56d4cb110d878f105832bc48d0f2" - integrity sha512-aL+NrZ/PfgOPY1jwTXwHjhdgVzuaKW00+GPMaisS0sNYdoKtjQfpXK6Z8zV7LWl73Jg9phUmHoYRqYjsVLMOMg== +aws-sdk@^2.637.0, aws-sdk@^2.648.0: + version "2.648.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.648.0.tgz#6cbea887b98c3ee8316870e9eead659194e35094" + integrity sha512-b+PdZmCFvZBisqXEH68jO4xB30LrDHQMWrEX6MJoZaOlxPJfpOqRFUH3zsiAXF5Q2jTdjYLtS5bs3vcIwRzi3Q== dependencies: buffer "4.9.1" events "1.1.1" From 74854488f1c5d9a479bd18aceda2c1817a5e201c Mon Sep 17 00:00:00 2001 From: Shiv Lakshminarayan Date: Fri, 27 Mar 2020 14:37:53 -0700 Subject: [PATCH 11/53] fix(stepfunctions-tasks): confusion between multiple ways to run a Lambda (#6796) The InvokeFunction Step Functions task is being marked as deprecated. It represents the legacy way to represent Lambda functions in Step Functions The RunLambda task represents the recommended way to invoke Lambdas in Step Functions. see: https://docs.aws.amazon.com/step-functions/latest/dg/connect-lambda.html Examples in the README have been updated to use RunLambdaTask Closes #4801 --- .../lib/invoke-function.ts | 4 ++ packages/@aws-cdk/aws-stepfunctions/README.md | 41 ++++++------------- 2 files changed, 16 insertions(+), 29 deletions(-) diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/invoke-function.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/invoke-function.ts index 5f9e5ffb94c4b..41210179a0dd0 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/invoke-function.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/invoke-function.ts @@ -4,6 +4,8 @@ import * as sfn from '@aws-cdk/aws-stepfunctions'; /** * Properties for InvokeFunction + * + * @deprecated use `RunLambdaTask` */ export interface InvokeFunctionProps { /** @@ -22,6 +24,8 @@ export interface InvokeFunctionProps { * The Lambda function Arn is defined as Resource in the state machine definition. * * OUTPUT: the output of this task is the return value of the Lambda Function. + * + * @deprecated Use `RunLambdaTask` */ export class InvokeFunction implements sfn.IStepFunctionsTask { constructor(private readonly lambdaFunction: lambda.IFunction, private readonly props: InvokeFunctionProps = {}) { diff --git a/packages/@aws-cdk/aws-stepfunctions/README.md b/packages/@aws-cdk/aws-stepfunctions/README.md index 70defad102f9b..b7c54e428d877 100644 --- a/packages/@aws-cdk/aws-stepfunctions/README.md +++ b/packages/@aws-cdk/aws-stepfunctions/README.md @@ -35,7 +35,9 @@ const submitLambda = new lambda.Function(this, 'SubmitLambda', { ... }); const getStatusLambda = new lambda.Function(this, 'CheckLambda', { ... }); const submitJob = new sfn.Task(this, 'Submit Job', { - task: new tasks.InvokeFunction(submitLambda), + task: new tasks.RunLambdaTask(submitLambda, { + integrationPattern: sfn.ServiceIntegrationPattern.WAIT_FOR_TASK_TOKEN, + }), // Put Lambda's result here in the execution's state object resultPath: '$.guid', }); @@ -45,7 +47,9 @@ const waitX = new sfn.Wait(this, 'Wait X Seconds', { }); const getStatus = new sfn.Task(this, 'Get Job Status', { - task: new tasks.InvokeFunction(getStatusLambda), + task: new tasks.RunLambdaTask(getStatusLambda, { + integrationPattern: sfn.ServiceIntegrationPattern.WAIT_FOR_TASK_TOKEN, + }), // Pass just the field named "guid" into the Lambda, put the // Lambda's result in a field called "status" inputPath: '$.guid', @@ -58,7 +62,9 @@ const jobFailed = new sfn.Fail(this, 'Job Failed', { }); const finalStatus = new sfn.Task(this, 'Get Final Job Status', { - task: new tasks.InvokeFunction(getStatusLambda), + task: new tasks.RunLambdaTask(getStatusLambda, { + integrationPattern: sfn.ServiceIntegrationPattern.WAIT_FOR_TASK_TOKEN, + }), // Use "guid" field as input, output of the Lambda becomes the // entire state machine output. inputPath: '$.guid', @@ -127,7 +133,6 @@ couple of the tasks available are: * `tasks.InvokeActivity` -- start an Activity (Activities represent a work queue that you poll on a compute fleet you manage yourself) -* `tasks.InvokeFunction` -- invoke a Lambda function with function ARN * `tasks.RunBatchJob` -- run a Batch job * `tasks.RunLambdaTask` -- call Lambda as integrated service with magic ARN * `tasks.RunGlueJobTask` -- call Glue Job as integrated service @@ -140,9 +145,9 @@ couple of the tasks available are: * `tasks.StartExecution` -- call StartExecution to a state machine of Step Functions * `tasks.EvaluateExpression` -- evaluate an expression referencing state paths -Except `tasks.InvokeActivity` and `tasks.InvokeFunction`, the [service integration +Except `tasks.InvokeActivity`, the [service integration pattern](https://docs.aws.amazon.com/step-functions/latest/dg/connect-to-resource.html) -(`integrationPattern`) are supposed to be given as parameter when customers want +(`integrationPattern`) is supposed to be provided as a parameter when customers want to call integrated services within a Task state. The default value is `FIRE_AND_FORGET`. #### Task parameters from the state json @@ -155,29 +160,7 @@ such as `Data.stringAt()`. If so, the value is taken from the indicated location in the state JSON, similar to (for example) `inputPath`. -#### Lambda example - InvokeFunction - -```ts -const task = new sfn.Task(this, 'Invoke1', { - task: new tasks.InvokeFunction(myLambda), - inputPath: '$.input', - timeout: Duration.minutes(5), -}); - -// Add a retry policy -task.addRetry({ - interval: Duration.seconds(5), - maxAttempts: 10 -}); - -// Add an error handler -task.addCatch(errorHandlerState); - -// Set the next state -task.next(nextState); -``` - -#### Lambda example - RunLambdaTask +#### Lambda example ```ts const task = new sfn.Task(stack, 'Invoke2', { From 45b68d5c7905559b70ef41867060ea42f03a3015 Mon Sep 17 00:00:00 2001 From: Pahud Hsieh Date: Sun, 29 Mar 2020 03:06:03 +0800 Subject: [PATCH 12/53] feat(applicationautoscaling): add PredefinedMetric for Lambda provisioned concurrency autoscaling (#6394) feat(applicationautoscaling): add PredefinedMetric for Lambda provisioned concurrency autoscaling (#6394 ) Closes #6369 --- .../aws-applicationautoscaling/README.md | 39 +++++++++++++++ .../lib/target-tracking-scaling-policy.ts | 49 +++++++++++++++++++ .../test/test.target-tracking.ts | 24 +++++++++ 3 files changed, 112 insertions(+) diff --git a/packages/@aws-cdk/aws-applicationautoscaling/README.md b/packages/@aws-cdk/aws-applicationautoscaling/README.md index 8f91543dbb0a5..899c8e8832666 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/README.md +++ b/packages/@aws-cdk/aws-applicationautoscaling/README.md @@ -157,3 +157,42 @@ capacity.scaleOnSchedule('AllowDownscalingAtNight', { schedule: autoscaling.Schedule.cron({ hour: '20', minute: '0' }), minCapacity: 1 }); +``` + +## Examples + +### Lambda Provisioned Concurrency Auto Scaling + +```ts + const handler = new lambda.Function(this, 'MyFunction', { + runtime: lambda.Runtime.PYTHON_3_7, + handler: 'index.handler', + code: new lambda.InlineCode(` +import json, time +def handler(event, context): + time.sleep(1) + return { + 'statusCode': 200, + 'body': json.dumps('Hello CDK from Lambda!') + }`), + reservedConcurrentExecutions: 2, + }); + + const fnVer = handler.addVersion('CDKLambdaVersion', undefined, 'demo alias', 10); + + new apigateway.LambdaRestApi(this, 'API', { handler: fnVer }) + + const target = new applicationautoscaling.ScalableTarget(this, 'ScalableTarget', { + serviceNamespace: applicationautoscaling.ServiceNamespace.LAMBDA, + maxCapacity: 100, + minCapacity: 10, + resourceId: `function:${handler.functionName}:${fnVer.version}`, + scalableDimension: 'lambda:function:ProvisionedConcurrency', + }) +s + target.scaleToTrackMetric('PceTracking', { + targetValue: 0.9, + predefinedMetric: applicationautoscaling.PredefinedMetric.LAMBDA_PROVISIONED_CONCURRENCY_UTILIZATION, + }) + } + ``` diff --git a/packages/@aws-cdk/aws-applicationautoscaling/lib/target-tracking-scaling-policy.ts b/packages/@aws-cdk/aws-applicationautoscaling/lib/target-tracking-scaling-policy.ts index f2f2a5bed2dfe..7ed301349a23f 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/lib/target-tracking-scaling-policy.ts +++ b/packages/@aws-cdk/aws-applicationautoscaling/lib/target-tracking-scaling-policy.ts @@ -173,15 +173,64 @@ function renderCustomMetric(metric?: cloudwatch.IMetric): CfnScalingPolicy.Custo * One of the predefined autoscaling metrics */ export enum PredefinedMetric { + /** + * DYNAMODB_READ_CAPACITY_UTILIZATIO + * @see https://docs.aws.amazon.com/autoscaling/application/APIReference/API_PredefinedMetricSpecification.html + */ DYNAMODB_READ_CAPACITY_UTILIZATION = 'DynamoDBReadCapacityUtilization', + /** + * DYANMODB_WRITE_CAPACITY_UTILIZATION + * @see https://docs.aws.amazon.com/autoscaling/application/APIReference/API_PredefinedMetricSpecification.html + */ DYANMODB_WRITE_CAPACITY_UTILIZATION = 'DynamoDBWriteCapacityUtilization', + /** + * ALB_REQUEST_COUNT_PER_TARGET + * @see https://docs.aws.amazon.com/autoscaling/application/APIReference/API_PredefinedMetricSpecification.html + */ ALB_REQUEST_COUNT_PER_TARGET = 'ALBRequestCountPerTarget', + /** + * RDS_READER_AVERAGE_CPU_UTILIZATION + * @see https://docs.aws.amazon.com/autoscaling/application/APIReference/API_PredefinedMetricSpecification.html + */ RDS_READER_AVERAGE_CPU_UTILIZATION = 'RDSReaderAverageCPUUtilization', + /** + * RDS_READER_AVERAGE_DATABASE_CONNECTIONS + * @see https://docs.aws.amazon.com/autoscaling/application/APIReference/API_PredefinedMetricSpecification.html + */ RDS_READER_AVERAGE_DATABASE_CONNECTIONS = 'RDSReaderAverageDatabaseConnections', + /** + * EC2_SPOT_FLEET_REQUEST_AVERAGE_CPU_UTILIZATION + * @see https://docs.aws.amazon.com/autoscaling/application/APIReference/API_PredefinedMetricSpecification.html + */ EC2_SPOT_FLEET_REQUEST_AVERAGE_CPU_UTILIZATION = 'EC2SpotFleetRequestAverageCPUUtilization', + /** + * EC2_SPOT_FLEET_REQUEST_AVERAGE_NETWORK_IN + * @see https://docs.aws.amazon.com/autoscaling/application/APIReference/API_PredefinedMetricSpecification.html + */ EC2_SPOT_FLEET_REQUEST_AVERAGE_NETWORK_IN = 'EC2SpotFleetRequestAverageNetworkIn', + /** + * EC2_SPOT_FLEET_REQUEST_AVERAGE_NETWORK_OUT + * @see https://docs.aws.amazon.com/autoscaling/application/APIReference/API_PredefinedMetricSpecification.html + */ EC2_SPOT_FLEET_REQUEST_AVERAGE_NETWORK_OUT = 'EC2SpotFleetRequestAverageNetworkOut', + /** + * SAGEMAKER_VARIANT_INVOCATIONS_PER_INSTANCE + * @see https://docs.aws.amazon.com/autoscaling/application/APIReference/API_PredefinedMetricSpecification.html + */ SAGEMAKER_VARIANT_INVOCATIONS_PER_INSTANCE = 'SageMakerVariantInvocationsPerInstance', + /** + * ECS_SERVICE_AVERAGE_CPU_UTILIZATION + * @see https://docs.aws.amazon.com/autoscaling/application/APIReference/API_PredefinedMetricSpecification.html + */ ECS_SERVICE_AVERAGE_CPU_UTILIZATION = 'ECSServiceAverageCPUUtilization', + /** + * ECS_SERVICE_AVERAGE_CPU_UTILIZATION + * @see https://docs.aws.amazon.com/autoscaling/application/APIReference/API_PredefinedMetricSpecification.html + */ ECS_SERVICE_AVERAGE_MEMORY_UTILIZATION = 'ECSServiceAverageMemoryUtilization', + /** + * LAMBDA_PROVISIONED_CONCURRENCY_UTILIZATION + * @see https://docs.aws.amazon.com/lambda/latest/dg/monitoring-metrics.html#monitoring-metrics-concurrency + */ + LAMBDA_PROVISIONED_CONCURRENCY_UTILIZATION = "LambdaProvisionedConcurrencyUtilization", } diff --git a/packages/@aws-cdk/aws-applicationautoscaling/test/test.target-tracking.ts b/packages/@aws-cdk/aws-applicationautoscaling/test/test.target-tracking.ts index c01826e5c7d6f..aefd3ecb10a10 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/test/test.target-tracking.ts +++ b/packages/@aws-cdk/aws-applicationautoscaling/test/test.target-tracking.ts @@ -30,6 +30,30 @@ export = { test.done(); }, + 'test setup target tracking on predefined metric for lambda'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const target = createScalableTarget(stack); + + // WHEN + target.scaleToTrackMetric('Tracking', { + predefinedMetric: appscaling.PredefinedMetric.LAMBDA_PROVISIONED_CONCURRENCY_UTILIZATION, + targetValue: 0.9, + }); + + // THEN + expect(stack).to(haveResource('AWS::ApplicationAutoScaling::ScalingPolicy', { + PolicyType: "TargetTrackingScaling", + TargetTrackingScalingPolicyConfiguration: { + PredefinedMetricSpecification: { PredefinedMetricType: "LambdaProvisionedConcurrencyUtilization" }, + TargetValue: 0.9 + } + + })); + + test.done(); + }, + 'test setup target tracking on custom metric'(test: Test) { // GIVEN const stack = new cdk.Stack(); From 260445732fd989c879260a9162200f490ba432d3 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 29 Mar 2020 05:33:35 +0000 Subject: [PATCH 13/53] chore(deps): bump eslint-plugin-import from 2.20.1 to 2.20.2 (#7056) Bumps [eslint-plugin-import](https://github.com/benmosher/eslint-plugin-import) from 2.20.1 to 2.20.2. - [Release notes](https://github.com/benmosher/eslint-plugin-import/releases) - [Changelog](https://github.com/benmosher/eslint-plugin-import/blob/master/CHANGELOG.md) - [Commits](https://github.com/benmosher/eslint-plugin-import/compare/v2.20.1...v2.20.2) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- tools/cdk-build-tools/package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/cdk-build-tools/package.json b/tools/cdk-build-tools/package.json index 1ef25d1110e49..03f547c1a40b6 100644 --- a/tools/cdk-build-tools/package.json +++ b/tools/cdk-build-tools/package.json @@ -44,7 +44,7 @@ "eslint": "^6.8.0", "eslint-import-resolver-node": "^0.3.3", "eslint-import-resolver-typescript": "^2.0.0", - "eslint-plugin-import": "^2.20.1", + "eslint-plugin-import": "^2.20.2", "fs-extra": "^8.1.0", "jest": "^24.9.0", "jsii": "^1.1.0", diff --git a/yarn.lock b/yarn.lock index 427c1bccf3e97..53ea94a099cf5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4761,10 +4761,10 @@ eslint-module-utils@^2.4.1: debug "^2.6.9" pkg-dir "^2.0.0" -eslint-plugin-import@^2.20.1: - version "2.20.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.20.1.tgz#802423196dcb11d9ce8435a5fc02a6d3b46939b3" - integrity sha512-qQHgFOTjguR+LnYRoToeZWT62XM55MBVXObHM6SKFd1VzDcX/vqT1kAz8ssqigh5eMj8qXcRoXXGZpPP6RfdCw== +eslint-plugin-import@^2.20.2: + version "2.20.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.20.2.tgz#91fc3807ce08be4837141272c8b99073906e588d" + integrity sha512-FObidqpXrR8OnCh4iNsxy+WACztJLXAHBO5hK79T1Hc77PgQZkyDGA5Ag9xAvRpglvLNxhH/zSmZ70/pZ31dHg== dependencies: array-includes "^3.0.3" array.prototype.flat "^1.2.1" From 3f75617ef5a90b40c04d7579cba3fccf6b4b31ef Mon Sep 17 00:00:00 2001 From: AlexCheema <41707476+AlexCheema@users.noreply.github.com> Date: Mon, 30 Mar 2020 00:02:14 +0200 Subject: [PATCH 14/53] chore(batch): update default value docs for min vcpus (#6781) --- packages/@aws-cdk/aws-batch/lib/compute-environment.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-batch/lib/compute-environment.ts b/packages/@aws-cdk/aws-batch/lib/compute-environment.ts index 49d4810d64f2e..b0e6016c9f4a3 100644 --- a/packages/@aws-cdk/aws-batch/lib/compute-environment.ts +++ b/packages/@aws-cdk/aws-batch/lib/compute-environment.ts @@ -172,7 +172,7 @@ export interface ComputeResources { * The minimum number of EC2 vCPUs that an environment should maintain (even if the compute environment state is DISABLED). * Each vCPU is equivalent to 1,024 CPU shares. You must specify at least one vCPU. * - * @default 1 + * @default 0 */ readonly minvCpus?: number; From 17aab3723f5e4ae8b06dac832774d457909722f8 Mon Sep 17 00:00:00 2001 From: netanir Date: Sun, 29 Mar 2020 22:22:44 -0700 Subject: [PATCH 15/53] fix(aws-kinesis): test assume order between stacks (#7065) Since StackA and StackB do not have a parent child relation, we can't assume StackB will be prepared between StackA. --- packages/@aws-cdk/aws-kinesis/test/test.stream.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/@aws-cdk/aws-kinesis/test/test.stream.ts b/packages/@aws-cdk/aws-kinesis/test/test.stream.ts index 40c37a49296ea..829e4f68f6b60 100644 --- a/packages/@aws-cdk/aws-kinesis/test/test.stream.ts +++ b/packages/@aws-cdk/aws-kinesis/test/test.stream.ts @@ -958,8 +958,7 @@ export = { const stackB = new Stack(app, 'stackB'); const user = new iam.User(stackB, 'UserWhoNeedsAccess'); streamFromStackA.grantRead(user); - - test.throws(() => app.synth(), /'stackB' depends on 'stackA'/); + test.throws(() => app.synth(), /'stack.' depends on 'stack.'/); test.done(); } } From d9bbc8e3559b3e89572914a6bab75994c113dc8b Mon Sep 17 00:00:00 2001 From: Shiv Lakshminarayan Date: Mon, 30 Mar 2020 01:44:47 -0700 Subject: [PATCH 16/53] chore: add key to disable announcing releases in awscdkio when creating missing libraries (#7064) chore: add key to disable announcing releases in awscdkio when creating missing libraries Following on from #6800 where we added a pkglint rule verifying that the awscdkio.announce key is set to false in `package.json` This change is to ensure that libraries created from Cfn spec updates in the future are compliant. --- .../@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts b/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts index 51741a5355403..8ee8a6600fda6 100644 --- a/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts +++ b/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts @@ -180,7 +180,10 @@ async function main() { engines: { node: '>= 10.3.0' }, - stability: "experimental" + stability: "experimental", + awscdkio: { + announce: false + } }); await write('.gitignore', [ From fa50e4a8203a40e15ae045810bcd5d24d9073349 Mon Sep 17 00:00:00 2001 From: Eli Polonsky Date: Mon, 30 Mar 2020 12:48:35 +0300 Subject: [PATCH 17/53] fix docstring for minVcpu in compute-environmnet according to console explanation (#7068) align docstring with actual default value. --- packages/@aws-cdk/aws-batch/lib/compute-environment.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-batch/lib/compute-environment.ts b/packages/@aws-cdk/aws-batch/lib/compute-environment.ts index b0e6016c9f4a3..0a48e274f9472 100644 --- a/packages/@aws-cdk/aws-batch/lib/compute-environment.ts +++ b/packages/@aws-cdk/aws-batch/lib/compute-environment.ts @@ -170,7 +170,8 @@ export interface ComputeResources { /** * The minimum number of EC2 vCPUs that an environment should maintain (even if the compute environment state is DISABLED). - * Each vCPU is equivalent to 1,024 CPU shares. You must specify at least one vCPU. + * Each vCPU is equivalent to 1,024 CPU shares. By keeping this set to 0 you will not have instance time wasted when + * there is no work to be run. If you set this above zero you will maintain that number of vCPUs at all times. * * @default 0 */ From 01ac364ddaac182e2607705a461606bdf6d9f753 Mon Sep 17 00:00:00 2001 From: Shiv Lakshminarayan Date: Mon, 30 Mar 2020 04:36:20 -0700 Subject: [PATCH 18/53] docs(kinesis): refresh README and add updated snippets (#7038) docs(kinesis): refresh README and add updated snippets Adds some context around Amazon Kinesis and walks through use cases for the Stream construct. --- packages/@aws-cdk/aws-kinesis/README.md | 94 +++++++++++++++++++++---- 1 file changed, 80 insertions(+), 14 deletions(-) diff --git a/packages/@aws-cdk/aws-kinesis/README.md b/packages/@aws-cdk/aws-kinesis/README.md index 6ffbb5db59a2e..2e7e0e6a26176 100644 --- a/packages/@aws-cdk/aws-kinesis/README.md +++ b/packages/@aws-cdk/aws-kinesis/README.md @@ -17,34 +17,100 @@ --- -Define an unencrypted Kinesis stream. +[Amazon Kinesis](https://docs.aws.amazon.com/streams/latest/dev/introduction.html) provides collection and processing of large +[streams](https://aws.amazon.com/streaming-data/) of data records in real time. Kinesis data streams can be used for rapid and continuous data +intake and aggregation. + +## Table Of Contents + +- [Streams](#streams) + - [Encryption](#encryption) + - [Import](#import) + +## Streams + +Amazon Kinesis Data Streams ingests a large amount of data in real time, durably stores the data, and makes the data available for consumption. + +Using the CDK, a new Kinesis stream can be created as part of the stack using the construct's constructor. You may specify the `streamName` to give +your own identifier to the stream. If not, CloudFormation will generate a name. + +```ts +new Stream(this, "MyFirstStream", { + streamName: "my-awesome-stream" +}); +``` + +You can also specify properties such as `shardCount` to indicate how many shards the stream should choose and a `retentionPeriod` +to specify how many logn the data in the shards should remain accessible. +Read more at [Creating and Managing Streams](https://docs.aws.amazon.com/streams/latest/dev/working-with-streams.html) ```ts -new Stream(this, 'MyFirstStream'); +new Stream(this, "MyFirstStream", { + streamName: "my-awesome-stream", + shardCount: 3, + retentionPeriod: Duration.hours(48) +}); ``` +Streams are not encrypted by default. + ### Encryption -Define a KMS-encrypted stream: +[Stream encryption](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesis-stream-streamencryption.html) enables +server-side encryption using an AWS KMS key for a specified stream. + +You can enable encryption on your streams by specifying the `encryption` property. A KMS key will be created for you and associated with the stream. ```ts -const stream = new Stream(this, 'MyEncryptedStream', { - encryption: StreamEncryption.Kms +const stream = new Stream(this, "MyEncryptedStream", { + encryption: StreamEncryption.KMS }); - -// you can access the encryption key: -assert(stream.encryptionKey instanceof kms.Key); ``` -You can also supply your own key: +You can also supply your own external KMS key to use for stream encryption by specifying the `encryptionKey` property. ```ts -const myKmsKey = new kms.Key(this, 'MyKey'); +import * as kms from "@aws-cdk/aws-kms"; -const stream = new Stream(this, 'MyEncryptedStream', { - encryption: StreamEncryption.Kms, - encryptionKey: myKmsKey +const key = new kms.Key(this, "MyKey"); + +const stream = new Stream(this, "MyEncryptedStream", { + encryption: StreamEncryption.KMS, + encryptionKey: key }); +``` + +### Import + +Any Kinesis stream that has been created outside the stack can be imported into your CDK app. + +Streams can be imported by their ARN via the `Stream.fromStreamArn()` API + +```ts +const stack = new Stack(app, "MyStack"); + +const importedStream = Stream.fromStreamArn( + stack, + "ImportedStream", + "arn:aws:kinesis:us-east-2:123456789012:stream/f3j09j2230j" +); +``` + +Encrypted Streams can also be imported by their attributes via the `Stream.fromStreamAttributes()` API + +```ts +import { Key } from "@aws-cdk/aws-kms"; + +const stack = new Stack(app, "MyStack"); -assert(stream.encryptionKey === myKmsKey); +const importedStream = Stream.fromStreamAttributes( + stack, + "ImportedEncryptedStream", + { + streamArn: "arn:aws:kinesis:us-east-2:123456789012:stream/f3j09j2230j", + encryptionKey: kms.Key.fromKeyArn( + "arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012" + ) + } +); ``` From 3dc3d75b17855d344b45a1dc48eb6b422237bff6 Mon Sep 17 00:00:00 2001 From: Jonathan Goldwasser Date: Mon, 30 Mar 2020 17:27:03 +0200 Subject: [PATCH 19/53] feat(amplify): source code providers (#6921) feat(amplify): source code providers Add source code providers classes for GitHub and CodeCommit that implement a new `ISourceCodeProvider` interface. Fixes #6818 BREAKING CHANGE: use the `sourceCodeProvider` prop to connect your app to a source code provider. The props `repository`, `accessToken` and `oauthToken` do not exist anymore in `AppProps`. --- packages/@aws-cdk/aws-amplify/README.md | 21 ++- packages/@aws-cdk/aws-amplify/lib/app.ts | 87 +++++++----- packages/@aws-cdk/aws-amplify/lib/index.ts | 1 + .../aws-amplify/lib/source-code-providers.ts | 62 +++++++++ packages/@aws-cdk/aws-amplify/package.json | 2 + .../@aws-cdk/aws-amplify/test/app.test.ts | 130 ++++++++++++++---- .../@aws-cdk/aws-amplify/test/branch.test.ts | 7 +- .../@aws-cdk/aws-amplify/test/domain.test.ts | 14 +- .../test/integ.app-codecommit.expected.json | 85 ++++++++++++ .../aws-amplify/test/integ.app-codecommit.ts | 23 ++++ .../@aws-cdk/aws-codecommit/lib/repository.ts | 47 +++++++ .../aws-codecommit/test/test.codecommit.ts | 48 ++++++- 12 files changed, 457 insertions(+), 70 deletions(-) create mode 100644 packages/@aws-cdk/aws-amplify/lib/source-code-providers.ts create mode 100644 packages/@aws-cdk/aws-amplify/test/integ.app-codecommit.expected.json create mode 100644 packages/@aws-cdk/aws-amplify/test/integ.app-codecommit.ts diff --git a/packages/@aws-cdk/aws-amplify/README.md b/packages/@aws-cdk/aws-amplify/README.md index dcadc124c4163..f72790e1dba58 100644 --- a/packages/@aws-cdk/aws-amplify/README.md +++ b/packages/@aws-cdk/aws-amplify/README.md @@ -27,8 +27,11 @@ import amplify = require('@aws-cdk/aws-amplify'); import cdk = require('@aws-cdk/core'); const amplifyApp = new amplify.App(this, 'MyApp', { - repository: 'https://github.com//', - oauthToken: cdk.SecretValue.secretsManager('my-github-token'), + sourceCodeProvider: new amplify.GitHubSourceCodeProvider({ + owner: '', + repository: '', + oauthToken: cdk.SecretValue.secretsManager('my-github-token') + }), buildSpec: codebuild.BuildSpec.fromObject({ // Alternatively add a `amplify.yml` to the repo version: '1.0', frontend: { @@ -53,6 +56,20 @@ const amplifyApp = new amplify.App(this, 'MyApp', { }); ``` +To connect your `App` to CodeCommit, use the `CodeCommitSourceCodeProvider`: +```ts +const repository = new codecommit.Repository(this, 'Repo', { + repositoryName: 'my-repo' +}); + +const amplifyApp = new amplify.App(this, 'App', { + sourceCodeProvider: new amplify.CodeCommitSourceCodeProvider({ repository }) +}); +``` + +The IAM role associated with the `App` will automatically be granted the permission +to pull the CodeCommit repository. + Add branches: ```ts const master = amplifyApp.addBranch('master'); // `id` will be used as repo branch name diff --git a/packages/@aws-cdk/aws-amplify/lib/app.ts b/packages/@aws-cdk/aws-amplify/lib/app.ts index 84226418c0510..c3d5db9c1fca3 100644 --- a/packages/@aws-cdk/aws-amplify/lib/app.ts +++ b/packages/@aws-cdk/aws-amplify/lib/app.ts @@ -20,9 +20,27 @@ export interface IApp extends IResource { } /** - * Properties for an App + * Configuration for the source code provider */ -export interface AppProps { +export interface SourceCodeProviderConfig { + /** + * The repository for the application. Must use the `HTTPS` protocol. + * + * @example https://github.com/aws/aws-cdk + */ + readonly repository: string; + + /** + * OAuth token for 3rd party source control system for an Amplify App, used + * to create webhook and read-only deploy key. OAuth token is not stored. + * + * Either `accessToken` or `oauthToken` must be specified if `repository` + * is sepcified. + * + * @default - do not use a token + */ + readonly oauthToken?: SecretValue; + /** * Personal Access token for 3rd party source control system for an Amplify * App, used to create webhook and read-only deploy key. Token is not stored. @@ -30,10 +48,27 @@ export interface AppProps { * Either `accessToken` or `oauthToken` must be specified if `repository` * is sepcified. * - * @default - use OAuth token + * @default - do not use a token */ readonly accessToken?: SecretValue; +} + +/** + * A source code provider + */ +export interface ISourceCodeProvider { + /** + * Binds the source code provider to an app + * + * @param app The app [disable-awslint:ref-via-interface] + */ + bind(app: App): SourceCodeProviderConfig; +} +/** + * Properties for an App + */ +export interface AppProps { /** * The name for the application * @@ -41,6 +76,13 @@ export interface AppProps { */ readonly appName?: string; + /** + * The source code provider for this application + * + * @default - not connected to a source code provider + */ + readonly sourceCodeProvider?: ISourceCodeProvider; + /** * The auto branch creation configuration. Use this to automatically create * branches that match a certain pattern. @@ -92,31 +134,12 @@ export interface AppProps { readonly environmentVariables?: { [name: string]: string }; /** - * The IAM service role to associate with the application + * The IAM service role to associate with the application. The App + * implements IGrantable. * * @default - a new role is created */ readonly role?: iam.IRole; - - /** - * OAuth token for 3rd party source control system for an Amplify App, used - * to create webhook and read-only deploy key. OAuth token is not stored. - * - * Either `accessToken` or `oauthToken` must be specified if `repository` - * is sepcified. - * - * @default - use access token - */ - readonly oauthToken?: SecretValue; - - /** - * The repository for the application. Must use the `HTTPS` protocol. - * - * @example https://github.com/aws/aws-cdk - * - * @default - not connected to a repository - */ - readonly repository?: string; } /** @@ -168,14 +191,6 @@ export class App extends Resource implements IApp, iam.IGrantable { constructor(scope: Construct, id: string, props: AppProps) { super(scope, id); - if (props.repository && !props.accessToken && !props.oauthToken) { - throw new Error('Either `accessToken` or `oauthToken` must be specified'); - } - - if (props.repository && !props.repository.startsWith('https://')) { - throw new Error('`repository` must use the HTTPS protocol'); - } - this.customRules = props.customRules || []; this.environmentVariables = props.environmentVariables || {}; this.autoBranchEnvironmentVariables = props.autoBranchCreation && props.autoBranchCreation.environmentVariables || {}; @@ -185,8 +200,10 @@ export class App extends Resource implements IApp, iam.IGrantable { }); this.grantPrincipal = role; + const sourceCodeProviderOptions = props.sourceCodeProvider?.bind(this); + const app = new CfnApp(this, 'Resource', { - accessToken: props.accessToken && props.accessToken.toString(), + accessToken: sourceCodeProviderOptions?.accessToken?.toString(), autoBranchCreationConfig: props.autoBranchCreation && { autoBranchCreationPatterns: props.autoBranchCreation.patterns, basicAuthConfig: props.autoBranchCreation.basicAuth && props.autoBranchCreation.basicAuth.bind(this, 'BranchBasicAuth'), @@ -205,8 +222,8 @@ export class App extends Resource implements IApp, iam.IGrantable { environmentVariables: Lazy.anyValue({ produce: () => renderEnvironmentVariables(this.environmentVariables) }, { omitEmptyArray: true }), iamServiceRole: role.roleArn, name: props.appName || this.node.id, - oauthToken: props.oauthToken && props.oauthToken.toString(), - repository: props.repository, + oauthToken: sourceCodeProviderOptions?.oauthToken?.toString(), + repository: sourceCodeProviderOptions?.repository, }); this.appId = app.attrAppId; diff --git a/packages/@aws-cdk/aws-amplify/lib/index.ts b/packages/@aws-cdk/aws-amplify/lib/index.ts index 9be2bd2d75f68..5a89be4af844c 100644 --- a/packages/@aws-cdk/aws-amplify/lib/index.ts +++ b/packages/@aws-cdk/aws-amplify/lib/index.ts @@ -2,6 +2,7 @@ export * from './app'; export * from './branch'; export * from './domain'; export * from './basic-auth'; +export * from './source-code-providers'; // AWS::Amplify CloudFormation Resources: export * from './amplify.generated'; diff --git a/packages/@aws-cdk/aws-amplify/lib/source-code-providers.ts b/packages/@aws-cdk/aws-amplify/lib/source-code-providers.ts new file mode 100644 index 0000000000000..17b8b09aa69fd --- /dev/null +++ b/packages/@aws-cdk/aws-amplify/lib/source-code-providers.ts @@ -0,0 +1,62 @@ +import * as codecommit from '@aws-cdk/aws-codecommit'; +import { SecretValue } from '@aws-cdk/core'; +import { App, ISourceCodeProvider, SourceCodeProviderConfig } from './app'; + +/** + * Properties for a GitHub source code provider + */ +export interface GitHubSourceCodeProviderProps { + /** + * The user or organization owning the repository + */ + readonly owner: string; + + /** + * The name of the repository + */ + readonly repository: string; + + /** + * A personal access token with the `repo` scope + */ + readonly oauthToken: SecretValue; +} + +/** + * GitHub source code provider + */ +export class GitHubSourceCodeProvider implements ISourceCodeProvider { + constructor(private readonly props: GitHubSourceCodeProviderProps) {} + + public bind(_app: App): SourceCodeProviderConfig { + return { + repository: `https://github.com/${this.props.owner}/${this.props.repository}`, + oauthToken: this.props.oauthToken + }; + } +} + +/** + * Properties for a CodeCommit source code provider + */ +export interface CodeCommitSourceCodeProviderProps { + /** + * The CodeCommit repository + */ + readonly repository: codecommit.IRepository; +} + +/** + * CodeCommit source code provider + */ +export class CodeCommitSourceCodeProvider implements ISourceCodeProvider { + constructor(private readonly props: CodeCommitSourceCodeProviderProps) {} + + public bind(app: App): SourceCodeProviderConfig { + this.props.repository.grantPull(app); + + return { + repository: this.props.repository.repositoryCloneUrlHttp + }; + } +} diff --git a/packages/@aws-cdk/aws-amplify/package.json b/packages/@aws-cdk/aws-amplify/package.json index 7fba9c5e07dce..99a1ee3399398 100644 --- a/packages/@aws-cdk/aws-amplify/package.json +++ b/packages/@aws-cdk/aws-amplify/package.json @@ -91,6 +91,7 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-codebuild": "0.0.0", + "@aws-cdk/aws-codecommit": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^2.0.0" @@ -99,6 +100,7 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-codebuild": "0.0.0", + "@aws-cdk/aws-codecommit": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^2.0.0" diff --git a/packages/@aws-cdk/aws-amplify/test/app.test.ts b/packages/@aws-cdk/aws-amplify/test/app.test.ts index 170cc3b9e76a6..89e3b48392a61 100644 --- a/packages/@aws-cdk/aws-amplify/test/app.test.ts +++ b/packages/@aws-cdk/aws-amplify/test/app.test.ts @@ -1,5 +1,6 @@ import '@aws-cdk/assert/jest'; import * as codebuild from '@aws-cdk/aws-codebuild'; +import * as codecommit from '@aws-cdk/aws-codecommit'; import { SecretValue, Stack } from '@aws-cdk/core'; import * as amplify from '../lib'; @@ -8,11 +9,14 @@ beforeEach(() => { stack = new Stack(); }); -test('create an app', () => { +test('create an app connected to a GitHub repository', () => { // WHEN new amplify.App(stack, 'App', { - repository: 'https://github.com/aws/aws-cdk', - oauthToken: SecretValue.plainText('secret'), + sourceCodeProvider: new amplify.GitHubSourceCodeProvider({ + owner: 'aws', + repository: 'aws-cdk', + oauthToken: SecretValue.plainText('secret') + }), buildSpec: codebuild.BuildSpec.fromObject({ version: '1.0', frontend: { @@ -57,11 +61,86 @@ test('create an app', () => { }); }); +test('create an app connected to a CodeCommit repository', () => { + // WHEN + new amplify.App(stack, 'App', { + sourceCodeProvider: new amplify.CodeCommitSourceCodeProvider({ + repository: codecommit.Repository.fromRepositoryName(stack, 'Repo', 'my-repo'), + }), + }); + + // THEN + expect(stack).toHaveResource('AWS::Amplify::App', { + IAMServiceRole: { + 'Fn::GetAtt': [ + 'AppRole1AF9B530', + 'Arn' + ] + }, + Repository: { + 'Fn::Join': [ + '', + [ + 'https://git-codecommit.', + { + Ref: 'AWS::Region' + }, + '.', + { + Ref: 'AWS::URLSuffix' + }, + '/v1/repos/my-repo' + ] + ] + } + }); + + expect(stack).toHaveResource('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: 'codecommit:GitPull', + Effect: 'Allow', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition' + }, + ':codecommit:', + { + Ref: 'AWS::Region' + }, + ':', + { + Ref: 'AWS::AccountId' + }, + ':my-repo' + ] + ] + }, + } + ], + Version: '2012-10-17' + }, + Roles: [ + { + Ref: 'AppRole1AF9B530' + } + ] + }); +}); + test('with basic auth from credentials', () => { // WHEN new amplify.App(stack, 'App', { - repository: 'https://github.com/aws/aws-cdk', - oauthToken: SecretValue.plainText('secret'), + sourceCodeProvider: new amplify.GitHubSourceCodeProvider({ + owner: 'aws', + repository: 'aws-cdk', + oauthToken: SecretValue.plainText('secret') + }), basicAuth: amplify.BasicAuth.fromCredentials('username', SecretValue.plainText('password')) }); @@ -78,8 +157,11 @@ test('with basic auth from credentials', () => { test('with basic auth from generated password', () => { // WHEN new amplify.App(stack, 'App', { - repository: 'https://github.com/aws/aws-cdk', - oauthToken: SecretValue.plainText('secret'), + sourceCodeProvider: new amplify.GitHubSourceCodeProvider({ + owner: 'aws', + repository: 'aws-cdk', + oauthToken: SecretValue.plainText('secret') + }), basicAuth: amplify.BasicAuth.fromGeneratedPassword('username') }); @@ -114,8 +196,11 @@ test('with basic auth from generated password', () => { test('with env vars', () => { // WHEN const app = new amplify.App(stack, 'App', { - repository: 'https://github.com/aws/aws-cdk', - oauthToken: SecretValue.plainText('secret'), + sourceCodeProvider: new amplify.GitHubSourceCodeProvider({ + owner: 'aws', + repository: 'aws-cdk', + oauthToken: SecretValue.plainText('secret') + }), environmentVariables: { key1: 'value1' } @@ -140,8 +225,11 @@ test('with env vars', () => { test('with custom rules', () => { // WHEN const app = new amplify.App(stack, 'App', { - repository: 'https://github.com/aws/aws-cdk', - oauthToken: SecretValue.plainText('secret'), + sourceCodeProvider: new amplify.GitHubSourceCodeProvider({ + owner: 'aws', + repository: 'aws-cdk', + oauthToken: SecretValue.plainText('secret') + }), customRules: [ { source: '/source1', @@ -176,8 +264,11 @@ test('with custom rules', () => { test('with auto branch creation', () => { // WHEN const app = new amplify.App(stack, 'App', { - repository: 'https://github.com/aws/aws-cdk', - oauthToken: SecretValue.plainText('secret'), + sourceCodeProvider: new amplify.GitHubSourceCodeProvider({ + owner: 'aws', + repository: 'aws-cdk', + oauthToken: SecretValue.plainText('secret') + }), autoBranchCreation: { environmentVariables: { key1: 'value1' @@ -205,16 +296,3 @@ test('with auto branch creation', () => { } }); }); - -test('throws when both access token and oauth token are not specified', () => { - expect(() => new amplify.App(stack, 'App', { - repository: 'https://github.com/aws/aws-cdk' - })).toThrow('Either `accessToken` or `oauthToken` must be specified'); -}); - -test('throws if repository is not https', () => { - expect(() => new amplify.App(stack, 'App', { - repository: 'git@github.com:aws/aws-cdk.git', - oauthToken: SecretValue.plainText('secret'), - })).toThrow('`repository` must use the HTTPS protocol'); -}); diff --git a/packages/@aws-cdk/aws-amplify/test/branch.test.ts b/packages/@aws-cdk/aws-amplify/test/branch.test.ts index a507d5d51f212..13e6e2ebe8dcb 100644 --- a/packages/@aws-cdk/aws-amplify/test/branch.test.ts +++ b/packages/@aws-cdk/aws-amplify/test/branch.test.ts @@ -7,8 +7,11 @@ let app: amplify.App; beforeEach(() => { stack = new Stack(); app = new amplify.App(stack, 'App', { - repository: 'https://github.com/aws/aws-cdk', - oauthToken: SecretValue.plainText('secret'), + sourceCodeProvider: new amplify.GitHubSourceCodeProvider({ + owner: 'aws', + repository: 'aws-cdk', + oauthToken: SecretValue.plainText('secret') + }), }); }); diff --git a/packages/@aws-cdk/aws-amplify/test/domain.test.ts b/packages/@aws-cdk/aws-amplify/test/domain.test.ts index 60e15af86f38a..b018a2186fcef 100644 --- a/packages/@aws-cdk/aws-amplify/test/domain.test.ts +++ b/packages/@aws-cdk/aws-amplify/test/domain.test.ts @@ -6,8 +6,11 @@ test('create a domain', () => { // GIVEN const stack = new Stack(); const app = new amplify.App(stack, 'App', { - repository: 'https://github.com/aws/aws-cdk', - oauthToken: SecretValue.plainText('secret'), + sourceCodeProvider: new amplify.GitHubSourceCodeProvider({ + owner: 'aws', + repository: 'aws-cdk', + oauthToken: SecretValue.plainText('secret') + }), }); const prodBranch = app.addBranch('master'); const devBranch = app.addBranch('dev'); @@ -65,8 +68,11 @@ test('throws at synthesis without subdomains', () => { const app = new App(); const stack = new Stack(app, 'test-stack'); const amplifyApp = new amplify.App(stack, 'App', { - repository: 'https://github.com/aws/aws-cdk', - oauthToken: SecretValue.plainText('secret'), + sourceCodeProvider: new amplify.GitHubSourceCodeProvider({ + owner: 'aws', + repository: 'aws-cdk', + oauthToken: SecretValue.plainText('secret') + }), }); // WHEN diff --git a/packages/@aws-cdk/aws-amplify/test/integ.app-codecommit.expected.json b/packages/@aws-cdk/aws-amplify/test/integ.app-codecommit.expected.json new file mode 100644 index 0000000000000..3c8d758a92492 --- /dev/null +++ b/packages/@aws-cdk/aws-amplify/test/integ.app-codecommit.expected.json @@ -0,0 +1,85 @@ +{ + "Resources": { + "Repo02AC86CF": { + "Type": "AWS::CodeCommit::Repository", + "Properties": { + "RepositoryName": "integ-amplify-app" + } + }, + "AppRole1AF9B530": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "amplify.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "AppRoleDefaultPolicy9CADBAA1": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "codecommit:GitPull", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "Repo02AC86CF", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "AppRoleDefaultPolicy9CADBAA1", + "Roles": [ + { + "Ref": "AppRole1AF9B530" + } + ] + } + }, + "AppF1B96344": { + "Type": "AWS::Amplify::App", + "Properties": { + "Name": "App", + "IAMServiceRole": { + "Fn::GetAtt": [ + "AppRole1AF9B530", + "Arn" + ] + }, + "Repository": { + "Fn::GetAtt": [ + "Repo02AC86CF", + "CloneUrlHttp" + ] + } + } + }, + "Appmaster71597E87": { + "Type": "AWS::Amplify::Branch", + "Properties": { + "AppId": { + "Fn::GetAtt": [ + "AppF1B96344", + "AppId" + ] + }, + "BranchName": "master", + "EnableAutoBuild": true, + "EnablePullRequestPreview": true + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-amplify/test/integ.app-codecommit.ts b/packages/@aws-cdk/aws-amplify/test/integ.app-codecommit.ts new file mode 100644 index 0000000000000..6d253016de2ea --- /dev/null +++ b/packages/@aws-cdk/aws-amplify/test/integ.app-codecommit.ts @@ -0,0 +1,23 @@ +import * as codecommit from '@aws-cdk/aws-codecommit'; +import { App, Construct, Stack, StackProps } from '@aws-cdk/core'; +import * as amplify from '../lib'; + +class TestStack extends Stack { + constructor(scope: Construct, id: string, props?: StackProps) { + super(scope, id, props); + + const repository = new codecommit.Repository(this, 'Repo', { + repositoryName: 'integ-amplify-app' + }); + + const amplifyApp = new amplify.App(this, 'App', { + sourceCodeProvider: new amplify.CodeCommitSourceCodeProvider({ repository }) + }); + + amplifyApp.addBranch('master'); + } +} + +const app = new App(); +new TestStack(app, 'cdk-amplify-codecommit-app'); +app.synth(); diff --git a/packages/@aws-cdk/aws-codecommit/lib/repository.ts b/packages/@aws-cdk/aws-codecommit/lib/repository.ts index 1ef1517180984..29e1150c056b9 100644 --- a/packages/@aws-cdk/aws-codecommit/lib/repository.ts +++ b/packages/@aws-cdk/aws-codecommit/lib/repository.ts @@ -1,4 +1,5 @@ import * as events from '@aws-cdk/aws-events'; +import * as iam from '@aws-cdk/aws-iam'; import { Construct, IConstruct, IResource, Lazy, Resource, Stack } from '@aws-cdk/core'; import { CfnRepository } from './codecommit.generated'; @@ -76,6 +77,26 @@ export interface IRepository extends IResource { * Defines a CloudWatch event rule which triggers when a commit is pushed to a branch. */ onCommit(id: string, options?: OnCommitOptions): events.Rule; + + /** + * Grant the given principal identity permissions to perform the actions on this repository + */ + grant(grantee: iam.IGrantable, ...actions: string[]): iam.Grant; + + /** + * Grant the given identity permissions to pull this repository. + */ + grantPull(grantee: iam.IGrantable): iam.Grant; + + /** + * Grant the given identity permissions to pull and push this repository. + */ + grantPullPush(grantee: iam.IGrantable): iam.Grant; + + /** + * Grant the given identity permissions to read this repository. + */ + grantRead(grantee: iam.IGrantable): iam.Grant; } /** @@ -206,6 +227,32 @@ abstract class RepositoryBase extends Resource implements IRepository { } return rule; } + + public grant(grantee: iam.IGrantable, ...actions: string[]) { + return iam.Grant.addToPrincipal({ + grantee, + actions, + resourceArns: [this.repositoryArn], + }); + } + + public grantPull(grantee: iam.IGrantable) { + return this.grant(grantee, 'codecommit:GitPull'); + } + + public grantPullPush(grantee: iam.IGrantable) { + this.grantPull(grantee); + return this.grant(grantee, 'codecommit:GitPush'); + } + + public grantRead(grantee: iam.IGrantable) { + this.grantPull(grantee); + return this.grant(grantee, + 'codecommit:EvaluatePullRequestApprovalRules', + 'codecommit:Get*', + 'codecommit:Describe*', + ); + } } export interface RepositoryProps { diff --git a/packages/@aws-cdk/aws-codecommit/test/test.codecommit.ts b/packages/@aws-cdk/aws-codecommit/test/test.codecommit.ts index de4203bdfcaf9..9721f69feba9a 100644 --- a/packages/@aws-cdk/aws-codecommit/test/test.codecommit.ts +++ b/packages/@aws-cdk/aws-codecommit/test/test.codecommit.ts @@ -1,4 +1,5 @@ -import { expect } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert'; +import { Role, ServicePrincipal } from '@aws-cdk/aws-iam'; import { Stack } from '@aws-cdk/core'; import { Test } from 'nodeunit'; import { Repository, RepositoryProps } from '../lib'; @@ -89,5 +90,50 @@ export = { test.done(); }, + + 'grant push'(test: Test) { + // GIVEN + const stack = new Stack(); + const repository = new Repository(stack, 'Repo', { + repositoryName: 'repo-name' + }); + const role = new Role(stack, 'Role', { + assumedBy: new ServicePrincipal('ec2.amazonaws.com') + }); + + // WHEN + repository.grantPullPush(role); + + // THEN + expect(stack).to(haveResource('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: 'codecommit:GitPull', + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': [ + 'Repo02AC86CF', + 'Arn' + ] + }, + }, + { + Action: 'codecommit:GitPush', + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': [ + 'Repo02AC86CF', + 'Arn' + ] + }, + } + ], + Version: '2012-10-17' + } + })); + + test.done(); + } }, }; From 4c7afb827b4005e337dd4635a80a7767bcec7b11 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 30 Mar 2020 16:22:56 +0000 Subject: [PATCH 20/53] chore(deps): bump ts-jest from 25.2.1 to 25.3.0 (#7070) Bumps [ts-jest](https://github.com/kulshekhar/ts-jest) from 25.2.1 to 25.3.0. - [Release notes](https://github.com/kulshekhar/ts-jest/releases) - [Changelog](https://github.com/kulshekhar/ts-jest/blob/master/CHANGELOG.md) - [Commits](https://github.com/kulshekhar/ts-jest/compare/25.2.1...v25.3.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- packages/@aws-cdk/assert/package.json | 2 +- packages/@aws-cdk/aws-sam/package.json | 2 +- .../@aws-cdk/cloudformation-diff/package.json | 2 +- .../@monocdk-experiment/assert/package.json | 2 +- packages/aws-cdk/package.json | 2 +- tools/cdk-build-tools/package.json | 2 +- yarn.lock | 22 +++++++++---------- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/@aws-cdk/assert/package.json b/packages/@aws-cdk/assert/package.json index 3215143fb8f04..a30d4045fcddb 100644 --- a/packages/@aws-cdk/assert/package.json +++ b/packages/@aws-cdk/assert/package.json @@ -33,7 +33,7 @@ "cdk-build-tools": "0.0.0", "jest": "^24.9.0", "pkglint": "0.0.0", - "ts-jest": "^25.2.0" + "ts-jest": "^25.3.0" }, "dependencies": { "@aws-cdk/cloudformation-diff": "0.0.0", diff --git a/packages/@aws-cdk/aws-sam/package.json b/packages/@aws-cdk/aws-sam/package.json index 2633365e81a83..2c46a3aa4a0ab 100644 --- a/packages/@aws-cdk/aws-sam/package.json +++ b/packages/@aws-cdk/aws-sam/package.json @@ -69,7 +69,7 @@ "cfn2ts": "0.0.0", "jest": "^24.9.0", "pkglint": "0.0.0", - "ts-jest": "^25.2.0" + "ts-jest": "^25.3.0" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/cloudformation-diff/package.json b/packages/@aws-cdk/cloudformation-diff/package.json index 71b4dd40fd174..b876a079dbf00 100644 --- a/packages/@aws-cdk/cloudformation-diff/package.json +++ b/packages/@aws-cdk/cloudformation-diff/package.json @@ -45,7 +45,7 @@ "fast-check": "^1.22.2", "jest": "^24.9.0", "pkglint": "0.0.0", - "ts-jest": "^25.2.0" + "ts-jest": "^25.3.0" }, "repository": { "url": "https://github.com/aws/aws-cdk.git", diff --git a/packages/@monocdk-experiment/assert/package.json b/packages/@monocdk-experiment/assert/package.json index 3aabbf3af0062..eac564b2299ba 100644 --- a/packages/@monocdk-experiment/assert/package.json +++ b/packages/@monocdk-experiment/assert/package.json @@ -45,7 +45,7 @@ "cdk-build-tools": "0.0.0", "jest": "^24.9.0", "pkglint": "0.0.0", - "ts-jest": "^25.2.0", + "ts-jest": "^25.3.0", "@monocdk-experiment/rewrite-imports": "0.0.0", "monocdk-experiment": "0.0.0", "constructs": "^2.0.0" diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index 24ab9cde20186..78fd3adfabc37 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -61,7 +61,7 @@ "mockery": "^2.1.0", "pkglint": "0.0.0", "sinon": "^9.0.1", - "ts-jest": "^25.2.0" + "ts-jest": "^25.3.0" }, "dependencies": { "@aws-cdk/cdk-assets-schema": "0.0.0", diff --git a/tools/cdk-build-tools/package.json b/tools/cdk-build-tools/package.json index 03f547c1a40b6..242e91c9a7c2b 100644 --- a/tools/cdk-build-tools/package.json +++ b/tools/cdk-build-tools/package.json @@ -51,7 +51,7 @@ "jsii-pacmak": "^1.1.0", "nodeunit": "^0.11.3", "nyc": "^15.0.0", - "ts-jest": "^25.2.0", + "ts-jest": "^25.3.0", "tslint": "^5.20.1", "typescript": "~3.8.3", "yargs": "^15.3.1" diff --git a/yarn.lock b/yarn.lock index 53ea94a099cf5..7d29a353f141e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7883,12 +7883,12 @@ mkdirp-promise@^5.0.1: dependencies: mkdirp "*" -mkdirp@*: +mkdirp@*, mkdirp@1.x: version "1.0.3" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.3.tgz#4cf2e30ad45959dddea53ad97d518b6c8205e1ea" integrity sha512-6uCP4Qc0sWsgMLy1EOqqS/3rjDHOEnsStVr/4vtAIK2Y5i2kA7lFFejYrpIyiN9w0pYf4ckeCYT9f1r1P9KX5g== -mkdirp@0.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1: +mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= @@ -10207,12 +10207,12 @@ semver-intersect@^1.4.0: dependencies: semver "^5.0.0" -"semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", semver@^5.0.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.0, semver@^5.7.1: +"semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", semver@^5.0.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.0, semver@^5.7.1: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@6.3.0, semver@^6.0.0, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: +semver@6.3.0, semver@6.x, semver@^6.0.0, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== @@ -11305,10 +11305,10 @@ trivial-deferred@^1.0.1: resolved "https://registry.yarnpkg.com/trivial-deferred/-/trivial-deferred-1.0.1.tgz#376d4d29d951d6368a6f7a0ae85c2f4d5e0658f3" integrity sha1-N21NKdlR1jaKb3oK6FwvTV4GWPM= -ts-jest@^25.2.0: - version "25.2.1" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-25.2.1.tgz#49bf05da26a8b7fbfbc36b4ae2fcdc2fef35c85d" - integrity sha512-TnntkEEjuXq/Gxpw7xToarmHbAafgCaAzOpnajnFC6jI7oo1trMzAHA04eWpc3MhV6+yvhE8uUBAmN+teRJh0A== +ts-jest@^25.3.0: + version "25.3.0" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-25.3.0.tgz#c12d34573cbe34d49f10567940e44fd19d1c9178" + integrity sha512-qH/uhaC+AFDU9JfAueSr0epIFJkGMvUPog4FxSEVAtPOur1Oni5WBJMiQIkfHvc7PviVRsnlVLLY2I6221CQew== dependencies: bs-logger "0.x" buffer-from "1.x" @@ -11316,10 +11316,10 @@ ts-jest@^25.2.0: json5 "2.x" lodash.memoize "4.x" make-error "1.x" - mkdirp "0.x" + mkdirp "1.x" resolve "1.x" - semver "^5.5" - yargs-parser "^16.1.0" + semver "6.x" + yargs-parser "^18.1.1" ts-mock-imports@^1.3.0: version "1.3.0" From 9a552c275ee011fd794b27735503d139f538f70a Mon Sep 17 00:00:00 2001 From: AWS CDK Automation <43080478+aws-cdk-automation@users.noreply.github.com> Date: Mon, 30 Mar 2020 19:30:23 +0200 Subject: [PATCH 21/53] feat(cfnspec): cloudformation spec v11.6.0 (#6995) * feat: cloudformation spec v11.6.0 * add a patch for ResourceGroups Tags as the spec has ItemType specified instead of PrimitiveType * add missing awscdk.io to package.json for newly added resources * patch to resource groups to specify tags as Json type * add linter exclusions for added AppMesh attributes in the spec update Co-authored-by: AWS CDK Team Co-authored-by: Shiv Lakshminarayan Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- packages/@aws-cdk/aws-appmesh/package.json | 10 + packages/@aws-cdk/aws-cassandra/.gitignore | 17 + packages/@aws-cdk/aws-cassandra/.npmignore | 20 + packages/@aws-cdk/aws-cassandra/LICENSE | 201 ++++ packages/@aws-cdk/aws-cassandra/NOTICE | 2 + packages/@aws-cdk/aws-cassandra/README.md | 24 + packages/@aws-cdk/aws-cassandra/lib/index.ts | 2 + packages/@aws-cdk/aws-cassandra/package.json | 86 ++ .../aws-cassandra/test/cassandra.test.ts | 6 + .../@aws-cdk/aws-codeguruprofiler/.gitignore | 17 + .../@aws-cdk/aws-codeguruprofiler/.npmignore | 20 + .../@aws-cdk/aws-codeguruprofiler/LICENSE | 201 ++++ packages/@aws-cdk/aws-codeguruprofiler/NOTICE | 2 + .../@aws-cdk/aws-codeguruprofiler/README.md | 24 + .../aws-codeguruprofiler/lib/index.ts | 2 + .../aws-codeguruprofiler/package.json | 86 ++ .../test/codeguruprofiler.test.ts | 6 + .../@aws-cdk/aws-networkmanager/.gitignore | 17 + .../@aws-cdk/aws-networkmanager/.npmignore | 20 + packages/@aws-cdk/aws-networkmanager/LICENSE | 201 ++++ packages/@aws-cdk/aws-networkmanager/NOTICE | 2 + .../@aws-cdk/aws-networkmanager/README.md | 24 + .../@aws-cdk/aws-networkmanager/lib/index.ts | 2 + .../@aws-cdk/aws-networkmanager/package.json | 86 ++ .../test/networkmanager.test.ts | 6 + .../@aws-cdk/aws-resourcegroups/.gitignore | 17 + .../@aws-cdk/aws-resourcegroups/.npmignore | 20 + packages/@aws-cdk/aws-resourcegroups/LICENSE | 201 ++++ packages/@aws-cdk/aws-resourcegroups/NOTICE | 2 + .../@aws-cdk/aws-resourcegroups/README.md | 24 + .../@aws-cdk/aws-resourcegroups/lib/index.ts | 2 + .../@aws-cdk/aws-resourcegroups/package.json | 86 ++ .../test/resourcegroups.test.ts | 6 + packages/@aws-cdk/cfnspec/CHANGELOG.md | 64 ++ packages/@aws-cdk/cfnspec/cfn.version | 2 +- ...0_CloudFormationResourceSpecification.json | 892 +++++++++++++++++- .../530_ResourceGroups_Tags_patch.json | 24 + packages/decdk/package.json | 6 +- packages/monocdk-experiment/package.json | 6 +- 39 files changed, 2421 insertions(+), 15 deletions(-) create mode 100644 packages/@aws-cdk/aws-cassandra/.gitignore create mode 100644 packages/@aws-cdk/aws-cassandra/.npmignore create mode 100644 packages/@aws-cdk/aws-cassandra/LICENSE create mode 100644 packages/@aws-cdk/aws-cassandra/NOTICE create mode 100644 packages/@aws-cdk/aws-cassandra/README.md create mode 100644 packages/@aws-cdk/aws-cassandra/lib/index.ts create mode 100644 packages/@aws-cdk/aws-cassandra/package.json create mode 100644 packages/@aws-cdk/aws-cassandra/test/cassandra.test.ts create mode 100644 packages/@aws-cdk/aws-codeguruprofiler/.gitignore create mode 100644 packages/@aws-cdk/aws-codeguruprofiler/.npmignore create mode 100644 packages/@aws-cdk/aws-codeguruprofiler/LICENSE create mode 100644 packages/@aws-cdk/aws-codeguruprofiler/NOTICE create mode 100644 packages/@aws-cdk/aws-codeguruprofiler/README.md create mode 100644 packages/@aws-cdk/aws-codeguruprofiler/lib/index.ts create mode 100644 packages/@aws-cdk/aws-codeguruprofiler/package.json create mode 100644 packages/@aws-cdk/aws-codeguruprofiler/test/codeguruprofiler.test.ts create mode 100644 packages/@aws-cdk/aws-networkmanager/.gitignore create mode 100644 packages/@aws-cdk/aws-networkmanager/.npmignore create mode 100644 packages/@aws-cdk/aws-networkmanager/LICENSE create mode 100644 packages/@aws-cdk/aws-networkmanager/NOTICE create mode 100644 packages/@aws-cdk/aws-networkmanager/README.md create mode 100644 packages/@aws-cdk/aws-networkmanager/lib/index.ts create mode 100644 packages/@aws-cdk/aws-networkmanager/package.json create mode 100644 packages/@aws-cdk/aws-networkmanager/test/networkmanager.test.ts create mode 100644 packages/@aws-cdk/aws-resourcegroups/.gitignore create mode 100644 packages/@aws-cdk/aws-resourcegroups/.npmignore create mode 100644 packages/@aws-cdk/aws-resourcegroups/LICENSE create mode 100644 packages/@aws-cdk/aws-resourcegroups/NOTICE create mode 100644 packages/@aws-cdk/aws-resourcegroups/README.md create mode 100644 packages/@aws-cdk/aws-resourcegroups/lib/index.ts create mode 100644 packages/@aws-cdk/aws-resourcegroups/package.json create mode 100644 packages/@aws-cdk/aws-resourcegroups/test/resourcegroups.test.ts create mode 100644 packages/@aws-cdk/cfnspec/spec-source/530_ResourceGroups_Tags_patch.json diff --git a/packages/@aws-cdk/aws-appmesh/package.json b/packages/@aws-cdk/aws-appmesh/package.json index 4361ca2150a7c..f45a7bf13ed01 100644 --- a/packages/@aws-cdk/aws-appmesh/package.json +++ b/packages/@aws-cdk/aws-appmesh/package.json @@ -105,15 +105,25 @@ "resource-attribute:@aws-cdk/aws-appmesh.IVirtualNode.virtualNodeUid", "resource-attribute:@aws-cdk/aws-appmesh.IVirtualRouter.virtualRouterUid", "resource-attribute:@aws-cdk/aws-appmesh.IVirtualService.virtualServiceUid", + "resource-attribute:@aws-cdk/aws-appmesh.Mesh.meshOwner", + "resource-attribute:@aws-cdk/aws-appmesh.Mesh.meshResourceOwner", "resource-attribute:@aws-cdk/aws-appmesh.Mesh.meshUid", "resource-attribute:@aws-cdk/aws-appmesh.Route.routeMeshName", + "resource-attribute:@aws-cdk/aws-appmesh.Route.routeMeshOwner", + "resource-attribute:@aws-cdk/aws-appmesh.Route.routeResourceOwner", "resource-attribute:@aws-cdk/aws-appmesh.Route.routeUid", "resource-attribute:@aws-cdk/aws-appmesh.Route.routeVirtualRouterName", "resource-attribute:@aws-cdk/aws-appmesh.VirtualNode.virtualNodeMeshName", + "resource-attribute:@aws-cdk/aws-appmesh.VirtualNode.virtualNodeMeshOwner", + "resource-attribute:@aws-cdk/aws-appmesh.VirtualNode.virtualNodeResourceOwner", "resource-attribute:@aws-cdk/aws-appmesh.VirtualNode.virtualNodeUid", "resource-attribute:@aws-cdk/aws-appmesh.VirtualRouter.virtualRouterMeshName", + "resource-attribute:@aws-cdk/aws-appmesh.VirtualRouter.virtualRouterMeshOwner", + "resource-attribute:@aws-cdk/aws-appmesh.VirtualRouter.virtualRouterResourceOwner", "resource-attribute:@aws-cdk/aws-appmesh.VirtualRouter.virtualRouterUid", "resource-attribute:@aws-cdk/aws-appmesh.VirtualService.virtualServiceMeshName", + "resource-attribute:@aws-cdk/aws-appmesh.VirtualService.virtualServiceMeshOwner", + "resource-attribute:@aws-cdk/aws-appmesh.VirtualService.virtualServiceResourceOwner", "resource-attribute:@aws-cdk/aws-appmesh.VirtualService.virtualServiceUid", "docs-public-apis:@aws-cdk/aws-appmesh.Protocol.TCP", "docs-public-apis:@aws-cdk/aws-appmesh.VirtualRouter", diff --git a/packages/@aws-cdk/aws-cassandra/.gitignore b/packages/@aws-cdk/aws-cassandra/.gitignore new file mode 100644 index 0000000000000..66bc512521d1f --- /dev/null +++ b/packages/@aws-cdk/aws-cassandra/.gitignore @@ -0,0 +1,17 @@ +*.js +*.js.map +*.d.ts +tsconfig.json +tslint.json +node_modules +*.generated.ts +dist +.jsii + +.LAST_BUILD +.nyc_output +coverage +.nycrc +.LAST_PACKAGE +*.snk +nyc.config.js diff --git a/packages/@aws-cdk/aws-cassandra/.npmignore b/packages/@aws-cdk/aws-cassandra/.npmignore new file mode 100644 index 0000000000000..c18b5f700c0c9 --- /dev/null +++ b/packages/@aws-cdk/aws-cassandra/.npmignore @@ -0,0 +1,20 @@ +# 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 diff --git a/packages/@aws-cdk/aws-cassandra/LICENSE b/packages/@aws-cdk/aws-cassandra/LICENSE new file mode 100644 index 0000000000000..b71ec1688783a --- /dev/null +++ b/packages/@aws-cdk/aws-cassandra/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/@aws-cdk/aws-cassandra/NOTICE b/packages/@aws-cdk/aws-cassandra/NOTICE new file mode 100644 index 0000000000000..bfccac9a7f69c --- /dev/null +++ b/packages/@aws-cdk/aws-cassandra/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/aws-cassandra/README.md b/packages/@aws-cdk/aws-cassandra/README.md new file mode 100644 index 0000000000000..9db2b132c3b83 --- /dev/null +++ b/packages/@aws-cdk/aws-cassandra/README.md @@ -0,0 +1,24 @@ +## AWS::Cassandra Construct Library + + +--- + +![Stability: Experimental](https://img.shields.io/badge/stability-Experimental-important.svg?style=for-the-badge) + +> **This is a _developer preview_ (public beta) module.** +> +> All classes with the `Cfn` prefix in this module ([CFN Resources](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) +> are auto-generated from CloudFormation. They are stable and safe to use. +> +> However, all other classes, i.e., higher level constructs, are under active development and subject to non-backward +> compatible changes or removal in any future version. These are not subject to the [Semantic Versioning](https://semver.org/) model. +> This means that while you may use them, you may need to update your source code when upgrading to a newer version of this package. + +--- + + +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts +import cassandra = require('@aws-cdk/aws-cassandra'); +``` diff --git a/packages/@aws-cdk/aws-cassandra/lib/index.ts b/packages/@aws-cdk/aws-cassandra/lib/index.ts new file mode 100644 index 0000000000000..86bc022f66915 --- /dev/null +++ b/packages/@aws-cdk/aws-cassandra/lib/index.ts @@ -0,0 +1,2 @@ +// AWS::Cassandra CloudFormation Resources: +export * from './cassandra.generated'; diff --git a/packages/@aws-cdk/aws-cassandra/package.json b/packages/@aws-cdk/aws-cassandra/package.json new file mode 100644 index 0000000000000..db8921799f8c7 --- /dev/null +++ b/packages/@aws-cdk/aws-cassandra/package.json @@ -0,0 +1,86 @@ +{ + "name": "@aws-cdk/aws-cassandra", + "version": "0.0.0", + "description": "The CDK Construct Library for AWS::Cassandra", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "targets": { + "dotnet": { + "namespace": "Amazon.CDK.AWS.Cassandra", + "packageId": "Amazon.CDK.AWS.Cassandra", + "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.cassandra", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "cassandra" + } + }, + "python": { + "distName": "aws-cdk.aws-cassandra", + "module": "aws_cdk.aws_cassandra" + } + } + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-cassandra" + }, + "homepage": "https://github.com/aws/aws-cdk", + "scripts": { + "build": "cdk-build", + "watch": "cdk-watch", + "lint": "cdk-lint", + "test": "cdk-test", + "integ": "cdk-integ", + "pkglint": "pkglint -f", + "package": "cdk-package", + "awslint": "cdk-awslint", + "cfn2ts": "cfn2ts", + "build+test+package": "npm run build+test && npm run package", + "build+test": "npm run build && npm test", + "compat": "cdk-compat" + }, + "cdk-build": { + "cloudformation": "AWS::Cassandra" + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "AWS::Cassandra", + "aws-cassandra" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "jest": {}, + "license": "Apache-2.0", + "devDependencies": { + "@aws-cdk/assert": "0.0.0", + "cdk-build-tools": "0.0.0", + "cfn2ts": "0.0.0", + "pkglint": "0.0.0" + }, + "dependencies": { + "@aws-cdk/core": "0.0.0" + }, + "peerDependencies": { + "@aws-cdk/core": "0.0.0" + }, + "engines": { + "node": ">= 10.3.0" + }, + "stability": "experimental", + "awscdkio": { + "announce": false + } +} diff --git a/packages/@aws-cdk/aws-cassandra/test/cassandra.test.ts b/packages/@aws-cdk/aws-cassandra/test/cassandra.test.ts new file mode 100644 index 0000000000000..e394ef336bfb4 --- /dev/null +++ b/packages/@aws-cdk/aws-cassandra/test/cassandra.test.ts @@ -0,0 +1,6 @@ +import '@aws-cdk/assert/jest'; +import {} from '../lib'; + +test('No tests are specified for this package', () => { + expect(true).toBe(true); +}); diff --git a/packages/@aws-cdk/aws-codeguruprofiler/.gitignore b/packages/@aws-cdk/aws-codeguruprofiler/.gitignore new file mode 100644 index 0000000000000..66bc512521d1f --- /dev/null +++ b/packages/@aws-cdk/aws-codeguruprofiler/.gitignore @@ -0,0 +1,17 @@ +*.js +*.js.map +*.d.ts +tsconfig.json +tslint.json +node_modules +*.generated.ts +dist +.jsii + +.LAST_BUILD +.nyc_output +coverage +.nycrc +.LAST_PACKAGE +*.snk +nyc.config.js diff --git a/packages/@aws-cdk/aws-codeguruprofiler/.npmignore b/packages/@aws-cdk/aws-codeguruprofiler/.npmignore new file mode 100644 index 0000000000000..c18b5f700c0c9 --- /dev/null +++ b/packages/@aws-cdk/aws-codeguruprofiler/.npmignore @@ -0,0 +1,20 @@ +# 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 diff --git a/packages/@aws-cdk/aws-codeguruprofiler/LICENSE b/packages/@aws-cdk/aws-codeguruprofiler/LICENSE new file mode 100644 index 0000000000000..b71ec1688783a --- /dev/null +++ b/packages/@aws-cdk/aws-codeguruprofiler/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/@aws-cdk/aws-codeguruprofiler/NOTICE b/packages/@aws-cdk/aws-codeguruprofiler/NOTICE new file mode 100644 index 0000000000000..bfccac9a7f69c --- /dev/null +++ b/packages/@aws-cdk/aws-codeguruprofiler/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/aws-codeguruprofiler/README.md b/packages/@aws-cdk/aws-codeguruprofiler/README.md new file mode 100644 index 0000000000000..e127d53b204f0 --- /dev/null +++ b/packages/@aws-cdk/aws-codeguruprofiler/README.md @@ -0,0 +1,24 @@ +## AWS::CodeGuruProfiler Construct Library + + +--- + +![Stability: Experimental](https://img.shields.io/badge/stability-Experimental-important.svg?style=for-the-badge) + +> **This is a _developer preview_ (public beta) module.** +> +> All classes with the `Cfn` prefix in this module ([CFN Resources](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) +> are auto-generated from CloudFormation. They are stable and safe to use. +> +> However, all other classes, i.e., higher level constructs, are under active development and subject to non-backward +> compatible changes or removal in any future version. These are not subject to the [Semantic Versioning](https://semver.org/) model. +> This means that while you may use them, you may need to update your source code when upgrading to a newer version of this package. + +--- + + +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts +import codeguruprofiler = require('@aws-cdk/aws-codeguruprofiler'); +``` diff --git a/packages/@aws-cdk/aws-codeguruprofiler/lib/index.ts b/packages/@aws-cdk/aws-codeguruprofiler/lib/index.ts new file mode 100644 index 0000000000000..1dca345aee39a --- /dev/null +++ b/packages/@aws-cdk/aws-codeguruprofiler/lib/index.ts @@ -0,0 +1,2 @@ +// AWS::CodeGuruProfiler CloudFormation Resources: +export * from './codeguruprofiler.generated'; diff --git a/packages/@aws-cdk/aws-codeguruprofiler/package.json b/packages/@aws-cdk/aws-codeguruprofiler/package.json new file mode 100644 index 0000000000000..fc0e62eb98c91 --- /dev/null +++ b/packages/@aws-cdk/aws-codeguruprofiler/package.json @@ -0,0 +1,86 @@ +{ + "name": "@aws-cdk/aws-codeguruprofiler", + "version": "0.0.0", + "description": "The CDK Construct Library for AWS::CodeGuruProfiler", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "targets": { + "dotnet": { + "namespace": "Amazon.CDK.AWS.CodeGuruProfiler", + "packageId": "Amazon.CDK.AWS.CodeGuruProfiler", + "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.codeguruprofiler", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "codeguruprofiler" + } + }, + "python": { + "distName": "aws-cdk.aws-codeguruprofiler", + "module": "aws_cdk.aws_codeguruprofiler" + } + } + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-codeguruprofiler" + }, + "homepage": "https://github.com/aws/aws-cdk", + "scripts": { + "build": "cdk-build", + "watch": "cdk-watch", + "lint": "cdk-lint", + "test": "cdk-test", + "integ": "cdk-integ", + "pkglint": "pkglint -f", + "package": "cdk-package", + "awslint": "cdk-awslint", + "cfn2ts": "cfn2ts", + "build+test+package": "npm run build+test && npm run package", + "build+test": "npm run build && npm test", + "compat": "cdk-compat" + }, + "cdk-build": { + "cloudformation": "AWS::CodeGuruProfiler" + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "AWS::CodeGuruProfiler", + "aws-codeguruprofiler" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "jest": {}, + "license": "Apache-2.0", + "devDependencies": { + "@aws-cdk/assert": "0.0.0", + "cdk-build-tools": "0.0.0", + "cfn2ts": "0.0.0", + "pkglint": "0.0.0" + }, + "dependencies": { + "@aws-cdk/core": "0.0.0" + }, + "peerDependencies": { + "@aws-cdk/core": "0.0.0" + }, + "engines": { + "node": ">= 10.3.0" + }, + "stability": "experimental", + "awscdkio": { + "announce": false + } +} diff --git a/packages/@aws-cdk/aws-codeguruprofiler/test/codeguruprofiler.test.ts b/packages/@aws-cdk/aws-codeguruprofiler/test/codeguruprofiler.test.ts new file mode 100644 index 0000000000000..e394ef336bfb4 --- /dev/null +++ b/packages/@aws-cdk/aws-codeguruprofiler/test/codeguruprofiler.test.ts @@ -0,0 +1,6 @@ +import '@aws-cdk/assert/jest'; +import {} from '../lib'; + +test('No tests are specified for this package', () => { + expect(true).toBe(true); +}); diff --git a/packages/@aws-cdk/aws-networkmanager/.gitignore b/packages/@aws-cdk/aws-networkmanager/.gitignore new file mode 100644 index 0000000000000..66bc512521d1f --- /dev/null +++ b/packages/@aws-cdk/aws-networkmanager/.gitignore @@ -0,0 +1,17 @@ +*.js +*.js.map +*.d.ts +tsconfig.json +tslint.json +node_modules +*.generated.ts +dist +.jsii + +.LAST_BUILD +.nyc_output +coverage +.nycrc +.LAST_PACKAGE +*.snk +nyc.config.js diff --git a/packages/@aws-cdk/aws-networkmanager/.npmignore b/packages/@aws-cdk/aws-networkmanager/.npmignore new file mode 100644 index 0000000000000..c18b5f700c0c9 --- /dev/null +++ b/packages/@aws-cdk/aws-networkmanager/.npmignore @@ -0,0 +1,20 @@ +# 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 diff --git a/packages/@aws-cdk/aws-networkmanager/LICENSE b/packages/@aws-cdk/aws-networkmanager/LICENSE new file mode 100644 index 0000000000000..b71ec1688783a --- /dev/null +++ b/packages/@aws-cdk/aws-networkmanager/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/@aws-cdk/aws-networkmanager/NOTICE b/packages/@aws-cdk/aws-networkmanager/NOTICE new file mode 100644 index 0000000000000..bfccac9a7f69c --- /dev/null +++ b/packages/@aws-cdk/aws-networkmanager/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/aws-networkmanager/README.md b/packages/@aws-cdk/aws-networkmanager/README.md new file mode 100644 index 0000000000000..08f8673704d89 --- /dev/null +++ b/packages/@aws-cdk/aws-networkmanager/README.md @@ -0,0 +1,24 @@ +## AWS::NetworkManager Construct Library + + +--- + +![Stability: Experimental](https://img.shields.io/badge/stability-Experimental-important.svg?style=for-the-badge) + +> **This is a _developer preview_ (public beta) module.** +> +> All classes with the `Cfn` prefix in this module ([CFN Resources](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) +> are auto-generated from CloudFormation. They are stable and safe to use. +> +> However, all other classes, i.e., higher level constructs, are under active development and subject to non-backward +> compatible changes or removal in any future version. These are not subject to the [Semantic Versioning](https://semver.org/) model. +> This means that while you may use them, you may need to update your source code when upgrading to a newer version of this package. + +--- + + +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts +import networkmanager = require('@aws-cdk/aws-networkmanager'); +``` diff --git a/packages/@aws-cdk/aws-networkmanager/lib/index.ts b/packages/@aws-cdk/aws-networkmanager/lib/index.ts new file mode 100644 index 0000000000000..d39cb0c0acb5e --- /dev/null +++ b/packages/@aws-cdk/aws-networkmanager/lib/index.ts @@ -0,0 +1,2 @@ +// AWS::NetworkManager CloudFormation Resources: +export * from './networkmanager.generated'; diff --git a/packages/@aws-cdk/aws-networkmanager/package.json b/packages/@aws-cdk/aws-networkmanager/package.json new file mode 100644 index 0000000000000..abcb5fb728dba --- /dev/null +++ b/packages/@aws-cdk/aws-networkmanager/package.json @@ -0,0 +1,86 @@ +{ + "name": "@aws-cdk/aws-networkmanager", + "version": "0.0.0", + "description": "The CDK Construct Library for AWS::NetworkManager", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "targets": { + "dotnet": { + "namespace": "Amazon.CDK.AWS.NetworkManager", + "packageId": "Amazon.CDK.AWS.NetworkManager", + "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.networkmanager", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "networkmanager" + } + }, + "python": { + "distName": "aws-cdk.aws-networkmanager", + "module": "aws_cdk.aws_networkmanager" + } + } + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-networkmanager" + }, + "homepage": "https://github.com/aws/aws-cdk", + "scripts": { + "build": "cdk-build", + "watch": "cdk-watch", + "lint": "cdk-lint", + "test": "cdk-test", + "integ": "cdk-integ", + "pkglint": "pkglint -f", + "package": "cdk-package", + "awslint": "cdk-awslint", + "cfn2ts": "cfn2ts", + "build+test+package": "npm run build+test && npm run package", + "build+test": "npm run build && npm test", + "compat": "cdk-compat" + }, + "cdk-build": { + "cloudformation": "AWS::NetworkManager" + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "AWS::NetworkManager", + "aws-networkmanager" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "jest": {}, + "license": "Apache-2.0", + "devDependencies": { + "@aws-cdk/assert": "0.0.0", + "cdk-build-tools": "0.0.0", + "cfn2ts": "0.0.0", + "pkglint": "0.0.0" + }, + "dependencies": { + "@aws-cdk/core": "0.0.0" + }, + "peerDependencies": { + "@aws-cdk/core": "0.0.0" + }, + "engines": { + "node": ">= 10.3.0" + }, + "stability": "experimental", + "awscdkio": { + "announce": false + } +} diff --git a/packages/@aws-cdk/aws-networkmanager/test/networkmanager.test.ts b/packages/@aws-cdk/aws-networkmanager/test/networkmanager.test.ts new file mode 100644 index 0000000000000..e394ef336bfb4 --- /dev/null +++ b/packages/@aws-cdk/aws-networkmanager/test/networkmanager.test.ts @@ -0,0 +1,6 @@ +import '@aws-cdk/assert/jest'; +import {} from '../lib'; + +test('No tests are specified for this package', () => { + expect(true).toBe(true); +}); diff --git a/packages/@aws-cdk/aws-resourcegroups/.gitignore b/packages/@aws-cdk/aws-resourcegroups/.gitignore new file mode 100644 index 0000000000000..66bc512521d1f --- /dev/null +++ b/packages/@aws-cdk/aws-resourcegroups/.gitignore @@ -0,0 +1,17 @@ +*.js +*.js.map +*.d.ts +tsconfig.json +tslint.json +node_modules +*.generated.ts +dist +.jsii + +.LAST_BUILD +.nyc_output +coverage +.nycrc +.LAST_PACKAGE +*.snk +nyc.config.js diff --git a/packages/@aws-cdk/aws-resourcegroups/.npmignore b/packages/@aws-cdk/aws-resourcegroups/.npmignore new file mode 100644 index 0000000000000..c18b5f700c0c9 --- /dev/null +++ b/packages/@aws-cdk/aws-resourcegroups/.npmignore @@ -0,0 +1,20 @@ +# 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 diff --git a/packages/@aws-cdk/aws-resourcegroups/LICENSE b/packages/@aws-cdk/aws-resourcegroups/LICENSE new file mode 100644 index 0000000000000..b71ec1688783a --- /dev/null +++ b/packages/@aws-cdk/aws-resourcegroups/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/@aws-cdk/aws-resourcegroups/NOTICE b/packages/@aws-cdk/aws-resourcegroups/NOTICE new file mode 100644 index 0000000000000..bfccac9a7f69c --- /dev/null +++ b/packages/@aws-cdk/aws-resourcegroups/NOTICE @@ -0,0 +1,2 @@ +AWS Cloud Development Kit (AWS CDK) +Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/packages/@aws-cdk/aws-resourcegroups/README.md b/packages/@aws-cdk/aws-resourcegroups/README.md new file mode 100644 index 0000000000000..60b9785675394 --- /dev/null +++ b/packages/@aws-cdk/aws-resourcegroups/README.md @@ -0,0 +1,24 @@ +## AWS::ResourceGroups Construct Library + + +--- + +![Stability: Experimental](https://img.shields.io/badge/stability-Experimental-important.svg?style=for-the-badge) + +> **This is a _developer preview_ (public beta) module.** +> +> All classes with the `Cfn` prefix in this module ([CFN Resources](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) +> are auto-generated from CloudFormation. They are stable and safe to use. +> +> However, all other classes, i.e., higher level constructs, are under active development and subject to non-backward +> compatible changes or removal in any future version. These are not subject to the [Semantic Versioning](https://semver.org/) model. +> This means that while you may use them, you may need to update your source code when upgrading to a newer version of this package. + +--- + + +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts +import resourcegroups = require('@aws-cdk/aws-resourcegroups'); +``` diff --git a/packages/@aws-cdk/aws-resourcegroups/lib/index.ts b/packages/@aws-cdk/aws-resourcegroups/lib/index.ts new file mode 100644 index 0000000000000..0dad84c84d64d --- /dev/null +++ b/packages/@aws-cdk/aws-resourcegroups/lib/index.ts @@ -0,0 +1,2 @@ +// AWS::ResourceGroups CloudFormation Resources: +export * from './resourcegroups.generated'; diff --git a/packages/@aws-cdk/aws-resourcegroups/package.json b/packages/@aws-cdk/aws-resourcegroups/package.json new file mode 100644 index 0000000000000..0e10735fdfc6d --- /dev/null +++ b/packages/@aws-cdk/aws-resourcegroups/package.json @@ -0,0 +1,86 @@ +{ + "name": "@aws-cdk/aws-resourcegroups", + "version": "0.0.0", + "description": "The CDK Construct Library for AWS::ResourceGroups", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "targets": { + "dotnet": { + "namespace": "Amazon.CDK.AWS.ResourceGroups", + "packageId": "Amazon.CDK.AWS.ResourceGroups", + "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.resourcegroups", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "resourcegroups" + } + }, + "python": { + "distName": "aws-cdk.aws-resourcegroups", + "module": "aws_cdk.aws_resourcegroups" + } + } + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-resourcegroups" + }, + "homepage": "https://github.com/aws/aws-cdk", + "scripts": { + "build": "cdk-build", + "watch": "cdk-watch", + "lint": "cdk-lint", + "test": "cdk-test", + "integ": "cdk-integ", + "pkglint": "pkglint -f", + "package": "cdk-package", + "awslint": "cdk-awslint", + "cfn2ts": "cfn2ts", + "build+test+package": "npm run build+test && npm run package", + "build+test": "npm run build && npm test", + "compat": "cdk-compat" + }, + "cdk-build": { + "cloudformation": "AWS::ResourceGroups" + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "AWS::ResourceGroups", + "aws-resourcegroups" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "jest": {}, + "license": "Apache-2.0", + "devDependencies": { + "@aws-cdk/assert": "0.0.0", + "cdk-build-tools": "0.0.0", + "cfn2ts": "0.0.0", + "pkglint": "0.0.0" + }, + "dependencies": { + "@aws-cdk/core": "0.0.0" + }, + "peerDependencies": { + "@aws-cdk/core": "0.0.0" + }, + "engines": { + "node": ">= 10.3.0" + }, + "stability": "experimental", + "awscdkio": { + "announce": false + } +} diff --git a/packages/@aws-cdk/aws-resourcegroups/test/resourcegroups.test.ts b/packages/@aws-cdk/aws-resourcegroups/test/resourcegroups.test.ts new file mode 100644 index 0000000000000..e394ef336bfb4 --- /dev/null +++ b/packages/@aws-cdk/aws-resourcegroups/test/resourcegroups.test.ts @@ -0,0 +1,6 @@ +import '@aws-cdk/assert/jest'; +import {} from '../lib'; + +test('No tests are specified for this package', () => { + expect(true).toBe(true); +}); diff --git a/packages/@aws-cdk/cfnspec/CHANGELOG.md b/packages/@aws-cdk/cfnspec/CHANGELOG.md index 145749514fda3..c7d02412f43a0 100644 --- a/packages/@aws-cdk/cfnspec/CHANGELOG.md +++ b/packages/@aws-cdk/cfnspec/CHANGELOG.md @@ -1,3 +1,67 @@ +# CloudFormation Resource Specification v11.6.0 + +## New Resource Types + +* AWS::Cassandra::Keyspace +* AWS::Cassandra::Table +* AWS::CodeGuruProfiler::ProfilingGroup +* AWS::NetworkManager::CustomerGatewayAssociation +* AWS::NetworkManager::Device +* AWS::NetworkManager::GlobalNetwork +* AWS::NetworkManager::Link +* AWS::NetworkManager::LinkAssociation +* AWS::NetworkManager::Site +* AWS::NetworkManager::TransitGatewayRegistration +* AWS::ResourceGroups::Group + +## Attribute Changes + +* AWS::AppMesh::Mesh MeshOwner.PrimitiveType (__added__) +* AWS::AppMesh::Mesh ResourceOwner.PrimitiveType (__added__) +* AWS::AppMesh::Route MeshOwner.PrimitiveType (__added__) +* AWS::AppMesh::Route ResourceOwner.PrimitiveType (__added__) +* AWS::AppMesh::VirtualNode MeshOwner.PrimitiveType (__added__) +* AWS::AppMesh::VirtualNode ResourceOwner.PrimitiveType (__added__) +* AWS::AppMesh::VirtualRouter MeshOwner.PrimitiveType (__added__) +* AWS::AppMesh::VirtualRouter ResourceOwner.PrimitiveType (__added__) +* AWS::AppMesh::VirtualService MeshOwner.PrimitiveType (__added__) +* AWS::AppMesh::VirtualService ResourceOwner.PrimitiveType (__added__) + +## Property Changes + +* AWS::ApiGatewayV2::Integration TlsConfig (__added__) +* AWS::AppMesh::Route MeshOwner (__added__) +* AWS::AppMesh::VirtualNode MeshOwner (__added__) +* AWS::AppMesh::VirtualRouter MeshOwner (__added__) +* AWS::AppMesh::VirtualService MeshOwner (__added__) +* AWS::DMS::Endpoint KafkaSettings (__added__) +* AWS::EC2::ClientVpnEndpoint SecurityGroupIds (__added__) +* AWS::EC2::ClientVpnEndpoint VpcId (__added__) +* AWS::MSK::Cluster LoggingInfo (__added__) +* AWS::ServiceCatalog::LaunchRoleConstraint LocalRoleName (__added__) +* AWS::ServiceCatalog::LaunchRoleConstraint RoleArn.Required (__changed__) + * Old: true + * New: false + +## Property Type Changes + +* AWS::ApiGatewayV2::Integration.TlsConfig (__added__) +* AWS::CloudFront::Distribution.OriginGroup (__added__) +* AWS::CloudFront::Distribution.OriginGroupFailoverCriteria (__added__) +* AWS::CloudFront::Distribution.OriginGroupMember (__added__) +* AWS::CloudFront::Distribution.OriginGroupMembers (__added__) +* AWS::CloudFront::Distribution.OriginGroups (__added__) +* AWS::CloudFront::Distribution.StatusCodes (__added__) +* AWS::DMS::Endpoint.KafkaSettings (__added__) +* AWS::MSK::Cluster.BrokerLogs (__added__) +* AWS::MSK::Cluster.CloudWatchLogs (__added__) +* AWS::MSK::Cluster.Firehose (__added__) +* AWS::MSK::Cluster.LoggingInfo (__added__) +* AWS::MSK::Cluster.S3 (__added__) +* AWS::CloudFront::Distribution.DistributionConfig OriginGroups (__added__) +* AWS::CloudFront::Distribution.LambdaFunctionAssociation IncludeBody (__added__) + + # CloudFormation Resource Specification v11.4.0 ## New Resource Types diff --git a/packages/@aws-cdk/cfnspec/cfn.version b/packages/@aws-cdk/cfnspec/cfn.version index 72773deb895e2..146d5de797140 100644 --- a/packages/@aws-cdk/cfnspec/cfn.version +++ b/packages/@aws-cdk/cfnspec/cfn.version @@ -1 +1 @@ -11.4.0 +11.6.0 diff --git a/packages/@aws-cdk/cfnspec/spec-source/000_CloudFormationResourceSpecification.json b/packages/@aws-cdk/cfnspec/spec-source/000_CloudFormationResourceSpecification.json index 332ce2c8339b8..9be67cb38b8f8 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/000_CloudFormationResourceSpecification.json +++ b/packages/@aws-cdk/cfnspec/spec-source/000_CloudFormationResourceSpecification.json @@ -1372,6 +1372,17 @@ } } }, + "AWS::ApiGatewayV2::Integration.TlsConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-integration-tlsconfig.html", + "Properties": { + "ServerNameToVerify": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-integration-tlsconfig.html#cfn-apigatewayv2-integration-tlsconfig-servernametoverify", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::ApiGatewayV2::Route.ParameterConstraints": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-route-parameterconstraints.html", "Properties": { @@ -5058,6 +5069,74 @@ } } }, + "AWS::Cassandra::Table.BillingMode": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cassandra-table-billingmode.html", + "Properties": { + "Mode": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cassandra-table-billingmode.html#cfn-cassandra-table-billingmode-mode", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ProvisionedThroughput": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cassandra-table-billingmode.html#cfn-cassandra-table-billingmode-provisionedthroughput", + "Required": false, + "Type": "ProvisionedThroughput", + "UpdateType": "Mutable" + } + } + }, + "AWS::Cassandra::Table.ClusteringKeyColumn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cassandra-table-clusteringkeycolumn.html", + "Properties": { + "Column": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cassandra-table-clusteringkeycolumn.html#cfn-cassandra-table-clusteringkeycolumn-column", + "Required": true, + "Type": "Column", + "UpdateType": "Immutable" + }, + "OrderBy": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cassandra-table-clusteringkeycolumn.html#cfn-cassandra-table-clusteringkeycolumn-orderby", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::Cassandra::Table.Column": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cassandra-table-column.html", + "Properties": { + "ColumnName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cassandra-table-column.html#cfn-cassandra-table-column-columnname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ColumnType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cassandra-table-column.html#cfn-cassandra-table-column-columntype", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::Cassandra::Table.ProvisionedThroughput": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cassandra-table-provisionedthroughput.html", + "Properties": { + "ReadCapacityUnits": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cassandra-table-provisionedthroughput.html#cfn-cassandra-table-provisionedthroughput-readcapacityunits", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + }, + "WriteCapacityUnits": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cassandra-table-provisionedthroughput.html#cfn-cassandra-table-provisionedthroughput-writecapacityunits", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::CertificateManager::Certificate.DomainValidationOption": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-certificatemanager-certificate-domainvalidationoption.html", "Properties": { @@ -5438,6 +5517,12 @@ "Type": "Logging", "UpdateType": "Mutable" }, + "OriginGroups": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-distributionconfig.html#cfn-cloudfront-distribution-distributionconfig-origingroups", + "Required": false, + "Type": "OriginGroups", + "UpdateType": "Mutable" + }, "Origins": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-distributionconfig.html#cfn-cloudfront-distribution-distributionconfig-origins", "ItemType": "Origin", @@ -5529,6 +5614,12 @@ "Required": false, "UpdateType": "Mutable" }, + "IncludeBody": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-lambdafunctionassociation.html#cfn-cloudfront-distribution-lambdafunctionassociation-includebody", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, "LambdaFunctionARN": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-lambdafunctionassociation.html#cfn-cloudfront-distribution-lambdafunctionassociation-lambdafunctionarn", "PrimitiveType": "String", @@ -5619,6 +5710,87 @@ } } }, + "AWS::CloudFront::Distribution.OriginGroup": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-origingroup.html", + "Properties": { + "FailoverCriteria": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-origingroup.html#cfn-cloudfront-distribution-origingroup-failovercriteria", + "Required": true, + "Type": "OriginGroupFailoverCriteria", + "UpdateType": "Mutable" + }, + "Id": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-origingroup.html#cfn-cloudfront-distribution-origingroup-id", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Members": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-origingroup.html#cfn-cloudfront-distribution-origingroup-members", + "Required": true, + "Type": "OriginGroupMembers", + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFront::Distribution.OriginGroupFailoverCriteria": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-origingroupfailovercriteria.html", + "Properties": { + "StatusCodes": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-origingroupfailovercriteria.html#cfn-cloudfront-distribution-origingroupfailovercriteria-statuscodes", + "Required": true, + "Type": "StatusCodes", + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFront::Distribution.OriginGroupMember": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-origingroupmember.html", + "Properties": { + "OriginId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-origingroupmember.html#cfn-cloudfront-distribution-origingroupmember-originid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFront::Distribution.OriginGroupMembers": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-origingroupmembers.html", + "Properties": { + "Items": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-origingroupmembers.html#cfn-cloudfront-distribution-origingroupmembers-items", + "ItemType": "OriginGroupMember", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "Quantity": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-origingroupmembers.html#cfn-cloudfront-distribution-origingroupmembers-quantity", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::CloudFront::Distribution.OriginGroups": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-origingroups.html", + "Properties": { + "Items": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-origingroups.html#cfn-cloudfront-distribution-origingroups-items", + "ItemType": "OriginGroup", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Quantity": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-origingroups.html#cfn-cloudfront-distribution-origingroups-quantity", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::CloudFront::Distribution.Restrictions": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-restrictions.html", "Properties": { @@ -5641,6 +5813,24 @@ } } }, + "AWS::CloudFront::Distribution.StatusCodes": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-statuscodes.html", + "Properties": { + "Items": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-statuscodes.html#cfn-cloudfront-distribution-statuscodes-items", + "PrimitiveItemType": "Integer", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "Quantity": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-statuscodes.html#cfn-cloudfront-distribution-statuscodes-quantity", + "PrimitiveType": "Integer", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::CloudFront::Distribution.ViewerCertificate": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-viewercertificate.html", "Properties": { @@ -8770,6 +8960,23 @@ } } }, + "AWS::DMS::Endpoint.KafkaSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-kafkasettings.html", + "Properties": { + "Broker": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-kafkasettings.html#cfn-dms-endpoint-kafkasettings-broker", + "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", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::DMS::Endpoint.KinesisSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dms-endpoint-kinesissettings.html", "Properties": { @@ -22528,6 +22735,29 @@ } } }, + "AWS::MSK::Cluster.BrokerLogs": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-brokerlogs.html", + "Properties": { + "CloudWatchLogs": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-brokerlogs.html#cfn-msk-cluster-brokerlogs-cloudwatchlogs", + "Required": false, + "Type": "CloudWatchLogs", + "UpdateType": "Mutable" + }, + "Firehose": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-brokerlogs.html#cfn-msk-cluster-brokerlogs-firehose", + "Required": false, + "Type": "Firehose", + "UpdateType": "Mutable" + }, + "S3": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-brokerlogs.html#cfn-msk-cluster-brokerlogs-s3", + "Required": false, + "Type": "S3", + "UpdateType": "Mutable" + } + } + }, "AWS::MSK::Cluster.BrokerNodeGroupInfo": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-brokernodegroupinfo.html", "Properties": { @@ -22576,6 +22806,23 @@ } } }, + "AWS::MSK::Cluster.CloudWatchLogs": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-cloudwatchlogs.html", + "Properties": { + "Enabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-cloudwatchlogs.html#cfn-msk-cluster-cloudwatchlogs-enabled", + "PrimitiveType": "Boolean", + "Required": true, + "UpdateType": "Mutable" + }, + "LogGroup": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-cloudwatchlogs.html#cfn-msk-cluster-cloudwatchlogs-loggroup", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::MSK::Cluster.ConfigurationInfo": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-configurationinfo.html", "Properties": { @@ -22649,6 +22896,23 @@ } } }, + "AWS::MSK::Cluster.Firehose": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-firehose.html", + "Properties": { + "DeliveryStream": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-firehose.html#cfn-msk-cluster-firehose-deliverystream", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Enabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-firehose.html#cfn-msk-cluster-firehose-enabled", + "PrimitiveType": "Boolean", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::MSK::Cluster.JmxExporter": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-jmxexporter.html", "Properties": { @@ -22660,6 +22924,17 @@ } } }, + "AWS::MSK::Cluster.LoggingInfo": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-logginginfo.html", + "Properties": { + "BrokerLogs": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-logginginfo.html#cfn-msk-cluster-logginginfo-brokerlogs", + "Required": true, + "Type": "BrokerLogs", + "UpdateType": "Mutable" + } + } + }, "AWS::MSK::Cluster.NodeExporter": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-nodeexporter.html", "Properties": { @@ -22699,6 +22974,29 @@ } } }, + "AWS::MSK::Cluster.S3": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-s3.html", + "Properties": { + "Bucket": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-s3.html#cfn-msk-cluster-s3-bucket", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Enabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-s3.html#cfn-msk-cluster-s3-enabled", + "PrimitiveType": "Boolean", + "Required": true, + "UpdateType": "Mutable" + }, + "Prefix": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-s3.html#cfn-msk-cluster-s3-prefix", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::MSK::Cluster.StorageInfo": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-storageinfo.html", "Properties": { @@ -23524,6 +23822,69 @@ } } }, + "AWS::NetworkManager::Device.Location": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkmanager-device-location.html", + "Properties": { + "Address": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkmanager-device-location.html#cfn-networkmanager-device-location-address", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Latitude": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkmanager-device-location.html#cfn-networkmanager-device-location-latitude", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Longitude": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkmanager-device-location.html#cfn-networkmanager-device-location-longitude", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::NetworkManager::Link.Bandwidth": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkmanager-link-bandwidth.html", + "Properties": { + "DownloadSpeed": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkmanager-link-bandwidth.html#cfn-networkmanager-link-bandwidth-downloadspeed", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "UploadSpeed": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkmanager-link-bandwidth.html#cfn-networkmanager-link-bandwidth-uploadspeed", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::NetworkManager::Site.Location": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkmanager-site-location.html", + "Properties": { + "Address": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkmanager-site-location.html#cfn-networkmanager-site-location-address", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Latitude": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkmanager-site-location.html#cfn-networkmanager-site-location-latitude", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Longitude": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-networkmanager-site-location.html#cfn-networkmanager-site-location-longitude", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::OpsWorks::App.DataSource": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-opsworks-app-datasource.html", "Properties": { @@ -25391,6 +25752,66 @@ } } }, + "AWS::ResourceGroups::Group.Query": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resourcegroups-group-query.html", + "Properties": { + "ResourceTypeFilters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resourcegroups-group-query.html#cfn-resourcegroups-group-query-resourcetypefilters", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "StackIdentifier": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resourcegroups-group-query.html#cfn-resourcegroups-group-query-stackidentifier", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "TagFilters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resourcegroups-group-query.html#cfn-resourcegroups-group-query-tagfilters", + "ItemType": "TagFilter", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::ResourceGroups::Group.ResourceQuery": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resourcegroups-group-resourcequery.html", + "Properties": { + "Query": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resourcegroups-group-resourcequery.html#cfn-resourcegroups-group-resourcequery-query", + "Required": false, + "Type": "Query", + "UpdateType": "Mutable" + }, + "Type": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resourcegroups-group-resourcequery.html#cfn-resourcegroups-group-resourcequery-type", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::ResourceGroups::Group.TagFilter": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resourcegroups-group-tagfilter.html", + "Properties": { + "Key": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resourcegroups-group-tagfilter.html#cfn-resourcegroups-group-tagfilter-key", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Values": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resourcegroups-group-tagfilter.html#cfn-resourcegroups-group-tagfilter-values", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::RoboMaker::RobotApplication.RobotSoftwareSuite": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-robomaker-robotapplication-robotsoftwaresuite.html", "Properties": { @@ -30327,7 +30748,7 @@ } } }, - "ResourceSpecificationVersion": "11.4.0", + "ResourceSpecificationVersion": "11.6.0", "ResourceTypes": { "AWS::ACMPCA::Certificate": { "Attributes": { @@ -32069,6 +32490,12 @@ "PrimitiveType": "Integer", "Required": false, "UpdateType": "Mutable" + }, + "TlsConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-integration.html#cfn-apigatewayv2-integration-tlsconfig", + "Required": false, + "Type": "TlsConfig", + "UpdateType": "Mutable" } } }, @@ -32564,8 +32991,12 @@ "MeshName": { "PrimitiveType": "String" }, - "MeshOwner": {}, - "ResourceOwner": {}, + "MeshOwner": { + "PrimitiveType": "String" + }, + "ResourceOwner": { + "PrimitiveType": "String" + }, "Uid": { "PrimitiveType": "String" } @@ -32601,8 +33032,12 @@ "MeshName": { "PrimitiveType": "String" }, - "MeshOwner": {}, - "ResourceOwner": {}, + "MeshOwner": { + "PrimitiveType": "String" + }, + "ResourceOwner": { + "PrimitiveType": "String" + }, "RouteName": { "PrimitiveType": "String" }, @@ -32621,6 +33056,12 @@ "Required": true, "UpdateType": "Immutable" }, + "MeshOwner": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appmesh-route.html#cfn-appmesh-route-meshowner", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, "RouteName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appmesh-route.html#cfn-appmesh-route-routename", "PrimitiveType": "String", @@ -32656,8 +33097,12 @@ "MeshName": { "PrimitiveType": "String" }, - "MeshOwner": {}, - "ResourceOwner": {}, + "MeshOwner": { + "PrimitiveType": "String" + }, + "ResourceOwner": { + "PrimitiveType": "String" + }, "Uid": { "PrimitiveType": "String" }, @@ -32673,6 +33118,12 @@ "Required": true, "UpdateType": "Immutable" }, + "MeshOwner": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appmesh-virtualnode.html#cfn-appmesh-virtualnode-meshowner", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, "Spec": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appmesh-virtualnode.html#cfn-appmesh-virtualnode-spec", "Required": true, @@ -32702,8 +33153,12 @@ "MeshName": { "PrimitiveType": "String" }, - "MeshOwner": {}, - "ResourceOwner": {}, + "MeshOwner": { + "PrimitiveType": "String" + }, + "ResourceOwner": { + "PrimitiveType": "String" + }, "Uid": { "PrimitiveType": "String" }, @@ -32719,6 +33174,12 @@ "Required": true, "UpdateType": "Immutable" }, + "MeshOwner": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appmesh-virtualrouter.html#cfn-appmesh-virtualrouter-meshowner", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, "Spec": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appmesh-virtualrouter.html#cfn-appmesh-virtualrouter-spec", "Required": true, @@ -32748,8 +33209,12 @@ "MeshName": { "PrimitiveType": "String" }, - "MeshOwner": {}, - "ResourceOwner": {}, + "MeshOwner": { + "PrimitiveType": "String" + }, + "ResourceOwner": { + "PrimitiveType": "String" + }, "Uid": { "PrimitiveType": "String" }, @@ -32765,6 +33230,12 @@ "Required": true, "UpdateType": "Immutable" }, + "MeshOwner": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appmesh-virtualservice.html#cfn-appmesh-virtualservice-meshowner", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, "Spec": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appmesh-virtualservice.html#cfn-appmesh-virtualservice-spec", "Required": true, @@ -34435,6 +34906,64 @@ } } }, + "AWS::Cassandra::Keyspace": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cassandra-keyspace.html", + "Properties": { + "KeyspaceName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cassandra-keyspace.html#cfn-cassandra-keyspace-keyspacename", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::Cassandra::Table": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cassandra-table.html", + "Properties": { + "BillingMode": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cassandra-table.html#cfn-cassandra-table-billingmode", + "Required": false, + "Type": "BillingMode", + "UpdateType": "Mutable" + }, + "ClusteringKeyColumns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cassandra-table.html#cfn-cassandra-table-clusteringkeycolumns", + "DuplicatesAllowed": false, + "ItemType": "ClusteringKeyColumn", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "KeyspaceName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cassandra-table.html#cfn-cassandra-table-keyspacename", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "PartitionKeyColumns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cassandra-table.html#cfn-cassandra-table-partitionkeycolumns", + "DuplicatesAllowed": false, + "ItemType": "Column", + "Required": true, + "Type": "List", + "UpdateType": "Immutable" + }, + "RegularColumns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cassandra-table.html#cfn-cassandra-table-regularcolumns", + "DuplicatesAllowed": false, + "ItemType": "Column", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "TableName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cassandra-table.html#cfn-cassandra-table-tablename", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, "AWS::CertificateManager::Certificate": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-certificatemanager-certificate.html", "Properties": { @@ -35529,6 +36058,22 @@ } } }, + "AWS::CodeGuruProfiler::ProfilingGroup": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codeguruprofiler-profilinggroup.html", + "Properties": { + "ProfilingGroupName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codeguruprofiler-profilinggroup.html#cfn-codeguruprofiler-profilinggroup-profilinggroupname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, "AWS::CodePipeline::CustomActionType": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codepipeline-customactiontype.html", "Properties": { @@ -37078,6 +37623,12 @@ "Required": false, "UpdateType": "Mutable" }, + "KafkaSettings": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-kafkasettings", + "Required": false, + "Type": "KafkaSettings", + "UpdateType": "Mutable" + }, "KinesisSettings": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dms-endpoint.html#cfn-dms-endpoint-kinesissettings", "Required": false, @@ -38070,6 +38621,13 @@ "Type": "List", "UpdateType": "Mutable" }, + "SecurityGroupIds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-clientvpnendpoint.html#cfn-ec2-clientvpnendpoint-securitygroupids", + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, "ServerCertificateArn": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-clientvpnendpoint.html#cfn-ec2-clientvpnendpoint-servercertificatearn", "PrimitiveType": "String", @@ -38095,6 +38653,12 @@ "Required": false, "UpdateType": "Immutable" }, + "VpcId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-clientvpnendpoint.html#cfn-ec2-clientvpnendpoint-vpcid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "VpnPort": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-clientvpnendpoint.html#cfn-ec2-clientvpnendpoint-vpnport", "PrimitiveType": "Integer", @@ -46409,6 +46973,12 @@ "Required": true, "UpdateType": "Immutable" }, + "LoggingInfo": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-msk-cluster.html#cfn-msk-cluster-logginginfo", + "Required": false, + "Type": "LoggingInfo", + "UpdateType": "Mutable" + }, "NumberOfBrokerNodes": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-msk-cluster.html#cfn-msk-cluster-numberofbrokernodes", "PrimitiveType": "Integer", @@ -47174,6 +47744,263 @@ } } }, + "AWS::NetworkManager::CustomerGatewayAssociation": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-customergatewayassociation.html", + "Properties": { + "CustomerGatewayArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-customergatewayassociation.html#cfn-networkmanager-customergatewayassociation-customergatewayarn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "DeviceId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-customergatewayassociation.html#cfn-networkmanager-customergatewayassociation-deviceid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "GlobalNetworkId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-customergatewayassociation.html#cfn-networkmanager-customergatewayassociation-globalnetworkid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "LinkId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-customergatewayassociation.html#cfn-networkmanager-customergatewayassociation-linkid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + } + } + }, + "AWS::NetworkManager::Device": { + "Attributes": { + "DeviceArn": { + "PrimitiveType": "String" + }, + "DeviceId": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-device.html", + "Properties": { + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-device.html#cfn-networkmanager-device-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "GlobalNetworkId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-device.html#cfn-networkmanager-device-globalnetworkid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Location": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-device.html#cfn-networkmanager-device-location", + "Required": false, + "Type": "Location", + "UpdateType": "Mutable" + }, + "Model": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-device.html#cfn-networkmanager-device-model", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SerialNumber": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-device.html#cfn-networkmanager-device-serialnumber", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SiteId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-device.html#cfn-networkmanager-device-siteid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-device.html#cfn-networkmanager-device-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Type": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-device.html#cfn-networkmanager-device-type", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Vendor": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-device.html#cfn-networkmanager-device-vendor", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::NetworkManager::GlobalNetwork": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, + "Id": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-globalnetwork.html", + "Properties": { + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-globalnetwork.html#cfn-networkmanager-globalnetwork-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-globalnetwork.html#cfn-networkmanager-globalnetwork-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::NetworkManager::Link": { + "Attributes": { + "LinkArn": { + "PrimitiveType": "String" + }, + "LinkId": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-link.html", + "Properties": { + "Bandwidth": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-link.html#cfn-networkmanager-link-bandwidth", + "Required": true, + "Type": "Bandwidth", + "UpdateType": "Mutable" + }, + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-link.html#cfn-networkmanager-link-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "GlobalNetworkId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-link.html#cfn-networkmanager-link-globalnetworkid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Provider": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-link.html#cfn-networkmanager-link-provider", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SiteId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-link.html#cfn-networkmanager-link-siteid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-link.html#cfn-networkmanager-link-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Type": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-link.html#cfn-networkmanager-link-type", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::NetworkManager::LinkAssociation": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-linkassociation.html", + "Properties": { + "DeviceId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-linkassociation.html#cfn-networkmanager-linkassociation-deviceid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "GlobalNetworkId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-linkassociation.html#cfn-networkmanager-linkassociation-globalnetworkid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "LinkId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-linkassociation.html#cfn-networkmanager-linkassociation-linkid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, + "AWS::NetworkManager::Site": { + "Attributes": { + "SiteArn": { + "PrimitiveType": "String" + }, + "SiteId": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-site.html", + "Properties": { + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-site.html#cfn-networkmanager-site-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "GlobalNetworkId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-site.html#cfn-networkmanager-site-globalnetworkid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Location": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-site.html#cfn-networkmanager-site-location", + "Required": false, + "Type": "Location", + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-site.html#cfn-networkmanager-site-tags", + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::NetworkManager::TransitGatewayRegistration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-transitgatewayregistration.html", + "Properties": { + "GlobalNetworkId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-transitgatewayregistration.html#cfn-networkmanager-transitgatewayregistration-globalnetworkid", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "TransitGatewayArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-networkmanager-transitgatewayregistration.html#cfn-networkmanager-transitgatewayregistration-transitgatewayarn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, "AWS::OpsWorks::App": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-opsworks-app.html", "Properties": { @@ -50026,6 +50853,41 @@ } } }, + "AWS::ResourceGroups::Group": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-resourcegroups-group.html", + "Properties": { + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-resourcegroups-group.html#cfn-resourcegroups-group-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Name": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-resourcegroups-group.html#cfn-resourcegroups-group-name", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "ResourceQuery": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-resourcegroups-group.html#cfn-resourcegroups-group-resourcequery", + "Required": false, + "Type": "ResourceQuery", + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-resourcegroups-group.html#cfn-resourcegroups-group-tags", + "ItemType": "Json", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::RoboMaker::Fleet": { "Attributes": { "Arn": { @@ -52242,6 +53104,12 @@ "Required": false, "UpdateType": "Mutable" }, + "LocalRoleName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-servicecatalog-launchroleconstraint.html#cfn-servicecatalog-launchroleconstraint-localrolename", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "PortfolioId": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-servicecatalog-launchroleconstraint.html#cfn-servicecatalog-launchroleconstraint-portfolioid", "PrimitiveType": "String", @@ -52257,7 +53125,7 @@ "RoleArn": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-servicecatalog-launchroleconstraint.html#cfn-servicecatalog-launchroleconstraint-rolearn", "PrimitiveType": "String", - "Required": true, + "Required": false, "UpdateType": "Mutable" } } diff --git a/packages/@aws-cdk/cfnspec/spec-source/530_ResourceGroups_Tags_patch.json b/packages/@aws-cdk/cfnspec/spec-source/530_ResourceGroups_Tags_patch.json new file mode 100644 index 0000000000000..da2d3c603ddbd --- /dev/null +++ b/packages/@aws-cdk/cfnspec/spec-source/530_ResourceGroups_Tags_patch.json @@ -0,0 +1,24 @@ +{ + "ResourceTypes": { + "AWS::ResourceGroups::Group": { + "patch": { + "description": "Sets AWS::ResourceGroups::Group#Tags to Json", + "operations": [ + { + "op": "remove", + "path": "/Properties/Tags/ItemType" + }, + { + "op": "remove", + "path": "/Properties/Tags/Type" + }, + { + "op": "add", + "path": "/Properties/Tags/PrimitiveType", + "value": "Json" + } + ] + } + } + } +} diff --git a/packages/decdk/package.json b/packages/decdk/package.json index 05822392a1725..dcae5b4cda00f 100644 --- a/packages/decdk/package.json +++ b/packages/decdk/package.json @@ -49,6 +49,7 @@ "@aws-cdk/aws-backup": "0.0.0", "@aws-cdk/aws-batch": "0.0.0", "@aws-cdk/aws-budgets": "0.0.0", + "@aws-cdk/aws-cassandra": "0.0.0", "@aws-cdk/aws-certificatemanager": "0.0.0", "@aws-cdk/aws-chatbot": "0.0.0", "@aws-cdk/aws-cloud9": "0.0.0", @@ -60,6 +61,7 @@ "@aws-cdk/aws-codebuild": "0.0.0", "@aws-cdk/aws-codecommit": "0.0.0", "@aws-cdk/aws-codedeploy": "0.0.0", + "@aws-cdk/aws-codeguruprofiler": "0.0.0", "@aws-cdk/aws-codepipeline": "0.0.0", "@aws-cdk/aws-codepipeline-actions": "0.0.0", "@aws-cdk/aws-codestar": "0.0.0", @@ -122,6 +124,7 @@ "@aws-cdk/aws-mediastore": "0.0.0", "@aws-cdk/aws-msk": "0.0.0", "@aws-cdk/aws-neptune": "0.0.0", + "@aws-cdk/aws-networkmanager": "0.0.0", "@aws-cdk/aws-opsworks": "0.0.0", "@aws-cdk/aws-opsworkscm": "0.0.0", "@aws-cdk/aws-pinpoint": "0.0.0", @@ -130,6 +133,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-resourcegroups": "0.0.0", "@aws-cdk/aws-robomaker": "0.0.0", "@aws-cdk/aws-route53": "0.0.0", "@aws-cdk/aws-route53-patterns": "0.0.0", @@ -165,10 +169,10 @@ "@aws-cdk/custom-resources": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/region-info": "0.0.0", + "constructs": "^2.0.0", "fs-extra": "^8.1.0", "jsii-reflect": "^1.1.0", "jsonschema": "^1.2.5", - "constructs": "^2.0.0", "yaml": "1.8.3", "yargs": "^15.3.1" }, diff --git a/packages/monocdk-experiment/package.json b/packages/monocdk-experiment/package.json index b12845679a9f2..2bd3469ea1b13 100644 --- a/packages/monocdk-experiment/package.json +++ b/packages/monocdk-experiment/package.json @@ -161,7 +161,11 @@ "@aws-cdk/region-info": "0.0.0", "@types/node": "^10.17.17", "@aws-cdk/aws-chatbot": "0.0.0", - "@aws-cdk/aws-codestarconnections": "0.0.0" + "@aws-cdk/aws-codestarconnections": "0.0.0", + "@aws-cdk/aws-cassandra": "0.0.0", + "@aws-cdk/aws-codeguruprofiler": "0.0.0", + "@aws-cdk/aws-networkmanager": "0.0.0", + "@aws-cdk/aws-resourcegroups": "0.0.0" }, "peerDependencies": { "constructs": "^2.0.0" From 0809746b6e8305dd975e3c66ff9e679d62b39029 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 30 Mar 2020 20:43:25 +0000 Subject: [PATCH 22/53] chore(deps): bump @typescript-eslint/eslint-plugin from 2.25.0 to 2.26.0 (#7077) Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 2.25.0 to 2.26.0. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v2.26.0/packages/eslint-plugin) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- tools/cdk-build-tools/package.json | 2 +- yarn.lock | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/tools/cdk-build-tools/package.json b/tools/cdk-build-tools/package.json index 242e91c9a7c2b..757b7b6cb17a3 100644 --- a/tools/cdk-build-tools/package.json +++ b/tools/cdk-build-tools/package.json @@ -37,7 +37,7 @@ "pkglint": "0.0.0" }, "dependencies": { - "@typescript-eslint/eslint-plugin": "^2.25.0", + "@typescript-eslint/eslint-plugin": "^2.26.0", "@typescript-eslint/parser": "^2.19.2", "awslint": "0.0.0", "colors": "^1.4.0", diff --git a/yarn.lock b/yarn.lock index 7d29a353f141e..19e63fa7f8432 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2131,12 +2131,12 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^2.25.0": - version "2.25.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.25.0.tgz#0b60917332f20dcff54d0eb9be2a9e9f4c9fbd02" - integrity sha512-W2YyMtjmlrOjtXc+FtTelVs9OhuR6OlYc4XKIslJ8PUJOqgYYAPRJhAqkYRQo3G4sjvG8jSodsNycEn4W2gHUw== +"@typescript-eslint/eslint-plugin@^2.26.0": + version "2.26.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.26.0.tgz#04c96560c8981421e5a9caad8394192363cc423f" + integrity sha512-4yUnLv40bzfzsXcTAtZyTjbiGUXMrcIJcIMioI22tSOyAxpdXiZ4r7YQUU8Jj6XXrLz9d5aMHPQf5JFR7h27Nw== dependencies: - "@typescript-eslint/experimental-utils" "2.25.0" + "@typescript-eslint/experimental-utils" "2.26.0" functional-red-black-tree "^1.0.1" regexpp "^3.0.0" tsutils "^3.17.1" @@ -2150,13 +2150,13 @@ "@typescript-eslint/typescript-estree" "2.23.0" eslint-scope "^5.0.0" -"@typescript-eslint/experimental-utils@2.25.0": - version "2.25.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.25.0.tgz#13691c4fe368bd377b1e5b1e4ad660b220bf7714" - integrity sha512-0IZ4ZR5QkFYbaJk+8eJ2kYeA+1tzOE1sBjbwwtSV85oNWYUBep+EyhlZ7DLUCyhMUGuJpcCCFL0fDtYAP1zMZw== +"@typescript-eslint/experimental-utils@2.26.0": + version "2.26.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.26.0.tgz#063390c404d9980767d76274df386c0aa675d91d" + integrity sha512-RELVoH5EYd+JlGprEyojUv9HeKcZqF7nZUGSblyAw1FwOGNnmQIU8kxJ69fttQvEwCsX5D6ECJT8GTozxrDKVQ== dependencies: "@types/json-schema" "^7.0.3" - "@typescript-eslint/typescript-estree" "2.25.0" + "@typescript-eslint/typescript-estree" "2.26.0" eslint-scope "^5.0.0" eslint-utils "^2.0.0" @@ -2183,10 +2183,10 @@ semver "^6.3.0" tsutils "^3.17.1" -"@typescript-eslint/typescript-estree@2.25.0": - version "2.25.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.25.0.tgz#b790497556734b7476fa7dd3fa539955a5c79e2c" - integrity sha512-VUksmx5lDxSi6GfmwSK7SSoIKSw9anukWWNitQPqt58LuYrKalzsgeuignbqnB+rK/xxGlSsCy8lYnwFfB6YJg== +"@typescript-eslint/typescript-estree@2.26.0": + version "2.26.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.26.0.tgz#d8132cf1ee8a72234f996519a47d8a9118b57d56" + integrity sha512-3x4SyZCLB4zsKsjuhxDLeVJN6W29VwBnYpCsZ7vIdPel9ZqLfIZJgJXO47MNUkurGpQuIBALdPQKtsSnWpE1Yg== dependencies: debug "^4.1.1" eslint-visitor-keys "^1.1.0" From 9b37211286e4d9def1a0a3d195c25c75487ba1bf Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 30 Mar 2020 21:40:53 +0000 Subject: [PATCH 23/53] chore(deps): bump aws-sdk from 2.648.0 to 2.649.0 (#7078) Bumps [aws-sdk](https://github.com/aws/aws-sdk-js) from 2.648.0 to 2.649.0. - [Release notes](https://github.com/aws/aws-sdk-js/releases) - [Changelog](https://github.com/aws/aws-sdk-js/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-js/compare/v2.648.0...v2.649.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- packages/@aws-cdk/aws-cloudfront/package.json | 2 +- packages/@aws-cdk/aws-cloudtrail/package.json | 2 +- packages/@aws-cdk/aws-codebuild/package.json | 2 +- packages/@aws-cdk/aws-codecommit/package.json | 2 +- packages/@aws-cdk/aws-dynamodb/package.json | 2 +- packages/@aws-cdk/aws-eks/package.json | 2 +- packages/@aws-cdk/aws-events-targets/package.json | 2 +- packages/@aws-cdk/aws-lambda/package.json | 2 +- packages/@aws-cdk/aws-route53/package.json | 2 +- packages/@aws-cdk/aws-sqs/package.json | 2 +- packages/@aws-cdk/custom-resources/package.json | 2 +- packages/aws-cdk/package.json | 2 +- packages/cdk-assets/package.json | 2 +- yarn.lock | 8 ++++---- 14 files changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/@aws-cdk/aws-cloudfront/package.json b/packages/@aws-cdk/aws-cloudfront/package.json index 7a4239c504273..bcc2543c2f221 100644 --- a/packages/@aws-cdk/aws-cloudfront/package.json +++ b/packages/@aws-cdk/aws-cloudfront/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.648.0", + "aws-sdk": "^2.649.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudtrail/package.json b/packages/@aws-cdk/aws-cloudtrail/package.json index a28db00fc3e55..0b9b9759b4dba 100644 --- a/packages/@aws-cdk/aws-cloudtrail/package.json +++ b/packages/@aws-cdk/aws-cloudtrail/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.648.0", + "aws-sdk": "^2.649.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-codebuild/package.json b/packages/@aws-cdk/aws-codebuild/package.json index ae6a3331e5a1b..2d82e832c8fe4 100644 --- a/packages/@aws-cdk/aws-codebuild/package.json +++ b/packages/@aws-cdk/aws-codebuild/package.json @@ -70,7 +70,7 @@ "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.648.0", + "aws-sdk": "^2.649.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-codecommit/package.json b/packages/@aws-cdk/aws-codecommit/package.json index c9dbf7c021c96..925f5eef7dbd3 100644 --- a/packages/@aws-cdk/aws-codecommit/package.json +++ b/packages/@aws-cdk/aws-codecommit/package.json @@ -70,7 +70,7 @@ "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.648.0", + "aws-sdk": "^2.649.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-dynamodb/package.json b/packages/@aws-cdk/aws-dynamodb/package.json index e7aec094f6238..72e5d4ddbd62c 100644 --- a/packages/@aws-cdk/aws-dynamodb/package.json +++ b/packages/@aws-cdk/aws-dynamodb/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.648.0", + "aws-sdk": "^2.649.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-eks/package.json b/packages/@aws-cdk/aws-eks/package.json index 4924f02579a7e..04ef99a9ff764 100644 --- a/packages/@aws-cdk/aws-eks/package.json +++ b/packages/@aws-cdk/aws-eks/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.648.0", + "aws-sdk": "^2.649.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-events-targets/package.json b/packages/@aws-cdk/aws-events-targets/package.json index f39e7a40bb7c2..32b6caaa092f7 100644 --- a/packages/@aws-cdk/aws-events-targets/package.json +++ b/packages/@aws-cdk/aws-events-targets/package.json @@ -86,7 +86,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-codecommit": "0.0.0", - "aws-sdk": "^2.648.0", + "aws-sdk": "^2.649.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-lambda/package.json b/packages/@aws-cdk/aws-lambda/package.json index 25b0362367c1c..4c490765330fc 100644 --- a/packages/@aws-cdk/aws-lambda/package.json +++ b/packages/@aws-cdk/aws-lambda/package.json @@ -71,7 +71,7 @@ "@types/lodash": "^4.14.149", "@types/nodeunit": "^0.0.30", "@types/sinon": "^7.5.2", - "aws-sdk": "^2.648.0", + "aws-sdk": "^2.649.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-route53/package.json b/packages/@aws-cdk/aws-route53/package.json index ee7a45fff725d..d92400cb785ba 100644 --- a/packages/@aws-cdk/aws-route53/package.json +++ b/packages/@aws-cdk/aws-route53/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.648.0", + "aws-sdk": "^2.649.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-sqs/package.json b/packages/@aws-cdk/aws-sqs/package.json index 77951dd6858c0..4c917cfac09d1 100644 --- a/packages/@aws-cdk/aws-sqs/package.json +++ b/packages/@aws-cdk/aws-sqs/package.json @@ -65,7 +65,7 @@ "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.648.0", + "aws-sdk": "^2.649.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/custom-resources/package.json b/packages/@aws-cdk/custom-resources/package.json index f5567a07d8fd6..8ae76a380e070 100644 --- a/packages/@aws-cdk/custom-resources/package.json +++ b/packages/@aws-cdk/custom-resources/package.json @@ -73,7 +73,7 @@ "@types/aws-lambda": "^8.10.39", "@types/fs-extra": "^8.1.0", "@types/sinon": "^7.5.2", - "aws-sdk": "^2.648.0", + "aws-sdk": "^2.649.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index 78fd3adfabc37..0391336ec21cc 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -69,7 +69,7 @@ "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/region-info": "0.0.0", "archiver": "^3.1.1", - "aws-sdk": "^2.648.0", + "aws-sdk": "^2.649.0", "camelcase": "^5.3.1", "cdk-assets": "0.0.0", "colors": "^1.4.0", diff --git a/packages/cdk-assets/package.json b/packages/cdk-assets/package.json index 5d38fbb4f8714..b450dedf744dc 100644 --- a/packages/cdk-assets/package.json +++ b/packages/cdk-assets/package.json @@ -44,7 +44,7 @@ "dependencies": { "@aws-cdk/cdk-assets-schema": "0.0.0", "archiver": "^3.1.1", - "aws-sdk": "^2.648.0", + "aws-sdk": "^2.649.0", "glob": "^7.1.6", "yargs": "^15.3.1" }, diff --git a/yarn.lock b/yarn.lock index 19e63fa7f8432..fc00fe4a7842c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2619,10 +2619,10 @@ aws-sdk-mock@^5.1.0: sinon "^9.0.1" traverse "^0.6.6" -aws-sdk@^2.637.0, aws-sdk@^2.648.0: - version "2.648.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.648.0.tgz#6cbea887b98c3ee8316870e9eead659194e35094" - integrity sha512-b+PdZmCFvZBisqXEH68jO4xB30LrDHQMWrEX6MJoZaOlxPJfpOqRFUH3zsiAXF5Q2jTdjYLtS5bs3vcIwRzi3Q== +aws-sdk@^2.637.0, aws-sdk@^2.649.0: + version "2.649.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.649.0.tgz#a600584171a53a4dcf09d768e514b7bdc408abab" + integrity sha512-0o3l+bfz++KOYHG0gdWofSX/1EdyaD1ixEvWXt71mBbDM1vWc71xfXGzPRtt8Cu8/Id47v7DE3ayELZytzLCXQ== dependencies: buffer "4.9.1" events "1.1.1" From 282b0ad14b1f9ba934e63b7cdb7b24b7e2c9d898 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 31 Mar 2020 00:51:19 +0000 Subject: [PATCH 24/53] chore(deps-dev): bump @types/node from 10.17.17 to 10.17.18 (#7081) Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 10.17.17 to 10.17.18. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- packages/@monocdk-experiment/rewrite-imports/package.json | 2 +- packages/aws-cdk/package.json | 2 +- packages/cdk-assets/package.json | 2 +- packages/monocdk-experiment/package.json | 2 +- yarn.lock | 8 ++++---- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/@monocdk-experiment/rewrite-imports/package.json b/packages/@monocdk-experiment/rewrite-imports/package.json index 87ea2ecc66796..0b76ed6bacea8 100644 --- a/packages/@monocdk-experiment/rewrite-imports/package.json +++ b/packages/@monocdk-experiment/rewrite-imports/package.json @@ -33,7 +33,7 @@ "devDependencies": { "@types/glob": "^7.1.1", "@types/jest": "^25.1.4", - "@types/node": "^10.17.17", + "@types/node": "^10.17.18", "cdk-build-tools": "0.0.0", "pkglint": "0.0.0" }, diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index 0391336ec21cc..f3cceb7d24163 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -47,7 +47,7 @@ "@types/jest": "^25.1.4", "@types/minimatch": "^3.0.3", "@types/mockery": "^1.4.29", - "@types/node": "^10.17.17", + "@types/node": "^10.17.18", "@types/promptly": "^3.0.0", "@types/semver": "^7.1.0", "@types/sinon": "^7.5.2", diff --git a/packages/cdk-assets/package.json b/packages/cdk-assets/package.json index b450dedf744dc..204764b7a0f3d 100644 --- a/packages/cdk-assets/package.json +++ b/packages/cdk-assets/package.json @@ -32,7 +32,7 @@ "@types/glob": "^7.1.1", "@types/jest": "^25.1.4", "@types/mock-fs": "^4.10.0", - "@types/node": "^10.17.17", + "@types/node": "^10.17.18", "@types/yargs": "^15.0.4", "@types/jszip": "^3.1.7", "jszip": "^3.2.2", diff --git a/packages/monocdk-experiment/package.json b/packages/monocdk-experiment/package.json index 2bd3469ea1b13..c43e2873dabc2 100644 --- a/packages/monocdk-experiment/package.json +++ b/packages/monocdk-experiment/package.json @@ -159,7 +159,7 @@ "@aws-cdk/custom-resources": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/region-info": "0.0.0", - "@types/node": "^10.17.17", + "@types/node": "^10.17.18", "@aws-cdk/aws-chatbot": "0.0.0", "@aws-cdk/aws-codestarconnections": "0.0.0", "@aws-cdk/aws-cassandra": "0.0.0", diff --git a/yarn.lock b/yarn.lock index fc00fe4a7842c..7338b2baf902b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2046,10 +2046,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-13.9.1.tgz#96f606f8cd67fb018847d9b61e93997dabdefc72" integrity sha512-E6M6N0blf/jiZx8Q3nb0vNaswQeEyn0XlupO+xN6DtJ6r6IT4nXrTry7zhIfYvFCl3/8Cu6WIysmUBKiqV0bqQ== -"@types/node@^10.17.17": - version "10.17.17" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.17.tgz#7a183163a9e6ff720d86502db23ba4aade5999b8" - integrity sha512-gpNnRnZP3VWzzj5k3qrpRC6Rk3H/uclhAVo1aIvwzK5p5cOrs9yEyQ8H/HBsBY0u5rrWxXEiVPQ0dEB6pkjE8Q== +"@types/node@^10.17.18": + version "10.17.18" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.18.tgz#ae364d97382aacdebf583fa4e7132af2dfe56a0c" + integrity sha512-DQ2hl/Jl3g33KuAUOcMrcAOtsbzb+y/ufakzAdeK9z/H/xsvkpbETZZbPNMIiQuk24f5ZRMCcZIViAwyFIiKmg== "@types/nodeunit@^0.0.30": version "0.0.30" From bded68336265a4c77804726208d3638fc5cbd260 Mon Sep 17 00:00:00 2001 From: Shiv Lakshminarayan Date: Mon, 30 Mar 2020 18:37:58 -0700 Subject: [PATCH 25/53] feat(kinesis): stream encryption with the Kinesis master key (#7057) feat(kinesis): stream encryption with the Kinesis master key Adds a `StreamEncryption` option to specify that encryption should be enabled on a Stream with the master key managed by Kinesis. Closes #751 --- packages/@aws-cdk/aws-kinesis/README.md | 15 ++++- packages/@aws-cdk/aws-kinesis/lib/stream.ts | 22 +++++-- .../@aws-cdk/aws-kinesis/test/test.stream.ts | 58 ++++++++++++++++++- 3 files changed, 87 insertions(+), 8 deletions(-) diff --git a/packages/@aws-cdk/aws-kinesis/README.md b/packages/@aws-cdk/aws-kinesis/README.md index 2e7e0e6a26176..d805856111752 100644 --- a/packages/@aws-cdk/aws-kinesis/README.md +++ b/packages/@aws-cdk/aws-kinesis/README.md @@ -59,10 +59,19 @@ Streams are not encrypted by default. [Stream encryption](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesis-stream-streamencryption.html) enables server-side encryption using an AWS KMS key for a specified stream. -You can enable encryption on your streams by specifying the `encryption` property. A KMS key will be created for you and associated with the stream. +You can enable encryption on your stream with the master key owned by Kinesis Data Streams by specifying the `encryption` property. ```ts -const stream = new Stream(this, "MyEncryptedStream", { +new Stream(this, 'MyEncryptedStream', { + encryption: StreamEncryption.MANAGED +}); +``` + +You can enable encryption on your stream with a user-managed key by specifying the `encryption` property. +A KMS key will be created for you and associated with the stream. + +```ts +new Stream(this, "MyEncryptedStream", { encryption: StreamEncryption.KMS }); ``` @@ -74,7 +83,7 @@ import * as kms from "@aws-cdk/aws-kms"; const key = new kms.Key(this, "MyKey"); -const stream = new Stream(this, "MyEncryptedStream", { +new Stream(this, "MyEncryptedStream", { encryption: StreamEncryption.KMS, encryptionKey: key }); diff --git a/packages/@aws-cdk/aws-kinesis/lib/stream.ts b/packages/@aws-cdk/aws-kinesis/lib/stream.ts index 09cc92e05e722..f6a683449c09d 100644 --- a/packages/@aws-cdk/aws-kinesis/lib/stream.ts +++ b/packages/@aws-cdk/aws-kinesis/lib/stream.ts @@ -201,7 +201,7 @@ export interface StreamProps { * If you choose KMS, you can specify a KMS key via `encryptionKey`. If * encryption key is not specified, a key will automatically be created. * - * @default Unencrypted + * @default - StreamEncryption.KMS if encryptionKey is specified, or StreamEncryption.UNENCRYPTED otherwise */ readonly encryption?: StreamEncryption; @@ -210,7 +210,7 @@ export interface StreamProps { * * The 'encryption' property must be set to "Kms". * - * @default If encryption is set to "Kms" and this property is undefined, a + * @default - If encryption is set to "KMS" and this property is undefined, a * new KMS key will be created and associated with this stream. */ readonly encryptionKey?: kms.IKey; @@ -294,8 +294,9 @@ export class Stream extends StreamBase { encryptionKey?: kms.IKey } { - // default to unencrypted. - const encryptionType = props.encryption || StreamEncryption.UNENCRYPTED; + // default based on whether encryption key is specified + const encryptionType = props.encryption ?? + (props.encryptionKey ? StreamEncryption.KMS : StreamEncryption.UNENCRYPTED); // if encryption key is set, encryption must be set to KMS. if (encryptionType !== StreamEncryption.KMS && props.encryptionKey) { @@ -306,6 +307,14 @@ export class Stream extends StreamBase { return { streamEncryption: undefined, encryptionKey: undefined }; } + if (encryptionType === StreamEncryption.MANAGED) { + const encryption = { encryptionType: 'KMS', keyId: 'alias/aws/kinesis'}; + return { + streamEncryption: encryption, + encryptionKey: undefined + }; + } + if (encryptionType === StreamEncryption.KMS) { const encryptionKey = props.encryptionKey || new kms.Key(this, 'Key', { description: `Created by ${this.node.path}` @@ -336,4 +345,9 @@ export enum StreamEncryption { * If `encryptionKey` is specified, this key will be used, otherwise, one will be defined. */ KMS = 'KMS', + + /** + * Server-side encryption with a master key managed by Amazon Kinesis + */ + MANAGED = 'MANAGED' } diff --git a/packages/@aws-cdk/aws-kinesis/test/test.stream.ts b/packages/@aws-cdk/aws-kinesis/test/test.stream.ts index 829e4f68f6b60..b229bc669808e 100644 --- a/packages/@aws-cdk/aws-kinesis/test/test.stream.ts +++ b/packages/@aws-cdk/aws-kinesis/test/test.stream.ts @@ -1,4 +1,4 @@ -import { expect } from '@aws-cdk/assert'; +import { expect, haveResource } from '@aws-cdk/assert'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import { App, Duration, Stack } from '@aws-cdk/core'; @@ -97,6 +97,62 @@ export = { test.done(); }, + + 'uses Kinesis master key if MANAGED encryption type is provided'(test: Test) { + // GIVEN + const stack = new Stack(); + + // WHEN + new Stream(stack, 'MyStream', { + encryption: StreamEncryption.MANAGED + }); + + // THEN + expect(stack).toMatch({ + "Resources": { + "MyStream5C050E93": { + "Type": "AWS::Kinesis::Stream", + "Properties": { + "ShardCount": 1, + "RetentionPeriodHours": 24, + "StreamEncryption": { + "EncryptionType": "KMS", + "KeyId": "alias/aws/kinesis" + } + } + } + } + }); + + test.done(); + }, + + 'if a KMS key is supplied, use KMS as the encryption type'(test: Test) { + // GIVEN + const stack = new Stack(); + const key = new kms.Key(stack, 'myKey'); + + // WHEN + new Stream(stack, 'myStream', { + encryptionKey: key + }); + + // THEN + expect(stack).to(haveResource('AWS::Kinesis::Stream', { + ShardCount: 1, + RetentionPeriodHours: 24, + StreamEncryption: { + EncryptionType: 'KMS', + KeyId: { + 'Fn::GetAtt': ['myKey441A1E73', 'Arn'] + } + } + }) + ); + + test.done(); + }, + "auto-creates KMS key if encryption type is KMS but no key is provided"(test: Test) { const stack = new Stack(); From 934d58e966a7ff99dfcff5a479dc75549b248c6f Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Tue, 31 Mar 2020 10:39:16 +0200 Subject: [PATCH 26/53] chore(cli): fix bootstrap v2 by adding a missing 'await' (#7087) The title says it all. Q: Why wasn't this caught in testing/why didn't you add a test? A: We had tests on this originally, but we reverted them because they made assumptions on the source environment and would fail when run in the pipeline. Restoring those is next on the agenda. https://github.com/aws/aws-cdk/commit/2e9f241833ea20112c134eaa904425a26007e9d6 --- packages/aws-cdk/lib/api/bootstrap/bootstrap-environment2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/aws-cdk/lib/api/bootstrap/bootstrap-environment2.ts b/packages/aws-cdk/lib/api/bootstrap/bootstrap-environment2.ts index d65ccc8c56072..2a42af34ae25f 100644 --- a/packages/aws-cdk/lib/api/bootstrap/bootstrap-environment2.ts +++ b/packages/aws-cdk/lib/api/bootstrap/bootstrap-environment2.ts @@ -19,7 +19,7 @@ export async function bootstrapEnvironment2(environment: cxapi.Environment, sdk: // convert from YAML to JSON (which the Cloud Assembly uses) const templateFile = `${toolkitStackName}.template.json`; const bootstrapTemplatePath = path.join(__dirname, 'bootstrap-template.yaml'); - const bootstrapTemplateObject = loadStructuredFile(bootstrapTemplatePath); + const bootstrapTemplateObject = await loadStructuredFile(bootstrapTemplatePath); await fs.writeJson( path.join(builder.outdir, templateFile), bootstrapTemplateObject); From 497f63e1884885c5647f08438199c38a89668e24 Mon Sep 17 00:00:00 2001 From: Jeremy Witte <48760600+jeremywitte@users.noreply.github.com> Date: Tue, 31 Mar 2020 07:48:27 -0500 Subject: [PATCH 27/53] docs(iam): improve consistency for static import methods (#7048) Updates inline documentation for static `from...Arn` and `from...Name` import methods to provide consistent verbiage, parameter specification, and known caveats. --- packages/@aws-cdk/aws-iam/lib/group.ts | 17 ++++++++++++--- .../@aws-cdk/aws-iam/lib/managed-policy.ts | 21 +++++++++++++++---- packages/@aws-cdk/aws-iam/lib/role.ts | 9 ++++---- packages/@aws-cdk/aws-iam/lib/user.ts | 6 +++++- 4 files changed, 41 insertions(+), 12 deletions(-) diff --git a/packages/@aws-cdk/aws-iam/lib/group.ts b/packages/@aws-cdk/aws-iam/lib/group.ts index 7a755b85cf26f..c4acde13ae5a7 100644 --- a/packages/@aws-cdk/aws-iam/lib/group.ts +++ b/packages/@aws-cdk/aws-iam/lib/group.ts @@ -108,10 +108,21 @@ abstract class GroupBase extends Resource implements IGroup { } export class Group extends GroupBase { - /** - * Imports a group from ARN - * @param groupArn (e.g. `arn:aws:iam::account-id:group/group-name`) + * Import an external group by ARN. + * + * If the imported Group ARN is a Token (such as a + * `CfnParameter.valueAsString` or a `Fn.importValue()`) *and* the referenced + * group has a `path` (like `arn:...:group/AdminGroup/NetworkAdmin`), the + * `groupName` property will not resolve to the correct value. Instead it + * will resolve to the first path component. We unfortunately cannot express + * the correct calculation of the full path name as a CloudFormation + * expression. In this scenario the Group ARN should be supplied without the + * `path` in order to resolve the correct group resource. + * + * @param scope construct scope + * @param id construct id + * @param groupArn the ARN of the group to import (e.g. `arn:aws:iam::account-id:group/group-name`) */ public static fromGroupArn(scope: Construct, id: string, groupArn: string): IGroup { const groupName = Stack.of(scope).parseArn(groupArn).resourceName!; diff --git a/packages/@aws-cdk/aws-iam/lib/managed-policy.ts b/packages/@aws-cdk/aws-iam/lib/managed-policy.ts index 93865dde18851..cd234ee39304c 100644 --- a/packages/@aws-cdk/aws-iam/lib/managed-policy.ts +++ b/packages/@aws-cdk/aws-iam/lib/managed-policy.ts @@ -88,7 +88,7 @@ export interface ManagedPolicyProps { */ export class ManagedPolicy extends Resource implements IManagedPolicy { /** - * Construct a customer managed policy from the managedPolicyName + * Import a customer managed policy from the managedPolicyName. * * For this managed policy, you only need to know the name to be able to use it. * @@ -107,10 +107,23 @@ export class ManagedPolicy extends Resource implements IManagedPolicy { } /** - * Constructs a managed policy from an ARN. + * Import an external managed policy by ARN. * - * For this managed policy, you only need to know the ARN to be able to use it. This can be useful if you got the ARN in a Cloudformation Export. + * For this managed policy, you only need to know the ARN to be able to use it. + * This can be useful if you got the ARN from a CloudFormation Export. * + * If the imported Managed Policy ARN is a Token (such as a + * `CfnParameter.valueAsString` or a `Fn.importValue()`) *and* the referenced + * managed policy has a `path` (like `arn:...:policy/AdminPolicy/AdminAllow`), the + * `managedPolicyName` property will not resolve to the correct value. Instead it + * will resolve to the first path component. We unfortunately cannot express + * the correct calculation of the full path name as a CloudFormation + * expression. In this scenario the Managed Policy ARN should be supplied without the + * `path` in order to resolve the correct managed policy resource. + * + * @param scope construct scope + * @param id construct id + * @param managedPolicyArn the ARN of the managed policy to import */ public static fromManagedPolicyArn(scope: Construct, id: string, managedPolicyArn: string): IManagedPolicy { class Import extends Resource implements IManagedPolicy { @@ -120,7 +133,7 @@ export class ManagedPolicy extends Resource implements IManagedPolicy { } /** - * Construct a managed policy from one of the policies that AWS manages + * Import a managed policy from one of the policies that AWS manages. * * For this managed policy, you only need to know the name to be able to use it. * diff --git a/packages/@aws-cdk/aws-iam/lib/role.ts b/packages/@aws-cdk/aws-iam/lib/role.ts index f90be6a9abb8e..b6edb80a861cf 100644 --- a/packages/@aws-cdk/aws-iam/lib/role.ts +++ b/packages/@aws-cdk/aws-iam/lib/role.ts @@ -153,15 +153,16 @@ export interface FromRoleArnOptions { */ export class Role extends Resource implements IRole { /** - * Imports an external role by ARN. + * Import an external role by ARN. * * If the imported Role ARN is a Token (such as a * `CfnParameter.valueAsString` or a `Fn.importValue()`) *and* the referenced * role has a `path` (like `arn:...:role/AdminRoles/Alice`), the - * `role.roleName` property will not resolve to the correct value. Instead it + * `roleName` property will not resolve to the correct value. Instead it * will resolve to the first path component. We unfortunately cannot express * the correct calculation of the full path name as a CloudFormation - * expression. + * expression. In this scenario the Role ARN should be supplied without the + * `path` in order to resolve the correct role resource. * * @param scope construct scope * @param id construct id @@ -479,4 +480,4 @@ class AwsStarStatement extends PolicyStatement { return stat; } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-iam/lib/user.ts b/packages/@aws-cdk/aws-iam/lib/user.ts index 977209f33252c..0affaf414e13b 100644 --- a/packages/@aws-cdk/aws-iam/lib/user.ts +++ b/packages/@aws-cdk/aws-iam/lib/user.ts @@ -115,7 +115,11 @@ export interface UserProps { */ export class User extends Resource implements IIdentity, IUser { /** - * Import an existing user given a username + * Import an existing user given a username. + * + * @param scope construct scope + * @param id construct id + * @param userName the username of the existing user to import */ public static fromUserName(scope: Construct, id: string, userName: string): IUser { const arn = Stack.of(scope).formatArn({ From b49881f4a21e02491088961860ea853428f49000 Mon Sep 17 00:00:00 2001 From: Rafal Wilinski Date: Tue, 31 Mar 2020 15:39:03 +0200 Subject: [PATCH 28/53] fix(cloudtrail): include s3KeyPrefix in bucket policy resource (#7053) Fixes: #6741 --- packages/@aws-cdk/aws-cloudtrail/lib/index.ts | 30 +++++----- .../aws-cloudtrail/test/test.cloudtrail.ts | 56 +++++++++++++++++-- 2 files changed, 66 insertions(+), 20 deletions(-) diff --git a/packages/@aws-cdk/aws-cloudtrail/lib/index.ts b/packages/@aws-cdk/aws-cloudtrail/lib/index.ts index bb93023204cde..fc7bea1792b3d 100644 --- a/packages/@aws-cdk/aws-cloudtrail/lib/index.ts +++ b/packages/@aws-cdk/aws-cloudtrail/lib/index.ts @@ -142,22 +142,24 @@ export class Trail extends Resource { const cloudTrailPrincipal = new iam.ServicePrincipal("cloudtrail.amazonaws.com"); - this.s3bucket = props.bucket || new s3.Bucket(this, 'S3', {encryption: s3.BucketEncryption.UNENCRYPTED}); + this.s3bucket = props.bucket || new s3.Bucket(this, 'S3', { encryption: s3.BucketEncryption.UNENCRYPTED }); this.s3bucket.addToResourcePolicy(new iam.PolicyStatement({ - resources: [this.s3bucket.bucketArn], - actions: ['s3:GetBucketAcl'], - principals: [cloudTrailPrincipal], - })); + resources: [this.s3bucket.bucketArn], + actions: ['s3:GetBucketAcl'], + principals: [cloudTrailPrincipal], + })); this.s3bucket.addToResourcePolicy(new iam.PolicyStatement({ - resources: [this.s3bucket.arnForObjects(`AWSLogs/${Stack.of(this).account}/*`)], - actions: ["s3:PutObject"], - principals: [cloudTrailPrincipal], - conditions: { - StringEquals: {'s3:x-amz-acl': "bucket-owner-full-control"} - } - })); + resources: [this.s3bucket.arnForObjects( + `${props.s3KeyPrefix ? `${props.s3KeyPrefix}/` : ''}AWSLogs/${Stack.of(this).account}/*` + )], + actions: ["s3:PutObject"], + principals: [cloudTrailPrincipal], + conditions: { + StringEquals: { 's3:x-amz-acl': "bucket-owner-full-control" } + } + })); let logGroup: logs.CfnLogGroup | undefined; let logsRole: iam.IRole | undefined; @@ -176,7 +178,7 @@ export class Trail extends Resource { } if (props.managementEvents) { - const managementEvent = { + const managementEvent = { includeManagementEvents: true, readWriteType: props.managementEvents }; @@ -190,7 +192,7 @@ export class Trail extends Resource { isMultiRegionTrail: props.isMultiRegionTrail == null ? true : props.isMultiRegionTrail, includeGlobalServiceEvents: props.includeGlobalServiceEvents == null ? true : props.includeGlobalServiceEvents, trailName: this.physicalName, - kmsKeyId: props.kmsKey && props.kmsKey.keyArn, + kmsKeyId: props.kmsKey && props.kmsKey.keyArn, s3BucketName: this.s3bucket.bucketName, s3KeyPrefix: props.s3KeyPrefix, cloudWatchLogsLogGroupArn: logGroup && logGroup.attrArn, diff --git a/packages/@aws-cdk/aws-cloudtrail/test/test.cloudtrail.ts b/packages/@aws-cdk/aws-cloudtrail/test/test.cloudtrail.ts index 653155b91b7ca..a2e9cf15c0383 100644 --- a/packages/@aws-cdk/aws-cloudtrail/test/test.cloudtrail.ts +++ b/packages/@aws-cdk/aws-cloudtrail/test/test.cloudtrail.ts @@ -75,20 +75,20 @@ export = { const cloudTrailPrincipal = new iam.ServicePrincipal("cloudtrail.amazonaws.com"); Trailbucket.addToResourcePolicy(new iam.PolicyStatement({ resources: [Trailbucket.bucketArn], - actions: ['s3:GetBucketAcl'], - principals: [cloudTrailPrincipal], - })); + actions: ['s3:GetBucketAcl'], + principals: [cloudTrailPrincipal], + })); Trailbucket.addToResourcePolicy(new iam.PolicyStatement({ resources: [Trailbucket.arnForObjects(`AWSLogs/${Stack.of(stack).account}/*`)], actions: ["s3:PutObject"], principals: [cloudTrailPrincipal], - conditions: { - StringEquals: {'s3:x-amz-acl': "bucket-owner-full-control"} + conditions: { + StringEquals: { 's3:x-amz-acl': "bucket-owner-full-control" } } })); - new Trail(stack, 'Trail', {bucket: Trailbucket}); + new Trail(stack, 'Trail', { bucket: Trailbucket }); expect(stack).to(haveResource("AWS::CloudTrail::Trail")); expect(stack).to(haveResource("AWS::S3::Bucket")); @@ -112,6 +112,50 @@ export = { test.done(); }, + 'with s3KeyPrefix'(test: Test) { + // GIVEN + const stack = getTestStack(); + + // WHEN + new Trail(stack, 'Trail', { s3KeyPrefix: 'someprefix' }); + + expect(stack).to(haveResource("AWS::CloudTrail::Trail")); + expect(stack).to(haveResource("AWS::S3::Bucket")); + expect(stack).to(haveResource('AWS::S3::BucketPolicy', { + Bucket: { Ref: 'TrailS30071F172' }, + PolicyDocument: { + Statement: [ + { + Action: 's3:GetBucketAcl', + Effect: 'Allow', + Principal: { Service: 'cloudtrail.amazonaws.com' }, + Resource: { 'Fn::GetAtt': ['TrailS30071F172', 'Arn'] } + }, + { + Action: 's3:PutObject', + Condition: { + StringEquals: { 's3:x-amz-acl': 'bucket-owner-full-control' } + }, + Effect: 'Allow', + Principal: { Service: 'cloudtrail.amazonaws.com' }, + Resource: { + 'Fn::Join': [ + '', + [ + { 'Fn::GetAtt': ['TrailS30071F172', 'Arn'] }, + '/someprefix/AWSLogs/123456789012/*' + ] + ] + } + } + ], + Version: '2012-10-17' + } + })); + + test.done(); + }, + 'with cloud watch logs': { 'enabled'(test: Test) { const stack = getTestStack(); From 2a1daede6eaa335a94aba0a8f20b2ed702af2084 Mon Sep 17 00:00:00 2001 From: Michael Moussa Date: Tue, 31 Mar 2020 11:15:11 -0400 Subject: [PATCH 29/53] Allow `ManagedPolicy` resources to have an initial `PolicyDocument` (#6748) Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> Co-authored-by: Rico Huijbers --- .../@aws-cdk/aws-iam/lib/managed-policy.ts | 13 ++++ .../aws-iam/test/managed-policy.test.ts | 65 ++++++++++++++++++- 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-iam/lib/managed-policy.ts b/packages/@aws-cdk/aws-iam/lib/managed-policy.ts index cd234ee39304c..1076b93095a05 100644 --- a/packages/@aws-cdk/aws-iam/lib/managed-policy.ts +++ b/packages/@aws-cdk/aws-iam/lib/managed-policy.ts @@ -80,6 +80,15 @@ export interface ManagedPolicyProps { * @default - No statements. */ readonly statements?: PolicyStatement[]; + + /** + * Initial PolicyDocument to use for this ManagedPolicy. If omited, any + * `PolicyStatement` provided in the `statements` property will be applied + * against the empty default `PolicyDocument`. + * + * @default - An empty policy. + */ + readonly document?: PolicyDocument; } /** @@ -203,6 +212,10 @@ export class ManagedPolicy extends Resource implements IManagedPolicy { this.description = props.description || ''; this.path = props.path || '/'; + if (props.document) { + this.document = props.document; + } + const resource = new CfnManagedPolicy(this, 'Resource', { policyDocument: this.document, managedPolicyName: this.physicalName, diff --git a/packages/@aws-cdk/aws-iam/test/managed-policy.test.ts b/packages/@aws-cdk/aws-iam/test/managed-policy.test.ts index b9a8ac525ac26..85b14074d1e6f 100644 --- a/packages/@aws-cdk/aws-iam/test/managed-policy.test.ts +++ b/packages/@aws-cdk/aws-iam/test/managed-policy.test.ts @@ -1,6 +1,6 @@ import '@aws-cdk/assert/jest'; import * as cdk from '@aws-cdk/core'; -import { Group, ManagedPolicy, PolicyStatement, Role, ServicePrincipal, User } from '../lib'; +import { Group, ManagedPolicy, PolicyDocument, PolicyStatement, Role, ServicePrincipal, User } from '../lib'; describe('managed policy', () => { let app: cdk.App; @@ -77,6 +77,69 @@ describe('managed policy', () => { }); }); + test('managed policy from policy document alone', () => { + new ManagedPolicy(stack, 'MyManagedPolicy', { + managedPolicyName: 'MyManagedPolicyName', + document: PolicyDocument.fromJson({ + Statement: [{ + Action: "sqs:SendMessage", + Effect: "Allow", + Resource: "*", + }], + }) + }); + + expect(stack).toMatchTemplate({ + Resources: { + MyManagedPolicy9F3720AE: { + Type: 'AWS::IAM::ManagedPolicy', + Properties: { + ManagedPolicyName: 'MyManagedPolicyName', + PolicyDocument: { + Statement: [{ Action: 'sqs:SendMessage', Effect: 'Allow', Resource: '*' }], + Version: '2012-10-17' + }, + Path: '/', + Description: '' + } + } + } + }); + }); + + test('managed policy from policy document with additional statements', () => { + new ManagedPolicy(stack, 'MyManagedPolicy', { + managedPolicyName: 'MyManagedPolicyName', + document: PolicyDocument.fromJson({ + Statement: [{ + Action: "sqs:SendMessage", + Effect: "Allow", + Resource: "*", + }], + }), + statements: [new PolicyStatement({ resources: ['arn'], actions: ['sns:Subscribe'] })] + }); + + expect(stack).toMatchTemplate({ + Resources: { + MyManagedPolicy9F3720AE: { + Type: 'AWS::IAM::ManagedPolicy', + Properties: { + ManagedPolicyName: 'MyManagedPolicyName', + PolicyDocument: { + Statement: + [{ Action: 'sqs:SendMessage', Effect: 'Allow', Resource: '*' }, + { Action: 'sns:Subscribe', Effect: 'Allow', Resource: 'arn' }], + Version: '2012-10-17' + }, + Path: '/', + Description: '' + } + } + } + }); + }); + test('policy name can be omitted, in which case the logical id will be used', () => { const policy = new ManagedPolicy(stack, 'MyManagedPolicy'); policy.addStatements(new PolicyStatement({ resources: ['*'], actions: ['sqs:SendMessage'] })); From cf8c83126cbcc0e6f14ba59a3ee32e8567bc5ac2 Mon Sep 17 00:00:00 2001 From: flemjame-at-amazon <57235867+flemjame-at-amazon@users.noreply.github.com> Date: Tue, 31 Mar 2020 12:04:04 -0400 Subject: [PATCH 30/53] feat(elbv2): health checks for Lambda targets (#7023) * Initial commit without addition of tests * Add tests * Need to add port * Fix test * Add note to README Co-authored-by: Rico Huijbers Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- .../aws-elasticloadbalancingv2/README.md | 8 +++- .../lib/shared/base-target-group.ts | 11 +++++ .../test/alb/test.target-group.ts | 46 +++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md b/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md index b35abffa4d374..761be94dccfbe 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/README.md @@ -174,7 +174,13 @@ const lb = new elbv2.ApplicationLoadBalancer(...); const listener = lb.addListener('Listener', { port: 80 }); listener.addTargets('Targets', { - targets: [new targets.LambdaTarget(lambdaFunction)] + targets: [new targets.LambdaTarget(lambdaFunction)], + + // For Lambda Targets, you need to explicitly enable health checks if you + // want them. + healthCheck: { + enabled: true, + } }); ``` diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts index 5e4e328f5bf53..2e9ff231fff5e 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts @@ -60,6 +60,16 @@ export interface BaseTargetGroupProps { * Properties for configuring a health check */ export interface HealthCheck { + + /** + * Indicates whether health checks are enabled. If the target type is lambda, + * health checks are disabled by default but can be enabled. If the target type + * is instance or ip, health checks are always enabled and cannot be disabled. + * + * @default - Determined automatically. + */ + readonly enabled?: boolean; + /** * The approximate number of seconds between health checks for an individual target. * @@ -231,6 +241,7 @@ export abstract class TargetGroupBase extends cdk.Construct implements ITargetGr vpcId: cdk.Lazy.stringValue({ produce: () => this.vpc && this.targetType !== TargetType.LAMBDA ? this.vpc.vpcId : undefined}), // HEALTH CHECK + healthCheckEnabled: cdk.Lazy.anyValue({ produce: () => this.healthCheck && this.healthCheck.enabled}), healthCheckIntervalSeconds: cdk.Lazy.numberValue({ produce: () => this.healthCheck && this.healthCheck.interval && this.healthCheck.interval.toSeconds() }), diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/test.target-group.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/test.target-group.ts index f4bb9a916c105..e964f672eac80 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/test.target-group.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/test.target-group.ts @@ -1,3 +1,4 @@ +import { expect, haveResource } from '@aws-cdk/assert'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; import { Test } from 'nodeunit'; @@ -50,6 +51,51 @@ export = { tg.addTarget(new elbv2.InstanceTarget('i-1234')); }, /Cannot add a non-self registering target to an imported TargetGroup/); + test.done(); + }, + + 'HealthCheck fields set if provided'(test: Test) { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, "VPC", {}); + const alb = new elbv2.ApplicationLoadBalancer(stack, 'ALB', {vpc}); + const listener = new elbv2.ApplicationListener(stack, "Listener", { + port: 80, + loadBalancer: alb, + open: false + }); + + // WHEN + const ipTarget = new elbv2.IpTarget("10.10.12.12"); + listener.addTargets("TargetGroup", { + targets: [ipTarget], + port: 80, + healthCheck: { + enabled: true, + healthyHttpCodes: "255", + interval: cdk.Duration.seconds(255), + timeout: cdk.Duration.seconds(192), + healthyThresholdCount: 29, + unhealthyThresholdCount: 27, + path: "/arbitrary" + } + }); + + // THEN + expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + HealthCheckEnabled : true, + HealthCheckIntervalSeconds : 255, + HealthCheckPath : "/arbitrary", + HealthCheckTimeoutSeconds : 192, + HealthyThresholdCount : 29, + Matcher : { + HttpCode : "255" + }, + Port: 80, + UnhealthyThresholdCount : 27, + })); + test.done(); } }; From abc2144a5e1ed3e18c1b6d1631f26ab7e29d1760 Mon Sep 17 00:00:00 2001 From: Niranjan Jayakar Date: Tue, 31 Mar 2020 18:15:40 +0100 Subject: [PATCH 31/53] feat(cognito): import an existing user pool client (#7091) Include other clean up around awslint exclusions and CloudFormation resource attributes. BREAKING CHANGE: `UserPoolClient` construct no longer has the property `userPoolClientClientSecret`. The functionality to retrieve the client secret never existed in CloudFormation, so this property was not working in the first place. * **cognito:** The `userPoolClientName` property on the `UserPoolClient` construct will throw an error if client name was not configured on the `UserPoolClient` during initialization. This property was previously incorrectly configured and was returning a not-implemented message from CloudFormation every time. --- packages/@aws-cdk/aws-cognito/README.md | 24 ++++++- .../aws-cognito/lib/user-pool-client.ts | 63 ++++++++++++++----- packages/@aws-cdk/aws-cognito/package.json | 6 +- .../aws-cognito/test/user-pool-client.test.ts | 36 ++++++++++- 4 files changed, 104 insertions(+), 25 deletions(-) diff --git a/packages/@aws-cdk/aws-cognito/README.md b/packages/@aws-cdk/aws-cognito/README.md index 3697b2b29573c..ac6e0510c3dc5 100644 --- a/packages/@aws-cdk/aws-cognito/README.md +++ b/packages/@aws-cdk/aws-cognito/README.md @@ -40,6 +40,7 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aw - [Emails](#emails) - [Lambda Triggers](#lambda-triggers) - [Import](#importing-user-pools) + - [App Clients](#app-clients) ## User Pools @@ -328,4 +329,25 @@ const awesomePool = UserPool.fromUserPoolId(stack, 'awesome-user-pool', 'us-east const otherAwesomePool = UserPool.fromUserPoolArn(stack, 'other-awesome-user-pool', 'arn:aws:cognito-idp:eu-west-1:123456789012:userpool/us-east-1_mtRyYQ14D'); -``` \ No newline at end of file +``` + +### App Clients + +An app is an entity within a user pool that has permission to call unauthenticated APIs (APIs that do not have an +authenticated user), such as APIs to register, sign in, and handle forgotten passwords. To call these APIs, you need an +app client ID and an optional client secret. Read [Configuring a User Pool App +Client](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-client-apps.html) to learn more. + +The following code creates an app client and retrieves the client id - + +```ts +const pool = new UserPool(this, 'Pool'); + +const client = new UserPoolClient(stack, 'Client', { + userPool: pool +}); + +const clientId = client.userPoolClientId; +``` + +Existing app clients can be imported into the CDK app using the `UserPoolClient.fromUserPoolClientId()` API. diff --git a/packages/@aws-cdk/aws-cognito/lib/user-pool-client.ts b/packages/@aws-cdk/aws-cognito/lib/user-pool-client.ts index 3c8ba65605148..c8b11ab7abc19 100644 --- a/packages/@aws-cdk/aws-cognito/lib/user-pool-client.ts +++ b/packages/@aws-cdk/aws-cognito/lib/user-pool-client.ts @@ -1,4 +1,4 @@ -import { Construct, Resource } from '@aws-cdk/core'; +import { Construct, IResource, Resource } from '@aws-cdk/core'; import { CfnUserPoolClient } from './cognito.generated'; import { IUserPool } from './user-pool'; @@ -22,10 +22,13 @@ export enum AuthFlow { USER_PASSWORD = 'USER_PASSWORD_AUTH' } +/** + * Properties for the UserPoolClient construct + */ export interface UserPoolClientProps { /** * Name of the application client - * @default cloudformation generated name + * @default - cloudformation generated name */ readonly userPoolClientName?: string; @@ -42,44 +45,70 @@ export interface UserPoolClientProps { /** * List of enabled authentication flows - * @default no enabled flows + * @default - no enabled flows */ readonly enabledAuthFlows?: AuthFlow[] } /** - * Define a UserPool App Client + * Represents a Cognito user pool client. */ -export class UserPoolClient extends Resource { +export interface IUserPoolClient extends IResource { /** + * Name of the application client * @attribute */ - public readonly userPoolClientId: string; + readonly userPoolClientId: string; +} +/** + * Define a UserPool App Client + */ +export class UserPoolClient extends Resource implements IUserPoolClient { /** - * @attribute + * Import a user pool client given its id. */ - public readonly userPoolClientName: string; + public static fromUserPoolClientId(scope: Construct, id: string, userPoolClientId: string): IUserPoolClient { + class Import extends Resource implements IUserPoolClient { + public readonly userPoolClientId = userPoolClientId; + } - /** - * @attribute + return new Import(scope, id); + } + + public readonly userPoolClientId: string; + private readonly _userPoolClientName?: string; + + /* + * Note to implementers: Two CloudFormation return values Name and ClientSecret are part of the spec. + * However, they have been explicity not implemented here. They are not documented in CloudFormation, and + * CloudFormation returns the following the string when these two attributes are 'GetAtt' - "attribute not supported + * at this time, please use the CLI or Console to retrieve this value". + * Awaiting updates from CloudFormation. */ - public readonly userPoolClientClientSecret: string; constructor(scope: Construct, id: string, props: UserPoolClientProps) { - super(scope, id, { - physicalName: props.userPoolClientName, - }); + super(scope, id); const resource = new CfnUserPoolClient(this, 'Resource', { - clientName: this.physicalName, + clientName: props.userPoolClientName, generateSecret: props.generateSecret, userPoolId: props.userPool.userPoolId, explicitAuthFlows: props.enabledAuthFlows }); this.userPoolClientId = resource.ref; - this.userPoolClientClientSecret = resource.attrClientSecret; - this.userPoolClientName = resource.attrName; + this._userPoolClientName = props.userPoolClientName; + } + + /** + * The client name that was specified via the `userPoolClientName` property during initialization, + * throws an error otherwise. + */ + public get userPoolClientName(): string { + if (this._userPoolClientName === undefined) { + throw new Error('userPoolClientName is available only if specified on the UserPoolClient during initialization'); + } + return this._userPoolClientName; } } diff --git a/packages/@aws-cdk/aws-cognito/package.json b/packages/@aws-cdk/aws-cognito/package.json index 145327eee48c4..e888b0e54dcb7 100644 --- a/packages/@aws-cdk/aws-cognito/package.json +++ b/packages/@aws-cdk/aws-cognito/package.json @@ -90,10 +90,8 @@ }, "awslint": { "exclude": [ - "docs-public-apis:@aws-cdk/aws-cognito.UserPoolClient.userPoolClientClientSecret", - "docs-public-apis:@aws-cdk/aws-cognito.UserPoolClient.userPoolClientId", - "docs-public-apis:@aws-cdk/aws-cognito.UserPoolClient.userPoolClientName", - "docs-public-apis:@aws-cdk/aws-cognito.UserPoolClientProps" + "attribute-tag:@aws-cdk/aws-cognito.UserPoolClient.userPoolClientName", + "resource-attribute:@aws-cdk/aws-cognito.UserPoolClient.userPoolClientClientSecret" ] }, "stability": "experimental", diff --git a/packages/@aws-cdk/aws-cognito/test/user-pool-client.test.ts b/packages/@aws-cdk/aws-cognito/test/user-pool-client.test.ts index 57e0fd9f675b1..278ef92cc45a6 100644 --- a/packages/@aws-cdk/aws-cognito/test/user-pool-client.test.ts +++ b/packages/@aws-cdk/aws-cognito/test/user-pool-client.test.ts @@ -6,7 +6,7 @@ describe('User Pool Client', () => { test('default setup', () => { // GIVEN const stack = new Stack(); - const pool = new UserPool(stack, 'Pool', { }); + const pool = new UserPool(stack, 'Pool'); // WHEN new UserPoolClient(stack, 'Client', { @@ -14,8 +14,38 @@ describe('User Pool Client', () => { }); // THEN - expect(stack).toHaveResourceLike('AWS::Cognito::UserPoolClient', { - UserPoolId: stack.resolve(pool.userPoolId) + expect(stack).toHaveResource('AWS::Cognito::UserPoolClient', { + UserPoolId: stack.resolve(pool.userPoolId), }); }); + + test('client name', () => { + // GIVEN + const stack = new Stack(); + const pool = new UserPool(stack, 'Pool'); + + // WHEN + const client1 = new UserPoolClient(stack, 'Client1', { + userPool: pool, + userPoolClientName: 'myclient' + }); + const client2 = new UserPoolClient(stack, 'Client2', { + userPool: pool, + }); + + // THEN + expect(client1.userPoolClientName).toEqual('myclient'); + expect(() => client2.userPoolClientName).toThrow(/available only if specified on the UserPoolClient during initialization/); + }); + + test('import', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + const client = UserPoolClient.fromUserPoolClientId(stack, 'Client', 'client-id-1'); + + // THEN + expect(client.userPoolClientId).toEqual('client-id-1'); + }); }); \ No newline at end of file From 86b37be17c1a5d7356ea89e3cbcfc47ad61c94cd Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 31 Mar 2020 20:25:49 +0000 Subject: [PATCH 32/53] chore(deps): bump aws-sdk from 2.649.0 to 2.650.0 (#7100) Bumps [aws-sdk](https://github.com/aws/aws-sdk-js) from 2.649.0 to 2.650.0. - [Release notes](https://github.com/aws/aws-sdk-js/releases) - [Changelog](https://github.com/aws/aws-sdk-js/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-js/compare/v2.649.0...v2.650.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- packages/@aws-cdk/aws-cloudfront/package.json | 2 +- packages/@aws-cdk/aws-cloudtrail/package.json | 2 +- packages/@aws-cdk/aws-codebuild/package.json | 2 +- packages/@aws-cdk/aws-codecommit/package.json | 2 +- packages/@aws-cdk/aws-dynamodb/package.json | 2 +- packages/@aws-cdk/aws-eks/package.json | 2 +- packages/@aws-cdk/aws-events-targets/package.json | 2 +- packages/@aws-cdk/aws-lambda/package.json | 2 +- packages/@aws-cdk/aws-route53/package.json | 2 +- packages/@aws-cdk/aws-sqs/package.json | 2 +- packages/@aws-cdk/custom-resources/package.json | 2 +- packages/aws-cdk/package.json | 2 +- packages/cdk-assets/package.json | 2 +- yarn.lock | 8 ++++---- 14 files changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/@aws-cdk/aws-cloudfront/package.json b/packages/@aws-cdk/aws-cloudfront/package.json index bcc2543c2f221..b05fafeca0386 100644 --- a/packages/@aws-cdk/aws-cloudfront/package.json +++ b/packages/@aws-cdk/aws-cloudfront/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.649.0", + "aws-sdk": "^2.650.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudtrail/package.json b/packages/@aws-cdk/aws-cloudtrail/package.json index 0b9b9759b4dba..49471d23ba425 100644 --- a/packages/@aws-cdk/aws-cloudtrail/package.json +++ b/packages/@aws-cdk/aws-cloudtrail/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.649.0", + "aws-sdk": "^2.650.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-codebuild/package.json b/packages/@aws-cdk/aws-codebuild/package.json index 2d82e832c8fe4..21d9dadf3568c 100644 --- a/packages/@aws-cdk/aws-codebuild/package.json +++ b/packages/@aws-cdk/aws-codebuild/package.json @@ -70,7 +70,7 @@ "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.649.0", + "aws-sdk": "^2.650.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-codecommit/package.json b/packages/@aws-cdk/aws-codecommit/package.json index 925f5eef7dbd3..786d9651bd6e1 100644 --- a/packages/@aws-cdk/aws-codecommit/package.json +++ b/packages/@aws-cdk/aws-codecommit/package.json @@ -70,7 +70,7 @@ "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.649.0", + "aws-sdk": "^2.650.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-dynamodb/package.json b/packages/@aws-cdk/aws-dynamodb/package.json index 72e5d4ddbd62c..0defcb6d508e8 100644 --- a/packages/@aws-cdk/aws-dynamodb/package.json +++ b/packages/@aws-cdk/aws-dynamodb/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.649.0", + "aws-sdk": "^2.650.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-eks/package.json b/packages/@aws-cdk/aws-eks/package.json index 04ef99a9ff764..71f984564b2a7 100644 --- a/packages/@aws-cdk/aws-eks/package.json +++ b/packages/@aws-cdk/aws-eks/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.649.0", + "aws-sdk": "^2.650.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-events-targets/package.json b/packages/@aws-cdk/aws-events-targets/package.json index 32b6caaa092f7..a78ee6b6cce4c 100644 --- a/packages/@aws-cdk/aws-events-targets/package.json +++ b/packages/@aws-cdk/aws-events-targets/package.json @@ -86,7 +86,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-codecommit": "0.0.0", - "aws-sdk": "^2.649.0", + "aws-sdk": "^2.650.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-lambda/package.json b/packages/@aws-cdk/aws-lambda/package.json index 4c490765330fc..e4d75c2a3cce2 100644 --- a/packages/@aws-cdk/aws-lambda/package.json +++ b/packages/@aws-cdk/aws-lambda/package.json @@ -71,7 +71,7 @@ "@types/lodash": "^4.14.149", "@types/nodeunit": "^0.0.30", "@types/sinon": "^7.5.2", - "aws-sdk": "^2.649.0", + "aws-sdk": "^2.650.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-route53/package.json b/packages/@aws-cdk/aws-route53/package.json index d92400cb785ba..40a5c45b79b0e 100644 --- a/packages/@aws-cdk/aws-route53/package.json +++ b/packages/@aws-cdk/aws-route53/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.649.0", + "aws-sdk": "^2.650.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-sqs/package.json b/packages/@aws-cdk/aws-sqs/package.json index 4c917cfac09d1..46533f90f6a9f 100644 --- a/packages/@aws-cdk/aws-sqs/package.json +++ b/packages/@aws-cdk/aws-sqs/package.json @@ -65,7 +65,7 @@ "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.649.0", + "aws-sdk": "^2.650.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/custom-resources/package.json b/packages/@aws-cdk/custom-resources/package.json index 8ae76a380e070..d5699151ca050 100644 --- a/packages/@aws-cdk/custom-resources/package.json +++ b/packages/@aws-cdk/custom-resources/package.json @@ -73,7 +73,7 @@ "@types/aws-lambda": "^8.10.39", "@types/fs-extra": "^8.1.0", "@types/sinon": "^7.5.2", - "aws-sdk": "^2.649.0", + "aws-sdk": "^2.650.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index f3cceb7d24163..71a2f50d9b96a 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -69,7 +69,7 @@ "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/region-info": "0.0.0", "archiver": "^3.1.1", - "aws-sdk": "^2.649.0", + "aws-sdk": "^2.650.0", "camelcase": "^5.3.1", "cdk-assets": "0.0.0", "colors": "^1.4.0", diff --git a/packages/cdk-assets/package.json b/packages/cdk-assets/package.json index 204764b7a0f3d..63af355fce9f2 100644 --- a/packages/cdk-assets/package.json +++ b/packages/cdk-assets/package.json @@ -44,7 +44,7 @@ "dependencies": { "@aws-cdk/cdk-assets-schema": "0.0.0", "archiver": "^3.1.1", - "aws-sdk": "^2.649.0", + "aws-sdk": "^2.650.0", "glob": "^7.1.6", "yargs": "^15.3.1" }, diff --git a/yarn.lock b/yarn.lock index 7338b2baf902b..abbb98683979e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2619,10 +2619,10 @@ aws-sdk-mock@^5.1.0: sinon "^9.0.1" traverse "^0.6.6" -aws-sdk@^2.637.0, aws-sdk@^2.649.0: - version "2.649.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.649.0.tgz#a600584171a53a4dcf09d768e514b7bdc408abab" - integrity sha512-0o3l+bfz++KOYHG0gdWofSX/1EdyaD1ixEvWXt71mBbDM1vWc71xfXGzPRtt8Cu8/Id47v7DE3ayELZytzLCXQ== +aws-sdk@^2.637.0, aws-sdk@^2.650.0: + version "2.650.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.650.0.tgz#edf995cf2805c918d7470a652f1316ae902c5aa4" + integrity sha512-MlTKXeRSe4IXXqnulAiXZccpTgDafs3ofYIQv/7ApR+oQUFsq96RHwe8MdW9N1cXn7fz302jLXUAykj4boR3DA== dependencies: buffer "4.9.1" events "1.1.1" From b70dbd4620eff8419afc3dee06c5a74455fd0f33 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2020 00:45:55 +0000 Subject: [PATCH 33/53] chore(deps-dev): bump @types/sinon from 7.5.2 to 9.0.0 (#7106) Bumps [@types/sinon](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/sinon) from 7.5.2 to 9.0.0. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/sinon) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- packages/@aws-cdk/assets/package.json | 2 +- packages/@aws-cdk/aws-lambda/package.json | 2 +- packages/@aws-cdk/aws-s3-assets/package.json | 2 +- packages/@aws-cdk/custom-resources/package.json | 2 +- packages/aws-cdk/package.json | 2 +- yarn.lock | 15 +++++++++++---- 6 files changed, 16 insertions(+), 9 deletions(-) diff --git a/packages/@aws-cdk/assets/package.json b/packages/@aws-cdk/assets/package.json index 8f33b03181def..4ca2f0ef605ff 100644 --- a/packages/@aws-cdk/assets/package.json +++ b/packages/@aws-cdk/assets/package.json @@ -66,7 +66,7 @@ "@aws-cdk/assert": "0.0.0", "@types/minimatch": "^3.0.3", "@types/nodeunit": "^0.0.30", - "@types/sinon": "^7.5.2", + "@types/sinon": "^9.0.0", "aws-cdk": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-lambda/package.json b/packages/@aws-cdk/aws-lambda/package.json index e4d75c2a3cce2..ebb9c43646a7a 100644 --- a/packages/@aws-cdk/aws-lambda/package.json +++ b/packages/@aws-cdk/aws-lambda/package.json @@ -70,7 +70,7 @@ "@types/aws-lambda": "^8.10.39", "@types/lodash": "^4.14.149", "@types/nodeunit": "^0.0.30", - "@types/sinon": "^7.5.2", + "@types/sinon": "^9.0.0", "aws-sdk": "^2.650.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-s3-assets/package.json b/packages/@aws-cdk/aws-s3-assets/package.json index 403195f083baa..9cbdeb80ad144 100644 --- a/packages/@aws-cdk/aws-s3-assets/package.json +++ b/packages/@aws-cdk/aws-s3-assets/package.json @@ -61,7 +61,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.30", - "@types/sinon": "^7.5.2", + "@types/sinon": "^9.0.0", "aws-cdk": "0.0.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/custom-resources/package.json b/packages/@aws-cdk/custom-resources/package.json index d5699151ca050..b4d1a33ebb874 100644 --- a/packages/@aws-cdk/custom-resources/package.json +++ b/packages/@aws-cdk/custom-resources/package.json @@ -72,7 +72,7 @@ "@aws-cdk/aws-ssm": "0.0.0", "@types/aws-lambda": "^8.10.39", "@types/fs-extra": "^8.1.0", - "@types/sinon": "^7.5.2", + "@types/sinon": "^9.0.0", "aws-sdk": "^2.650.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index 71a2f50d9b96a..3befb12e786fe 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -50,7 +50,7 @@ "@types/node": "^10.17.18", "@types/promptly": "^3.0.0", "@types/semver": "^7.1.0", - "@types/sinon": "^7.5.2", + "@types/sinon": "^9.0.0", "@types/table": "^4.0.7", "@types/uuid": "^7.0.2", "@types/yaml": "^1.2.0", diff --git a/yarn.lock b/yarn.lock index abbb98683979e..7da2a6688b660 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2080,10 +2080,17 @@ dependencies: "@types/node" "*" -"@types/sinon@^7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-7.5.2.tgz#5e2f1d120f07b9cda07e5dedd4f3bf8888fccdb9" - integrity sha512-T+m89VdXj/eidZyejvmoP9jivXgBDdkOSBVQjU9kF349NEx10QdPNGxHeZUaj1IlJ32/ewdyXJjnJxyxJroYwg== +"@types/sinon@^9.0.0": + version "9.0.0" + resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-9.0.0.tgz#5b70a360f55645dd64f205defd2a31b749a59799" + integrity sha512-v2TkYHkts4VXshMkcmot/H+ERZ2SevKa10saGaJPGCJ8vh3lKrC4u663zYEeRZxep+VbG6YRDtQ6gVqw9dYzPA== + dependencies: + "@types/sinonjs__fake-timers" "*" + +"@types/sinonjs__fake-timers@*": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.1.tgz#681df970358c82836b42f989188d133e218c458e" + integrity sha512-yYezQwGWty8ziyYLdZjwxyMb0CZR49h8JALHGrxjQHWlqGgc8kLdHEgWrgL0uZ29DMvEVBDnHU2Wg36zKSIUtA== "@types/stack-utils@^1.0.1": version "1.0.1" From 877093415588927d175262454b646a4d21f925c7 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2020 01:38:25 +0000 Subject: [PATCH 34/53] chore(deps): bump uuid from 7.0.2 to 7.0.3 (#7101) Bumps [uuid](https://github.com/uuidjs/uuid) from 7.0.2 to 7.0.3. - [Release notes](https://github.com/uuidjs/uuid/releases) - [Changelog](https://github.com/uuidjs/uuid/blob/master/CHANGELOG.md) - [Commits](https://github.com/uuidjs/uuid/compare/v7.0.2...v7.0.3) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- packages/aws-cdk/package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index 3befb12e786fe..65ce2cd610eda 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -83,7 +83,7 @@ "semver": "^7.1.3", "source-map-support": "^0.5.16", "table": "^5.4.6", - "uuid": "^7.0.2", + "uuid": "^7.0.3", "yaml": "^1.8.3", "yargs": "^15.3.1" }, diff --git a/yarn.lock b/yarn.lock index 7da2a6688b660..7f93f671851c2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11690,10 +11690,10 @@ uuid@^3.0.1, uuid@^3.3.2, uuid@^3.3.3: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== -uuid@^7.0.2: - version "7.0.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.2.tgz#7ff5c203467e91f5e0d85cfcbaaf7d2ebbca9be6" - integrity sha512-vy9V/+pKG+5ZTYKf+VcphF5Oc6EFiu3W8Nv3P3zIh0EqVI80ZxOzuPfe9EHjkFNvf8+xuTHVeei4Drydlx4zjw== +uuid@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b" + integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg== v8-compile-cache@^2.0.0, v8-compile-cache@^2.0.3: version "2.1.0" From 4994e0de8f4681eb49a174b903236d15d32372ba Mon Sep 17 00:00:00 2001 From: Lapderk Date: Wed, 1 Apr 2020 10:43:05 +0200 Subject: [PATCH 35/53] feat(lambda): ruby 2.7 runtime (#7024) closes #6979 --- packages/@aws-cdk/aws-lambda/lib/runtime.ts | 129 ++++++++++++++++---- packages/@aws-cdk/aws-lambda/package.json | 18 --- 2 files changed, 106 insertions(+), 41 deletions(-) diff --git a/packages/@aws-cdk/aws-lambda/lib/runtime.ts b/packages/@aws-cdk/aws-lambda/lib/runtime.ts index 61a1475ee3c89..bb175074aca0d 100644 --- a/packages/@aws-cdk/aws-lambda/lib/runtime.ts +++ b/packages/@aws-cdk/aws-lambda/lib/runtime.ts @@ -26,29 +26,112 @@ export class Runtime { /** A list of all known `Runtime`'s. */ public static readonly ALL = new Array(); - /** @deprecated Use {@link NODEJS_10_X} */ - public static readonly NODEJS = new Runtime('nodejs', RuntimeFamily.NODEJS, { supportsInlineCode: true }); - /** @deprecated Use {@link NODEJS_10_X} */ - public static readonly NODEJS_4_3 = new Runtime('nodejs4.3', RuntimeFamily.NODEJS, { supportsInlineCode: true }); - /** @deprecated Use {@link NODEJS_10_X} */ - public static readonly NODEJS_6_10 = new Runtime('nodejs6.10', RuntimeFamily.NODEJS, { supportsInlineCode: true }); - /** @deprecated Use {@link NODEJS_10_X} */ - public static readonly NODEJS_8_10 = new Runtime('nodejs8.10', RuntimeFamily.NODEJS, { supportsInlineCode: true }); - public static readonly NODEJS_10_X = new Runtime('nodejs10.x', RuntimeFamily.NODEJS, { supportsInlineCode: true }); - public static readonly NODEJS_12_X = new Runtime('nodejs12.x', RuntimeFamily.NODEJS, { supportsInlineCode: true }); - public static readonly PYTHON_2_7 = new Runtime('python2.7', RuntimeFamily.PYTHON, { supportsInlineCode: true }); - public static readonly PYTHON_3_6 = new Runtime('python3.6', RuntimeFamily.PYTHON, { supportsInlineCode: true }); - public static readonly PYTHON_3_7 = new Runtime('python3.7', RuntimeFamily.PYTHON, { supportsInlineCode: true }); - public static readonly PYTHON_3_8 = new Runtime('python3.8', RuntimeFamily.PYTHON); - public static readonly JAVA_8 = new Runtime('java8', RuntimeFamily.JAVA); - public static readonly JAVA_11 = new Runtime('java11', RuntimeFamily.JAVA); - public static readonly DOTNET_CORE_1 = new Runtime('dotnetcore1.0', RuntimeFamily.DOTNET_CORE); - /** @deprecated Use {@link DotNetCore21} */ - public static readonly DOTNET_CORE_2 = new Runtime('dotnetcore2.0', RuntimeFamily.DOTNET_CORE); - public static readonly DOTNET_CORE_2_1 = new Runtime('dotnetcore2.1', RuntimeFamily.DOTNET_CORE); - public static readonly GO_1_X = new Runtime('go1.x', RuntimeFamily.GO); - public static readonly RUBY_2_5 = new Runtime('ruby2.5', RuntimeFamily.RUBY); - public static readonly PROVIDED = new Runtime('provided', RuntimeFamily.OTHER); + /** + * The NodeJS runtime (nodejs) + * + * @deprecated Use {@link NODEJS_10_X} + */ + public static readonly NODEJS = new Runtime('nodejs', RuntimeFamily.NODEJS, { supportsInlineCode: true }); + + /** + * The NodeJS 4.3 runtime (nodejs4.3) + * + * @deprecated Use {@link NODEJS_10_X} + */ + public static readonly NODEJS_4_3 = new Runtime('nodejs4.3', RuntimeFamily.NODEJS, { supportsInlineCode: true }); + + /** + * The NodeJS 6.10 runtime (nodejs6.10) + * + * @deprecated Use {@link NODEJS_10_X} + */ + public static readonly NODEJS_6_10 = new Runtime('nodejs6.10', RuntimeFamily.NODEJS, { supportsInlineCode: true }); + + /** + * The NodeJS 8.10 runtime (nodejs8.10) + * + * @deprecated Use {@link NODEJS_10_X} + */ + public static readonly NODEJS_8_10 = new Runtime('nodejs8.10', RuntimeFamily.NODEJS, { supportsInlineCode: true }); + + /** + * The NodeJS 10.x runtime (nodejs10.x) + */ + public static readonly NODEJS_10_X = new Runtime('nodejs10.x', RuntimeFamily.NODEJS, { supportsInlineCode: true }); + + /** + * The NodeJS 12.x runtime (nodejs12.x) + */ + public static readonly NODEJS_12_X = new Runtime('nodejs12.x', RuntimeFamily.NODEJS, { supportsInlineCode: true }); + + /** + * The Python 2.7 runtime (python2.7) + */ + public static readonly PYTHON_2_7 = new Runtime('python2.7', RuntimeFamily.PYTHON, { supportsInlineCode: true }); + + /** + * The Python 3.6 runtime (python3.6) + */ + public static readonly PYTHON_3_6 = new Runtime('python3.6', RuntimeFamily.PYTHON, { supportsInlineCode: true }); + + /** + * The Python 3.7 runtime (python3.7) + */ + public static readonly PYTHON_3_7 = new Runtime('python3.7', RuntimeFamily.PYTHON, { supportsInlineCode: true }); + + /** + * The Python 3.8 runtime (python3.8) + */ + public static readonly PYTHON_3_8 = new Runtime('python3.8', RuntimeFamily.PYTHON); + + /** + * The Java 8 runtime (java8) + */ + public static readonly JAVA_8 = new Runtime('java8', RuntimeFamily.JAVA); + + /** + * The Java 11 runtime (java11) + */ + public static readonly JAVA_11 = new Runtime('java11', RuntimeFamily.JAVA); + + /** + * The .NET Core 1.0 runtime (dotnetcore1.0) + * + * @deprecated Use {@link DOTNET_CORE_2_1} + */ + public static readonly DOTNET_CORE_1 = new Runtime('dotnetcore1.0', RuntimeFamily.DOTNET_CORE); + + /** + * The .NET Core 2.0 runtime (dotnetcore2.0) + * + * @deprecated Use {@link DOTNET_CORE_2_1} + */ + public static readonly DOTNET_CORE_2 = new Runtime('dotnetcore2.0', RuntimeFamily.DOTNET_CORE); + + /** + * The .NET Core 2.1 runtime (dotnetcore2.1) + */ + public static readonly DOTNET_CORE_2_1 = new Runtime('dotnetcore2.1', RuntimeFamily.DOTNET_CORE); + + /** + * The Go 1.x runtime (go1.x) + */ + public static readonly GO_1_X = new Runtime('go1.x', RuntimeFamily.GO); + + /** + * The Ruby 2.5 runtime (ruby2.5) + */ + public static readonly RUBY_2_5 = new Runtime('ruby2.5', RuntimeFamily.RUBY); + + /** + * The Ruby 2.7 runtime (ruby2.7) + */ + public static readonly RUBY_2_7 = new Runtime('ruby2.7', RuntimeFamily.RUBY); + + /** + * The custom provided runtime (provided) + */ + public static readonly PROVIDED = new Runtime('provided', RuntimeFamily.OTHER); /** * The name of this runtime, as expected by the Lambda resource. diff --git a/packages/@aws-cdk/aws-lambda/package.json b/packages/@aws-cdk/aws-lambda/package.json index ebb9c43646a7a..dd14974012e44 100644 --- a/packages/@aws-cdk/aws-lambda/package.json +++ b/packages/@aws-cdk/aws-lambda/package.json @@ -138,24 +138,6 @@ "docs-public-apis:@aws-cdk/aws-lambda.FunctionBase", "docs-public-apis:@aws-cdk/aws-lambda.QualifiedFunctionBase", "docs-public-apis:@aws-cdk/aws-lambda.QualifiedFunctionBase.lambda", - "docs-public-apis:@aws-cdk/aws-lambda.Runtime.DOTNET_CORE_1", - "docs-public-apis:@aws-cdk/aws-lambda.Runtime.DOTNET_CORE_2", - "docs-public-apis:@aws-cdk/aws-lambda.Runtime.DOTNET_CORE_2_1", - "docs-public-apis:@aws-cdk/aws-lambda.Runtime.GO_1_X", - "docs-public-apis:@aws-cdk/aws-lambda.Runtime.JAVA_8", - "docs-public-apis:@aws-cdk/aws-lambda.Runtime.JAVA_11", - "docs-public-apis:@aws-cdk/aws-lambda.Runtime.NODEJS", - "docs-public-apis:@aws-cdk/aws-lambda.Runtime.NODEJS_10_X", - "docs-public-apis:@aws-cdk/aws-lambda.Runtime.NODEJS_12_X", - "docs-public-apis:@aws-cdk/aws-lambda.Runtime.NODEJS_4_3", - "docs-public-apis:@aws-cdk/aws-lambda.Runtime.NODEJS_6_10", - "docs-public-apis:@aws-cdk/aws-lambda.Runtime.NODEJS_8_10", - "docs-public-apis:@aws-cdk/aws-lambda.Runtime.PROVIDED", - "docs-public-apis:@aws-cdk/aws-lambda.Runtime.PYTHON_2_7", - "docs-public-apis:@aws-cdk/aws-lambda.Runtime.PYTHON_3_6", - "docs-public-apis:@aws-cdk/aws-lambda.Runtime.PYTHON_3_7", - "docs-public-apis:@aws-cdk/aws-lambda.Runtime.PYTHON_3_8", - "docs-public-apis:@aws-cdk/aws-lambda.Runtime.RUBY_2_5", "docs-public-apis:@aws-cdk/aws-lambda.RuntimeFamily", "docs-public-apis:@aws-cdk/aws-lambda.Runtime.toString", "docs-public-apis:@aws-cdk/aws-lambda.Version.fromVersionAttributes", From fbc1df3c6d34a10cda226d0dd7be5f16bebf0084 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2020 09:47:13 +0000 Subject: [PATCH 36/53] chore(deps): bump jsonschema from 1.2.5 to 1.2.6 (#7109) Bumps [jsonschema](https://github.com/tdegrunt/jsonschema) from 1.2.5 to 1.2.6. - [Release notes](https://github.com/tdegrunt/jsonschema/releases) - [Commits](https://github.com/tdegrunt/jsonschema/compare/v1.2.5...v1.2.6) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- packages/decdk/package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/decdk/package.json b/packages/decdk/package.json index dcae5b4cda00f..d717d4b3776cc 100644 --- a/packages/decdk/package.json +++ b/packages/decdk/package.json @@ -172,7 +172,7 @@ "constructs": "^2.0.0", "fs-extra": "^8.1.0", "jsii-reflect": "^1.1.0", - "jsonschema": "^1.2.5", + "jsonschema": "^1.2.6", "yaml": "1.8.3", "yargs": "^15.3.1" }, diff --git a/yarn.lock b/yarn.lock index 7f93f671851c2..ec01a35402adc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7202,10 +7202,10 @@ jsonparse@^1.2.0: resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= -jsonschema@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.2.5.tgz#bab69d97fa28946aec0a56a9cc266d23fe80ae61" - integrity sha512-kVTF+08x25PQ0CjuVc0gRM9EUPb0Fe9Ln/utFOgcdxEIOHuU7ooBk/UPTd7t1M91pP35m0MU1T8M5P7vP1bRRw== +jsonschema@^1.2.5, jsonschema@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.2.6.tgz#52b0a8e9dc06bbae7295249d03e4b9faee8a0c0b" + integrity sha512-SqhURKZG07JyKKeo/ir24QnS4/BV7a6gQy93bUSe4lUdNp0QNpIz2c9elWJQ9dpc5cQYY6cvCzgRwy0MQCLyqA== jsprim@^1.2.2: version "1.4.1" From 573464d0b214f943fa31fdfa5af0091adc593de6 Mon Sep 17 00:00:00 2001 From: Pankaj Yadav Date: Wed, 1 Apr 2020 19:53:01 +0530 Subject: [PATCH 37/53] feat(apigateway): auto-create RequestValidator from options to addMethod() (#6780) closes #6193 --- packages/@aws-cdk/aws-apigateway/README.md | 16 ++-- .../@aws-cdk/aws-apigateway/lib/method.ts | 27 ++++++- .../aws-apigateway/test/test.method.ts | 78 +++++++++++++++++++ 3 files changed, 112 insertions(+), 9 deletions(-) diff --git a/packages/@aws-cdk/aws-apigateway/README.md b/packages/@aws-cdk/aws-apigateway/README.md index 34d414c0f9f36..05f44abc54862 100644 --- a/packages/@aws-cdk/aws-apigateway/README.md +++ b/packages/@aws-cdk/aws-apigateway/README.md @@ -297,18 +297,17 @@ const errorResponseModel = api.addModel('ErrorResponseModel', { And reference all on your method definition. ```ts -// If you want to define parameter mappings for the request, you need a validator -const validator = api.addRequestValidator('DefaultValidator', { - validateRequestBody: false, - validateRequestParameters: true -}); resource.addMethod('GET', integration, { // We can mark the parameters as required requestParameters: { 'method.request.querystring.who': true }, - // We need to set the validator for ensuring they are passed - requestValidator: validator, + // we can set request validator options like below + requestValidatorOptions: { + requestValidatorName: 'test-validator', + validateRequestBody: true, + validateRequestParameters: false + } methodResponses: [ { // Successful response from the integration @@ -340,6 +339,9 @@ resource.addMethod('GET', integration, { }); ``` +Specifying `requestValidatorOptions` automatically creates the RequestValidator construct with the given options. +However, if you have your RequestValidator already initialized or imported, use the `requestValidator` option instead. + #### Default Integration and Method Options The `defaultIntegration` and `defaultMethodOptions` properties can be used to diff --git a/packages/@aws-cdk/aws-apigateway/lib/method.ts b/packages/@aws-cdk/aws-apigateway/lib/method.ts index 9b43cec12d593..8120823d410fb 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/method.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/method.ts @@ -5,7 +5,7 @@ import { ConnectionType, Integration } from './integration'; import { MockIntegration } from './integrations/mock'; import { MethodResponse } from './methodresponse'; import { IModel } from './model'; -import { IRequestValidator } from './requestvalidator'; +import { IRequestValidator, RequestValidatorOptions } from './requestvalidator'; import { IResource } from './resource'; import { RestApi } from './restapi'; import { validateHttpMethod } from './util'; @@ -73,6 +73,8 @@ export interface MethodOptions { /** * The ID of the associated request validator. + * Only one of `requestValidator` or `requestValidatorOptions` must be specified. + * @default - No default validator */ readonly requestValidator?: IRequestValidator; @@ -83,6 +85,13 @@ export interface MethodOptions { * @default - no authorization scopes */ readonly authorizationScopes?: string[] + + /** + * Request validator options to create new validator + * Only one of `requestValidator` or `requestValidatorOptions` must be specified. + * @default - No default validator + */ + readonly requestValidatorOptions?: RequestValidatorOptions; } export interface MethodProps { @@ -160,7 +169,7 @@ export class Method extends Resource { integration: this.renderIntegration(props.integration), methodResponses: this.renderMethodResponses(options.methodResponses), requestModels: this.renderRequestModels(options.requestModels), - requestValidatorId: options.requestValidator ? options.requestValidator.requestValidatorId : undefined, + requestValidatorId: this.requestValidatorId(options), authorizationScopes: options.authorizationScopes ?? defaultMethodOptions.authorizationScopes, }; @@ -302,6 +311,20 @@ export class Method extends Resource { return models; } + + private requestValidatorId(options: MethodOptions): string | undefined { + if (options.requestValidator && options.requestValidatorOptions) { + throw new Error(`Only one of 'requestValidator' or 'requestValidatorOptions' must be specified.`); + } + + if (options.requestValidatorOptions) { + const validator = this.restApi.addRequestValidator('validator', options.requestValidatorOptions); + return validator.requestValidatorId; + } + + // For backward compatibility + return options.requestValidator?.requestValidatorId; + } } export enum AuthorizationType { diff --git a/packages/@aws-cdk/aws-apigateway/test/test.method.ts b/packages/@aws-cdk/aws-apigateway/test/test.method.ts index f4c5052e1ec40..7c898c11b606b 100644 --- a/packages/@aws-cdk/aws-apigateway/test/test.method.ts +++ b/packages/@aws-cdk/aws-apigateway/test/test.method.ts @@ -802,6 +802,84 @@ export = { AuthorizationScopes: ABSENT })); + test.done(); + }, + + 'method has a request validator with provided properties'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const api = new apigw.RestApi(stack, 'test-api', { deploy: false }); + + // WHEN + new apigw.Method(stack, 'method-man', { + httpMethod: 'GET', + resource: api.root, + options: { + requestValidatorOptions: { + requestValidatorName: 'test-validator', + validateRequestBody: true, + validateRequestParameters: false + } + } + }); + + // THEN + expect(stack).to(haveResource('AWS::ApiGateway::RequestValidator', { + RestApiId: stack.resolve(api.restApiId), + ValidateRequestBody: true, + ValidateRequestParameters: false, + Name: 'test-validator' + })); + + test.done(); + }, + + 'method does not have a request validator'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const api = new apigw.RestApi(stack, 'test-api', { deploy: false }); + + // WHEN + new apigw.Method(stack, 'method-man', { + httpMethod: 'GET', + resource: api.root + }); + + // THEN + expect(stack).to(haveResource('AWS::ApiGateway::Method', { + RequestValidatorId: ABSENT + })); + + test.done(); + }, + + 'method does not support both request validator and request validator options'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const api = new apigw.RestApi(stack, 'test-api', { deploy: false }); + const validator = api.addRequestValidator('test-validator1', { + validateRequestBody: true, + validateRequestParameters: false + }); + + // WHEN + const methodProps = { + httpMethod: 'GET', + resource: api.root, + options: { + requestValidatorOptions: { + requestValidatorName: 'test-validator2', + validateRequestBody: true, + validateRequestParameters: false + }, + requestValidator: validator + } + }; + + // THEN + test.throws(() => new apigw.Method(stack, 'method', methodProps), + /Only one of 'requestValidator' or 'requestValidatorOptions' must be specified./); + test.done(); } }; From a6bd34fe6ef0831fdca89063348a6965848c7555 Mon Sep 17 00:00:00 2001 From: Romain Marcadier-Muller Date: Wed, 1 Apr 2020 19:51:50 +0200 Subject: [PATCH 38/53] fix(dynamodb): cannot use attribute as key in a GSI, non-key in another (#7075) Removes the restriction that a key attribute cannot be used as a non-key attribute in a distinct secondary index. This was excessively restricting what can be done, as new integration tests demonstrated that there is no problem in deploying such a configuration. Also, switches from `Array`s to `Set`s to represent the sets of names that must be unique. Fixes #4398 --- packages/@aws-cdk/aws-dynamodb/lib/table.ts | 27 +- packages/@aws-cdk/aws-dynamodb/package.json | 10 +- .../aws-dynamodb/test/dynamodb.test.ts | 1758 ++++++++++++++++ ...integ.dynamodb.mixed-key-gsi.expected.json | 83 + .../test/integ.dynamodb.mixed-key-gsi.ts | 32 + .../test/replica-provider.test.ts | 166 ++ .../aws-dynamodb/test/test.dynamodb.ts | 1839 ----------------- .../test/test.replica-provider.ts | 183 -- 8 files changed, 2054 insertions(+), 2044 deletions(-) create mode 100644 packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts create mode 100644 packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.mixed-key-gsi.expected.json create mode 100644 packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.mixed-key-gsi.ts create mode 100644 packages/@aws-cdk/aws-dynamodb/test/replica-provider.test.ts delete mode 100644 packages/@aws-cdk/aws-dynamodb/test/test.dynamodb.ts delete mode 100644 packages/@aws-cdk/aws-dynamodb/test/test.replica-provider.ts diff --git a/packages/@aws-cdk/aws-dynamodb/lib/table.ts b/packages/@aws-cdk/aws-dynamodb/lib/table.ts index 722faed5f3eb9..4cbbc7dfba1e3 100644 --- a/packages/@aws-cdk/aws-dynamodb/lib/table.ts +++ b/packages/@aws-cdk/aws-dynamodb/lib/table.ts @@ -632,8 +632,8 @@ export class Table extends TableBase { private readonly globalSecondaryIndexes = new Array(); private readonly localSecondaryIndexes = new Array(); - private readonly secondaryIndexNames: string[] = []; - private readonly nonKeyAttributes: string[] = []; + private readonly secondaryIndexNames = new Set(); + private readonly nonKeyAttributes = new Set(); private readonly tablePartitionKey: Attribute; private readonly tableSortKey?: Attribute; @@ -723,7 +723,7 @@ export class Table extends TableBase { const gsiKeySchema = this.buildIndexKeySchema(props.partitionKey, props.sortKey); const gsiProjection = this.buildIndexProjection(props); - this.secondaryIndexNames.push(props.indexName); + this.secondaryIndexNames.add(props.indexName); this.globalSecondaryIndexes.push({ indexName: props.indexName, keySchema: gsiKeySchema, @@ -754,7 +754,7 @@ export class Table extends TableBase { const lsiKeySchema = this.buildIndexKeySchema(this.tablePartitionKey, props.sortKey); const lsiProjection = this.buildIndexProjection(props); - this.secondaryIndexNames.push(props.indexName); + this.secondaryIndexNames.add(props.indexName); this.localSecondaryIndexes.push({ indexName: props.indexName, keySchema: lsiKeySchema, @@ -895,11 +895,11 @@ export class Table extends TableBase { * @param indexName a name of global or local secondary index */ private validateIndexName(indexName: string) { - if (this.secondaryIndexNames.includes(indexName)) { + if (this.secondaryIndexNames.has(indexName)) { // a duplicate index name causes validation exception, status code 400, while trying to create CFN stack throw new Error(`a duplicate index name, ${indexName}, is not allowed`); } - this.secondaryIndexNames.push(indexName); + this.secondaryIndexNames.add(indexName); } /** @@ -908,21 +908,13 @@ export class Table extends TableBase { * @param nonKeyAttributes a list of non-key attribute names */ private validateNonKeyAttributes(nonKeyAttributes: string[]) { - if (this.nonKeyAttributes.length + nonKeyAttributes.length > 20) { + if (this.nonKeyAttributes.size + nonKeyAttributes.length > 20) { // https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Limits.html#limits-secondary-indexes throw new RangeError('a maximum number of nonKeyAttributes across all of secondary indexes is 20'); } // store all non-key attributes - this.nonKeyAttributes.push(...nonKeyAttributes); - - // throw error if key attribute is part of non-key attributes - this.attributeDefinitions.forEach(keyAttribute => { - if (typeof keyAttribute.attributeName === 'string' && this.nonKeyAttributes.includes(keyAttribute.attributeName)) { - throw new Error(`a key attribute, ${keyAttribute.attributeName}, is part of a list of non-key attributes, ${this.nonKeyAttributes}` + - ', which is not allowed since all key attributes are added automatically and this configuration causes stack creation failure'); - } - }); + nonKeyAttributes.forEach(att => this.nonKeyAttributes.add(att)); } private buildIndexKeySchema(partitionKey: Attribute, sortKey?: Attribute): CfnTable.KeySchemaProperty[] { @@ -983,8 +975,7 @@ export class Table extends TableBase { * @param attribute the key attribute of table or secondary index */ private registerAttribute(attribute: Attribute) { - const name = attribute.name; - const type = attribute.type; + const { name, type } = attribute; const existingDef = this.attributeDefinitions.find(def => def.attributeName === name); if (existingDef && existingDef.attributeType !== type) { throw new Error(`Unable to specify ${name} as ${type} because it was already defined as ${existingDef.attributeType}`); diff --git a/packages/@aws-cdk/aws-dynamodb/package.json b/packages/@aws-cdk/aws-dynamodb/package.json index 0defcb6d508e8..afa22e9fd6fc9 100644 --- a/packages/@aws-cdk/aws-dynamodb/package.json +++ b/packages/@aws-cdk/aws-dynamodb/package.json @@ -63,15 +63,16 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/nodeunit": "^0.0.30", + "@types/jest": "^25.1.4", "aws-sdk": "^2.650.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "nodeunit": "^0.11.3", + "jest": "^25.2.4", "pkglint": "0.0.0", - "sinon": "^9.0.1" + "sinon": "^9.0.1", + "ts-jest": "^25.3.0" }, "dependencies": { "@aws-cdk/aws-applicationautoscaling": "0.0.0", @@ -115,5 +116,6 @@ }, "awscdkio": { "announce": false - } + }, + "jest": {} } diff --git a/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts b/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts new file mode 100644 index 0000000000000..651879f0d0743 --- /dev/null +++ b/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts @@ -0,0 +1,1758 @@ +import { ResourcePart, SynthUtils } from '@aws-cdk/assert'; +import '@aws-cdk/assert/jest'; +import * as appscaling from '@aws-cdk/aws-applicationautoscaling'; +import * as iam from '@aws-cdk/aws-iam'; +import { App, CfnDeletionPolicy, ConstructNode, Duration, RemovalPolicy, Stack, Tag } from '@aws-cdk/core'; +import { + Attribute, + AttributeType, + BillingMode, + GlobalSecondaryIndexProps, + LocalSecondaryIndexProps, + ProjectionType, + StreamViewType, + Table, +} from '../lib'; + +// tslint:disable:object-literal-key-quotes + +// CDK parameters +const CONSTRUCT_NAME = 'MyTable'; + +// DynamoDB table parameters +const TABLE_NAME = 'MyTable'; +const TABLE_PARTITION_KEY: Attribute = { name: 'hashKey', type: AttributeType.STRING }; +const TABLE_SORT_KEY: Attribute = { name: 'sortKey', type: AttributeType.NUMBER }; + +// DynamoDB global secondary index parameters +const GSI_NAME = 'MyGSI'; +const GSI_PARTITION_KEY: Attribute = { name: 'gsiHashKey', type: AttributeType.STRING }; +const GSI_SORT_KEY: Attribute = { name: 'gsiSortKey', type: AttributeType.BINARY }; +const GSI_NON_KEY = 'gsiNonKey'; +function* GSI_GENERATOR(): Generator { + let n = 0; + while (true) { + const globalSecondaryIndexProps: GlobalSecondaryIndexProps = { + indexName: `${GSI_NAME}${n}`, + partitionKey: { name: `${GSI_PARTITION_KEY.name}${n}`, type: GSI_PARTITION_KEY.type } + }; + yield globalSecondaryIndexProps; + n++; + } +} +function* NON_KEY_ATTRIBUTE_GENERATOR(nonKeyPrefix: string): Generator { + let n = 0; + while (true) { + yield `${nonKeyPrefix}${n}`; + n++; + } +} + +// DynamoDB local secondary index parameters +const LSI_NAME = 'MyLSI'; +const LSI_SORT_KEY: Attribute = { name: 'lsiSortKey', type: AttributeType.NUMBER }; +const LSI_NON_KEY = 'lsiNonKey'; +function* LSI_GENERATOR(): Generator { + let n = 0; + while (true) { + const localSecondaryIndexProps: LocalSecondaryIndexProps = { + indexName: `${LSI_NAME}${n}`, + sortKey: { name : `${LSI_SORT_KEY.name}${n}`, type: LSI_SORT_KEY.type } + }; + yield localSecondaryIndexProps; + n++; + } +} + +describe('default properties', () => { + test('hash key only', () => { + const stack = new Stack(); + new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY }); + + expect(stack).toHaveResource('AWS::DynamoDB::Table', { + AttributeDefinitions: [{ AttributeName: 'hashKey', AttributeType: 'S' }], + KeySchema: [{ AttributeName: 'hashKey', KeyType: 'HASH' }], + ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } + }); + + expect(stack).toHaveResource('AWS::DynamoDB::Table', { DeletionPolicy: CfnDeletionPolicy.RETAIN }, ResourcePart.CompleteDefinition); + + }); + + test('removalPolicy is DESTROY', () => { + const stack = new Stack(); + new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY, removalPolicy: RemovalPolicy.DESTROY }); + + expect(stack).toHaveResource('AWS::DynamoDB::Table', { DeletionPolicy: CfnDeletionPolicy.DELETE }, ResourcePart.CompleteDefinition); + + }); + + test('hash + range key', () => { + const stack = new Stack(); + new Table(stack, CONSTRUCT_NAME, { + partitionKey: TABLE_PARTITION_KEY, + sortKey: TABLE_SORT_KEY + }); + + expect(stack).toHaveResource('AWS::DynamoDB::Table', { + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' } + ], + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' } + ], + ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 }, + }); + }); + + test('hash + range key can also be specified in props', () => { + const stack = new Stack(); + + new Table(stack, CONSTRUCT_NAME, { + partitionKey: TABLE_PARTITION_KEY, + sortKey: TABLE_SORT_KEY + }); + + expect(stack).toHaveResource('AWS::DynamoDB::Table', + { + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' } + ], + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' } + ], + ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 }, + }); + }); + + test('point-in-time recovery is not enabled', () => { + const stack = new Stack(); + new Table(stack, CONSTRUCT_NAME, { + partitionKey: TABLE_PARTITION_KEY, + sortKey: TABLE_SORT_KEY + }); + + expect(stack).toHaveResource('AWS::DynamoDB::Table', + { + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' } + ], + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' } + ], + ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } + } + ); + }); + + test('server-side encryption is not enabled', () => { + const stack = new Stack(); + new Table(stack, CONSTRUCT_NAME, { + partitionKey: TABLE_PARTITION_KEY, + sortKey: TABLE_SORT_KEY, + }); + + expect(stack).toHaveResource('AWS::DynamoDB::Table', + { + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' } + ], + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' } + ], + ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } + } + ); + }); + + test('stream is not enabled', () => { + const stack = new Stack(); + new Table(stack, CONSTRUCT_NAME, { + partitionKey: TABLE_PARTITION_KEY, + sortKey: TABLE_SORT_KEY, + }); + + expect(stack).toHaveResource('AWS::DynamoDB::Table', + { + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' } + ], + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' } + ], + ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } + } + ); + }); + + test('ttl is not enabled', () => { + const stack = new Stack(); + new Table(stack, CONSTRUCT_NAME, { + partitionKey: TABLE_PARTITION_KEY, + sortKey: TABLE_SORT_KEY, + }); + + expect(stack).toHaveResource('AWS::DynamoDB::Table', + { + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' } + ], + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' } + ], + ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } + } + ); + }); + + test('can specify new and old images', () => { + const stack = new Stack(); + + new Table(stack, CONSTRUCT_NAME, { + tableName: TABLE_NAME, + readCapacity: 42, + writeCapacity: 1337, + stream: StreamViewType.NEW_AND_OLD_IMAGES, + partitionKey: TABLE_PARTITION_KEY, + sortKey: TABLE_SORT_KEY + }); + + expect(stack).toHaveResource('AWS::DynamoDB::Table', + { + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' } + ], + StreamSpecification: { StreamViewType: 'NEW_AND_OLD_IMAGES' }, + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' } + ], + ProvisionedThroughput: { ReadCapacityUnits: 42, WriteCapacityUnits: 1337 }, + TableName: 'MyTable' + } + ); + }); + + test('can specify new images only', () => { + const stack = new Stack(); + + new Table(stack, CONSTRUCT_NAME, { + tableName: TABLE_NAME, + readCapacity: 42, + writeCapacity: 1337, + stream: StreamViewType.NEW_IMAGE, + partitionKey: TABLE_PARTITION_KEY, + sortKey: TABLE_SORT_KEY + }); + + expect(stack).toHaveResource('AWS::DynamoDB::Table', + { + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' } + ], + ProvisionedThroughput: { ReadCapacityUnits: 42, WriteCapacityUnits: 1337 }, + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' } + ], + StreamSpecification: { StreamViewType: 'NEW_IMAGE' }, + TableName: 'MyTable', + } + ); + }); + + test('can specify old images only', () => { + const stack = new Stack(); + + new Table(stack, CONSTRUCT_NAME, { + tableName: TABLE_NAME, + readCapacity: 42, + writeCapacity: 1337, + stream: StreamViewType.OLD_IMAGE, + partitionKey: TABLE_PARTITION_KEY, + sortKey: TABLE_SORT_KEY + }); + + expect(stack).toHaveResource('AWS::DynamoDB::Table', + { + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' } + ], + ProvisionedThroughput: { ReadCapacityUnits: 42, WriteCapacityUnits: 1337 }, + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' } + ], + StreamSpecification: { StreamViewType: 'OLD_IMAGE' }, + TableName: 'MyTable', + } + ); + }); +}); + +test('when specifying every property', () => { + const stack = new Stack(); + const table = new Table(stack, CONSTRUCT_NAME, { + tableName: TABLE_NAME, + readCapacity: 42, + writeCapacity: 1337, + pointInTimeRecovery: true, + serverSideEncryption: true, + billingMode: BillingMode.PROVISIONED, + stream: StreamViewType.KEYS_ONLY, + timeToLiveAttribute: 'timeToLive', + partitionKey: TABLE_PARTITION_KEY, + sortKey: TABLE_SORT_KEY, + }); + table.node.applyAspect(new Tag('Environment', 'Production')); + + expect(stack).toHaveResource('AWS::DynamoDB::Table', + { + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' } + ], + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' } + ], + ProvisionedThroughput: { + ReadCapacityUnits: 42, + WriteCapacityUnits: 1337 + }, + PointInTimeRecoverySpecification: { PointInTimeRecoveryEnabled: true }, + SSESpecification: { SSEEnabled: true }, + StreamSpecification: { StreamViewType: 'KEYS_ONLY' }, + TableName: 'MyTable', + Tags: [{ Key: 'Environment', Value: 'Production' }], + TimeToLiveSpecification: { AttributeName: 'timeToLive', Enabled: true } + } + ); +}); + +test('when specifying PAY_PER_REQUEST billing mode', () => { + const stack = new Stack(); + new Table(stack, CONSTRUCT_NAME, { + tableName: TABLE_NAME, + billingMode: BillingMode.PAY_PER_REQUEST, + partitionKey: TABLE_PARTITION_KEY + }); + + expect(stack).toHaveResource('AWS::DynamoDB::Table', + { + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + ], + BillingMode: 'PAY_PER_REQUEST', + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + ], + TableName: 'MyTable', + } + ); +}); + +test('error when specifying read or write capacity with a PAY_PER_REQUEST billing mode', () => { + const stack = new Stack(); + expect(() => new Table(stack, 'Table A', { + tableName: TABLE_NAME, + billingMode: BillingMode.PAY_PER_REQUEST, + partitionKey: TABLE_PARTITION_KEY, + readCapacity: 1 + })).toThrow(/PAY_PER_REQUEST/); + expect(() => new Table(stack, 'Table B', { + tableName: TABLE_NAME, + billingMode: BillingMode.PAY_PER_REQUEST, + partitionKey: TABLE_PARTITION_KEY, + writeCapacity: 1 + })).toThrow(/PAY_PER_REQUEST/); + expect(() => new Table(stack, 'Table C', { + tableName: TABLE_NAME, + billingMode: BillingMode.PAY_PER_REQUEST, + partitionKey: TABLE_PARTITION_KEY, + readCapacity: 1, + writeCapacity: 1 + })).toThrow(/PAY_PER_REQUEST/); +}); + +test('when adding a global secondary index with hash key only', () => { + const stack = new Stack(); + + const table = new Table(stack, CONSTRUCT_NAME, { + partitionKey: TABLE_PARTITION_KEY, + sortKey: TABLE_SORT_KEY + }); + + table.addGlobalSecondaryIndex({ + indexName: GSI_NAME, + partitionKey: GSI_PARTITION_KEY, + readCapacity: 42, + writeCapacity: 1337 + }); + + expect(stack).toHaveResource('AWS::DynamoDB::Table', + { + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' }, + { AttributeName: 'gsiHashKey', AttributeType: 'S' }, + ], + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' } + ], + ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 }, + GlobalSecondaryIndexes: [ + { + IndexName: 'MyGSI', + KeySchema: [ + { AttributeName: 'gsiHashKey', KeyType: 'HASH' }, + ], + Projection: { ProjectionType: 'ALL' }, + ProvisionedThroughput: { ReadCapacityUnits: 42, WriteCapacityUnits: 1337 } + } + ] + } + ); +}); + +test('when adding a global secondary index with hash + range key', () => { + const stack = new Stack(); + const table = new Table(stack, CONSTRUCT_NAME, { + partitionKey: TABLE_PARTITION_KEY, + sortKey: TABLE_SORT_KEY + }); + + table.addGlobalSecondaryIndex({ + indexName: GSI_NAME, + partitionKey: GSI_PARTITION_KEY, + sortKey: GSI_SORT_KEY, + projectionType: ProjectionType.ALL, + readCapacity: 42, + writeCapacity: 1337 + }); + + expect(stack).toHaveResource('AWS::DynamoDB::Table', + { + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' }, + { AttributeName: 'gsiHashKey', AttributeType: 'S' }, + { AttributeName: 'gsiSortKey', AttributeType: 'B' } + ], + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' } + ], + ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 }, + GlobalSecondaryIndexes: [ + { + IndexName: 'MyGSI', + KeySchema: [ + { AttributeName: 'gsiHashKey', KeyType: 'HASH' }, + { AttributeName: 'gsiSortKey', KeyType: 'RANGE' } + ], + Projection: { ProjectionType: 'ALL' }, + ProvisionedThroughput: { ReadCapacityUnits: 42, WriteCapacityUnits: 1337 } + } + ] + } + ); +}); + +test('when adding a global secondary index with projection type KEYS_ONLY', () => { + const stack = new Stack(); + const table = new Table(stack, CONSTRUCT_NAME, { + partitionKey: TABLE_PARTITION_KEY, + sortKey: TABLE_SORT_KEY + }); + + table.addGlobalSecondaryIndex({ + indexName: GSI_NAME, + partitionKey: GSI_PARTITION_KEY, + sortKey: GSI_SORT_KEY, + projectionType: ProjectionType.KEYS_ONLY, + }); + + expect(stack).toHaveResource('AWS::DynamoDB::Table', + { + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' }, + { AttributeName: 'gsiHashKey', AttributeType: 'S' }, + { AttributeName: 'gsiSortKey', AttributeType: 'B' } + ], + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' } + ], + ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 }, + GlobalSecondaryIndexes: [ + { + IndexName: 'MyGSI', + KeySchema: [ + { AttributeName: 'gsiHashKey', KeyType: 'HASH' }, + { AttributeName: 'gsiSortKey', KeyType: 'RANGE' } + ], + Projection: { ProjectionType: 'KEYS_ONLY' }, + ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } + } + ] + } + ); +}); + +test('when adding a global secondary index with projection type INCLUDE', () => { + const stack = new Stack(); + const table = new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY, sortKey: TABLE_SORT_KEY }); + const gsiNonKeyAttributeGenerator = NON_KEY_ATTRIBUTE_GENERATOR(GSI_NON_KEY); + table.addGlobalSecondaryIndex({ + indexName: GSI_NAME, + partitionKey: GSI_PARTITION_KEY, + sortKey: GSI_SORT_KEY, + projectionType: ProjectionType.INCLUDE, + nonKeyAttributes: [gsiNonKeyAttributeGenerator.next().value, gsiNonKeyAttributeGenerator.next().value], + readCapacity: 42, + writeCapacity: 1337 + }); + + expect(stack).toHaveResource('AWS::DynamoDB::Table', + { + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' }, + { AttributeName: 'gsiHashKey', AttributeType: 'S' }, + { AttributeName: 'gsiSortKey', AttributeType: 'B' } + ], + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' } + ], + ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 }, + GlobalSecondaryIndexes: [ + { + IndexName: 'MyGSI', + KeySchema: [ + { AttributeName: 'gsiHashKey', KeyType: 'HASH' }, + { AttributeName: 'gsiSortKey', KeyType: 'RANGE' } + ], + Projection: { NonKeyAttributes: ['gsiNonKey0', 'gsiNonKey1'], ProjectionType: 'INCLUDE' }, + ProvisionedThroughput: { ReadCapacityUnits: 42, WriteCapacityUnits: 1337 } + } + ] + } + ); +}); + +test('when adding a global secondary index on a table with PAY_PER_REQUEST billing mode', () => { + const stack = new Stack(); + new Table(stack, CONSTRUCT_NAME, { + billingMode: BillingMode.PAY_PER_REQUEST, + partitionKey: TABLE_PARTITION_KEY, + sortKey: TABLE_SORT_KEY + }).addGlobalSecondaryIndex({ + indexName: GSI_NAME, + partitionKey: GSI_PARTITION_KEY, + }); + + expect(stack).toHaveResource('AWS::DynamoDB::Table', + { + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' }, + { AttributeName: 'gsiHashKey', AttributeType: 'S' }, + ], + BillingMode: 'PAY_PER_REQUEST', + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' } + ], + GlobalSecondaryIndexes: [ + { + IndexName: 'MyGSI', + KeySchema: [ + { AttributeName: 'gsiHashKey', KeyType: 'HASH' }, + ], + Projection: { ProjectionType: 'ALL' } + } + ] + } + ); +}); + +test('error when adding a global secondary index with projection type INCLUDE, but without specifying non-key attributes', () => { + const stack = new Stack(); + const table = new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY, sortKey: TABLE_SORT_KEY }); + expect(() => table.addGlobalSecondaryIndex({ + indexName: GSI_NAME, + partitionKey: GSI_PARTITION_KEY, + sortKey: GSI_SORT_KEY, + projectionType: ProjectionType.INCLUDE + })).toThrow(/non-key attributes should be specified when using INCLUDE projection type/); +}); + +test('error when adding a global secondary index with projection type ALL, but with non-key attributes', () => { + const stack = new Stack(); + const table = new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY, sortKey: TABLE_SORT_KEY }); + const gsiNonKeyAttributeGenerator = NON_KEY_ATTRIBUTE_GENERATOR(GSI_NON_KEY); + + expect(() => table.addGlobalSecondaryIndex({ + indexName: GSI_NAME, + partitionKey: GSI_PARTITION_KEY, + nonKeyAttributes: [gsiNonKeyAttributeGenerator.next().value] + })).toThrow(/non-key attributes should not be specified when not using INCLUDE projection type/); +}); + +test('error when adding a global secondary index with projection type KEYS_ONLY, but with non-key attributes', () => { + const stack = new Stack(); + const table = new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY, sortKey: TABLE_SORT_KEY }); + const gsiNonKeyAttributeGenerator = NON_KEY_ATTRIBUTE_GENERATOR(GSI_NON_KEY); + + expect(() => table.addGlobalSecondaryIndex({ + indexName: GSI_NAME, + partitionKey: GSI_PARTITION_KEY, + projectionType: ProjectionType.KEYS_ONLY, + nonKeyAttributes: [gsiNonKeyAttributeGenerator.next().value] + })).toThrow(/non-key attributes should not be specified when not using INCLUDE projection type/); +}); + +test('error when adding a global secondary index with projection type INCLUDE, but with more than 20 non-key attributes', () => { + const stack = new Stack(); + const table = new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY, sortKey: TABLE_SORT_KEY }); + const gsiNonKeyAttributeGenerator = NON_KEY_ATTRIBUTE_GENERATOR(GSI_NON_KEY); + const gsiNonKeyAttributes: string[] = []; + for (let i = 0; i < 21; i++) { + gsiNonKeyAttributes.push(gsiNonKeyAttributeGenerator.next().value); + } + + expect(() => table.addGlobalSecondaryIndex({ + indexName: GSI_NAME, + partitionKey: GSI_PARTITION_KEY, + sortKey: GSI_SORT_KEY, + projectionType: ProjectionType.INCLUDE, + nonKeyAttributes: gsiNonKeyAttributes + })).toThrow(/a maximum number of nonKeyAttributes across all of secondary indexes is 20/); +}); + +test('error when adding a global secondary index with read or write capacity on a PAY_PER_REQUEST table', () => { + const stack = new Stack(); + const table = new Table(stack, CONSTRUCT_NAME, { + partitionKey: TABLE_PARTITION_KEY, + billingMode: BillingMode.PAY_PER_REQUEST + }); + + expect(() => table.addGlobalSecondaryIndex({ + indexName: GSI_NAME, + partitionKey: GSI_PARTITION_KEY, + sortKey: GSI_SORT_KEY, + readCapacity: 1 + })).toThrow(/PAY_PER_REQUEST/); + expect(() => table.addGlobalSecondaryIndex({ + indexName: GSI_NAME, + partitionKey: GSI_PARTITION_KEY, + sortKey: GSI_SORT_KEY, + writeCapacity: 1 + })).toThrow(/PAY_PER_REQUEST/); + expect(() => table.addGlobalSecondaryIndex({ + indexName: GSI_NAME, + partitionKey: GSI_PARTITION_KEY, + sortKey: GSI_SORT_KEY, + readCapacity: 1, + writeCapacity: 1 + })).toThrow(/PAY_PER_REQUEST/); +}); + +test('when adding multiple global secondary indexes', () => { + const stack = new Stack(); + const table = new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY, sortKey: TABLE_SORT_KEY }); + const gsiGenerator = GSI_GENERATOR(); + for (let i = 0; i < 5; i++) { + table.addGlobalSecondaryIndex(gsiGenerator.next().value); + } + + expect(stack).toHaveResource('AWS::DynamoDB::Table', + { + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' }, + { AttributeName: 'gsiHashKey0', AttributeType: 'S' }, + { AttributeName: 'gsiHashKey1', AttributeType: 'S' }, + { AttributeName: 'gsiHashKey2', AttributeType: 'S' }, + { AttributeName: 'gsiHashKey3', AttributeType: 'S' }, + { AttributeName: 'gsiHashKey4', AttributeType: 'S' } + ], + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' } + ], + ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 }, + GlobalSecondaryIndexes: [ + { + IndexName: 'MyGSI0', + KeySchema: [ + { AttributeName: 'gsiHashKey0', KeyType: 'HASH' }, + ], + Projection: { ProjectionType: 'ALL' }, + ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } + }, + { + IndexName: 'MyGSI1', + KeySchema: [ + { AttributeName: 'gsiHashKey1', KeyType: 'HASH' }, + ], + Projection: { ProjectionType: 'ALL' }, + ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } + }, + { + IndexName: 'MyGSI2', + KeySchema: [ + { AttributeName: 'gsiHashKey2', KeyType: 'HASH' }, + ], + Projection: { ProjectionType: 'ALL' }, + ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } + }, + { + IndexName: 'MyGSI3', + KeySchema: [ + { AttributeName: 'gsiHashKey3', KeyType: 'HASH' }, + ], + Projection: { ProjectionType: 'ALL' }, + ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } + }, + { + IndexName: 'MyGSI4', + KeySchema: [ + { AttributeName: 'gsiHashKey4', KeyType: 'HASH' }, + ], + Projection: { ProjectionType: 'ALL' }, + ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } + }, + ] + } + ); +}); + +test('when adding a global secondary index without specifying read and write capacity', () => { + const stack = new Stack(); + const table = new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY, sortKey: TABLE_SORT_KEY }); + + table.addGlobalSecondaryIndex({ + indexName: GSI_NAME, + partitionKey: GSI_PARTITION_KEY, + }); + + expect(stack).toHaveResource('AWS::DynamoDB::Table', + { + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' }, + { AttributeName: 'gsiHashKey', AttributeType: 'S' } + ], + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' } + ], + ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 }, + GlobalSecondaryIndexes: [ + { + IndexName: 'MyGSI', + KeySchema: [ + { AttributeName: 'gsiHashKey', KeyType: 'HASH' }, + ], + Projection: { ProjectionType: 'ALL' }, + ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } + } + ] + } + ); +}); + +test('when adding a local secondary index with hash + range key', () => { + const stack = new Stack(); + const table = new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY, sortKey: TABLE_SORT_KEY }); + + table.addLocalSecondaryIndex({ + indexName: LSI_NAME, + sortKey: LSI_SORT_KEY, + }); + + expect(stack).toHaveResource('AWS::DynamoDB::Table', + { + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' }, + { AttributeName: 'lsiSortKey', AttributeType: 'N' } + ], + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' } + ], + ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 }, + LocalSecondaryIndexes: [ + { + IndexName: 'MyLSI', + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'lsiSortKey', KeyType: 'RANGE' } + ], + Projection: { ProjectionType: 'ALL' }, + } + ], + } + ); +}); + +test('when adding a local secondary index with projection type KEYS_ONLY', () => { + const stack = new Stack(); + const table = new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY, sortKey: TABLE_SORT_KEY }); + table.addLocalSecondaryIndex({ + indexName: LSI_NAME, + sortKey: LSI_SORT_KEY, + projectionType: ProjectionType.KEYS_ONLY + }); + + expect(stack).toHaveResource('AWS::DynamoDB::Table', + { + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' }, + { AttributeName: 'lsiSortKey', AttributeType: 'N' } + ], + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' } + ], + ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 }, + LocalSecondaryIndexes: [ + { + IndexName: 'MyLSI', + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'lsiSortKey', KeyType: 'RANGE' } + ], + Projection: { ProjectionType: 'KEYS_ONLY' }, + } + ], + } + ); +}); + +test('when adding a local secondary index with projection type INCLUDE', () => { + const stack = new Stack(); + const table = new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY, sortKey: TABLE_SORT_KEY }); + const lsiNonKeyAttributeGenerator = NON_KEY_ATTRIBUTE_GENERATOR(LSI_NON_KEY); + table.addLocalSecondaryIndex({ + indexName: LSI_NAME, + sortKey: LSI_SORT_KEY, + projectionType: ProjectionType.INCLUDE, + nonKeyAttributes: [lsiNonKeyAttributeGenerator.next().value, lsiNonKeyAttributeGenerator.next().value] + }); + + expect(stack).toHaveResource('AWS::DynamoDB::Table', + { + AttributeDefinitions: [ + { AttributeName: 'hashKey', AttributeType: 'S' }, + { AttributeName: 'sortKey', AttributeType: 'N' }, + { AttributeName: 'lsiSortKey', AttributeType: 'N' } + ], + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'sortKey', KeyType: 'RANGE' } + ], + ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 }, + LocalSecondaryIndexes: [ + { + IndexName: 'MyLSI', + KeySchema: [ + { AttributeName: 'hashKey', KeyType: 'HASH' }, + { AttributeName: 'lsiSortKey', KeyType: 'RANGE' } + ], + Projection: { NonKeyAttributes: ['lsiNonKey0', 'lsiNonKey1'], ProjectionType: 'INCLUDE' }, + } + ], + } + ); +}); + +test('error when adding more than 5 local secondary indexes', () => { + const stack = new Stack(); + const table = new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY, sortKey: TABLE_SORT_KEY }); + const lsiGenerator = LSI_GENERATOR(); + for (let i = 0; i < 5; i++) { + table.addLocalSecondaryIndex(lsiGenerator.next().value); + } + + expect(() => table.addLocalSecondaryIndex(lsiGenerator.next().value)) + .toThrow(/a maximum number of local secondary index per table is 5/); + +}); + +test('error when adding a local secondary index with the name of a global secondary index', () => { + const stack = new Stack(); + const table = new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY, sortKey: TABLE_SORT_KEY }); + table.addGlobalSecondaryIndex({ + indexName: 'SecondaryIndex', + partitionKey: GSI_PARTITION_KEY + }); + + expect(() => table.addLocalSecondaryIndex({ + indexName: 'SecondaryIndex', + sortKey: LSI_SORT_KEY + })).toThrow(/a duplicate index name, SecondaryIndex, is not allowed/); +}); + +test('error when validating construct if a local secondary index exists without a sort key of the table', () => { + const stack = new Stack(); + const table = new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY }); + + table.addLocalSecondaryIndex({ + indexName: LSI_NAME, + sortKey: LSI_SORT_KEY + }); + + const errors = ConstructNode.validate(table.node); + + expect(errors.length).toBe(1); + expect(errors[0]?.message).toBe('a sort key of the table must be specified to add local secondary indexes'); +}); + +test('can enable Read AutoScaling', () => { + // GIVEN + const stack = new Stack(); + const table = new Table(stack, CONSTRUCT_NAME, { readCapacity: 42, writeCapacity: 1337, partitionKey: TABLE_PARTITION_KEY }); + + // WHEN + table.autoScaleReadCapacity({ minCapacity: 50, maxCapacity: 500 }).scaleOnUtilization({ targetUtilizationPercent: 75 }); + + // THEN + expect(stack).toHaveResource('AWS::ApplicationAutoScaling::ScalableTarget', { + MaxCapacity: 500, + MinCapacity: 50, + ScalableDimension: 'dynamodb:table:ReadCapacityUnits', + ServiceNamespace: 'dynamodb' + }); + expect(stack).toHaveResource('AWS::ApplicationAutoScaling::ScalingPolicy', { + PolicyType: 'TargetTrackingScaling', + TargetTrackingScalingPolicyConfiguration: { + PredefinedMetricSpecification: { PredefinedMetricType: 'DynamoDBReadCapacityUtilization' }, + TargetValue: 75 + } + }); +}); + +test('can enable Write AutoScaling', () => { + // GIVEN + const stack = new Stack(); + const table = new Table(stack, CONSTRUCT_NAME, { readCapacity: 42, writeCapacity: 1337, partitionKey: TABLE_PARTITION_KEY }); + + // WHEN + table.autoScaleWriteCapacity({ minCapacity: 50, maxCapacity: 500 }).scaleOnUtilization({ targetUtilizationPercent: 75 }); + + // THEN + expect(stack).toHaveResource('AWS::ApplicationAutoScaling::ScalableTarget', { + MaxCapacity: 500, + MinCapacity: 50, + ScalableDimension: 'dynamodb:table:WriteCapacityUnits', + ServiceNamespace: 'dynamodb' + }); + expect(stack).toHaveResource('AWS::ApplicationAutoScaling::ScalingPolicy', { + PolicyType: 'TargetTrackingScaling', + TargetTrackingScalingPolicyConfiguration: { + PredefinedMetricSpecification: { PredefinedMetricType: 'DynamoDBWriteCapacityUtilization' }, + TargetValue: 75 + } + }); +}); + +test('cannot enable AutoScaling twice on the same property', () => { + // GIVEN + const stack = new Stack(); + const table = new Table(stack, CONSTRUCT_NAME, { readCapacity: 42, writeCapacity: 1337, partitionKey: TABLE_PARTITION_KEY }); + table.autoScaleReadCapacity({ minCapacity: 50, maxCapacity: 500 }).scaleOnUtilization({ targetUtilizationPercent: 75 }); + + // WHEN + expect(() => { + table.autoScaleReadCapacity({ minCapacity: 50, maxCapacity: 500 }); + }).toThrow(/Read AutoScaling already enabled for this table/); +}); + +test('error when enabling AutoScaling on the PAY_PER_REQUEST table', () => { + // GIVEN + const stack = new Stack(); + const table = new Table(stack, CONSTRUCT_NAME, { billingMode: BillingMode.PAY_PER_REQUEST, partitionKey: TABLE_PARTITION_KEY }); + table.addGlobalSecondaryIndex({ + indexName: GSI_NAME, + partitionKey: GSI_PARTITION_KEY + }); + + // WHEN + expect(() => { + table.autoScaleReadCapacity({ minCapacity: 50, maxCapacity: 500 }); + }).toThrow(/PAY_PER_REQUEST/); + expect(() => { + table.autoScaleWriteCapacity({ minCapacity: 50, maxCapacity: 500 }); + }).toThrow(/PAY_PER_REQUEST/); + expect(() => table.autoScaleGlobalSecondaryIndexReadCapacity(GSI_NAME, { + minCapacity: 1, + maxCapacity: 5 + })).toThrow(/PAY_PER_REQUEST/); +}); + +test('error when specifying Read Auto Scaling with invalid scalingTargetValue < 10', () => { + // GIVEN + const stack = new Stack(); + const table = new Table(stack, CONSTRUCT_NAME, { readCapacity: 42, writeCapacity: 1337, partitionKey: TABLE_PARTITION_KEY }); + + // THEN + expect(() => { + table.autoScaleReadCapacity({ minCapacity: 50, maxCapacity: 500 }).scaleOnUtilization({ targetUtilizationPercent: 5 }); + }).toThrow(/targetUtilizationPercent for DynamoDB scaling must be between 10 and 90 percent, got: 5/); +}); + +test('error when specifying Read Auto Scaling with invalid minimumCapacity', () => { + // GIVEN + const stack = new Stack(); + const table = new Table(stack, CONSTRUCT_NAME, { readCapacity: 42, writeCapacity: 1337, partitionKey: TABLE_PARTITION_KEY }); + + // THEN + expect(() => table.autoScaleReadCapacity({ minCapacity: 10, maxCapacity: 5 })) + .toThrow(/minCapacity \(10\) should be lower than maxCapacity \(5\)/); +}); + +test('can autoscale on a schedule', () => { + // GIVEN + const stack = new Stack(); + const table = new Table(stack, CONSTRUCT_NAME, { + readCapacity: 42, + writeCapacity: 1337, + partitionKey: { name: 'Hash', type: AttributeType.STRING } + }); + + // WHEN + const scaling = table.autoScaleReadCapacity({ minCapacity: 1, maxCapacity: 100 }); + scaling.scaleOnSchedule('SaveMoneyByNotScalingUp', { + schedule: appscaling.Schedule.cron({}), + maxCapacity: 10 + }); + + // THEN + expect(stack).toHaveResource('AWS::ApplicationAutoScaling::ScalableTarget', { + ScheduledActions: [ + { + ScalableTargetAction: { "MaxCapacity": 10 }, + Schedule: "cron(* * * * ? *)", + ScheduledActionName: "SaveMoneyByNotScalingUp" + } + ] + }); +}); + +describe('metrics', () => { + test('Can use metricConsumedReadCapacityUnits on a Dynamodb Table', () => { + // GIVEN + const stack = new Stack(); + const table = new Table(stack, 'Table', { + partitionKey: { name: 'id', type: AttributeType.STRING } + }); + + // THEN + expect(stack.resolve(table.metricConsumedReadCapacityUnits())).toEqual({ + period: Duration.minutes(5), + dimensions: { TableName: { Ref: 'TableCD117FA1' } }, + namespace: 'AWS/DynamoDB', + metricName: 'ConsumedReadCapacityUnits', + statistic: 'Sum', + }); + }); + + test('Can use metricConsumedWriteCapacityUnits on a Dynamodb Table', () => { + // GIVEN + const stack = new Stack(); + const table = new Table(stack, 'Table', { + partitionKey: { name: 'id', type: AttributeType.STRING } + }); + + // THEN + expect(stack.resolve(table.metricConsumedWriteCapacityUnits())).toEqual({ + period: Duration.minutes(5), + dimensions: { TableName: { Ref: 'TableCD117FA1' } }, + namespace: 'AWS/DynamoDB', + metricName: 'ConsumedWriteCapacityUnits', + statistic: 'Sum', + }); + }); + + test('Can use metricSystemErrors on a Dynamodb Table', () => { + // GIVEN + const stack = new Stack(); + const table = new Table(stack, 'Table', { + partitionKey: { name: 'id', type: AttributeType.STRING } + }); + + // THEN + expect(stack.resolve(table.metricSystemErrors())).toEqual({ + period: Duration.minutes(5), + dimensions: { TableName: { Ref: 'TableCD117FA1' } }, + namespace: 'AWS/DynamoDB', + metricName: 'SystemErrors', + statistic: 'Sum', + }); + }); + + test('Can use metricUserErrors on a Dynamodb Table', () => { + // GIVEN + const stack = new Stack(); + const table = new Table(stack, 'Table', { + partitionKey: { name: 'id', type: AttributeType.STRING } + }); + + // THEN + expect(stack.resolve(table.metricUserErrors())).toEqual({ + period: Duration.minutes(5), + dimensions: { TableName: { Ref: 'TableCD117FA1' } }, + namespace: 'AWS/DynamoDB', + metricName: 'UserErrors', + statistic: 'Sum', + }); + }); + + test('Can use metricConditionalCheckFailedRequests on a Dynamodb Table', () => { + // GIVEN + const stack = new Stack(); + const table = new Table(stack, 'Table', { + partitionKey: { name: 'id', type: AttributeType.STRING } + }); + + // THEN + expect(stack.resolve(table.metricConditionalCheckFailedRequests())).toEqual({ + period: Duration.minutes(5), + dimensions: { TableName: { Ref: 'TableCD117FA1' } }, + namespace: 'AWS/DynamoDB', + metricName: 'ConditionalCheckFailedRequests', + statistic: 'Sum', + }); + }); + + test('Can use metricSuccessfulRequestLatency on a Dynamodb Table', () => { + // GIVEN + const stack = new Stack(); + const table = new Table(stack, 'Table', { + partitionKey: { name: 'id', type: AttributeType.STRING } + }); + + // THEN + expect(stack.resolve(table.metricSuccessfulRequestLatency())).toEqual({ + period: Duration.minutes(5), + dimensions: { TableName: { Ref: 'TableCD117FA1' } }, + namespace: 'AWS/DynamoDB', + metricName: 'SuccessfulRequestLatency', + statistic: 'Average', + }); + }); +}); + +describe('grants', () => { + + test('"grant" allows adding arbitrary actions associated with this table resource', () => { + testGrant( + ['action1', 'action2'], (p, t) => t.grant(p, 'dynamodb:action1', 'dynamodb:action2')); + }); + + test('"grantReadData" allows the principal to read data from the table', () => { + testGrant( + ['BatchGetItem', 'GetRecords', 'GetShardIterator', 'Query', 'GetItem', 'Scan'], (p, t) => t.grantReadData(p)); + }); + + test('"grantWriteData" allows the principal to write data to the table', () => { + testGrant( + ['BatchWriteItem', 'PutItem', 'UpdateItem', 'DeleteItem'], (p, t) => t.grantWriteData(p)); + }); + + test('"grantReadWriteData" allows the principal to read/write data', () => { + testGrant([ + 'BatchGetItem', 'GetRecords', 'GetShardIterator', 'Query', 'GetItem', 'Scan', + 'BatchWriteItem', 'PutItem', 'UpdateItem', 'DeleteItem'], (p, t) => t.grantReadWriteData(p)); + }); + + test('"grantFullAccess" allows the principal to perform any action on the table ("*")', () => { + testGrant(['*'], (p, t) => t.grantFullAccess(p)); + }); + + test('"Table.grantListStreams" allows principal to list all streams', () => { + // GIVEN + const stack = new Stack(); + const user = new iam.User(stack, 'user'); + + // WHEN + Table.grantListStreams(user); + + // THEN + expect(stack).toHaveResource('AWS::IAM::Policy', { + "PolicyDocument": { + "Statement": [ + { + "Action": "dynamodb:ListStreams", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "Users": [{ "Ref": "user2C2B57AE" }] + }); + }); + + test('"grantTableListStreams" should fail if streaming is not enabled on table"', () => { + // GIVEN + const stack = new Stack(); + const table = new Table(stack, 'my-table', { + partitionKey: { + name: 'id', + type: AttributeType.STRING + } + }); + const user = new iam.User(stack, 'user'); + + // WHEN + expect(() => table.grantTableListStreams(user)).toThrow(/DynamoDB Streams must be enabled on the table my-table/); + }); + + test('"grantTableListStreams" allows principal to list all streams for this table', () => { + // GIVEN + const stack = new Stack(); + const table = new Table(stack, 'my-table', { + partitionKey: { + name: 'id', + type: AttributeType.STRING + }, + stream: StreamViewType.NEW_IMAGE + }); + const user = new iam.User(stack, 'user'); + + // WHEN + table.grantTableListStreams(user); + + // THEN + expect(stack).toHaveResource('AWS::IAM::Policy', { + "PolicyDocument": { + "Statement": [ + { + "Action": "dynamodb:ListStreams", + "Effect": "Allow", + "Resource": { "Fn::Join": ["", [{ "Fn::GetAtt": ["mytable0324D45C", "Arn"] }, "/stream/*"]] } + } + ], + "Version": "2012-10-17" + }, + "Users": [{ "Ref": "user2C2B57AE" }] + }); + }); + + test('"grantStreamRead" should fail if streaming is not enabled on table"', () => { + // GIVEN + const stack = new Stack(); + const table = new Table(stack, 'my-table', { + partitionKey: { + name: 'id', + type: AttributeType.STRING + } + }); + const user = new iam.User(stack, 'user'); + + // WHEN + expect(() => table.grantStreamRead(user)).toThrow(/DynamoDB Streams must be enabled on the table my-table/); + }); + + test('"grantStreamRead" allows principal to read and describe the table stream"', () => { + // GIVEN + const stack = new Stack(); + const table = new Table(stack, 'my-table', { + partitionKey: { + name: 'id', + type: AttributeType.STRING + }, + stream: StreamViewType.NEW_IMAGE + }); + const user = new iam.User(stack, 'user'); + + // WHEN + table.grantStreamRead(user); + + // THEN + expect(stack).toHaveResource('AWS::IAM::Policy', { + "PolicyDocument": { + "Statement": [ + { + "Action": "dynamodb:ListStreams", + "Effect": "Allow", + "Resource": { "Fn::Join": ["", [{ "Fn::GetAtt": ["mytable0324D45C", "Arn"] }, "/stream/*"]] } + }, + { + "Action": [ + "dynamodb:DescribeStream", + "dynamodb:GetRecords", + "dynamodb:GetShardIterator" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "mytable0324D45C", + "StreamArn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "Users": [{ "Ref": "user2C2B57AE" }] + }); + }); + + test('if table has an index grant gives access to the index', () => { + // GIVEN + const stack = new Stack(); + + const table = new Table(stack, 'my-table', { partitionKey: { name: 'ID', type: AttributeType.STRING } }); + table.addGlobalSecondaryIndex({ indexName: 'MyIndex', partitionKey: { name: 'Age', type: AttributeType.NUMBER } }); + const user = new iam.User(stack, 'user'); + + // WHEN + table.grantReadData(user); + + // THEN + expect(stack).toHaveResource('AWS::IAM::Policy', { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + 'dynamodb:BatchGetItem', + 'dynamodb:GetRecords', + 'dynamodb:GetShardIterator', + 'dynamodb:Query', + 'dynamodb:GetItem', + 'dynamodb:Scan' + ], + "Effect": "Allow", + "Resource": [ + { "Fn::GetAtt": ["mytable0324D45C", "Arn"] }, + { "Fn::Join": ["", [{ "Fn::GetAtt": ["mytable0324D45C", "Arn"] }, "/index/*"]] } + ] + } + ], + "Version": "2012-10-17" + }, + "Users": [{ "Ref": "user2C2B57AE" }] + }); + }); +}); + +describe('secondary indexes', () => { + // See https://github.com/aws/aws-cdk/issues/4398 + test('attribute can be used as key attribute in one index, and non-key in another', () => { + // GIVEN + const stack = new Stack(); + const table = new Table(stack, 'Table', { + partitionKey: { name: 'pkey', type: AttributeType.NUMBER } + }); + + // WHEN + table.addGlobalSecondaryIndex({ + indexName: 'IndexA', + partitionKey: { name: 'foo', type: AttributeType.STRING }, + projectionType: ProjectionType.INCLUDE, + nonKeyAttributes: ['bar'], + }); + + // THEN + expect(() => table.addGlobalSecondaryIndex({ + indexName: 'IndexB', + partitionKey: { name: 'baz', type: AttributeType.STRING }, + sortKey: { name: 'bar', type: AttributeType.STRING }, + projectionType: ProjectionType.INCLUDE, + nonKeyAttributes: ['blah'], + })).not.toThrow(); + }); +}); + +describe('import', () => { + test('report error when importing an external/existing table from invalid arn missing resource name', () => { + const stack = new Stack(); + + const tableArn = 'arn:aws:dynamodb:us-east-1::table/'; + // WHEN + expect(() => Table.fromTableArn(stack, 'ImportedTable', tableArn)).toThrow(/ARN for DynamoDB table must be in the form: .../); + }); + + test('static fromTableArn(arn) allows importing an external/existing table from arn', () => { + const stack = new Stack(); + + const tableArn = 'arn:aws:dynamodb:us-east-1:11111111:table/MyTable'; + const table = Table.fromTableArn(stack, 'ImportedTable', tableArn); + + const role = new iam.Role(stack, 'NewRole', { + assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), + }); + table.grantReadData(role); + + // it is possible to obtain a permission statement for a ref + expect(stack).toHaveResource('AWS::IAM::Policy', { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + 'dynamodb:BatchGetItem', + 'dynamodb:GetRecords', + 'dynamodb:GetShardIterator', + 'dynamodb:Query', + 'dynamodb:GetItem', + 'dynamodb:Scan' + ], + "Effect": "Allow", + "Resource": [ + tableArn, + { "Ref": "AWS::NoValue" } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": 'NewRoleDefaultPolicy90E8F49D', + "Roles": [{ "Ref": 'NewRole99763075' }] + }); + + expect(table.tableArn).toBe(tableArn); + expect(stack.resolve(table.tableName)).toBe('MyTable'); + }); + + test('static fromTableName(name) allows importing an external/existing table from table name', () => { + const stack = new Stack(); + + const tableName = 'MyTable'; + const table = Table.fromTableName(stack, 'ImportedTable', tableName); + + const role = new iam.Role(stack, 'NewRole', { + assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), + }); + table.grantReadWriteData(role); + + // it is possible to obtain a permission statement for a ref + expect(stack).toHaveResource('AWS::IAM::Policy', { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + 'dynamodb:BatchGetItem', + 'dynamodb:GetRecords', + 'dynamodb:GetShardIterator', + 'dynamodb:Query', + 'dynamodb:GetItem', + 'dynamodb:Scan', + 'dynamodb:BatchWriteItem', + 'dynamodb:PutItem', + 'dynamodb:UpdateItem', + 'dynamodb:DeleteItem' + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":dynamodb:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":table/MyTable" + ] + ] + }, + { + "Ref": "AWS::NoValue" + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": 'NewRoleDefaultPolicy90E8F49D', + "Roles": [{ "Ref": 'NewRole99763075' }] + }); + + expect(table.tableArn).toBe('arn:${Token[AWS::Partition.3]}:dynamodb:${Token[AWS::Region.4]}:${Token[AWS::AccountId.0]}:table/MyTable'); + expect(stack.resolve(table.tableName)).toBe(tableName); + }); + + describe('stream permissions on imported tables', () => { + test('throw if no tableStreamArn is specified', () => { + const stack = new Stack(); + + const tableName = 'MyTable'; + const table = Table.fromTableAttributes(stack, 'ImportedTable', { tableName }); + + const role = new iam.Role(stack, 'NewRole', { + assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), + }); + + expect(() => table.grantTableListStreams(role)).toThrow(/DynamoDB Streams must be enabled on the table/); + expect(() => table.grantStreamRead(role)).toThrow(/DynamoDB Streams must be enabled on the table/); + }); + + test('creates the correct list streams grant', () => { + const stack = new Stack(); + + const tableName = 'MyTable'; + const tableStreamArn = 'arn:foo:bar:baz:TrustMeThisIsATableStream'; + const table = Table.fromTableAttributes(stack, 'ImportedTable', { tableName, tableStreamArn }); + + const role = new iam.Role(stack, 'NewRole', { + assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), + }); + + expect(table.grantTableListStreams(role)).toBeDefined(); + + expect(stack).toHaveResource('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: "dynamodb:ListStreams", + Effect: 'Allow', + Resource: stack.resolve(`${table.tableArn}/stream/*`), + }, + ], + Version: '2012-10-17' + }, + Roles: [stack.resolve(role.roleName)] + }); + }); + + test('creates the correct stream read grant', () => { + const stack = new Stack(); + + const tableName = 'MyTable'; + const tableStreamArn = 'arn:foo:bar:baz:TrustMeThisIsATableStream'; + const table = Table.fromTableAttributes(stack, 'ImportedTable', { tableName, tableStreamArn }); + + const role = new iam.Role(stack, 'NewRole', { + assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), + }); + + expect(table.grantStreamRead(role)).toBeDefined(); + + expect(stack).toHaveResource('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: "dynamodb:ListStreams", + Effect: 'Allow', + Resource: stack.resolve(`${table.tableArn}/stream/*`), + }, + { + Action: ['dynamodb:DescribeStream', 'dynamodb:GetRecords', 'dynamodb:GetShardIterator'], + Effect: 'Allow', + Resource: tableStreamArn, + } + ], + Version: '2012-10-17' + }, + Roles: [stack.resolve(role.roleName)] + }); + }); + }); +}); + +describe('global', () => { + test('create replicas', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + new Table(stack, 'Table', { + partitionKey: { + name: 'id', + type: AttributeType.STRING + }, + replicationRegions: [ + 'eu-west-2', + 'eu-central-1' + ], + }); + + // THEN + expect(stack).toHaveResource('Custom::DynamoDBReplica', { + Properties: { + ServiceToken: { + 'Fn::GetAtt': [ + 'awscdkawsdynamodbReplicaProviderNestedStackawscdkawsdynamodbReplicaProviderNestedStackResource18E3F12D', + 'Outputs.awscdkawsdynamodbReplicaProviderframeworkonEventF9504691Arn' + ] + }, + TableName: { + Ref: 'TableCD117FA1' + }, + Region: 'eu-west-2' + }, + Condition: 'TableStackRegionNotEqualseuwest2A03859E7' + }, ResourcePart.CompleteDefinition); + + expect(stack).toHaveResource('Custom::DynamoDBReplica', { + Properties: { + ServiceToken: { + 'Fn::GetAtt': [ + 'awscdkawsdynamodbReplicaProviderNestedStackawscdkawsdynamodbReplicaProviderNestedStackResource18E3F12D', + 'Outputs.awscdkawsdynamodbReplicaProviderframeworkonEventF9504691Arn' + ] + }, + TableName: { + Ref: 'TableCD117FA1' + }, + Region: 'eu-central-1' + }, + Condition: 'TableStackRegionNotEqualseucentral199D46FC0' + }, ResourcePart.CompleteDefinition); + + expect(SynthUtils.toCloudFormation(stack).Conditions).toEqual({ + TableStackRegionNotEqualseuwest2A03859E7: { + 'Fn::Not': [ + { 'Fn::Equals': ['eu-west-2', { Ref: 'AWS::Region' }] } + ] + }, + TableStackRegionNotEqualseucentral199D46FC0: { + 'Fn::Not': [ + { 'Fn::Equals': ['eu-central-1', { Ref: 'AWS::Region' }] } + ] + } + }); + }); + + test('throws with PROVISIONED billing mode', () => { + // GIVEN + const stack = new Stack(); + + // THEN + expect(() => new Table(stack, 'Table', { + partitionKey: { + name: 'id', + type: AttributeType.STRING + }, + replicationRegions: [ + 'eu-west-2', + 'eu-central-1' + ], + billingMode: BillingMode.PROVISIONED, + })).toThrow(/`PAY_PER_REQUEST`/); + }); + + test('throws when stream is set and not set to NEW_AND_OLD_IMAGES', () => { + // GIVEN + const stack = new Stack(); + + // THEN + expect(() => new Table(stack, 'Table', { + partitionKey: { + name: 'id', + type: AttributeType.STRING + }, + replicationRegions: [ + 'eu-west-2', + 'eu-central-1' + ], + stream: StreamViewType.OLD_IMAGE, + })).toThrow(/`NEW_AND_OLD_IMAGES`/); + }); + + test('throws with replica in same region as stack', () => { + // GIVEN + const app = new App(); + const stack = new Stack(app, 'Stack', { + env: { region: 'us-east-1' } + }); + + // THEN + expect(() => new Table(stack, 'Table', { + partitionKey: { + name: 'id', + type: AttributeType.STRING + }, + replicationRegions: [ + 'eu-west-1', + 'us-east-1', + 'eu-west-2', + ], + })).toThrow(/`replicationRegions` cannot include the region where this stack is deployed/); + }); + + test('no conditions when region is known', () => { + // GIVEN + const app = new App(); + const stack = new Stack(app, 'Stack', { + env: { region: 'eu-west-1' } + }); + + // WHEN + new Table(stack, 'Table', { + partitionKey: { + name: 'id', + type: AttributeType.STRING + }, + replicationRegions: [ + 'eu-west-2', + 'eu-central-1' + ], + }); + + // THEN + expect(SynthUtils.toCloudFormation(stack).Conditions).toBeUndefined(); + }); +}); + +function testGrant(expectedActions: string[], invocation: (user: iam.IPrincipal, table: Table) => void) { + // GIVEN + const stack = new Stack(); + const table = new Table(stack, 'my-table', { partitionKey: { name: 'ID', type: AttributeType.STRING } }); + const user = new iam.User(stack, 'user'); + + // WHEN + invocation(user, table); + + // THEN + const action = expectedActions.length > 1 ? expectedActions.map(a => `dynamodb:${a}`) : `dynamodb:${expectedActions[0]}`; + expect(stack).toHaveResource('AWS::IAM::Policy', { + "PolicyDocument": { + "Statement": [ + { + "Action": action, + "Effect": "Allow", + "Resource": [ + { "Fn::GetAtt": [ "mytable0324D45C", "Arn" ] }, + { "Ref" : "AWS::NoValue" } + ] + } + ], + "Version": "2012-10-17" + }, + "Users": [ { "Ref": "user2C2B57AE" } ] + }); +} diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.mixed-key-gsi.expected.json b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.mixed-key-gsi.expected.json new file mode 100644 index 0000000000000..ce5538286f9e5 --- /dev/null +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.mixed-key-gsi.expected.json @@ -0,0 +1,83 @@ +{ + "Resources": { + "TableCD117FA1": { + "Type": "AWS::DynamoDB::Table", + "Properties": { + "KeySchema": [ + { + "AttributeName": "pkey", + "KeyType": "HASH" + } + ], + "AttributeDefinitions": [ + { + "AttributeName": "pkey", + "AttributeType": "N" + }, + { + "AttributeName": "foo", + "AttributeType": "S" + }, + { + "AttributeName": "baz", + "AttributeType": "S" + }, + { + "AttributeName": "bar", + "AttributeType": "S" + } + ], + "GlobalSecondaryIndexes": [ + { + "IndexName": "IndexA", + "KeySchema": [ + { + "AttributeName": "foo", + "KeyType": "HASH" + } + ], + "Projection": { + "NonKeyAttributes": [ + "bar" + ], + "ProjectionType": "INCLUDE" + }, + "ProvisionedThroughput": { + "ReadCapacityUnits": 5, + "WriteCapacityUnits": 5 + } + }, + { + "IndexName": "IndexB", + "KeySchema": [ + { + "AttributeName": "baz", + "KeyType": "HASH" + }, + { + "AttributeName": "bar", + "KeyType": "RANGE" + } + ], + "Projection": { + "NonKeyAttributes": [ + "blah" + ], + "ProjectionType": "INCLUDE" + }, + "ProvisionedThroughput": { + "ReadCapacityUnits": 5, + "WriteCapacityUnits": 5 + } + } + ], + "ProvisionedThroughput": { + "ReadCapacityUnits": 5, + "WriteCapacityUnits": 5 + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.mixed-key-gsi.ts b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.mixed-key-gsi.ts new file mode 100644 index 0000000000000..8c0b55f1f48a2 --- /dev/null +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.mixed-key-gsi.ts @@ -0,0 +1,32 @@ +/** + * This aimes to verify we can deploy a DynamoDB table with an attribute being + * a key attribute in one GSI, and a non-key attribute in another. + * + * See https://github.com/aws/aws-cdk/issues/4398 + */ + +import { App, RemovalPolicy, Stack } from '@aws-cdk/core'; +import { AttributeType, ProjectionType, Table } from '../lib'; + +const app = new App(); +const stack = new Stack(app, 'aws-cdk-dynamodb-gsi'); + +const table = new Table(stack, 'Table', { + partitionKey: { name: 'pkey', type: AttributeType.NUMBER }, + removalPolicy: RemovalPolicy.DESTROY, +}); + +table.addGlobalSecondaryIndex({ + indexName: 'IndexA', + partitionKey: { name: 'foo', type: AttributeType.STRING }, + projectionType: ProjectionType.INCLUDE, + nonKeyAttributes: ['bar'], +}); + +table.addGlobalSecondaryIndex({ + indexName: 'IndexB', + partitionKey: { name: 'baz', type: AttributeType.STRING }, + sortKey: { name: 'bar', type: AttributeType.STRING }, + projectionType: ProjectionType.INCLUDE, + nonKeyAttributes: ['blah'], +}); diff --git a/packages/@aws-cdk/aws-dynamodb/test/replica-provider.test.ts b/packages/@aws-cdk/aws-dynamodb/test/replica-provider.test.ts new file mode 100644 index 0000000000000..1f1aa6f6ae033 --- /dev/null +++ b/packages/@aws-cdk/aws-dynamodb/test/replica-provider.test.ts @@ -0,0 +1,166 @@ +import { OnEventRequest } from '@aws-cdk/custom-resources/lib/provider-framework/types'; +import * as AWS from 'aws-sdk-mock'; +import * as sinon from 'sinon'; +import { isCompleteHandler, onEventHandler } from '../lib/replica-handler'; + +AWS.setSDK(require.resolve('aws-sdk')); + +const createEvent: OnEventRequest = { + RequestType: 'Create', + ResourceProperties: { + TableName: 'my-table', + Region: 'eu-west-2', + ServiceToken: 'token' + }, + ServiceToken: 'token', + ResponseURL: 'url', + LogicalResourceId: 'logical-id', + RequestId: 'request-id', + StackId: 'stack-id', + ResourceType: 'resource-type' +}; + +beforeEach(done => { + process.env.USE_NORMAL_SDK = 'true'; + done(); +}); + +afterEach(done => { + delete process.env.USE_NORMAL_SDK; + AWS.restore(); + done(); +}); + +test('on event', async () => { + const updateTableMock = sinon.fake.resolves({}); + + AWS.mock('DynamoDB', 'updateTable', updateTableMock); + + const data = await onEventHandler(createEvent); + + sinon.assert.calledWith(updateTableMock, { + TableName: 'my-table', + ReplicaUpdates: [ + { + Create: { + RegionName: 'eu-west-2' + } + }, + ] + }); + + expect(data).toEqual({ + PhysicalResourceId: 'eu-west-2' + }); +}); + +test('on event does not call updateTable for Update requests', async () => { + const updateTableMock = sinon.fake.resolves({}); + + AWS.mock('DynamoDB', 'updateTable', updateTableMock); + + const data = await onEventHandler({ + ...createEvent, + RequestType: 'Update', + }); + + sinon.assert.notCalled(updateTableMock); + + expect(data).toEqual({ + PhysicalResourceId: 'eu-west-2' + }); +}); + +test('is complete for create returns false without replicas', async () => { + const describeTableMock = sinon.fake.resolves({ + Table: {} + }); + + AWS.mock('DynamoDB', 'describeTable', describeTableMock); + + const data = await isCompleteHandler(createEvent); + + expect(data).toEqual({ IsComplete: false }); +}); + +test('is complete for create returns false when replica is not active', async () => { + const describeTableMock = sinon.fake.resolves({ + Table: { + Replicas: [ + { + RegionName: 'eu-west-2', + ReplicaStatus: 'CREATING' + } + ] + } + }); + + AWS.mock('DynamoDB', 'describeTable', describeTableMock); + + const data = await isCompleteHandler(createEvent); + + expect(data).toEqual({ IsComplete: false }); +}); + +test('is complete for create returns false when table is not active', async () => { + const describeTableMock = sinon.fake.resolves({ + Table: { + Replicas: [ + { + RegionName: 'eu-west-2', + ReplicaStatus: 'ACTIVE' + } + ], + TableStatus: 'UPDATING', + } + }); + + AWS.mock('DynamoDB', 'describeTable', describeTableMock); + + const data = await isCompleteHandler(createEvent); + + expect(data).toEqual({ IsComplete: false }); +}); + +test('is complete for create returns true when replica is active', async () => { + const describeTableMock = sinon.fake.resolves({ + Table: { + Replicas: [ + { + RegionName: 'eu-west-2', + ReplicaStatus: 'ACTIVE' + } + ], + TableStatus: 'ACTIVE', + } + }); + + AWS.mock('DynamoDB', 'describeTable', describeTableMock); + + const data = await isCompleteHandler(createEvent); + + expect(data).toEqual({ IsComplete: true }); +}); + +test('is complete for delete returns true when replica is gone', async () => { + const describeTableMock = sinon.fake.resolves({ + Table: { + Replicas: [ + { + RegionName: 'eu-west-1', + ReplicaStatus: 'ACTIVE' + } + ], + TableStatus: 'ACTIVE', + } + }); + + AWS.mock('DynamoDB', 'describeTable', describeTableMock); + + const data = await isCompleteHandler({ + ...createEvent, + RequestType: 'Delete' + }); + + expect(data).toEqual({ IsComplete: true }); +}); diff --git a/packages/@aws-cdk/aws-dynamodb/test/test.dynamodb.ts b/packages/@aws-cdk/aws-dynamodb/test/test.dynamodb.ts deleted file mode 100644 index a833471b733ef..0000000000000 --- a/packages/@aws-cdk/aws-dynamodb/test/test.dynamodb.ts +++ /dev/null @@ -1,1839 +0,0 @@ -import { expect, haveResource, ResourcePart, SynthUtils } from '@aws-cdk/assert'; -import * as appscaling from '@aws-cdk/aws-applicationautoscaling'; -import * as iam from '@aws-cdk/aws-iam'; -import { App, CfnDeletionPolicy, ConstructNode, Duration, RemovalPolicy, Stack, Tag } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; -import { - Attribute, - AttributeType, - BillingMode, - GlobalSecondaryIndexProps, - LocalSecondaryIndexProps, - ProjectionType, - StreamViewType, - Table, -} from '../lib'; - -// tslint:disable:object-literal-key-quotes - -// CDK parameters -const CONSTRUCT_NAME = 'MyTable'; - -// DynamoDB table parameters -const TABLE_NAME = 'MyTable'; -const TABLE_PARTITION_KEY: Attribute = { name: 'hashKey', type: AttributeType.STRING }; -const TABLE_SORT_KEY: Attribute = { name: 'sortKey', type: AttributeType.NUMBER }; - -// DynamoDB global secondary index parameters -const GSI_NAME = 'MyGSI'; -const GSI_PARTITION_KEY: Attribute = { name: 'gsiHashKey', type: AttributeType.STRING }; -const GSI_SORT_KEY: Attribute = { name: 'gsiSortKey', type: AttributeType.BINARY }; -const GSI_NON_KEY = 'gsiNonKey'; -function* GSI_GENERATOR(): Generator { - let n = 0; - while (true) { - const globalSecondaryIndexProps: GlobalSecondaryIndexProps = { - indexName: `${GSI_NAME}${n}`, - partitionKey: { name: `${GSI_PARTITION_KEY.name}${n}`, type: GSI_PARTITION_KEY.type } - }; - yield globalSecondaryIndexProps; - n++; - } -} -function* NON_KEY_ATTRIBUTE_GENERATOR(nonKeyPrefix: string): Generator { - let n = 0; - while (true) { - yield `${nonKeyPrefix}${n}`; - n++; - } -} - -// DynamoDB local secondary index parameters -const LSI_NAME = 'MyLSI'; -const LSI_SORT_KEY: Attribute = { name: 'lsiSortKey', type: AttributeType.NUMBER }; -const LSI_NON_KEY = 'lsiNonKey'; -function* LSI_GENERATOR(): Generator { - let n = 0; - while (true) { - const localSecondaryIndexProps: LocalSecondaryIndexProps = { - indexName: `${LSI_NAME}${n}`, - sortKey: { name : `${LSI_SORT_KEY.name}${n}`, type: LSI_SORT_KEY.type } - }; - yield localSecondaryIndexProps; - n++; - } -} - -export = { - 'default properties': { - 'hash key only'(test: Test) { - const stack = new Stack(); - new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY }); - - expect(stack).to(haveResource('AWS::DynamoDB::Table', { - AttributeDefinitions: [{ AttributeName: 'hashKey', AttributeType: 'S' }], - KeySchema: [{ AttributeName: 'hashKey', KeyType: 'HASH' }], - ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } - })); - - expect(stack).to(haveResource('AWS::DynamoDB::Table', { DeletionPolicy: CfnDeletionPolicy.RETAIN }, ResourcePart.CompleteDefinition)); - - test.done(); - }, - - 'removalPolicy is DESTROY'(test: Test) { - const stack = new Stack(); - new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY, removalPolicy: RemovalPolicy.DESTROY }); - - expect(stack).to(haveResource('AWS::DynamoDB::Table', { DeletionPolicy: CfnDeletionPolicy.DELETE }, ResourcePart.CompleteDefinition)); - - test.done(); - }, - - 'hash + range key'(test: Test) { - const stack = new Stack(); - new Table(stack, CONSTRUCT_NAME, { - partitionKey: TABLE_PARTITION_KEY, - sortKey: TABLE_SORT_KEY - }); - - expect(stack).to(haveResource('AWS::DynamoDB::Table', { - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - { AttributeName: 'sortKey', AttributeType: 'N' } - ], - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'sortKey', KeyType: 'RANGE' } - ], - ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 }, - })); - test.done(); - }, - - 'hash + range key can also be specified in props'(test: Test) { - const stack = new Stack(); - - new Table(stack, CONSTRUCT_NAME, { - partitionKey: TABLE_PARTITION_KEY, - sortKey: TABLE_SORT_KEY - }); - - expect(stack).to(haveResource('AWS::DynamoDB::Table', - { - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - { AttributeName: 'sortKey', AttributeType: 'N' } - ], - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'sortKey', KeyType: 'RANGE' } - ], - ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 }, - })); - - test.done(); - }, - - 'point-in-time recovery is not enabled'(test: Test) { - const stack = new Stack(); - new Table(stack, CONSTRUCT_NAME, { - partitionKey: TABLE_PARTITION_KEY, - sortKey: TABLE_SORT_KEY - }); - - expect(stack).to(haveResource('AWS::DynamoDB::Table', - { - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - { AttributeName: 'sortKey', AttributeType: 'N' } - ], - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'sortKey', KeyType: 'RANGE' } - ], - ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } - } - )); - test.done(); - }, - - 'server-side encryption is not enabled'(test: Test) { - const stack = new Stack(); - new Table(stack, CONSTRUCT_NAME, { - partitionKey: TABLE_PARTITION_KEY, - sortKey: TABLE_SORT_KEY, - }); - - expect(stack).to(haveResource('AWS::DynamoDB::Table', - { - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - { AttributeName: 'sortKey', AttributeType: 'N' } - ], - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'sortKey', KeyType: 'RANGE' } - ], - ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } - } - )); - test.done(); - }, - - 'stream is not enabled'(test: Test) { - const stack = new Stack(); - new Table(stack, CONSTRUCT_NAME, { - partitionKey: TABLE_PARTITION_KEY, - sortKey: TABLE_SORT_KEY, - }); - - expect(stack).to(haveResource('AWS::DynamoDB::Table', - { - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - { AttributeName: 'sortKey', AttributeType: 'N' } - ], - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'sortKey', KeyType: 'RANGE' } - ], - ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } - } - )); - test.done(); - }, - - 'ttl is not enabled'(test: Test) { - const stack = new Stack(); - new Table(stack, CONSTRUCT_NAME, { - partitionKey: TABLE_PARTITION_KEY, - sortKey: TABLE_SORT_KEY, - }); - - expect(stack).to(haveResource('AWS::DynamoDB::Table', - { - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - { AttributeName: 'sortKey', AttributeType: 'N' } - ], - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'sortKey', KeyType: 'RANGE' } - ], - ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } - } - )); - test.done(); - }, - - 'can specify new and old images'(test: Test) { - const stack = new Stack(); - - new Table(stack, CONSTRUCT_NAME, { - tableName: TABLE_NAME, - readCapacity: 42, - writeCapacity: 1337, - stream: StreamViewType.NEW_AND_OLD_IMAGES, - partitionKey: TABLE_PARTITION_KEY, - sortKey: TABLE_SORT_KEY - }); - - expect(stack).to(haveResource('AWS::DynamoDB::Table', - { - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - { AttributeName: 'sortKey', AttributeType: 'N' } - ], - StreamSpecification: { StreamViewType: 'NEW_AND_OLD_IMAGES' }, - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'sortKey', KeyType: 'RANGE' } - ], - ProvisionedThroughput: { ReadCapacityUnits: 42, WriteCapacityUnits: 1337 }, - TableName: 'MyTable' - } - )); - test.done(); - }, - - 'can specify new images only'(test: Test) { - const stack = new Stack(); - - new Table(stack, CONSTRUCT_NAME, { - tableName: TABLE_NAME, - readCapacity: 42, - writeCapacity: 1337, - stream: StreamViewType.NEW_IMAGE, - partitionKey: TABLE_PARTITION_KEY, - sortKey: TABLE_SORT_KEY - }); - - expect(stack).to(haveResource('AWS::DynamoDB::Table', - { - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'sortKey', KeyType: 'RANGE' } - ], - ProvisionedThroughput: { ReadCapacityUnits: 42, WriteCapacityUnits: 1337 }, - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - { AttributeName: 'sortKey', AttributeType: 'N' } - ], - StreamSpecification: { StreamViewType: 'NEW_IMAGE' }, - TableName: 'MyTable', - } - )); - test.done(); - }, - - 'can specify old images only'(test: Test) { - const stack = new Stack(); - - new Table(stack, CONSTRUCT_NAME, { - tableName: TABLE_NAME, - readCapacity: 42, - writeCapacity: 1337, - stream: StreamViewType.OLD_IMAGE, - partitionKey: TABLE_PARTITION_KEY, - sortKey: TABLE_SORT_KEY - }); - - expect(stack).to(haveResource('AWS::DynamoDB::Table', - { - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'sortKey', KeyType: 'RANGE' } - ], - ProvisionedThroughput: { ReadCapacityUnits: 42, WriteCapacityUnits: 1337 }, - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - { AttributeName: 'sortKey', AttributeType: 'N' } - ], - StreamSpecification: { StreamViewType: 'OLD_IMAGE' }, - TableName: 'MyTable', - } - )); - test.done(); - } - }, - - 'when specifying every property'(test: Test) { - const stack = new Stack(); - const table = new Table(stack, CONSTRUCT_NAME, { - tableName: TABLE_NAME, - readCapacity: 42, - writeCapacity: 1337, - pointInTimeRecovery: true, - serverSideEncryption: true, - billingMode: BillingMode.PROVISIONED, - stream: StreamViewType.KEYS_ONLY, - timeToLiveAttribute: 'timeToLive', - partitionKey: TABLE_PARTITION_KEY, - sortKey: TABLE_SORT_KEY, - }); - table.node.applyAspect(new Tag('Environment', 'Production')); - - expect(stack).to(haveResource('AWS::DynamoDB::Table', - { - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - { AttributeName: 'sortKey', AttributeType: 'N' } - ], - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'sortKey', KeyType: 'RANGE' } - ], - ProvisionedThroughput: { - ReadCapacityUnits: 42, - WriteCapacityUnits: 1337 - }, - PointInTimeRecoverySpecification: { PointInTimeRecoveryEnabled: true }, - SSESpecification: { SSEEnabled: true }, - StreamSpecification: { StreamViewType: 'KEYS_ONLY' }, - TableName: 'MyTable', - Tags: [ { Key: 'Environment', Value: 'Production' } ], - TimeToLiveSpecification: { AttributeName: 'timeToLive', Enabled: true } - } - )); - test.done(); - }, - - 'when specifying PAY_PER_REQUEST billing mode'(test: Test) { - const stack = new Stack(); - new Table(stack, CONSTRUCT_NAME, { - tableName: TABLE_NAME, - billingMode: BillingMode.PAY_PER_REQUEST, - partitionKey: TABLE_PARTITION_KEY - }); - - expect(stack).to(haveResource('AWS::DynamoDB::Table', - { - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - ], - BillingMode: 'PAY_PER_REQUEST', - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - ], - TableName: 'MyTable', - } - )); - test.done(); - }, - - 'error when specifying read or write capacity with a PAY_PER_REQUEST billing mode'(test: Test) { - const stack = new Stack(); - test.throws(() => new Table(stack, CONSTRUCT_NAME, { - tableName: TABLE_NAME, - billingMode: BillingMode.PAY_PER_REQUEST, - partitionKey: TABLE_PARTITION_KEY, - readCapacity: 1 - })); - test.throws(() => new Table(stack, CONSTRUCT_NAME, { - tableName: TABLE_NAME, - billingMode: BillingMode.PAY_PER_REQUEST, - partitionKey: TABLE_PARTITION_KEY, - writeCapacity: 1 - })); - test.throws(() => new Table(stack, CONSTRUCT_NAME, { - tableName: TABLE_NAME, - billingMode: BillingMode.PAY_PER_REQUEST, - partitionKey: TABLE_PARTITION_KEY, - readCapacity: 1, - writeCapacity: 1 - })); - test.done(); - }, - - 'when adding a global secondary index with hash key only'(test: Test) { - const stack = new Stack(); - - const table = new Table(stack, CONSTRUCT_NAME, { - partitionKey: TABLE_PARTITION_KEY, - sortKey: TABLE_SORT_KEY - }); - - table.addGlobalSecondaryIndex({ - indexName: GSI_NAME, - partitionKey: GSI_PARTITION_KEY, - readCapacity: 42, - writeCapacity: 1337 - }); - - expect(stack).to(haveResource('AWS::DynamoDB::Table', - { - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - { AttributeName: 'sortKey', AttributeType: 'N' }, - { AttributeName: 'gsiHashKey', AttributeType: 'S' }, - ], - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'sortKey', KeyType: 'RANGE' } - ], - ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 }, - GlobalSecondaryIndexes: [ - { - IndexName: 'MyGSI', - KeySchema: [ - { AttributeName: 'gsiHashKey', KeyType: 'HASH' }, - ], - Projection: { ProjectionType: 'ALL' }, - ProvisionedThroughput: { ReadCapacityUnits: 42, WriteCapacityUnits: 1337 } - } - ] - } - )); - test.done(); - }, - - 'when adding a global secondary index with hash + range key'(test: Test) { - const stack = new Stack(); - const table = new Table(stack, CONSTRUCT_NAME, { - partitionKey: TABLE_PARTITION_KEY, - sortKey: TABLE_SORT_KEY - }); - - table.addGlobalSecondaryIndex({ - indexName: GSI_NAME, - partitionKey: GSI_PARTITION_KEY, - sortKey: GSI_SORT_KEY, - projectionType: ProjectionType.ALL, - readCapacity: 42, - writeCapacity: 1337 - }); - - expect(stack).to(haveResource('AWS::DynamoDB::Table', - { - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - { AttributeName: 'sortKey', AttributeType: 'N' }, - { AttributeName: 'gsiHashKey', AttributeType: 'S' }, - { AttributeName: 'gsiSortKey', AttributeType: 'B' } - ], - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'sortKey', KeyType: 'RANGE' } - ], - ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 }, - GlobalSecondaryIndexes: [ - { - IndexName: 'MyGSI', - KeySchema: [ - { AttributeName: 'gsiHashKey', KeyType: 'HASH' }, - { AttributeName: 'gsiSortKey', KeyType: 'RANGE' } - ], - Projection: { ProjectionType: 'ALL' }, - ProvisionedThroughput: { ReadCapacityUnits: 42, WriteCapacityUnits: 1337 } - } - ] - } - )); - test.done(); - }, - - 'when adding a global secondary index with projection type KEYS_ONLY'(test: Test) { - const stack = new Stack(); - const table = new Table(stack, CONSTRUCT_NAME, { - partitionKey: TABLE_PARTITION_KEY, - sortKey: TABLE_SORT_KEY - }); - - table.addGlobalSecondaryIndex({ - indexName: GSI_NAME, - partitionKey: GSI_PARTITION_KEY, - sortKey: GSI_SORT_KEY, - projectionType: ProjectionType.KEYS_ONLY, - }); - - expect(stack).to(haveResource('AWS::DynamoDB::Table', - { - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - { AttributeName: 'sortKey', AttributeType: 'N' }, - { AttributeName: 'gsiHashKey', AttributeType: 'S' }, - { AttributeName: 'gsiSortKey', AttributeType: 'B' } - ], - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'sortKey', KeyType: 'RANGE' } - ], - ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 }, - GlobalSecondaryIndexes: [ - { - IndexName: 'MyGSI', - KeySchema: [ - { AttributeName: 'gsiHashKey', KeyType: 'HASH' }, - { AttributeName: 'gsiSortKey', KeyType: 'RANGE' } - ], - Projection: { ProjectionType: 'KEYS_ONLY' }, - ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } - } - ] - } - )); - test.done(); - }, - - 'when adding a global secondary index with projection type INCLUDE'(test: Test) { - const stack = new Stack(); - const table = new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY, sortKey: TABLE_SORT_KEY }); - const gsiNonKeyAttributeGenerator = NON_KEY_ATTRIBUTE_GENERATOR(GSI_NON_KEY); - table.addGlobalSecondaryIndex({ - indexName: GSI_NAME, - partitionKey: GSI_PARTITION_KEY, - sortKey: GSI_SORT_KEY, - projectionType: ProjectionType.INCLUDE, - nonKeyAttributes: [gsiNonKeyAttributeGenerator.next().value, gsiNonKeyAttributeGenerator.next().value], - readCapacity: 42, - writeCapacity: 1337 - }); - - expect(stack).to(haveResource('AWS::DynamoDB::Table', - { - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - { AttributeName: 'sortKey', AttributeType: 'N' }, - { AttributeName: 'gsiHashKey', AttributeType: 'S' }, - { AttributeName: 'gsiSortKey', AttributeType: 'B' } - ], - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'sortKey', KeyType: 'RANGE' } - ], - ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 }, - GlobalSecondaryIndexes: [ - { - IndexName: 'MyGSI', - KeySchema: [ - { AttributeName: 'gsiHashKey', KeyType: 'HASH' }, - { AttributeName: 'gsiSortKey', KeyType: 'RANGE' } - ], - Projection: { NonKeyAttributes: ['gsiNonKey0', 'gsiNonKey1'], ProjectionType: 'INCLUDE' }, - ProvisionedThroughput: { ReadCapacityUnits: 42, WriteCapacityUnits: 1337 } - } - ] - } - )); - test.done(); - }, - - 'when adding a global secondary index on a table with PAY_PER_REQUEST billing mode'(test: Test) { - const stack = new Stack(); - new Table(stack, CONSTRUCT_NAME, { - billingMode: BillingMode.PAY_PER_REQUEST, - partitionKey: TABLE_PARTITION_KEY, - sortKey: TABLE_SORT_KEY - }).addGlobalSecondaryIndex({ - indexName: GSI_NAME, - partitionKey: GSI_PARTITION_KEY, - }); - - expect(stack).to(haveResource('AWS::DynamoDB::Table', - { - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - { AttributeName: 'sortKey', AttributeType: 'N' }, - { AttributeName: 'gsiHashKey', AttributeType: 'S' }, - ], - BillingMode: 'PAY_PER_REQUEST', - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'sortKey', KeyType: 'RANGE' } - ], - GlobalSecondaryIndexes: [ - { - IndexName: 'MyGSI', - KeySchema: [ - { AttributeName: 'gsiHashKey', KeyType: 'HASH' }, - ], - Projection: { ProjectionType: 'ALL' } - } - ] - } - )); - test.done(); - }, - - 'error when adding a global secondary index with projection type INCLUDE, but without specifying non-key attributes'(test: Test) { - const stack = new Stack(); - const table = new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY, sortKey: TABLE_SORT_KEY }); - test.throws(() => table.addGlobalSecondaryIndex({ - indexName: GSI_NAME, - partitionKey: GSI_PARTITION_KEY, - sortKey: GSI_SORT_KEY, - projectionType: ProjectionType.INCLUDE - }), /non-key attributes should be specified when using INCLUDE projection type/); - - test.done(); - }, - - 'error when adding a global secondary index with projection type ALL, but with non-key attributes'(test: Test) { - const stack = new Stack(); - const table = new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY, sortKey: TABLE_SORT_KEY }); - const gsiNonKeyAttributeGenerator = NON_KEY_ATTRIBUTE_GENERATOR(GSI_NON_KEY); - - test.throws(() => table.addGlobalSecondaryIndex({ - indexName: GSI_NAME, - partitionKey: GSI_PARTITION_KEY, - nonKeyAttributes: [gsiNonKeyAttributeGenerator.next().value] - }), /non-key attributes should not be specified when not using INCLUDE projection type/); - - test.done(); - }, - - 'error when adding a global secondary index with projection type KEYS_ONLY, but with non-key attributes'(test: Test) { - const stack = new Stack(); - const table = new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY, sortKey: TABLE_SORT_KEY }); - const gsiNonKeyAttributeGenerator = NON_KEY_ATTRIBUTE_GENERATOR(GSI_NON_KEY); - - test.throws(() => table.addGlobalSecondaryIndex({ - indexName: GSI_NAME, - partitionKey: GSI_PARTITION_KEY, - projectionType: ProjectionType.KEYS_ONLY, - nonKeyAttributes: [gsiNonKeyAttributeGenerator.next().value] - }), /non-key attributes should not be specified when not using INCLUDE projection type/); - - test.done(); - }, - - 'error when adding a global secondary index with projection type INCLUDE, but with more than 20 non-key attributes'(test: Test) { - const stack = new Stack(); - const table = new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY, sortKey: TABLE_SORT_KEY }); - const gsiNonKeyAttributeGenerator = NON_KEY_ATTRIBUTE_GENERATOR(GSI_NON_KEY); - const gsiNonKeyAttributes: string[] = []; - for (let i = 0; i < 21; i++) { - gsiNonKeyAttributes.push(gsiNonKeyAttributeGenerator.next().value); - } - - test.throws(() => table.addGlobalSecondaryIndex({ - indexName: GSI_NAME, - partitionKey: GSI_PARTITION_KEY, - sortKey: GSI_SORT_KEY, - projectionType: ProjectionType.INCLUDE, - nonKeyAttributes: gsiNonKeyAttributes - }), /a maximum number of nonKeyAttributes across all of secondary indexes is 20/); - - test.done(); - }, - - 'error when adding a global secondary index with projection type INCLUDE, but with key attributes'(test: Test) { - const stack = new Stack(); - const table = new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY, sortKey: TABLE_SORT_KEY }); - - test.throws(() => table.addGlobalSecondaryIndex({ - indexName: GSI_NAME, - partitionKey: GSI_PARTITION_KEY, - sortKey: GSI_SORT_KEY, - projectionType: ProjectionType.INCLUDE, - nonKeyAttributes: [GSI_NON_KEY, TABLE_PARTITION_KEY.name] - // tslint:disable-next-line:max-line-length - }), /a key attribute, hashKey, is part of a list of non-key attributes, gsiNonKey,hashKey, which is not allowed since all key attributes are added automatically and this configuration causes stack creation failure/); - - test.done(); - }, - - 'error when adding a global secondary index with read or write capacity on a PAY_PER_REQUEST table'(test: Test) { - const stack = new Stack(); - const table = new Table(stack, CONSTRUCT_NAME, { - partitionKey: TABLE_PARTITION_KEY, - billingMode: BillingMode.PAY_PER_REQUEST - }); - - test.throws(() => table.addGlobalSecondaryIndex({ - indexName: GSI_NAME, - partitionKey: GSI_PARTITION_KEY, - sortKey: GSI_SORT_KEY, - readCapacity: 1 - })); - test.throws(() => table.addGlobalSecondaryIndex({ - indexName: GSI_NAME, - partitionKey: GSI_PARTITION_KEY, - sortKey: GSI_SORT_KEY, - writeCapacity: 1 - })); - test.throws(() => table.addGlobalSecondaryIndex({ - indexName: GSI_NAME, - partitionKey: GSI_PARTITION_KEY, - sortKey: GSI_SORT_KEY, - readCapacity: 1, - writeCapacity: 1 - })); - - test.done(); - }, - - 'when adding multiple global secondary indexes'(test: Test) { - const stack = new Stack(); - const table = new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY, sortKey: TABLE_SORT_KEY }); - const gsiGenerator = GSI_GENERATOR(); - for (let i = 0; i < 5; i++) { - table.addGlobalSecondaryIndex(gsiGenerator.next().value); - } - - expect(stack).to(haveResource('AWS::DynamoDB::Table', - { - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - { AttributeName: 'sortKey', AttributeType: 'N' }, - { AttributeName: 'gsiHashKey0', AttributeType: 'S' }, - { AttributeName: 'gsiHashKey1', AttributeType: 'S' }, - { AttributeName: 'gsiHashKey2', AttributeType: 'S' }, - { AttributeName: 'gsiHashKey3', AttributeType: 'S' }, - { AttributeName: 'gsiHashKey4', AttributeType: 'S' } - ], - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'sortKey', KeyType: 'RANGE' } - ], - ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 }, - GlobalSecondaryIndexes: [ - { - IndexName: 'MyGSI0', - KeySchema: [ - { AttributeName: 'gsiHashKey0', KeyType: 'HASH' }, - ], - Projection: { ProjectionType: 'ALL' }, - ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } - }, - { - IndexName: 'MyGSI1', - KeySchema: [ - { AttributeName: 'gsiHashKey1', KeyType: 'HASH' }, - ], - Projection: { ProjectionType: 'ALL' }, - ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } - }, - { - IndexName: 'MyGSI2', - KeySchema: [ - { AttributeName: 'gsiHashKey2', KeyType: 'HASH' }, - ], - Projection: { ProjectionType: 'ALL' }, - ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } - }, - { - IndexName: 'MyGSI3', - KeySchema: [ - { AttributeName: 'gsiHashKey3', KeyType: 'HASH' }, - ], - Projection: { ProjectionType: 'ALL' }, - ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } - }, - { - IndexName: 'MyGSI4', - KeySchema: [ - { AttributeName: 'gsiHashKey4', KeyType: 'HASH' }, - ], - Projection: { ProjectionType: 'ALL' }, - ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } - }, - ] - } - )); - test.done(); - }, - - 'when adding a global secondary index without specifying read and write capacity'(test: Test) { - const stack = new Stack(); - const table = new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY, sortKey: TABLE_SORT_KEY }); - - table.addGlobalSecondaryIndex({ - indexName: GSI_NAME, - partitionKey: GSI_PARTITION_KEY, - }); - - expect(stack).to(haveResource('AWS::DynamoDB::Table', - { - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - { AttributeName: 'sortKey', AttributeType: 'N' }, - { AttributeName: 'gsiHashKey', AttributeType: 'S' } - ], - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'sortKey', KeyType: 'RANGE' } - ], - ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 }, - GlobalSecondaryIndexes: [ - { - IndexName: 'MyGSI', - KeySchema: [ - { AttributeName: 'gsiHashKey', KeyType: 'HASH' }, - ], - Projection: { ProjectionType: 'ALL' }, - ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 } - } - ] - } - )); - test.done(); - }, - - 'when adding a local secondary index with hash + range key'(test: Test) { - const stack = new Stack(); - const table = new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY, sortKey: TABLE_SORT_KEY }); - - table.addLocalSecondaryIndex({ - indexName: LSI_NAME, - sortKey: LSI_SORT_KEY, - }); - - expect(stack).to(haveResource('AWS::DynamoDB::Table', - { - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - { AttributeName: 'sortKey', AttributeType: 'N' }, - { AttributeName: 'lsiSortKey', AttributeType: 'N' } - ], - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'sortKey', KeyType: 'RANGE' } - ], - ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 }, - LocalSecondaryIndexes: [ - { - IndexName: 'MyLSI', - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'lsiSortKey', KeyType: 'RANGE' } - ], - Projection: { ProjectionType: 'ALL' }, - } - ], - } - )); - test.done(); - }, - - 'when adding a local secondary index with projection type KEYS_ONLY'(test: Test) { - const stack = new Stack(); - const table = new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY, sortKey: TABLE_SORT_KEY }); - table.addLocalSecondaryIndex({ - indexName: LSI_NAME, - sortKey: LSI_SORT_KEY, - projectionType: ProjectionType.KEYS_ONLY - }); - - expect(stack).to(haveResource('AWS::DynamoDB::Table', - { - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - { AttributeName: 'sortKey', AttributeType: 'N' }, - { AttributeName: 'lsiSortKey', AttributeType: 'N' } - ], - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'sortKey', KeyType: 'RANGE' } - ], - ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 }, - LocalSecondaryIndexes: [ - { - IndexName: 'MyLSI', - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'lsiSortKey', KeyType: 'RANGE' } - ], - Projection: { ProjectionType: 'KEYS_ONLY' }, - } - ], - } - )); - test.done(); - }, - - 'when adding a local secondary index with projection type INCLUDE'(test: Test) { - const stack = new Stack(); - const table = new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY, sortKey: TABLE_SORT_KEY }); - const lsiNonKeyAttributeGenerator = NON_KEY_ATTRIBUTE_GENERATOR(LSI_NON_KEY); - table.addLocalSecondaryIndex({ - indexName: LSI_NAME, - sortKey: LSI_SORT_KEY, - projectionType: ProjectionType.INCLUDE, - nonKeyAttributes: [ lsiNonKeyAttributeGenerator.next().value, lsiNonKeyAttributeGenerator.next().value ] - }); - - expect(stack).to(haveResource('AWS::DynamoDB::Table', - { - AttributeDefinitions: [ - { AttributeName: 'hashKey', AttributeType: 'S' }, - { AttributeName: 'sortKey', AttributeType: 'N' }, - { AttributeName: 'lsiSortKey', AttributeType: 'N' } - ], - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'sortKey', KeyType: 'RANGE' } - ], - ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5 }, - LocalSecondaryIndexes: [ - { - IndexName: 'MyLSI', - KeySchema: [ - { AttributeName: 'hashKey', KeyType: 'HASH' }, - { AttributeName: 'lsiSortKey', KeyType: 'RANGE' } - ], - Projection: { NonKeyAttributes: ['lsiNonKey0', 'lsiNonKey1'], ProjectionType: 'INCLUDE' }, - } - ], - } - )); - test.done(); - }, - - 'error when adding more than 5 local secondary indexes'(test: Test) { - const stack = new Stack(); - const table = new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY, sortKey: TABLE_SORT_KEY }); - const lsiGenerator = LSI_GENERATOR(); - for (let i = 0; i < 5; i++) { - table.addLocalSecondaryIndex(lsiGenerator.next().value); - } - - test.throws(() => table.addLocalSecondaryIndex(lsiGenerator.next().value), - /a maximum number of local secondary index per table is 5/); - - test.done(); - }, - - 'error when adding a local secondary index with the name of a global secondary index'(test: Test) { - const stack = new Stack(); - const table = new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY, sortKey: TABLE_SORT_KEY }); - table.addGlobalSecondaryIndex({ - indexName: 'SecondaryIndex', - partitionKey: GSI_PARTITION_KEY - }); - - test.throws(() => table.addLocalSecondaryIndex({ - indexName: 'SecondaryIndex', - sortKey: LSI_SORT_KEY - }), /a duplicate index name, SecondaryIndex, is not allowed/); - - test.done(); - }, - - 'error when validating construct if a local secondary index exists without a sort key of the table'(test: Test) { - const stack = new Stack(); - const table = new Table(stack, CONSTRUCT_NAME, { partitionKey: TABLE_PARTITION_KEY }); - - table.addLocalSecondaryIndex({ - indexName: LSI_NAME, - sortKey: LSI_SORT_KEY - }); - - const errors = ConstructNode.validate(table.node); - - test.strictEqual(1, errors.length); - test.strictEqual('a sort key of the table must be specified to add local secondary indexes', errors[0].message); - - test.done(); - }, - - 'can enable Read AutoScaling'(test: Test) { - // GIVEN - const stack = new Stack(); - const table = new Table(stack, CONSTRUCT_NAME, { readCapacity: 42, writeCapacity: 1337, partitionKey: TABLE_PARTITION_KEY }); - - // WHEN - table.autoScaleReadCapacity({ minCapacity: 50, maxCapacity: 500 }).scaleOnUtilization({ targetUtilizationPercent: 75 }); - - // THEN - expect(stack).to(haveResource('AWS::ApplicationAutoScaling::ScalableTarget', { - MaxCapacity: 500, - MinCapacity: 50, - ScalableDimension: 'dynamodb:table:ReadCapacityUnits', - ServiceNamespace: 'dynamodb' - })); - expect(stack).to(haveResource('AWS::ApplicationAutoScaling::ScalingPolicy', { - PolicyType: 'TargetTrackingScaling', - TargetTrackingScalingPolicyConfiguration: { - PredefinedMetricSpecification: { PredefinedMetricType: 'DynamoDBReadCapacityUtilization' }, - TargetValue: 75 - } - })); - - test.done(); - }, - - 'can enable Write AutoScaling'(test: Test) { - // GIVEN - const stack = new Stack(); - const table = new Table(stack, CONSTRUCT_NAME, { readCapacity: 42, writeCapacity: 1337, partitionKey: TABLE_PARTITION_KEY }); - - // WHEN - table.autoScaleWriteCapacity({ minCapacity: 50, maxCapacity: 500 }).scaleOnUtilization({ targetUtilizationPercent: 75 }); - - // THEN - expect(stack).to(haveResource('AWS::ApplicationAutoScaling::ScalableTarget', { - MaxCapacity: 500, - MinCapacity: 50, - ScalableDimension: 'dynamodb:table:WriteCapacityUnits', - ServiceNamespace: 'dynamodb' - })); - expect(stack).to(haveResource('AWS::ApplicationAutoScaling::ScalingPolicy', { - PolicyType: 'TargetTrackingScaling', - TargetTrackingScalingPolicyConfiguration: { - PredefinedMetricSpecification: { PredefinedMetricType: 'DynamoDBWriteCapacityUtilization' }, - TargetValue: 75 - } - })); - - test.done(); - }, - - 'cannot enable AutoScaling twice on the same property'(test: Test) { - // GIVEN - const stack = new Stack(); - const table = new Table(stack, CONSTRUCT_NAME, { readCapacity: 42, writeCapacity: 1337, partitionKey: TABLE_PARTITION_KEY }); - table.autoScaleReadCapacity({ minCapacity: 50, maxCapacity: 500 }).scaleOnUtilization({ targetUtilizationPercent: 75 }); - - // WHEN - test.throws(() => { - table.autoScaleReadCapacity({ minCapacity: 50, maxCapacity: 500 }); - }); - - test.done(); - }, - - 'error when enabling AutoScaling on the PAY_PER_REQUEST table'(test: Test) { - // GIVEN - const stack = new Stack(); - const table = new Table(stack, CONSTRUCT_NAME, { billingMode: BillingMode.PAY_PER_REQUEST, partitionKey: TABLE_PARTITION_KEY }); - table.addGlobalSecondaryIndex({ - indexName: GSI_NAME, - partitionKey: GSI_PARTITION_KEY - }); - - // WHEN - test.throws(() => { - table.autoScaleReadCapacity({ minCapacity: 50, maxCapacity: 500 }); - }); - test.throws(() => { - table.autoScaleWriteCapacity({ minCapacity: 50, maxCapacity: 500 }); - }); - test.throws(() => table.autoScaleGlobalSecondaryIndexReadCapacity(GSI_NAME, { - minCapacity: 1, - maxCapacity: 5 - })); - - test.done(); - }, - - 'error when specifying Read Auto Scaling with invalid scalingTargetValue < 10'(test: Test) { - // GIVEN - const stack = new Stack(); - const table = new Table(stack, CONSTRUCT_NAME, { readCapacity: 42, writeCapacity: 1337, partitionKey: TABLE_PARTITION_KEY }); - - // THEN - test.throws(() => { - table.autoScaleReadCapacity({ minCapacity: 50, maxCapacity: 500 }).scaleOnUtilization({ targetUtilizationPercent: 5 }); - }); - - test.done(); - }, - - 'error when specifying Read Auto Scaling with invalid minimumCapacity'(test: Test) { - // GIVEN - const stack = new Stack(); - const table = new Table(stack, CONSTRUCT_NAME, { readCapacity: 42, writeCapacity: 1337, partitionKey: TABLE_PARTITION_KEY }); - - // THEN - test.throws(() => table.autoScaleReadCapacity({ minCapacity: 10, maxCapacity: 5 })); - - test.done(); - }, - - 'can autoscale on a schedule'(test: Test) { - // GIVEN - const stack = new Stack(); - const table = new Table(stack, CONSTRUCT_NAME, { - readCapacity: 42, - writeCapacity: 1337, - partitionKey: { name: 'Hash', type: AttributeType.STRING } - }); - - // WHEN - const scaling = table.autoScaleReadCapacity({ minCapacity: 1, maxCapacity: 100 }); - scaling.scaleOnSchedule('SaveMoneyByNotScalingUp', { - schedule: appscaling.Schedule.cron({}), - maxCapacity: 10 - }); - - // THEN - expect(stack).to(haveResource('AWS::ApplicationAutoScaling::ScalableTarget', { - ScheduledActions: [ - { - ScalableTargetAction: { "MaxCapacity": 10 }, - Schedule: "cron(* * * * ? *)", - ScheduledActionName: "SaveMoneyByNotScalingUp" - } - ] - })); - - test.done(); - }, - - 'metrics': { - 'Can use metricConsumedReadCapacityUnits on a Dynamodb Table'(test: Test) { - // GIVEN - const stack = new Stack(); - const table = new Table(stack, 'Table', { - partitionKey: { name: 'id', type: AttributeType.STRING } - }); - - // THEN - test.deepEqual(stack.resolve(table.metricConsumedReadCapacityUnits()), { - period: Duration.minutes(5), - dimensions: { TableName: { Ref: 'TableCD117FA1' } }, - namespace: 'AWS/DynamoDB', - metricName: 'ConsumedReadCapacityUnits', - statistic: 'Sum', - }); - - test.done(); - }, - - 'Can use metricConsumedWriteCapacityUnits on a Dynamodb Table'(test: Test) { - // GIVEN - const stack = new Stack(); - const table = new Table(stack, 'Table', { - partitionKey: { name: 'id', type: AttributeType.STRING } - }); - - // THEN - test.deepEqual(stack.resolve(table.metricConsumedWriteCapacityUnits()), { - period: Duration.minutes(5), - dimensions: { TableName: { Ref: 'TableCD117FA1' } }, - namespace: 'AWS/DynamoDB', - metricName: 'ConsumedWriteCapacityUnits', - statistic: 'Sum', - }); - - test.done(); - }, - - 'Can use metricSystemErrors on a Dynamodb Table'(test: Test) { - // GIVEN - const stack = new Stack(); - const table = new Table(stack, 'Table', { - partitionKey: { name: 'id', type: AttributeType.STRING } - }); - - // THEN - test.deepEqual(stack.resolve(table.metricSystemErrors()), { - period: Duration.minutes(5), - dimensions: { TableName: { Ref: 'TableCD117FA1' } }, - namespace: 'AWS/DynamoDB', - metricName: 'SystemErrors', - statistic: 'Sum', - }); - - test.done(); - }, - - 'Can use metricUserErrors on a Dynamodb Table'(test: Test) { - // GIVEN - const stack = new Stack(); - const table = new Table(stack, 'Table', { - partitionKey: { name: 'id', type: AttributeType.STRING } - }); - - // THEN - test.deepEqual(stack.resolve(table.metricUserErrors()), { - period: Duration.minutes(5), - dimensions: { TableName: { Ref: 'TableCD117FA1' } }, - namespace: 'AWS/DynamoDB', - metricName: 'UserErrors', - statistic: 'Sum', - }); - - test.done(); - }, - - 'Can use metricConditionalCheckFailedRequests on a Dynamodb Table'(test: Test) { - // GIVEN - const stack = new Stack(); - const table = new Table(stack, 'Table', { - partitionKey: { name: 'id', type: AttributeType.STRING } - }); - - // THEN - test.deepEqual(stack.resolve(table.metricConditionalCheckFailedRequests()), { - period: Duration.minutes(5), - dimensions: { TableName: { Ref: 'TableCD117FA1' } }, - namespace: 'AWS/DynamoDB', - metricName: 'ConditionalCheckFailedRequests', - statistic: 'Sum', - }); - - test.done(); - }, - - 'Can use metricSuccessfulRequestLatency on a Dynamodb Table'(test: Test) { - // GIVEN - const stack = new Stack(); - const table = new Table(stack, 'Table', { - partitionKey: { name: 'id', type: AttributeType.STRING } - }); - - // THEN - test.deepEqual(stack.resolve(table.metricSuccessfulRequestLatency()), { - period: Duration.minutes(5), - dimensions: { TableName: { Ref: 'TableCD117FA1' } }, - namespace: 'AWS/DynamoDB', - metricName: 'SuccessfulRequestLatency', - statistic: 'Average', - }); - - test.done(); - }, - - }, - - 'grants': { - - '"grant" allows adding arbitrary actions associated with this table resource'(test: Test) { - testGrant(test, - [ 'action1', 'action2' ], (p, t) => t.grant(p, 'dynamodb:action1', 'dynamodb:action2')); - }, - - '"grantReadData" allows the principal to read data from the table'(test: Test) { - testGrant(test, - [ 'BatchGetItem', 'GetRecords', 'GetShardIterator', 'Query', 'GetItem', 'Scan' ], (p, t) => t.grantReadData(p)); - }, - - '"grantWriteData" allows the principal to write data to the table'(test: Test) { - testGrant(test, [ - 'BatchWriteItem', 'PutItem', 'UpdateItem', 'DeleteItem' ], (p, t) => t.grantWriteData(p)); - }, - - '"grantReadWriteData" allows the principal to read/write data'(test: Test) { - testGrant(test, [ - 'BatchGetItem', 'GetRecords', 'GetShardIterator', 'Query', 'GetItem', 'Scan', - 'BatchWriteItem', 'PutItem', 'UpdateItem', 'DeleteItem' ], (p, t) => t.grantReadWriteData(p)); - }, - - '"grantFullAccess" allows the principal to perform any action on the table ("*")'(test: Test) { - testGrant(test, [ '*' ], (p, t) => t.grantFullAccess(p)); - }, - - '"Table.grantListStreams" allows principal to list all streams'(test: Test) { - // GIVEN - const stack = new Stack(); - const user = new iam.User(stack, 'user'); - - // WHEN - Table.grantListStreams(user); - - // THEN - expect(stack).to(haveResource('AWS::IAM::Policy', { - "PolicyDocument": { - "Statement": [ - { - "Action": "dynamodb:ListStreams", - "Effect": "Allow", - "Resource": "*" - } - ], - "Version": "2012-10-17" - }, - "Users": [ { "Ref": "user2C2B57AE" } ] - })); - test.done(); - }, - - '"grantTableListStreams" should fail if streaming is not enabled on table"'(test: Test) { - // GIVEN - const stack = new Stack(); - const table = new Table(stack, 'my-table', { - partitionKey: { - name: 'id', - type: AttributeType.STRING - } - }); - const user = new iam.User(stack, 'user'); - - // WHEN - test.throws(() => table.grantTableListStreams(user), /DynamoDB Streams must be enabled on the table my-table/); - - test.done(); - }, - - '"grantTableListStreams" allows principal to list all streams for this table'(test: Test) { - // GIVEN - const stack = new Stack(); - const table = new Table(stack, 'my-table', { - partitionKey: { - name: 'id', - type: AttributeType.STRING - }, - stream: StreamViewType.NEW_IMAGE - }); - const user = new iam.User(stack, 'user'); - - // WHEN - table.grantTableListStreams(user); - - // THEN - expect(stack).to(haveResource('AWS::IAM::Policy', { - "PolicyDocument": { - "Statement": [ - { - "Action": "dynamodb:ListStreams", - "Effect": "Allow", - "Resource": { "Fn::Join": [ "", [ { "Fn::GetAtt": [ "mytable0324D45C", "Arn" ] }, "/stream/*" ] ] } - } - ], - "Version": "2012-10-17" - }, - "Users": [ { "Ref": "user2C2B57AE" } ] - })); - test.done(); - }, - - '"grantStreamRead" should fail if streaming is not enabled on table"'(test: Test) { - // GIVEN - const stack = new Stack(); - const table = new Table(stack, 'my-table', { - partitionKey: { - name: 'id', - type: AttributeType.STRING - } - }); - const user = new iam.User(stack, 'user'); - - // WHEN - test.throws(() => table.grantStreamRead(user), /DynamoDB Streams must be enabled on the table my-table/); - - test.done(); - }, - - '"grantStreamRead" allows principal to read and describe the table stream"'(test: Test) { - // GIVEN - const stack = new Stack(); - const table = new Table(stack, 'my-table', { - partitionKey: { - name: 'id', - type: AttributeType.STRING - }, - stream: StreamViewType.NEW_IMAGE - }); - const user = new iam.User(stack, 'user'); - - // WHEN - table.grantStreamRead(user); - - // THEN - expect(stack).to(haveResource('AWS::IAM::Policy', { - "PolicyDocument": { - "Statement": [ - { - "Action": "dynamodb:ListStreams", - "Effect": "Allow", - "Resource": { "Fn::Join": [ "", [ { "Fn::GetAtt": [ "mytable0324D45C", "Arn" ] }, "/stream/*" ] ] } - }, - { - "Action": [ - "dynamodb:DescribeStream", - "dynamodb:GetRecords", - "dynamodb:GetShardIterator" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "mytable0324D45C", - "StreamArn" - ] - } - } - ], - "Version": "2012-10-17" - }, - "Users": [ { "Ref": "user2C2B57AE" } ] - })); - test.done(); - }, - 'if table has an index grant gives access to the index'(test: Test) { - // GIVEN - const stack = new Stack(); - - const table = new Table(stack, 'my-table', { partitionKey: { name: 'ID', type: AttributeType.STRING } }); - table.addGlobalSecondaryIndex({ indexName: 'MyIndex', partitionKey: { name: 'Age', type: AttributeType.NUMBER }}); - const user = new iam.User(stack, 'user'); - - // WHEN - table.grantReadData(user); - - // THEN - expect(stack).to(haveResource('AWS::IAM::Policy', { - "PolicyDocument": { - "Statement": [ - { - "Action": [ - 'dynamodb:BatchGetItem', - 'dynamodb:GetRecords', - 'dynamodb:GetShardIterator', - 'dynamodb:Query', - 'dynamodb:GetItem', - 'dynamodb:Scan' - ], - "Effect": "Allow", - "Resource": [ - { "Fn::GetAtt": ["mytable0324D45C", "Arn"] }, - { "Fn::Join": [ "", [ { "Fn::GetAtt": [ "mytable0324D45C", "Arn" ] }, "/index/*" ] ] } - ] - } - ], - "Version": "2012-10-17" - }, - "Users": [ { "Ref": "user2C2B57AE" } ] - })); - test.done(); - } - }, - - 'import': { - 'report error when importing an external/existing table from invalid arn missing resource name'(test: Test) { - const stack = new Stack(); - - const tableArn = 'arn:aws:dynamodb:us-east-1::table/'; - // WHEN - test.throws(() => Table.fromTableArn(stack, 'ImportedTable', tableArn), /ARN for DynamoDB table must be in the form: .../); - - test.done(); - }, - 'static fromTableArn(arn) allows importing an external/existing table from arn'(test: Test) { - const stack = new Stack(); - - const tableArn = 'arn:aws:dynamodb:us-east-1:11111111:table/MyTable'; - const table = Table.fromTableArn(stack, 'ImportedTable', tableArn); - - const role = new iam.Role(stack, 'NewRole', { - assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), - }); - table.grantReadData(role); - - // it is possible to obtain a permission statement for a ref - expect(stack).to(haveResource('AWS::IAM::Policy', { - "PolicyDocument": { - "Statement": [ - { - "Action": [ - 'dynamodb:BatchGetItem', - 'dynamodb:GetRecords', - 'dynamodb:GetShardIterator', - 'dynamodb:Query', - 'dynamodb:GetItem', - 'dynamodb:Scan' - ], - "Effect": "Allow", - "Resource": [ - tableArn, - { "Ref": "AWS::NoValue" } - ] - } - ], - "Version": "2012-10-17" - }, - "PolicyName": 'NewRoleDefaultPolicy90E8F49D', - "Roles": [ { "Ref": 'NewRole99763075' } ] - })); - - test.deepEqual(table.tableArn, tableArn); - test.deepEqual(stack.resolve(table.tableName), 'MyTable'); - test.done(); - }, - 'static fromTableName(name) allows importing an external/existing table from table name'(test: Test) { - const stack = new Stack(); - - const tableName = 'MyTable'; - const table = Table.fromTableName(stack, 'ImportedTable', tableName); - - const role = new iam.Role(stack, 'NewRole', { - assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), - }); - table.grantReadWriteData(role); - - // it is possible to obtain a permission statement for a ref - expect(stack).to(haveResource('AWS::IAM::Policy', { - "PolicyDocument": { - "Statement": [ - { - "Action": [ - 'dynamodb:BatchGetItem', - 'dynamodb:GetRecords', - 'dynamodb:GetShardIterator', - 'dynamodb:Query', - 'dynamodb:GetItem', - 'dynamodb:Scan', - 'dynamodb:BatchWriteItem', - 'dynamodb:PutItem', - 'dynamodb:UpdateItem', - 'dynamodb:DeleteItem' - ], - "Effect": "Allow", - "Resource": [ - { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":dynamodb:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":table/MyTable" - ] - ] - }, - { - "Ref": "AWS::NoValue" - } - ] - } - ], - "Version": "2012-10-17" - }, - "PolicyName": 'NewRoleDefaultPolicy90E8F49D', - "Roles": [ { "Ref": 'NewRole99763075' } ] - })); - - test.deepEqual(table.tableArn, 'arn:${Token[AWS::Partition.3]}:dynamodb:${Token[AWS::Region.4]}:${Token[AWS::AccountId.0]}:table/MyTable'); - test.deepEqual(stack.resolve(table.tableName), tableName); - test.done(); - }, - 'stream permissions on imported tables': { - 'throw if no tableStreamArn is specified'(test: Test) { - const stack = new Stack(); - - const tableName = 'MyTable'; - const table = Table.fromTableAttributes(stack, 'ImportedTable', { tableName }); - - const role = new iam.Role(stack, 'NewRole', { - assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), - }); - - test.throws(() => table.grantTableListStreams(role), /DynamoDB Streams must be enabled on the table/); - test.throws(() => table.grantStreamRead(role), /DynamoDB Streams must be enabled on the table/); - - test.done(); - }, - - 'creates the correct list streams grant'(test: Test) { - const stack = new Stack(); - - const tableName = 'MyTable'; - const tableStreamArn = 'arn:foo:bar:baz:TrustMeThisIsATableStream'; - const table = Table.fromTableAttributes(stack, 'ImportedTable', { tableName, tableStreamArn }); - - const role = new iam.Role(stack, 'NewRole', { - assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), - }); - - test.notEqual(table.grantTableListStreams(role), null); - - expect(stack).to(haveResource('AWS::IAM::Policy', { - PolicyDocument: { - Statement: [ - { - Action: "dynamodb:ListStreams", - Effect: 'Allow', - Resource: stack.resolve(`${table.tableArn}/stream/*`), - }, - ], - Version: '2012-10-17' - }, - Roles: [stack.resolve(role.roleName)] - })); - - test.done(); - }, - - 'creates the correct stream read grant'(test: Test) { - const stack = new Stack(); - - const tableName = 'MyTable'; - const tableStreamArn = 'arn:foo:bar:baz:TrustMeThisIsATableStream'; - const table = Table.fromTableAttributes(stack, 'ImportedTable', { tableName, tableStreamArn }); - - const role = new iam.Role(stack, 'NewRole', { - assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), - }); - - test.notEqual(table.grantStreamRead(role), null); - - expect(stack).to(haveResource('AWS::IAM::Policy', { - PolicyDocument: { - Statement: [ - { - Action: "dynamodb:ListStreams", - Effect: 'Allow', - Resource: stack.resolve(`${table.tableArn}/stream/*`), - }, - { - Action: ['dynamodb:DescribeStream', 'dynamodb:GetRecords', 'dynamodb:GetShardIterator'], - Effect: 'Allow', - Resource: tableStreamArn, - } - ], - Version: '2012-10-17' - }, - Roles: [stack.resolve(role.roleName)] - })); - - test.done(); - }, - } - }, - - 'global': { - 'create replicas'(test: Test) { - // GIVEN - const stack = new Stack(); - - // WHEN - new Table(stack, 'Table', { - partitionKey: { - name: 'id', - type: AttributeType.STRING - }, - replicationRegions: [ - 'eu-west-2', - 'eu-central-1' - ], - }); - - // THEN - expect(stack).to(haveResource('Custom::DynamoDBReplica', { - Properties: { - ServiceToken: { - 'Fn::GetAtt': [ - 'awscdkawsdynamodbReplicaProviderNestedStackawscdkawsdynamodbReplicaProviderNestedStackResource18E3F12D', - 'Outputs.awscdkawsdynamodbReplicaProviderframeworkonEventF9504691Arn' - ] - }, - TableName: { - Ref: 'TableCD117FA1' - }, - Region: 'eu-west-2' - }, - Condition: 'TableStackRegionNotEqualseuwest2A03859E7' - }, ResourcePart.CompleteDefinition)); - - expect(stack).to(haveResource('Custom::DynamoDBReplica', { - Properties: { - ServiceToken: { - 'Fn::GetAtt': [ - 'awscdkawsdynamodbReplicaProviderNestedStackawscdkawsdynamodbReplicaProviderNestedStackResource18E3F12D', - 'Outputs.awscdkawsdynamodbReplicaProviderframeworkonEventF9504691Arn' - ] - }, - TableName: { - Ref: 'TableCD117FA1' - }, - Region: 'eu-central-1' - }, - Condition: 'TableStackRegionNotEqualseucentral199D46FC0' - }, ResourcePart.CompleteDefinition)); - - test.deepEqual(SynthUtils.toCloudFormation(stack).Conditions, { - TableStackRegionNotEqualseuwest2A03859E7: { - 'Fn::Not': [ - { 'Fn::Equals': [ 'eu-west-2', { Ref: 'AWS::Region' } ] } - ] - }, - TableStackRegionNotEqualseucentral199D46FC0: { - 'Fn::Not': [ - { 'Fn::Equals': [ 'eu-central-1', { Ref: 'AWS::Region' } ] } - ] - } - }); - - test.done(); - }, - - 'throws with PROVISIONED billing mode'(test: Test) { - // GIVEN - const stack = new Stack(); - - // THEN - test.throws(() => new Table(stack, 'Table', { - partitionKey: { - name: 'id', - type: AttributeType.STRING - }, - replicationRegions: [ - 'eu-west-2', - 'eu-central-1' - ], - billingMode: BillingMode.PROVISIONED, - }), /`PAY_PER_REQUEST`/); - - test.done(); - }, - - 'throws when stream is set and not set to NEW_AND_OLD_IMAGES'(test: Test) { - // GIVEN - const stack = new Stack(); - - // THEN - test.throws(() => new Table(stack, 'Table', { - partitionKey: { - name: 'id', - type: AttributeType.STRING - }, - replicationRegions: [ - 'eu-west-2', - 'eu-central-1' - ], - stream: StreamViewType.OLD_IMAGE, - }), /`NEW_AND_OLD_IMAGES`/); - - test.done(); - }, - - 'throws with replica in same region as stack'(test: Test) { - // GIVEN - const app = new App(); - const stack = new Stack(app, 'Stack', { - env: { region: 'us-east-1' } - }); - - // THEN - test.throws(() => new Table(stack, 'Table', { - partitionKey: { - name: 'id', - type: AttributeType.STRING - }, - replicationRegions: [ - 'eu-west-1', - 'us-east-1', - 'eu-west-2', - ], - }), /`replicationRegions` cannot include the region where this stack is deployed/); - - test.done(); - }, - - 'no conditions when region is known'(test: Test) { - // GIVEN - const app = new App(); - const stack = new Stack(app, 'Stack', { - env: { region: 'eu-west-1' } - }); - - // WHEN - new Table(stack, 'Table', { - partitionKey: { - name: 'id', - type: AttributeType.STRING - }, - replicationRegions: [ - 'eu-west-2', - 'eu-central-1' - ], - }); - - // THEN - test.equal(SynthUtils.toCloudFormation(stack).Conditions, undefined); - - test.done(); - }, - } -}; - -function testGrant(test: Test, expectedActions: string[], invocation: (user: iam.IPrincipal, table: Table) => void) { - // GIVEN - const stack = new Stack(); - const table = new Table(stack, 'my-table', { partitionKey: { name: 'ID', type: AttributeType.STRING } }); - const user = new iam.User(stack, 'user'); - - // WHEN - invocation(user, table); - - // THEN - const action = expectedActions.length > 1 ? expectedActions.map(a => `dynamodb:${a}`) : `dynamodb:${expectedActions[0]}`; - expect(stack).to(haveResource('AWS::IAM::Policy', { - "PolicyDocument": { - "Statement": [ - { - "Action": action, - "Effect": "Allow", - "Resource": [ - { "Fn::GetAtt": [ "mytable0324D45C", "Arn" ] }, - { "Ref" : "AWS::NoValue" } - ] - } - ], - "Version": "2012-10-17" - }, - "Users": [ { "Ref": "user2C2B57AE" } ] - })); - test.done(); -} diff --git a/packages/@aws-cdk/aws-dynamodb/test/test.replica-provider.ts b/packages/@aws-cdk/aws-dynamodb/test/test.replica-provider.ts deleted file mode 100644 index ada04b41c4301..0000000000000 --- a/packages/@aws-cdk/aws-dynamodb/test/test.replica-provider.ts +++ /dev/null @@ -1,183 +0,0 @@ -import { OnEventRequest } from '@aws-cdk/custom-resources/lib/provider-framework/types'; -import * as AWS from 'aws-sdk-mock'; -import { Test } from 'nodeunit'; -import * as sinon from 'sinon'; -import { isCompleteHandler, onEventHandler } from '../lib/replica-handler'; - -AWS.setSDK(require.resolve('aws-sdk')); - -const createEvent: OnEventRequest = { - RequestType: 'Create', - ResourceProperties: { - TableName: 'my-table', - Region: 'eu-west-2', - ServiceToken: 'token' - }, - ServiceToken: 'token', - ResponseURL: 'url', - LogicalResourceId: 'logical-id', - RequestId: 'request-id', - StackId: 'stack-id', - ResourceType: 'resource-type' -}; - -export = { - 'setUp'(callback: any) { - process.env.USE_NORMAL_SDK = 'true'; - callback(); - }, - - 'tearDown'(callback: any) { - delete process.env.USE_NORMAL_SDK; - AWS.restore(); - callback(); - }, - - async 'on event'(test: Test) { - const updateTableMock = sinon.fake.resolves({}); - - AWS.mock('DynamoDB', 'updateTable', updateTableMock); - - const data = await onEventHandler(createEvent); - - sinon.assert.calledWith(updateTableMock, { - TableName: 'my-table', - ReplicaUpdates: [ - { - Create: { - RegionName: 'eu-west-2' - } - }, - ] - }); - - test.deepEqual(data, { - PhysicalResourceId: 'eu-west-2' - }); - - test.done(); - }, - - async 'on event does not call updateTable for Update requests'(test: Test) { - const updateTableMock = sinon.fake.resolves({}); - - AWS.mock('DynamoDB', 'updateTable', updateTableMock); - - const data = await onEventHandler({ - ...createEvent, - RequestType: 'Update', - }); - - sinon.assert.notCalled(updateTableMock); - - test.deepEqual(data, { - PhysicalResourceId: 'eu-west-2' - }); - - test.done(); - }, - - async 'is complete for create returns false without replicas'(test: Test) { - const describeTableMock = sinon.fake.resolves({ - Table: {} - }); - - AWS.mock('DynamoDB', 'describeTable', describeTableMock); - - const data = await isCompleteHandler(createEvent); - - test.deepEqual(data, { IsComplete: false }); - - test.done(); - }, - - async 'is complete for create returns false when replica is not active'(test: Test) { - const describeTableMock = sinon.fake.resolves({ - Table: { - Replicas: [ - { - RegionName: 'eu-west-2', - ReplicaStatus: 'CREATING' - } - ] - } - }); - - AWS.mock('DynamoDB', 'describeTable', describeTableMock); - - const data = await isCompleteHandler(createEvent); - - test.deepEqual(data, { IsComplete: false }); - - test.done(); - }, - - async 'is complete for create returns false when table is not active'(test: Test) { - const describeTableMock = sinon.fake.resolves({ - Table: { - Replicas: [ - { - RegionName: 'eu-west-2', - ReplicaStatus: 'ACTIVE' - } - ], - TableStatus: 'UPDATING', - } - }); - - AWS.mock('DynamoDB', 'describeTable', describeTableMock); - - const data = await isCompleteHandler(createEvent); - - test.deepEqual(data, { IsComplete: false }); - - test.done(); - }, - - async 'is complete for create returns true when replica is active'(test: Test) { - const describeTableMock = sinon.fake.resolves({ - Table: { - Replicas: [ - { - RegionName: 'eu-west-2', - ReplicaStatus: 'ACTIVE' - } - ], - TableStatus: 'ACTIVE', - } - }); - - AWS.mock('DynamoDB', 'describeTable', describeTableMock); - - const data = await isCompleteHandler(createEvent); - - test.deepEqual(data, { IsComplete: true }); - - test.done(); - }, - - async 'is complete for delete returns true when replica is gone'(test: Test) { - const describeTableMock = sinon.fake.resolves({ - Table: { - Replicas: [ - { - RegionName: 'eu-west-1', - ReplicaStatus: 'ACTIVE' - } - ], - TableStatus: 'ACTIVE', - } - }); - - AWS.mock('DynamoDB', 'describeTable', describeTableMock); - - const data = await isCompleteHandler({ - ...createEvent, - RequestType: 'Delete' - }); - - test.deepEqual(data, { IsComplete: true }); - - test.done(); - }, -}; From 2b9a8a43ff98b49768b376ad460b2ad25ffd29db Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2020 18:45:18 +0000 Subject: [PATCH 39/53] chore(deps-dev): bump jszip from 3.2.2 to 3.3.0 (#7123) Bumps [jszip](https://github.com/Stuk/jszip) from 3.2.2 to 3.3.0. - [Release notes](https://github.com/Stuk/jszip/releases) - [Changelog](https://github.com/Stuk/jszip/blob/master/CHANGES.md) - [Commits](https://github.com/Stuk/jszip/compare/v3.2.2...v3.3.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- packages/cdk-assets/package.json | 2 +- yarn.lock | 889 ++++++++++++++++++++++++++++++- 2 files changed, 873 insertions(+), 18 deletions(-) diff --git a/packages/cdk-assets/package.json b/packages/cdk-assets/package.json index 63af355fce9f2..5064c412125b7 100644 --- a/packages/cdk-assets/package.json +++ b/packages/cdk-assets/package.json @@ -35,7 +35,7 @@ "@types/node": "^10.17.18", "@types/yargs": "^15.0.4", "@types/jszip": "^3.1.7", - "jszip": "^3.2.2", + "jszip": "^3.3.0", "cdk-build-tools": "0.0.0", "jest": "^24.9.0", "mock-fs": "^4.11.0", diff --git a/yarn.lock b/yarn.lock index ec01a35402adc..7b30930e19afd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -328,6 +328,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" +"@babel/plugin-syntax-bigint@^7.0.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + "@babel/plugin-syntax-dynamic-import@^7.8.0": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" @@ -756,6 +763,11 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + "@cnakazawa/watch@^1.0.3": version "1.0.4" resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" @@ -867,6 +879,16 @@ chalk "^2.0.1" slash "^2.0.0" +"@jest/console@^25.2.3": + version "25.2.3" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-25.2.3.tgz#38ac19b916ff61457173799239472659e1a67c39" + integrity sha512-k+37B1aSvOt9tKHWbZZSOy1jdgzesB0bj96igCVUG1nAH1W5EoUfgc5EXbBVU08KSLvkVdWopLXaO3xfVGlxtQ== + dependencies: + "@jest/source-map" "^25.2.1" + chalk "^3.0.0" + jest-util "^25.2.3" + slash "^3.0.0" + "@jest/core@^24.9.0": version "24.9.0" resolved "https://registry.yarnpkg.com/@jest/core/-/core-24.9.0.tgz#2ceccd0b93181f9c4850e74f2a9ad43d351369c4" @@ -901,6 +923,40 @@ slash "^2.0.0" strip-ansi "^5.0.0" +"@jest/core@^25.2.4": + version "25.2.4" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-25.2.4.tgz#382ef80369d3311f1df79db1ee19e958ae95cdad" + integrity sha512-WcWYShl0Bqfcb32oXtjwbiR78D/djhMdJW+ulp4/bmHgeODcsieqUJfUH+kEv8M7VNV77E6jds5aA+WuGh1nmg== + dependencies: + "@jest/console" "^25.2.3" + "@jest/reporters" "^25.2.4" + "@jest/test-result" "^25.2.4" + "@jest/transform" "^25.2.4" + "@jest/types" "^25.2.3" + ansi-escapes "^4.2.1" + chalk "^3.0.0" + exit "^0.1.2" + graceful-fs "^4.2.3" + jest-changed-files "^25.2.3" + jest-config "^25.2.4" + jest-haste-map "^25.2.3" + jest-message-util "^25.2.4" + jest-regex-util "^25.2.1" + jest-resolve "^25.2.3" + jest-resolve-dependencies "^25.2.4" + jest-runner "^25.2.4" + jest-runtime "^25.2.4" + jest-snapshot "^25.2.4" + jest-util "^25.2.3" + jest-validate "^25.2.3" + jest-watcher "^25.2.4" + micromatch "^4.0.2" + p-each-series "^2.1.0" + realpath-native "^2.0.0" + rimraf "^3.0.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + "@jest/environment@^24.9.0": version "24.9.0" resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-24.9.0.tgz#21e3afa2d65c0586cbd6cbefe208bafade44ab18" @@ -911,6 +967,15 @@ "@jest/types" "^24.9.0" jest-mock "^24.9.0" +"@jest/environment@^25.2.4": + version "25.2.4" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-25.2.4.tgz#74f4d8dd87b427434d0b822cde37bc0e78f3e28b" + integrity sha512-wA4xlhD19/gukkDpJ5HQsTle0pgnzI5qMFEjw267lpTDC8d9N7Ihqr5pI+l0p8Qn1SQhai+glSqxrGdzKy4jxw== + dependencies: + "@jest/fake-timers" "^25.2.4" + "@jest/types" "^25.2.3" + jest-mock "^25.2.3" + "@jest/fake-timers@^24.9.0": version "24.9.0" resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-24.9.0.tgz#ba3e6bf0eecd09a636049896434d306636540c93" @@ -920,6 +985,17 @@ jest-message-util "^24.9.0" jest-mock "^24.9.0" +"@jest/fake-timers@^25.2.4": + version "25.2.4" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-25.2.4.tgz#6821b6edde74fda2a42467ae92cc93095d4c9527" + integrity sha512-oC1TJiwfMcBttVN7Wz+VZnqEAgYTiEMu0QLOXpypR89nab0uCB31zm/QeBZddhSstn20qe3yqOXygp6OwvKT/Q== + dependencies: + "@jest/types" "^25.2.3" + jest-message-util "^25.2.4" + jest-mock "^25.2.3" + jest-util "^25.2.3" + lolex "^5.0.0" + "@jest/reporters@^24.9.0": version "24.9.0" resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-24.9.0.tgz#86660eff8e2b9661d042a8e98a028b8d631a5b43" @@ -947,6 +1023,37 @@ source-map "^0.6.0" string-length "^2.0.0" +"@jest/reporters@^25.2.4": + version "25.2.4" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-25.2.4.tgz#aa01c20aab217150d3a6080d5c98ce0bf34b17ed" + integrity sha512-VHbLxM03jCc+bTLOluW/IqHR2G0Cl0iATwIQbuZtIUast8IXO4fD0oy4jpVGpG5b20S6REA8U3BaQoCW/CeVNQ== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^25.2.3" + "@jest/test-result" "^25.2.4" + "@jest/transform" "^25.2.4" + "@jest/types" "^25.2.3" + chalk "^3.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.2" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^4.0.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.0.0" + jest-haste-map "^25.2.3" + jest-resolve "^25.2.3" + jest-util "^25.2.3" + jest-worker "^25.2.1" + slash "^3.0.0" + source-map "^0.6.0" + string-length "^3.1.0" + terminal-link "^2.0.0" + v8-to-istanbul "^4.0.1" + optionalDependencies: + node-notifier "^6.0.0" + "@jest/source-map@^24.3.0", "@jest/source-map@^24.9.0": version "24.9.0" resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-24.9.0.tgz#0e263a94430be4b41da683ccc1e6bffe2a191714" @@ -956,6 +1063,15 @@ graceful-fs "^4.1.15" source-map "^0.6.0" +"@jest/source-map@^25.2.1": + version "25.2.1" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-25.2.1.tgz#b62ecf8ae76170b08eff8859b56eb7576df34ab8" + integrity sha512-PgScGJm1U27+9Te/cxP4oUFqJ2PX6NhBL2a6unQ7yafCgs8k02c0LSyjSIx/ao0AwcAdCczfAPDf5lJ7zoB/7A== + dependencies: + callsites "^3.0.0" + graceful-fs "^4.2.3" + source-map "^0.6.0" + "@jest/test-result@^24.9.0": version "24.9.0" resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-24.9.0.tgz#11796e8aa9dbf88ea025757b3152595ad06ba0ca" @@ -965,6 +1081,17 @@ "@jest/types" "^24.9.0" "@types/istanbul-lib-coverage" "^2.0.0" +"@jest/test-result@^25.2.4": + version "25.2.4" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-25.2.4.tgz#8fc9eac58e82eb2a82e4058e68c3814f98f59cf5" + integrity sha512-AI7eUy+q2lVhFnaibDFg68NGkrxVWZdD6KBr9Hm6EvN0oAe7GxpEwEavgPfNHQjU2mi6g+NsFn/6QPgTUwM1qg== + dependencies: + "@jest/console" "^25.2.3" + "@jest/transform" "^25.2.4" + "@jest/types" "^25.2.3" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + "@jest/test-sequencer@^24.9.0": version "24.9.0" resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz#f8f334f35b625a4f2f355f2fe7e6036dad2e6b31" @@ -975,6 +1102,16 @@ jest-runner "^24.9.0" jest-runtime "^24.9.0" +"@jest/test-sequencer@^25.2.4": + version "25.2.4" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-25.2.4.tgz#28364aeddec140c696324114f63570f3de536c87" + integrity sha512-TEZm/Rkd6YgskdpTJdYLBtu6Gc11tfWPuSpatq0duH77ekjU8dpqX2zkPdY/ayuHxztV5LTJoV5BLtI9mZfXew== + dependencies: + "@jest/test-result" "^25.2.4" + jest-haste-map "^25.2.3" + jest-runner "^25.2.4" + jest-runtime "^25.2.4" + "@jest/transform@^24.9.0": version "24.9.0" resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-24.9.0.tgz#4ae2768b296553fadab09e9ec119543c90b16c56" @@ -997,6 +1134,28 @@ source-map "^0.6.1" write-file-atomic "2.4.1" +"@jest/transform@^25.2.4": + version "25.2.4" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-25.2.4.tgz#34336f37f13f62f7d1f5b93d5d150ba9eb3e11b9" + integrity sha512-6eRigvb+G6bs4kW5j1/y8wu4nCrmVuIe0epPBbiWaYlwawJ8yi1EIyK3d/btDqmBpN5GpN4YhR6iPPnDmkYdTA== + dependencies: + "@babel/core" "^7.1.0" + "@jest/types" "^25.2.3" + babel-plugin-istanbul "^6.0.0" + chalk "^3.0.0" + convert-source-map "^1.4.0" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.2.3" + jest-haste-map "^25.2.3" + jest-regex-util "^25.2.1" + jest-util "^25.2.3" + micromatch "^4.0.2" + pirates "^4.0.1" + realpath-native "^2.0.0" + slash "^3.0.0" + source-map "^0.6.1" + write-file-atomic "^3.0.0" + "@jest/types@^24.9.0": version "24.9.0" resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.9.0.tgz#63cb26cb7500d069e5a389441a7c6ab5e909fc59" @@ -1016,6 +1175,16 @@ "@types/yargs" "^15.0.0" chalk "^3.0.0" +"@jest/types@^25.2.3": + version "25.2.3" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-25.2.3.tgz#035c4fb94e2da472f359ff9a211915d59987f6b6" + integrity sha512-6oLQwO9mKif3Uph3RX5J1i3S7X7xtDHWBaaaoeKw8hOzV6YUd0qDcYcHZ6QXMHDIzSr7zzrEa51o2Ovlj6AtKQ== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^1.1.1" + "@types/yargs" "^15.0.0" + chalk "^3.0.0" + "@jsii/spec@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@jsii/spec/-/spec-1.1.0.tgz#1e7093807d191970bf2b22c537b905e298091d1f" @@ -1967,7 +2136,7 @@ "@types/minimatch" "*" "@types/node" "*" -"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": version "2.0.1" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff" integrity sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg== @@ -2056,6 +2225,11 @@ resolved "https://registry.yarnpkg.com/@types/nodeunit/-/nodeunit-0.0.30.tgz#48d2c2719a118c7723b83306c3e800b11a2bf678" integrity sha1-SNLCcZoRjHcjuDMGw+gAsRor9ng= +"@types/prettier@^1.19.0": + version "1.19.1" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-1.19.1.tgz#33509849f8e679e4add158959fdb086440e9553f" + integrity sha512-5qOlnZscTn4xxM5MeGXAMOsIOIKIbh9e85zJWfBRVPlRMEVawzoPhINYbRGkBZCI8LxvBe7tJCdWiarA99OZfQ== + "@types/promptly@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/promptly/-/promptly-3.0.0.tgz#6978ffa3abb1796ad18ec31441d6b7629d96433c" @@ -2230,7 +2404,7 @@ abbrev@1: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== -acorn-globals@^4.1.0, acorn-globals@^4.3.0: +acorn-globals@^4.1.0, acorn-globals@^4.3.0, acorn-globals@^4.3.2: version "4.3.4" resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.4.tgz#9fa1926addc11c97308c4e66d7add0d40c3272e7" integrity sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A== @@ -2258,7 +2432,7 @@ acorn@^6.0.1, acorn@^6.0.4: resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA== -acorn@^7.1.1: +acorn@^7.1.0, acorn@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.1.tgz#e35668de0b402f359de515c5482a1ab9f89a69bf" integrity sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg== @@ -2384,6 +2558,14 @@ anymatch@^2.0.0: micromatch "^3.1.4" normalize-path "^2.1.1" +anymatch@^3.0.3: + version "3.1.1" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" + integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + append-transform@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-1.0.0.tgz#046a52ae582a228bd72f58acfbe2967c678759ab" @@ -2671,6 +2853,19 @@ babel-jest@^24.9.0: chalk "^2.4.2" slash "^2.0.0" +babel-jest@^25.2.4: + version "25.2.4" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-25.2.4.tgz#b21b68d3af8f161c3e6e501e91f0dea8e652e344" + integrity sha512-+yDzlyJVWrqih9i2Cvjpt7COaN8vUwCsKGtxJLzg6I0xhxD54K8mvDUCliPKLufyzHh/c5C4MRj4Vk7VMjOjIg== + dependencies: + "@jest/transform" "^25.2.4" + "@jest/types" "^25.2.3" + "@types/babel__core" "^7.1.0" + babel-plugin-istanbul "^6.0.0" + babel-preset-jest "^25.2.1" + chalk "^3.0.0" + slash "^3.0.0" + babel-plugin-dynamic-import-node@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz#f00f507bdaa3c3e3ff6e7e5e98d90a7acab96f7f" @@ -2688,6 +2883,17 @@ babel-plugin-istanbul@^5.1.0: istanbul-lib-instrument "^3.3.0" test-exclude "^5.2.3" +babel-plugin-istanbul@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz#e159ccdc9af95e0b570c75b4573b7c34d671d765" + integrity sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ== + 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" + test-exclude "^6.0.0" + babel-plugin-jest-hoist@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz#4f837091eb407e01447c8843cbec546d0002d756" @@ -2695,6 +2901,13 @@ babel-plugin-jest-hoist@^24.9.0: dependencies: "@types/babel__traverse" "^7.0.6" +babel-plugin-jest-hoist@^25.2.1: + version "25.2.1" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-25.2.1.tgz#d0003a1f3d5caa281e1107fe03bbf16b799f9955" + integrity sha512-HysbCQfJhxLlyxDbKcB2ucGYV0LjqK4h6dBoI3RtFuOxTiTWK6XGZMsHb0tGh8iJdV4hC6Z2GCHzVvDeh9i0lQ== + dependencies: + "@types/babel__traverse" "^7.0.6" + babel-preset-jest@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz#192b521e2217fb1d1f67cf73f70c336650ad3cdc" @@ -2703,6 +2916,15 @@ babel-preset-jest@^24.9.0: "@babel/plugin-syntax-object-rest-spread" "^7.0.0" babel-plugin-jest-hoist "^24.9.0" +babel-preset-jest@^25.2.1: + version "25.2.1" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-25.2.1.tgz#4ccd0e577f69aa11b71806edfe8b25a5c3ac93a2" + integrity sha512-zXHJBM5iR8oEO4cvdF83AQqqJf3tJrXy3x8nfu2Nlqvn4cneg4Ca8M7cQvC5S9BzDDy1O0tZ9iXru9J6E3ym+A== + dependencies: + "@babel/plugin-syntax-bigint" "^7.0.0" + "@babel/plugin-syntax-object-rest-spread" "^7.0.0" + babel-plugin-jest-hoist "^25.2.1" + babel-runtime@^6.11.6, babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" @@ -2828,6 +3050,13 @@ braces@^2.3.1, braces@^2.3.2: split-string "^3.0.2" to-regex "^3.0.1" +braces@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + brfs@^1.2.0: version "1.6.1" resolved "https://registry.yarnpkg.com/brfs/-/brfs-1.6.1.tgz#b78ce2336d818e25eea04a0947cba6d4fb8849c3" @@ -3377,6 +3606,11 @@ codemaker@^1.1.0: decamelize "^1.2.0" fs-extra "^8.1.0" +collect-v8-coverage@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.0.tgz#150ee634ac3650b71d9c985eb7f608942334feb1" + integrity sha512-VKIhJgvk8E1W28m5avZ2Gv2Ruv5YiF56ug2oclvaG9md69BuZImMG2sk9g7QNKLUbtYAKQjXjYxbYZVUlMMKmQ== + collection-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" @@ -4094,11 +4328,16 @@ csso@^4.0.2: dependencies: css-tree "1.0.0-alpha.37" -cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0", cssom@^0.3.4: +cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0", cssom@^0.3.4, cssom@~0.3.6: version "0.3.8" resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== +cssom@^0.4.1: + version "0.4.4" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" + integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== + cssstyle@^1.0.0, cssstyle@^1.1.1: version "1.4.0" resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-1.4.0.tgz#9d31328229d3c565c61e586b02041a28fccdccf1" @@ -4106,6 +4345,13 @@ cssstyle@^1.0.0, cssstyle@^1.1.1: dependencies: cssom "0.3.x" +cssstyle@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.2.0.tgz#e4c44debccd6b7911ed617a4395e5754bba59992" + integrity sha512-sEb3XFPx3jNnCAMtqrXPDeSgQr+jojtCeNf8cvMNMh1cG970+lljssvQDzPq6lmmJu2Vhqood/gtEomBiHOGnA== + dependencies: + cssom "~0.3.6" + currently-unhandled@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" @@ -4253,6 +4499,11 @@ deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= +deepmerge@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" + integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== + default-require-extensions@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-2.0.0.tgz#f5f8fbb18a7d6d50b21f641f649ebb522cfe24f7" @@ -4355,7 +4606,7 @@ detect-indent@^5.0.0: resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" integrity sha1-OHHMCmoALow+Wzz38zYmRnXwa50= -detect-newline@3.1.0: +detect-newline@3.1.0, detect-newline@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== @@ -4383,6 +4634,11 @@ diff-sequences@^25.1.0: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-25.1.0.tgz#fd29a46f1c913fd66c22645dc75bffbe43051f32" integrity sha512-nFIfVk5B/NStCsJ+zaPO4vYuLjlzQ6uFvPxzYyHlejNZ/UGa7G/n7peOXVrVNvRuyfstt+mZQYGpjxg9Z6N8Kw== +diff-sequences@^25.2.1: + version "25.2.1" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-25.2.1.tgz#fcfe8aa07dd9b0c648396a478dabca8e76c6ab27" + integrity sha512-foe7dXnGlSh3jR1ovJmdv+77VQj98eKCHHwJPbZ2eEf0fHwKbkZicpPxEch9smZ+n2dnF6QFwkOQdLq9hpeJUg== + diff@^1.3.2: version "1.4.0" resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" @@ -4955,6 +5211,22 @@ execa@^1.0.0: signal-exit "^3.0.0" strip-eof "^1.0.0" +execa@^3.2.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-3.4.0.tgz#c08ed4550ef65d858fac269ffc8572446f37eb89" + integrity sha512-r9vdGQk4bmCuK1yKQu1KTwcT2zwfWdbdaXfCtAh+5nU/4fSX+JAb7vZGvI5naJrQlvONrEB20jeruESI69530g== + dependencies: + cross-spawn "^7.0.0" + get-stream "^5.0.0" + human-signals "^1.1.1" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.0" + onetime "^5.1.0" + p-finally "^2.0.0" + signal-exit "^3.0.2" + strip-final-newline "^2.0.0" + exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -4985,6 +5257,18 @@ expect@^24.9.0: jest-message-util "^24.9.0" jest-regex-util "^24.9.0" +expect@^25.2.4: + version "25.2.4" + resolved "https://registry.yarnpkg.com/expect/-/expect-25.2.4.tgz#b66e0777c861034ebc21730bb34e1839d5d46806" + integrity sha512-hfuPhPds4yOsZtIw4kwAg70r0hqGmpqekgA+VX7pf/3wZ6FY+xIOXZhNsPMMMsspYG/YIsbAiwqsdnD4Ht+bCA== + dependencies: + "@jest/types" "^25.2.3" + ansi-styles "^4.0.0" + jest-get-type "^25.2.1" + jest-matcher-utils "^25.2.3" + jest-message-util "^25.2.4" + jest-regex-util "^25.2.1" + extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" @@ -5173,6 +5457,13 @@ fill-range@^4.0.0: repeat-string "^1.6.1" to-regex-range "^2.1.0" +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + find-cache-dir@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" @@ -5371,6 +5662,11 @@ fsevents@^1.2.7: bindings "^1.5.0" nan "^2.12.1" +fsevents@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.2.tgz#4c0a1fb34bc68e543b4b82a9ec392bfbda840805" + integrity sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA== + ftp@~0.3.10: version "0.3.10" resolved "https://registry.yarnpkg.com/ftp/-/ftp-0.3.10.tgz#9197d861ad8142f3e63d5a83bfe4c59f7330885d" @@ -5461,6 +5757,13 @@ get-stream@^4.0.0, get-stream@^4.1.0: dependencies: pump "^3.0.0" +get-stream@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.1.0.tgz#01203cdc92597f9b909067c3e656cc1f4d3c4dc9" + integrity sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw== + dependencies: + pump "^3.0.0" + get-uri@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-2.0.4.tgz#d4937ab819e218d4cb5ae18e4f5962bef169cc6a" @@ -5620,7 +5923,7 @@ globrex@^0.1.1: resolved "https://registry.yarnpkg.com/globrex/-/globrex-0.1.2.tgz#dd5d9ec826232730cd6793a5e33a9302985e6098" integrity sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg== -graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2: +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== @@ -5899,6 +6202,11 @@ https-proxy-agent@^3.0.0: agent-base "^4.3.0" debug "^3.1.0" +human-signals@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" + integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== + humanize-ms@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" @@ -5969,6 +6277,14 @@ import-local@^2.0.0: pkg-dir "^3.0.0" resolve-cwd "^2.0.0" +import-local@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.0.2.tgz#a8cfd0431d1de4a2199703d003e3e62364fa6db6" + integrity sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -6093,6 +6409,11 @@ invert-kv@^1.0.0: resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= +ip-regex@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" + integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= + ip@1.1.5, ip@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" @@ -6307,6 +6628,11 @@ is-number@^3.0.0: dependencies: kind-of "^3.0.2" +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + is-obj@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" @@ -6441,6 +6767,11 @@ is-wsl@^1.1.0: resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= +is-wsl@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.1.1.tgz#4a1c152d429df3d441669498e2486d3596ebaf1d" + integrity sha512-umZHcSrwlDHo2TGMXv0DZ8dIUGunZ2Iv68YZnrmCiBPkZ4aaOhtv7pXJKeki9k3qJ3RJr0cDyitcl5wEH3AYog== + isarray@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" @@ -6608,6 +6939,15 @@ jest-changed-files@^24.9.0: execa "^1.0.0" throat "^4.0.0" +jest-changed-files@^25.2.3: + version "25.2.3" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-25.2.3.tgz#ad19deef9e47ba37efb432d2c9a67dfd97cc78af" + integrity sha512-EFxy94dvvbqRB36ezIPLKJ4fDIC+jAdNs8i8uTwFpaXd6H3LVc3ova1lNS4ZPWk09OCR2vq5kSdSQgar7zMORg== + dependencies: + "@jest/types" "^25.2.3" + execa "^3.2.0" + throat "^5.0.0" + jest-cli@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-24.9.0.tgz#ad2de62d07472d419c6abc301fc432b98b10d2af" @@ -6627,6 +6967,25 @@ jest-cli@^24.9.0: realpath-native "^1.1.0" yargs "^13.3.0" +jest-cli@^25.2.4: + version "25.2.4" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-25.2.4.tgz#021c2383904696597abc060dcb133c82ebd8bfcc" + integrity sha512-zeY2pRDWKj2LZudIncvvguwLMEdcnJqc2jJbwza1beqi80qqLvkPF/BjbFkK2sIV3r+mfTJS+7ITrvK6pCdRjg== + dependencies: + "@jest/core" "^25.2.4" + "@jest/test-result" "^25.2.4" + "@jest/types" "^25.2.3" + chalk "^3.0.0" + exit "^0.1.2" + import-local "^3.0.2" + is-ci "^2.0.0" + jest-config "^25.2.4" + jest-util "^25.2.3" + jest-validate "^25.2.3" + prompts "^2.0.1" + realpath-native "^2.0.0" + yargs "^15.3.1" + jest-config@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-24.9.0.tgz#fb1bbc60c73a46af03590719efa4825e6e4dd1b5" @@ -6650,6 +7009,30 @@ jest-config@^24.9.0: pretty-format "^24.9.0" realpath-native "^1.1.0" +jest-config@^25.2.4: + version "25.2.4" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-25.2.4.tgz#f4f33238979f225683179c89d1e402893008975d" + integrity sha512-fxy3nIpwJqOUQJRVF/q+pNQb6dv5b9YufOeCbpPZJ/md1zXpiupbhfehpfODhnKOfqbzSiigtSLzlWWmbRxnqQ== + dependencies: + "@babel/core" "^7.1.0" + "@jest/test-sequencer" "^25.2.4" + "@jest/types" "^25.2.3" + babel-jest "^25.2.4" + chalk "^3.0.0" + deepmerge "^4.2.2" + glob "^7.1.1" + jest-environment-jsdom "^25.2.4" + jest-environment-node "^25.2.4" + jest-get-type "^25.2.1" + jest-jasmine2 "^25.2.4" + jest-regex-util "^25.2.1" + jest-resolve "^25.2.3" + jest-util "^25.2.3" + jest-validate "^25.2.3" + micromatch "^4.0.2" + pretty-format "^25.2.3" + realpath-native "^2.0.0" + jest-diff@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.9.0.tgz#931b7d0d5778a1baf7452cb816e325e3724055da" @@ -6670,6 +7053,16 @@ jest-diff@^25.1.0: jest-get-type "^25.1.0" pretty-format "^25.1.0" +jest-diff@^25.2.3: + version "25.2.3" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-25.2.3.tgz#54d601a0a754ef26e808a8c8dbadd278c215aa3f" + integrity sha512-VtZ6LAQtaQpFsmEzps15dQc5ELbJxy4L2DOSo2Ev411TUEtnJPkAMD7JneVypeMJQ1y3hgxN9Ao13n15FAnavg== + dependencies: + chalk "^3.0.0" + diff-sequences "^25.2.1" + jest-get-type "^25.2.1" + pretty-format "^25.2.3" + jest-docblock@^24.3.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-24.9.0.tgz#7970201802ba560e1c4092cc25cbedf5af5a8ce2" @@ -6677,6 +7070,13 @@ jest-docblock@^24.3.0: dependencies: detect-newline "^2.1.0" +jest-docblock@^25.2.3: + version "25.2.3" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-25.2.3.tgz#ac45280c43d59e7139f9fbe5896c6e0320c01ebb" + integrity sha512-d3/tmjLLrH5fpRGmIm3oFa3vOaD/IjPxtXVOrfujpfJ9y1tCDB1x/tvunmdOVAyF03/xeMwburl6ITbiQT1mVA== + dependencies: + detect-newline "^3.0.0" + jest-each@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-24.9.0.tgz#eb2da602e2a610898dbc5f1f6df3ba86b55f8b05" @@ -6688,6 +7088,17 @@ jest-each@^24.9.0: jest-util "^24.9.0" pretty-format "^24.9.0" +jest-each@^25.2.3: + version "25.2.3" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-25.2.3.tgz#64067ba1508ebbd07e9b126c173ab371e8e6309d" + integrity sha512-RTlmCjsBDK2c9T5oO4MqccA3/5Y8BUtiEy7OOQik1iyCgdnNdHbI0pNEpyapZPBG0nlvZ4mIu7aY6zNUvLraAQ== + dependencies: + "@jest/types" "^25.2.3" + chalk "^3.0.0" + jest-get-type "^25.2.1" + jest-util "^25.2.3" + pretty-format "^25.2.3" + jest-environment-jsdom@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz#4b0806c7fc94f95edb369a69cc2778eec2b7375b" @@ -6700,6 +7111,18 @@ jest-environment-jsdom@^24.9.0: jest-util "^24.9.0" jsdom "^11.5.1" +jest-environment-jsdom@^25.2.4: + version "25.2.4" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-25.2.4.tgz#f2783541d0538b1bc43641703372cea6a2e83611" + integrity sha512-5dm+tNwrLmhELdjAwiQnVGf/U9iFMWdTL4/wyrMg2HU6RQnCiuxpWbIigLHUhuP1P2Ak0F4k3xhjrikboKyShA== + dependencies: + "@jest/environment" "^25.2.4" + "@jest/fake-timers" "^25.2.4" + "@jest/types" "^25.2.3" + jest-mock "^25.2.3" + jest-util "^25.2.3" + jsdom "^15.2.1" + jest-environment-node@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-24.9.0.tgz#333d2d2796f9687f2aeebf0742b519f33c1cbfd3" @@ -6711,6 +7134,18 @@ jest-environment-node@^24.9.0: jest-mock "^24.9.0" jest-util "^24.9.0" +jest-environment-node@^25.2.4: + version "25.2.4" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-25.2.4.tgz#dc211dfb0d8b66dfc1965a8f846e72e54ff0c430" + integrity sha512-Jkc5Y8goyXPrLRHnrUlqC7P4o5zn2m4zw6qWoRJ59kxV1f2a5wK+TTGhrhCwnhW/Ckpdl/pm+LufdvhJkvJbiw== + dependencies: + "@jest/environment" "^25.2.4" + "@jest/fake-timers" "^25.2.4" + "@jest/types" "^25.2.3" + jest-mock "^25.2.3" + jest-util "^25.2.3" + semver "^6.3.0" + jest-get-type@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.9.0.tgz#1684a0c8a50f2e4901b6644ae861f579eed2ef0e" @@ -6721,6 +7156,11 @@ jest-get-type@^25.1.0: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-25.1.0.tgz#1cfe5fc34f148dc3a8a3b7275f6b9ce9e2e8a876" integrity sha512-yWkBnT+5tMr8ANB6V+OjmrIJufHtCAqI5ic2H40v+tRqxDmE0PGnIiTyvRWFOMtmVHYpwRqyazDbTnhpjsGvLw== +jest-get-type@^25.2.1: + version "25.2.1" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-25.2.1.tgz#6c83de603c41b1627e6964da2f5454e6aa3c13a6" + integrity sha512-EYjTiqcDTCRJDcSNKbLTwn/LcDPEE7ITk8yRMNAOjEsN6yp+Uu+V1gx4djwnuj/DvWg0YGmqaBqPVGsPxlvE7w== + jest-haste-map@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-24.9.0.tgz#b38a5d64274934e21fa417ae9a9fbeb77ceaac7d" @@ -6740,6 +7180,25 @@ jest-haste-map@^24.9.0: optionalDependencies: fsevents "^1.2.7" +jest-haste-map@^25.2.3: + version "25.2.3" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-25.2.3.tgz#2649392b5af191f0167a27bfb62e5d96d7eaaade" + integrity sha512-pAP22OHtPr4qgZlJJFks2LLgoQUr4XtM1a+F5UaPIZNiCRnePA0hM3L7aiJ0gzwiNIYwMTfKRwG/S1L28J3A3A== + dependencies: + "@jest/types" "^25.2.3" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.3" + jest-serializer "^25.2.1" + jest-util "^25.2.3" + jest-worker "^25.2.1" + micromatch "^4.0.2" + sane "^4.0.3" + walker "^1.0.7" + which "^2.0.2" + optionalDependencies: + fsevents "^2.1.2" + jest-jasmine2@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz#1f7b1bd3242c1774e62acabb3646d96afc3be6a0" @@ -6762,6 +7221,29 @@ jest-jasmine2@^24.9.0: pretty-format "^24.9.0" throat "^4.0.0" +jest-jasmine2@^25.2.4: + version "25.2.4" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-25.2.4.tgz#5f77de83e1027f0c7588137055a80da773872374" + integrity sha512-juoKrmNmLwaheNbAg71SuUF9ovwUZCFNTpKVhvCXWk+SSeORcIUMptKdPCoLXV3D16htzhTSKmNxnxSk4SrTjA== + dependencies: + "@babel/traverse" "^7.1.0" + "@jest/environment" "^25.2.4" + "@jest/source-map" "^25.2.1" + "@jest/test-result" "^25.2.4" + "@jest/types" "^25.2.3" + chalk "^3.0.0" + co "^4.6.0" + expect "^25.2.4" + is-generator-fn "^2.0.0" + jest-each "^25.2.3" + jest-matcher-utils "^25.2.3" + jest-message-util "^25.2.4" + jest-runtime "^25.2.4" + jest-snapshot "^25.2.4" + jest-util "^25.2.3" + pretty-format "^25.2.3" + throat "^5.0.0" + jest-leak-detector@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz#b665dea7c77100c5c4f7dfcb153b65cf07dcf96a" @@ -6770,6 +7252,14 @@ jest-leak-detector@^24.9.0: jest-get-type "^24.9.0" pretty-format "^24.9.0" +jest-leak-detector@^25.2.3: + version "25.2.3" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-25.2.3.tgz#4cf39f137925e0061c04c24ca65cae36465f0238" + integrity sha512-yblCMPE7NJKl7778Cf/73yyFWAas5St0iiEBwq7RDyaz6Xd4WPFnPz2j7yDb/Qce71A1IbDoLADlcwD8zT74Aw== + dependencies: + jest-get-type "^25.2.1" + pretty-format "^25.2.3" + jest-matcher-utils@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz#f5b3661d5e628dffe6dd65251dfdae0e87c3a073" @@ -6780,6 +7270,16 @@ jest-matcher-utils@^24.9.0: jest-get-type "^24.9.0" pretty-format "^24.9.0" +jest-matcher-utils@^25.2.3: + version "25.2.3" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-25.2.3.tgz#59285bd6d6c810debc9caa585ed985e46a3f28fd" + integrity sha512-ZmiXiwQRVM9MoKjGMP5YsGGk2Th5ncyRxfXKz5AKsmU8m43kgNZirckVzaP61MlSa9LKmXbevdYqVp1ZKAw2Rw== + dependencies: + chalk "^3.0.0" + jest-diff "^25.2.3" + jest-get-type "^25.2.1" + pretty-format "^25.2.3" + jest-message-util@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-24.9.0.tgz#527f54a1e380f5e202a8d1149b0ec872f43119e3" @@ -6794,6 +7294,20 @@ jest-message-util@^24.9.0: slash "^2.0.0" stack-utils "^1.0.1" +jest-message-util@^25.2.4: + version "25.2.4" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-25.2.4.tgz#b1441b9c82f5c11fc661303cbf200a2f136a7762" + integrity sha512-9wWMH3Bf+GVTv0GcQLmH/FRr0x0toptKw9TA8U5YFLVXx7Tq9pvcNzTyJrcTJ+wLqNbMPPJlJNft4MnlcrtF5Q== + dependencies: + "@babel/code-frame" "^7.0.0" + "@jest/test-result" "^25.2.4" + "@jest/types" "^25.2.3" + "@types/stack-utils" "^1.0.1" + chalk "^3.0.0" + micromatch "^4.0.2" + slash "^3.0.0" + stack-utils "^1.0.1" + jest-mock@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-24.9.0.tgz#c22835541ee379b908673ad51087a2185c13f1c6" @@ -6801,6 +7315,13 @@ jest-mock@^24.9.0: dependencies: "@jest/types" "^24.9.0" +jest-mock@^25.2.3: + version "25.2.3" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-25.2.3.tgz#b37a581f59d61bd91db27a99bf7eb8b3e5e993d5" + integrity sha512-xlf+pyY0j47zoCs8zGGOGfWyxxLximE8YFOfEK8s4FruR8DtM/UjNj61um+iDuMAFEBDe1bhCXkqiKoCmWjJzg== + dependencies: + "@jest/types" "^25.2.3" + jest-pnp-resolver@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz#ecdae604c077a7fbc70defb6d517c3c1c898923a" @@ -6811,6 +7332,11 @@ jest-regex-util@^24.3.0, jest-regex-util@^24.9.0: resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-24.9.0.tgz#c13fb3380bde22bf6575432c493ea8fe37965636" integrity sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA== +jest-regex-util@^25.2.1: + version "25.2.1" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-25.2.1.tgz#db64b0d15cd3642c93b7b9627801d7c518600584" + integrity sha512-wroFVJw62LdqTdkL508ZLV82FrJJWVJMIuYG7q4Uunl1WAPTf4ftPKrqqfec4SvOIlvRZUdEX2TFpWR356YG/w== + jest-resolve-dependencies@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz#ad055198959c4cfba8a4f066c673a3f0786507ab" @@ -6820,6 +7346,15 @@ jest-resolve-dependencies@^24.9.0: jest-regex-util "^24.3.0" jest-snapshot "^24.9.0" +jest-resolve-dependencies@^25.2.4: + version "25.2.4" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-25.2.4.tgz#2d904400387d74a366dff54badb40a2b3210e733" + integrity sha512-qhUnK4PfNHzNdca7Ub1mbAqE0j5WNyMTwxBZZJjQlUrdqsiYho/QGK65FuBkZuSoYtKIIqriR9TpGrPEc3P5Gg== + dependencies: + "@jest/types" "^25.2.3" + jest-regex-util "^25.2.1" + jest-snapshot "^25.2.4" + jest-resolve@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-24.9.0.tgz#dff04c7687af34c4dd7e524892d9cf77e5d17321" @@ -6831,6 +7366,18 @@ jest-resolve@^24.9.0: jest-pnp-resolver "^1.2.1" realpath-native "^1.1.0" +jest-resolve@^25.2.3: + version "25.2.3" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-25.2.3.tgz#ababeaf2bb948cb6d2dea8453759116da0fb7842" + integrity sha512-1vZMsvM/DBH258PnpUNSXIgtzpYz+vCVCj9+fcy4akZl4oKbD+9hZSlfe9RIDpU0Fc28ozHQrmwX3EqFRRIHGg== + dependencies: + "@jest/types" "^25.2.3" + browser-resolve "^1.11.3" + chalk "^3.0.0" + jest-pnp-resolver "^1.2.1" + realpath-native "^2.0.0" + resolve "^1.15.1" + jest-runner@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-24.9.0.tgz#574fafdbd54455c2b34b4bdf4365a23857fcdf42" @@ -6856,6 +7403,31 @@ jest-runner@^24.9.0: source-map-support "^0.5.6" throat "^4.0.0" +jest-runner@^25.2.4: + version "25.2.4" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-25.2.4.tgz#d0daf7c56b4a83b6b675863d5cdcd502c960f9a1" + integrity sha512-5xaIfqqxck9Wg2CV4b9KmJtf/sWO7zWQx7O+34GCLGPzoPcVmB3mZtdrQI1/jS3Reqjru9ycLjgLHSf6XoxRqA== + dependencies: + "@jest/console" "^25.2.3" + "@jest/environment" "^25.2.4" + "@jest/test-result" "^25.2.4" + "@jest/types" "^25.2.3" + chalk "^3.0.0" + exit "^0.1.2" + graceful-fs "^4.2.3" + jest-config "^25.2.4" + jest-docblock "^25.2.3" + jest-haste-map "^25.2.3" + jest-jasmine2 "^25.2.4" + jest-leak-detector "^25.2.3" + jest-message-util "^25.2.4" + jest-resolve "^25.2.3" + jest-runtime "^25.2.4" + jest-util "^25.2.3" + jest-worker "^25.2.1" + source-map-support "^0.5.6" + throat "^5.0.0" + jest-runtime@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-24.9.0.tgz#9f14583af6a4f7314a6a9d9f0226e1a781c8e4ac" @@ -6885,11 +7457,47 @@ jest-runtime@^24.9.0: strip-bom "^3.0.0" yargs "^13.3.0" +jest-runtime@^25.2.4: + version "25.2.4" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-25.2.4.tgz#c66a421e115944426b377a7fd331f6c0902cfa56" + integrity sha512-6ehOUizgIghN+aV5YSrDzTZ+zJ9omgEjJbTHj3Jqes5D52XHfhzT7cSfdREwkNjRytrR7mNwZ7pRauoyNLyJ8Q== + dependencies: + "@jest/console" "^25.2.3" + "@jest/environment" "^25.2.4" + "@jest/source-map" "^25.2.1" + "@jest/test-result" "^25.2.4" + "@jest/transform" "^25.2.4" + "@jest/types" "^25.2.3" + "@types/yargs" "^15.0.0" + chalk "^3.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.3" + jest-config "^25.2.4" + jest-haste-map "^25.2.3" + jest-message-util "^25.2.4" + jest-mock "^25.2.3" + jest-regex-util "^25.2.1" + jest-resolve "^25.2.3" + jest-snapshot "^25.2.4" + jest-util "^25.2.3" + jest-validate "^25.2.3" + realpath-native "^2.0.0" + slash "^3.0.0" + strip-bom "^4.0.0" + yargs "^15.3.1" + jest-serializer@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-24.9.0.tgz#e6d7d7ef96d31e8b9079a714754c5d5c58288e73" integrity sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ== +jest-serializer@^25.2.1: + version "25.2.1" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-25.2.1.tgz#51727a5fc04256f461abe0fa024a022ba165877a" + integrity sha512-fibDi7M5ffx6c/P66IkvR4FKkjG5ldePAK1WlbNoaU4GZmIAkS9Le/frAwRUFEX0KdnisSPWf+b1RC5jU7EYJQ== + jest-snapshot@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-24.9.0.tgz#ec8e9ca4f2ec0c5c87ae8f925cf97497b0e951ba" @@ -6909,6 +7517,26 @@ jest-snapshot@^24.9.0: pretty-format "^24.9.0" semver "^6.2.0" +jest-snapshot@^25.2.4: + version "25.2.4" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-25.2.4.tgz#08d4517579c864df4280bcc948ceea34327a4ded" + integrity sha512-nIwpW7FZCq5p0AE3Oyqyb6jL0ENJixXzJ5/CD/XRuOqp3gS5OM3O/k+NnTrniCXxPFV4ry6s9HNfiPQBi0wcoA== + dependencies: + "@babel/types" "^7.0.0" + "@jest/types" "^25.2.3" + "@types/prettier" "^1.19.0" + chalk "^3.0.0" + expect "^25.2.4" + jest-diff "^25.2.3" + jest-get-type "^25.2.1" + jest-matcher-utils "^25.2.3" + jest-message-util "^25.2.4" + jest-resolve "^25.2.3" + make-dir "^3.0.0" + natural-compare "^1.4.0" + pretty-format "^25.2.3" + semver "^6.3.0" + jest-util@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-24.9.0.tgz#7396814e48536d2e85a37de3e4c431d7cb140162" @@ -6927,6 +7555,16 @@ jest-util@^24.9.0: slash "^2.0.0" source-map "^0.6.0" +jest-util@^25.2.3: + version "25.2.3" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-25.2.3.tgz#0abf95a1d6b96f2de5a3ecd61b36c40a182dc256" + integrity sha512-7tWiMICVSo9lNoObFtqLt9Ezt5exdFlWs5fLe1G4XLY2lEbZc814cw9t4YHScqBkWMfzth8ASHKlYBxiX2rdCw== + dependencies: + "@jest/types" "^25.2.3" + chalk "^3.0.0" + is-ci "^2.0.0" + make-dir "^3.0.0" + jest-validate@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-24.9.0.tgz#0775c55360d173cd854e40180756d4ff52def8ab" @@ -6939,6 +7577,18 @@ jest-validate@^24.9.0: leven "^3.1.0" pretty-format "^24.9.0" +jest-validate@^25.2.3: + version "25.2.3" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-25.2.3.tgz#ecb0f093cf8ae71d15075fb48439b6f78f1fcb5a" + integrity sha512-GObn91jzU0B0Bv4cusAwjP6vnWy78hJUM8MOSz7keRfnac/ZhQWIsUjvk01IfeXNTemCwgR57EtdjQMzFZGREg== + dependencies: + "@jest/types" "^25.2.3" + camelcase "^5.3.1" + chalk "^3.0.0" + jest-get-type "^25.2.1" + leven "^3.1.0" + pretty-format "^25.2.3" + jest-watcher@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-24.9.0.tgz#4b56e5d1ceff005f5b88e528dc9afc8dd4ed2b3b" @@ -6952,6 +7602,18 @@ jest-watcher@^24.9.0: jest-util "^24.9.0" string-length "^2.0.0" +jest-watcher@^25.2.4: + version "25.2.4" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-25.2.4.tgz#dda85b914d470fa4145164a8f70bda4f208bafb6" + integrity sha512-p7g7s3zqcy69slVzQYcphyzkB2FBmJwMbv6k6KjI5mqd6KnUnQPfQVKuVj2l+34EeuxnbXqnrjtUFmxhcL87rg== + dependencies: + "@jest/test-result" "^25.2.4" + "@jest/types" "^25.2.3" + ansi-escapes "^4.2.1" + chalk "^3.0.0" + jest-util "^25.2.3" + string-length "^3.1.0" + jest-worker@^24.6.0, jest-worker@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.9.0.tgz#5dbfdb5b2d322e98567898238a9697bcce67b3e5" @@ -6960,6 +7622,14 @@ jest-worker@^24.6.0, jest-worker@^24.9.0: merge-stream "^2.0.0" supports-color "^6.1.0" +jest-worker@^25.2.1: + version "25.2.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-25.2.1.tgz#209617015c768652646aa33a7828cc2ab472a18a" + integrity sha512-IHnpekk8H/hCUbBlfeaPZzU6v75bqwJp3n4dUrQuQOAgOneI4tx3jV2o8pvlXnDfcRsfkFIUD//HWXpCmR+evQ== + dependencies: + merge-stream "^2.0.0" + supports-color "^7.0.0" + jest@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest/-/jest-24.9.0.tgz#987d290c05a08b52c56188c1002e368edb007171" @@ -6968,6 +7638,15 @@ jest@^24.9.0: import-local "^2.0.0" jest-cli "^24.9.0" +jest@^25.2.4: + version "25.2.4" + resolved "https://registry.yarnpkg.com/jest/-/jest-25.2.4.tgz#d10941948a2b57eb7accc2e7ae78af4a0e11b40a" + integrity sha512-Lu4LXxf4+durzN/IFilcAoQSisOwgHIXgl9vffopePpSSwFqfj1Pj4y+k3nL8oTbnvjxgDIsEcepy6he4bWqnQ== + dependencies: + "@jest/core" "^25.2.4" + import-local "^3.0.2" + jest-cli "^25.2.4" + jmespath@0.15.0: version "0.15.0" resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" @@ -7060,6 +7739,38 @@ jsdom@^14.1.0: ws "^6.1.2" xml-name-validator "^3.0.0" +jsdom@^15.2.1: + version "15.2.1" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-15.2.1.tgz#d2feb1aef7183f86be521b8c6833ff5296d07ec5" + integrity sha512-fAl1W0/7T2G5vURSyxBzrJ1LSdQn6Tr5UX/xD4PXDx/PDgwygedfW6El/KIj3xJ7FU61TTYnc/l/B7P49Eqt6g== + dependencies: + abab "^2.0.0" + acorn "^7.1.0" + acorn-globals "^4.3.2" + array-equal "^1.0.0" + cssom "^0.4.1" + cssstyle "^2.0.0" + data-urls "^1.1.0" + domexception "^1.0.1" + escodegen "^1.11.1" + html-encoding-sniffer "^1.0.2" + nwsapi "^2.2.0" + parse5 "5.1.0" + pn "^1.1.0" + request "^2.88.0" + request-promise-native "^1.0.7" + saxes "^3.1.9" + symbol-tree "^3.2.2" + tough-cookie "^3.0.1" + w3c-hr-time "^1.0.1" + w3c-xmlserializer "^1.1.2" + webidl-conversions "^4.0.2" + whatwg-encoding "^1.0.5" + whatwg-mimetype "^2.3.0" + whatwg-url "^7.0.0" + ws "^7.0.0" + xml-name-validator "^3.0.0" + jsesc@^2.5.1: version "2.5.2" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" @@ -7217,10 +7928,10 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" -jszip@^3.2.2: - version "3.2.2" - resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.2.2.tgz#b143816df7e106a9597a94c77493385adca5bd1d" - integrity sha512-NmKajvAFQpbg3taXQXr/ccS2wcucR1AZ+NtyWp2Nq7HHVsXhcJFR8p0Baf32C2yVvBylFWVeKf+WI2AnvlPhpA== +jszip@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.3.0.tgz#29d72c21a54990fa885b11fc843db320640d5271" + integrity sha512-EJ9k766htB1ZWnsV5ZMDkKLgA+201r/ouFF8R2OigVjVdcm2rurcBrrdXaeqBJbqnUVMko512PYmlncBKE1Huw== dependencies: lie "~3.3.0" pako "~1.0.2" @@ -7524,6 +8235,13 @@ log4js@^6.1.2: rfdc "^1.1.4" streamroller "^2.2.3" +lolex@^5.0.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/lolex/-/lolex-5.1.2.tgz#953694d098ce7c07bc5ed6d0e42bc6c0c6d5a367" + integrity sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A== + dependencies: + "@sinonjs/commons" "^1.7.0" + loose-envify@^1.0.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" @@ -7769,6 +8487,14 @@ micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.2" +micromatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" + integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== + dependencies: + braces "^3.0.1" + picomatch "^2.0.5" + miller-rabin@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" @@ -8137,6 +8863,17 @@ node-notifier@^5.4.2: shellwords "^0.1.1" which "^1.3.0" +node-notifier@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-6.0.0.tgz#cea319e06baa16deec8ce5cd7f133c4a46b68e12" + integrity sha512-SVfQ/wMw+DesunOm5cKqr6yDcvUTDl/yc97ybGHMrteNEY6oekXpNpS3lZwgLlwz0FLgHoiW28ZpmBHUDg37cw== + dependencies: + growly "^1.3.0" + is-wsl "^2.1.1" + semver "^6.3.0" + shellwords "^0.1.1" + which "^1.3.1" + node-preload@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/node-preload/-/node-preload-0.2.1.tgz#c03043bb327f417a18fee7ab7ee57b408a144301" @@ -8260,6 +8997,13 @@ npm-run-path@^2.0.0: dependencies: path-key "^2.0.0" +npm-run-path@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + npmlog@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" @@ -8287,7 +9031,7 @@ number-is-nan@^1.0.0: resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= -nwsapi@^2.0.7, nwsapi@^2.1.3: +nwsapi@^2.0.7, nwsapi@^2.1.3, nwsapi@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== @@ -8577,11 +9321,21 @@ p-each-series@^1.0.0: dependencies: p-reduce "^1.0.0" +p-each-series@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-2.1.0.tgz#961c8dd3f195ea96c747e636b262b800a6b1af48" + integrity sha512-ZuRs1miPT4HrjFa+9fRfOFXxGJfORgelKV9f9nNOWw2gl6gVsRaVDOQP0+MI0G0wGKns1Yacsu0GjOFbTK0JFQ== + p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= +p-finally@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-2.0.1.tgz#bd6fcaa9c559a096b680806f4d657b3f0f240561" + integrity sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw== + p-limit@^1.1.0: version "1.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" @@ -8913,7 +9667,7 @@ path-key@^2.0.0, path-key@^2.0.1: resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= -path-key@^3.1.0: +path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== @@ -8974,6 +9728,11 @@ physical-cpu-count@^2.0.0: resolved "https://registry.yarnpkg.com/physical-cpu-count/-/physical-cpu-count-2.0.0.tgz#18de2f97e4bf7a9551ad7511942b5496f7aba660" integrity sha1-GN4vl+S/epVRrXURlCtUlverpmA= +picomatch@^2.0.4, picomatch@^2.0.5: + version "2.2.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" + integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== + pify@^2.0.0, pify@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -9022,7 +9781,7 @@ pkg-dir@^3.0.0: dependencies: find-up "^3.0.0" -pkg-dir@^4.1.0: +pkg-dir@^4.1.0, pkg-dir@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== @@ -9425,6 +10184,16 @@ pretty-format@^25.1.0: ansi-styles "^4.0.0" react-is "^16.12.0" +pretty-format@^25.2.3: + version "25.2.3" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-25.2.3.tgz#ba6e9603a0d80fa2e470b1fed55de1f9bfd81421" + integrity sha512-IP4+5UOAVGoyqC/DiomOeHBUKN6q00gfyT2qpAsRH64tgOKB2yF7FHJXC18OCiU0/YFierACup/zdCOWw0F/0w== + dependencies: + "@jest/types" "^25.2.3" + ansi-regex "^5.0.0" + ansi-styles "^4.0.0" + react-is "^16.12.0" + private@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" @@ -9836,6 +10605,11 @@ realpath-native@^1.1.0: dependencies: util.promisify "^1.0.0" +realpath-native@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-2.0.0.tgz#7377ac429b6e1fd599dc38d08ed942d0d7beb866" + integrity sha512-v1SEYUOXXdbBZK8ZuNgO4TBjamPsiSgcFr0aP+tEKpQZK8vooEUqV6nm6Cv502mX4NF2EfsnVqtNAHG+/6Ur1Q== + redent@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" @@ -9968,7 +10742,7 @@ request-promise-core@1.1.3: dependencies: lodash "^4.17.15" -request-promise-native@^1.0.5: +request-promise-native@^1.0.5, request-promise-native@^1.0.7: version "1.0.8" resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.8.tgz#a455b960b826e44e2bf8999af64dff2bfe58cb36" integrity sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ== @@ -10025,6 +10799,13 @@ resolve-cwd@^2.0.0: dependencies: resolve-from "^3.0.0" +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + resolve-from@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" @@ -10050,7 +10831,7 @@ resolve@1.1.7: resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= -resolve@1.x, resolve@^1.1.5, resolve@^1.10.0, resolve@^1.11.1, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.3.2, resolve@^1.4.0: +resolve@1.x, resolve@^1.1.5, resolve@^1.10.0, resolve@^1.11.1, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.15.1, resolve@^1.3.2, resolve@^1.4.0: version "1.15.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.1.tgz#27bdcdeffeaf2d6244b95bb0f9f4b4653451f3e8" integrity sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w== @@ -10390,6 +11171,11 @@ slash@^2.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + slice-ansi@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" @@ -10505,6 +11291,11 @@ source-map@^0.5.0, source-map@^0.5.6: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= +source-map@^0.7.3: + version "0.7.3" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== + spawn-wrap@^1.4.2: version "1.4.3" resolved "https://registry.yarnpkg.com/spawn-wrap/-/spawn-wrap-1.4.3.tgz#81b7670e170cca247d80bf5faf0cfb713bdcf848" @@ -10733,6 +11524,14 @@ string-length@^2.0.0: astral-regex "^1.0.0" strip-ansi "^4.0.0" +string-length@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-3.1.0.tgz#107ef8c23456e187a8abd4a61162ff4ac6e25837" + integrity sha512-Ttp5YvkGm5v9Ijagtaz1BnN+k9ObpvS0eIBblPMp2YWL8FBmi9qblQ9fexc2k/CXFgrTIteU3jAw3payCnwSTA== + dependencies: + astral-regex "^1.0.0" + strip-ansi "^5.2.0" + string-width@*, string-width@^4.1.0, string-width@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" @@ -10863,6 +11662,11 @@ strip-eof@^1.0.0: resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + strip-indent@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" @@ -10924,13 +11728,21 @@ supports-color@^6.1.0: dependencies: has-flag "^3.0.0" -supports-color@^7.1.0: +supports-color@^7.0.0, supports-color@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== dependencies: has-flag "^4.0.0" +supports-hyperlinks@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz#f663df252af5f37c5d49bbd7eeefa9e0b9e59e47" + integrity sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA== + dependencies: + has-flag "^4.0.0" + supports-color "^7.0.0" + svgo@^1.0.0, svgo@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167" @@ -11094,6 +11906,14 @@ tempfile@^3.0.0: temp-dir "^2.0.0" uuid "^3.3.2" +terminal-link@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" + integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== + dependencies: + ansi-escapes "^4.2.1" + supports-hyperlinks "^2.0.0" + terser@^3.7.3: version "3.17.0" resolved "https://registry.yarnpkg.com/terser/-/terser-3.17.0.tgz#f88ffbeda0deb5637f9d24b0da66f4e15ab10cb2" @@ -11160,6 +11980,11 @@ throat@^4.0.0: resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" integrity sha1-iQN8vJLFarGJJua6TLsgDhVnKmo= +throat@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" + integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA== + through2@^2.0.0, through2@^2.0.2, through2@~2.0.3: version "2.0.5" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" @@ -11257,6 +12082,13 @@ to-regex-range@^2.1.0: is-number "^3.0.0" repeat-string "^1.6.1" +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + to-regex@^3.0.1, to-regex@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" @@ -11280,6 +12112,15 @@ tough-cookie@^2.3.3, tough-cookie@^2.3.4, tough-cookie@^2.5.0, tough-cookie@~2.5 psl "^1.1.28" punycode "^2.1.1" +tough-cookie@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-3.0.1.tgz#9df4f57e739c26930a018184887f4adb7dca73b2" + integrity sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg== + dependencies: + ip-regex "^2.1.0" + psl "^1.1.28" + punycode "^2.1.1" + tr46@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" @@ -11700,6 +12541,15 @@ v8-compile-cache@^2.0.0, v8-compile-cache@^2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e" integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g== +v8-to-istanbul@^4.0.1: + version "4.1.3" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-4.1.3.tgz#22fe35709a64955f49a08a7c7c959f6520ad6f20" + integrity sha512-sAjOC+Kki6aJVbUOXJbcR0MnbfjvBzwKZazEJymA2IX49uoOdEdk+4fBq5cXgYgiyKtAyrrJNtBZdOeDIF+Fng== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^1.6.0" + source-map "^0.7.3" + validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.3: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" @@ -11842,7 +12692,7 @@ which@^1.2.9, which@^1.3.0, which@^1.3.1: dependencies: isexe "^2.0.0" -which@^2.0.1: +which@^2.0.1, which@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== @@ -11995,6 +12845,11 @@ ws@^6.1.2: dependencies: async-limiter "~1.0.0" +ws@^7.0.0: + version "7.2.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.3.tgz#a5411e1fb04d5ed0efee76d26d5c46d830c39b46" + integrity sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ== + xml-name-validator@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" From 8843808edd3df433241201778879b8cfe6b66224 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2020 19:41:47 +0000 Subject: [PATCH 40/53] chore(deps-dev): bump fast-check from 1.23.0 to 1.24.0 (#7124) Bumps [fast-check](https://github.com/dubzzz/fast-check) from 1.23.0 to 1.24.0. - [Release notes](https://github.com/dubzzz/fast-check/releases) - [Changelog](https://github.com/dubzzz/fast-check/blob/master/CHANGELOG.md) - [Commits](https://github.com/dubzzz/fast-check/compare/v1.23.0...v1.24.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- packages/@aws-cdk/app-delivery/package.json | 2 +- packages/@aws-cdk/aws-applicationautoscaling/package.json | 2 +- packages/@aws-cdk/aws-autoscaling-common/package.json | 2 +- packages/@aws-cdk/cloudformation-diff/package.json | 2 +- packages/@aws-cdk/core/package.json | 2 +- yarn.lock | 8 ++++---- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/@aws-cdk/app-delivery/package.json b/packages/@aws-cdk/app-delivery/package.json index e210719eab5e6..78c53e9098fd0 100644 --- a/packages/@aws-cdk/app-delivery/package.json +++ b/packages/@aws-cdk/app-delivery/package.json @@ -56,7 +56,7 @@ "@types/nodeunit": "^0.0.30", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", - "fast-check": "^1.22.2", + "fast-check": "^1.24.0", "nodeunit": "^0.11.3", "pkglint": "0.0.0" }, diff --git a/packages/@aws-cdk/aws-applicationautoscaling/package.json b/packages/@aws-cdk/aws-applicationautoscaling/package.json index 6dcc9c5aa4d65..90ce9862b5291 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/package.json +++ b/packages/@aws-cdk/aws-applicationautoscaling/package.json @@ -66,7 +66,7 @@ "@types/nodeunit": "^0.0.30", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "fast-check": "^1.22.2", + "fast-check": "^1.24.0", "nodeunit": "^0.11.3", "pkglint": "0.0.0" }, diff --git a/packages/@aws-cdk/aws-autoscaling-common/package.json b/packages/@aws-cdk/aws-autoscaling-common/package.json index c51b376995c45..d1e4b4ded3f6d 100644 --- a/packages/@aws-cdk/aws-autoscaling-common/package.json +++ b/packages/@aws-cdk/aws-autoscaling-common/package.json @@ -62,7 +62,7 @@ "@types/nodeunit": "^0.0.30", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", - "fast-check": "^1.22.2", + "fast-check": "^1.24.0", "nodeunit": "^0.11.3", "pkglint": "0.0.0" }, diff --git a/packages/@aws-cdk/cloudformation-diff/package.json b/packages/@aws-cdk/cloudformation-diff/package.json index b876a079dbf00..02983b3de8aba 100644 --- a/packages/@aws-cdk/cloudformation-diff/package.json +++ b/packages/@aws-cdk/cloudformation-diff/package.json @@ -42,7 +42,7 @@ "@types/string-width": "^4.0.1", "@types/table": "^4.0.7", "cdk-build-tools": "0.0.0", - "fast-check": "^1.22.2", + "fast-check": "^1.24.0", "jest": "^24.9.0", "pkglint": "0.0.0", "ts-jest": "^25.3.0" diff --git a/packages/@aws-cdk/core/package.json b/packages/@aws-cdk/core/package.json index a61878a17fff1..1b25a836bff3d 100644 --- a/packages/@aws-cdk/core/package.json +++ b/packages/@aws-cdk/core/package.json @@ -140,7 +140,7 @@ "@types/nodeunit": "^0.0.30", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "fast-check": "^1.22.2", + "fast-check": "^1.24.0", "lodash": "^4.17.15", "nodeunit": "^0.11.3", "pkglint": "0.0.0" diff --git a/yarn.lock b/yarn.lock index 7b30930e19afd..a5a7b2c8391b1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5332,10 +5332,10 @@ falafel@^2.1.0: isarray "^2.0.1" object-keys "^1.0.6" -fast-check@^1.22.2: - version "1.23.0" - resolved "https://registry.yarnpkg.com/fast-check/-/fast-check-1.23.0.tgz#7abe0059b192fb9025cd7d6640532fe8ab538746" - integrity sha512-MRxcYG4YHTzP8wbjPsl6lZeUpY9sBuYsp6/w8lWmSvgS0wBrhMSErVnHmt5zi9sDWROCd+H7bk2jpr6wzToM6w== +fast-check@^1.24.0: + version "1.24.0" + resolved "https://registry.yarnpkg.com/fast-check/-/fast-check-1.24.0.tgz#55b8c990fc529a65412ed6c43a9ae52974dd8f0b" + integrity sha512-GnEs2bUHKMXRbVdNiccsGM3O38wl2NfZkAfGwU7bGTOZBN5xzjGjXzh4uvN4NR/mwqoaoEkcZ+LE5Yedc5RIeA== dependencies: pure-rand "^2.0.0" tslib "^1.10.0" From 1956ded4eb75613d46a3ea163c3041f402d98fa5 Mon Sep 17 00:00:00 2001 From: AWS CDK Automation <43080478+aws-cdk-automation@users.noreply.github.com> Date: Wed, 1 Apr 2020 21:44:25 +0200 Subject: [PATCH 41/53] feat: cloudformation spec v12.0.0 (#7113) see CHANGELOG --- packages/@aws-cdk/cfnspec/CHANGELOG.md | 32 ++ packages/@aws-cdk/cfnspec/cfn.version | 2 +- ...0_CloudFormationResourceSpecification.json | 274 +++++++++++++++++- 3 files changed, 306 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/cfnspec/CHANGELOG.md b/packages/@aws-cdk/cfnspec/CHANGELOG.md index c7d02412f43a0..7e56077ba150b 100644 --- a/packages/@aws-cdk/cfnspec/CHANGELOG.md +++ b/packages/@aws-cdk/cfnspec/CHANGELOG.md @@ -1,3 +1,35 @@ +# CloudFormation Resource Specification v12.0.0 + +## New Resource Types + + +## Attribute Changes + + +## Property Changes + +* AWS::ApiGatewayV2::Integration ConnectionId (__added__) +* AWS::AutoScaling::AutoScalingGroup MaxInstanceLifetime (__added__) +* AWS::EC2::Volume MultiAttachEnabled (__added__) + +## Property Type Changes + +* AWS::IoT::TopicRule.AssetPropertyTimestamp (__added__) +* AWS::IoT::TopicRule.AssetPropertyValue (__added__) +* AWS::IoT::TopicRule.AssetPropertyVariant (__added__) +* AWS::IoT::TopicRule.HttpAction (__added__) +* AWS::IoT::TopicRule.HttpActionHeader (__added__) +* AWS::IoT::TopicRule.HttpAuthorization (__added__) +* AWS::IoT::TopicRule.IotEventsAction (__added__) +* AWS::IoT::TopicRule.IotSiteWiseAction (__added__) +* AWS::IoT::TopicRule.PutAssetPropertyValueEntry (__added__) +* AWS::IoT::TopicRule.SigV4Authorization (__added__) +* AWS::IoT::TopicRule.Action Http (__added__) +* AWS::IoT::TopicRule.Action IotEvents (__added__) +* AWS::IoT::TopicRule.Action IotSiteWise (__added__) +* AWS::IoT::TopicRule.RepublishAction Qos (__added__) + + # CloudFormation Resource Specification v11.6.0 ## New Resource Types diff --git a/packages/@aws-cdk/cfnspec/cfn.version b/packages/@aws-cdk/cfnspec/cfn.version index 146d5de797140..4044f90867dfb 100644 --- a/packages/@aws-cdk/cfnspec/cfn.version +++ b/packages/@aws-cdk/cfnspec/cfn.version @@ -1 +1 @@ -11.6.0 +12.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 9be67cb38b8f8..f3eb72a467c74 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/000_CloudFormationResourceSpecification.json +++ b/packages/@aws-cdk/cfnspec/spec-source/000_CloudFormationResourceSpecification.json @@ -18791,12 +18791,30 @@ "Type": "FirehoseAction", "UpdateType": "Mutable" }, + "Http": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-action.html#cfn-iot-topicrule-action-http", + "Required": false, + "Type": "HttpAction", + "UpdateType": "Mutable" + }, "IotAnalytics": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-action.html#cfn-iot-topicrule-action-iotanalytics", "Required": false, "Type": "IotAnalyticsAction", "UpdateType": "Mutable" }, + "IotEvents": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-action.html#cfn-iot-topicrule-action-iotevents", + "Required": false, + "Type": "IotEventsAction", + "UpdateType": "Mutable" + }, + "IotSiteWise": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-action.html#cfn-iot-topicrule-action-iotsitewise", + "Required": false, + "Type": "IotSiteWiseAction", + "UpdateType": "Mutable" + }, "Kinesis": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-action.html#cfn-iot-topicrule-action-kinesis", "Required": false, @@ -18841,6 +18859,75 @@ } } }, + "AWS::IoT::TopicRule.AssetPropertyTimestamp": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-assetpropertytimestamp.html", + "Properties": { + "OffsetInNanos": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-assetpropertytimestamp.html#cfn-iot-topicrule-assetpropertytimestamp-offsetinnanos", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "TimeInSeconds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-assetpropertytimestamp.html#cfn-iot-topicrule-assetpropertytimestamp-timeinseconds", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::IoT::TopicRule.AssetPropertyValue": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-assetpropertyvalue.html", + "Properties": { + "Quality": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-assetpropertyvalue.html#cfn-iot-topicrule-assetpropertyvalue-quality", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Timestamp": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-assetpropertyvalue.html#cfn-iot-topicrule-assetpropertyvalue-timestamp", + "Required": true, + "Type": "AssetPropertyTimestamp", + "UpdateType": "Mutable" + }, + "Value": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-assetpropertyvalue.html#cfn-iot-topicrule-assetpropertyvalue-value", + "Required": true, + "Type": "AssetPropertyVariant", + "UpdateType": "Mutable" + } + } + }, + "AWS::IoT::TopicRule.AssetPropertyVariant": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-assetpropertyvariant.html", + "Properties": { + "BooleanValue": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-assetpropertyvariant.html#cfn-iot-topicrule-assetpropertyvariant-booleanvalue", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "DoubleValue": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-assetpropertyvariant.html#cfn-iot-topicrule-assetpropertyvariant-doublevalue", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "IntegerValue": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-assetpropertyvariant.html#cfn-iot-topicrule-assetpropertyvariant-integervalue", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "StringValue": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-assetpropertyvariant.html#cfn-iot-topicrule-assetpropertyvariant-stringvalue", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::IoT::TopicRule.CloudwatchAlarmAction": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-cloudwatchalarmaction.html", "Properties": { @@ -19045,6 +19132,65 @@ } } }, + "AWS::IoT::TopicRule.HttpAction": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-httpaction.html", + "Properties": { + "Auth": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-httpaction.html#cfn-iot-topicrule-httpaction-auth", + "Required": false, + "Type": "HttpAuthorization", + "UpdateType": "Mutable" + }, + "ConfirmationUrl": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-httpaction.html#cfn-iot-topicrule-httpaction-confirmationurl", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Headers": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-httpaction.html#cfn-iot-topicrule-httpaction-headers", + "DuplicatesAllowed": false, + "ItemType": "HttpActionHeader", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Url": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-httpaction.html#cfn-iot-topicrule-httpaction-url", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::IoT::TopicRule.HttpActionHeader": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-httpactionheader.html", + "Properties": { + "Key": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-httpactionheader.html#cfn-iot-topicrule-httpactionheader-key", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Value": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-httpactionheader.html#cfn-iot-topicrule-httpactionheader-value", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::IoT::TopicRule.HttpAuthorization": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-httpauthorization.html", + "Properties": { + "Sigv4": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-httpauthorization.html#cfn-iot-topicrule-httpauthorization-sigv4", + "Required": false, + "Type": "SigV4Authorization", + "UpdateType": "Mutable" + } + } + }, "AWS::IoT::TopicRule.IotAnalyticsAction": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-iotanalyticsaction.html", "Properties": { @@ -19062,6 +19208,48 @@ } } }, + "AWS::IoT::TopicRule.IotEventsAction": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-ioteventsaction.html", + "Properties": { + "InputName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-ioteventsaction.html#cfn-iot-topicrule-ioteventsaction-inputname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "MessageId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-ioteventsaction.html#cfn-iot-topicrule-ioteventsaction-messageid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "RoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-ioteventsaction.html#cfn-iot-topicrule-ioteventsaction-rolearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, + "AWS::IoT::TopicRule.IotSiteWiseAction": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-iotsitewiseaction.html", + "Properties": { + "PutAssetPropertyValueEntries": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-iotsitewiseaction.html#cfn-iot-topicrule-iotsitewiseaction-putassetpropertyvalueentries", + "DuplicatesAllowed": false, + "ItemType": "PutAssetPropertyValueEntry", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + }, + "RoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-iotsitewiseaction.html#cfn-iot-topicrule-iotsitewiseaction-rolearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::IoT::TopicRule.KinesisAction": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-kinesisaction.html", "Properties": { @@ -19096,6 +19284,43 @@ } } }, + "AWS::IoT::TopicRule.PutAssetPropertyValueEntry": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-putassetpropertyvalueentry.html", + "Properties": { + "AssetId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-putassetpropertyvalueentry.html#cfn-iot-topicrule-putassetpropertyvalueentry-assetid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "EntryId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-putassetpropertyvalueentry.html#cfn-iot-topicrule-putassetpropertyvalueentry-entryid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "PropertyAlias": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-putassetpropertyvalueentry.html#cfn-iot-topicrule-putassetpropertyvalueentry-propertyalias", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "PropertyId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-putassetpropertyvalueentry.html#cfn-iot-topicrule-putassetpropertyvalueentry-propertyid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "PropertyValues": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-putassetpropertyvalueentry.html#cfn-iot-topicrule-putassetpropertyvalueentry-propertyvalues", + "DuplicatesAllowed": false, + "ItemType": "AssetPropertyValue", + "Required": true, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, "AWS::IoT::TopicRule.PutItemInput": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-putiteminput.html", "Properties": { @@ -19110,6 +19335,12 @@ "AWS::IoT::TopicRule.RepublishAction": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-republishaction.html", "Properties": { + "Qos": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-republishaction.html#cfn-iot-topicrule-republishaction-qos", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, "RoleArn": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-republishaction.html#cfn-iot-topicrule-republishaction-rolearn", "PrimitiveType": "String", @@ -19147,6 +19378,29 @@ } } }, + "AWS::IoT::TopicRule.SigV4Authorization": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-sigv4authorization.html", + "Properties": { + "RoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-sigv4authorization.html#cfn-iot-topicrule-sigv4authorization-rolearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "ServiceName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-sigv4authorization.html#cfn-iot-topicrule-sigv4authorization-servicename", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "SigningRegion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-sigv4authorization.html#cfn-iot-topicrule-sigv4authorization-signingregion", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::IoT::TopicRule.SnsAction": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-snsaction.html", "Properties": { @@ -30748,7 +31002,7 @@ } } }, - "ResourceSpecificationVersion": "11.6.0", + "ResourceSpecificationVersion": "12.0.0", "ResourceTypes": { "AWS::ACMPCA::Certificate": { "Attributes": { @@ -32413,6 +32667,12 @@ "Required": true, "UpdateType": "Immutable" }, + "ConnectionId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-integration.html#cfn-apigatewayv2-integration-connectionid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, "ConnectionType": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-integration.html#cfn-apigatewayv2-integration-connectiontype", "PrimitiveType": "String", @@ -34288,6 +34548,12 @@ "Type": "List", "UpdateType": "Mutable" }, + "MaxInstanceLifetime": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-group.html#cfn-as-group-maxinstancelifetime", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, "MaxSize": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-group.html#cfn-as-group-maxsize", "PrimitiveType": "String", @@ -40858,6 +41124,12 @@ "Required": false, "UpdateType": "Mutable" }, + "MultiAttachEnabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ebs-volume.html#cfn-ec2-ebs-volume-multiattachenabled", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, "Size": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-ebs-volume.html#cfn-ec2-ebs-volume-size", "PrimitiveType": "Integer", From 75d5ee9e41935a9525fa6cfe5a059398d0a799cd Mon Sep 17 00:00:00 2001 From: Shiv Lakshminarayan Date: Wed, 1 Apr 2020 14:56:07 -0700 Subject: [PATCH 42/53] feat(cli): write stack outputs to a file (#7020) feat(cli): write stack outputs to a file Write stack outputs from deployments into a file. A flag `--outputs-file` can be provided where stack outputs will be written in `json` format. Supports multi-stack and wild-card deployments where all the generated outputs from deployed stacks will be written to the outputs file. Closes #1773 --- packages/aws-cdk/README.md | 62 ++++++++++++++++++- packages/aws-cdk/bin/cdk.ts | 4 +- packages/aws-cdk/lib/cdk-toolkit.ts | 22 +++++++ packages/aws-cdk/test/integ/cli/app/app.js | 31 ++++++++++ ...deploy-wildcard-with-outputs-expected.json | 8 +++ .../cli/cdk-deploy-with-outputs-expected.json | 5 ++ packages/aws-cdk/test/integ/cli/common.bash | 2 + .../test-cdk-deploy-wildcard-with-outputs.sh | 28 +++++++++ .../integ/cli/test-cdk-deploy-with-outputs.sh | 26 ++++++++ .../aws-cdk/test/integ/cli/test-cdk-ls.sh | 2 + 10 files changed, 187 insertions(+), 3 deletions(-) create mode 100644 packages/aws-cdk/test/integ/cli/cdk-deploy-wildcard-with-outputs-expected.json create mode 100644 packages/aws-cdk/test/integ/cli/cdk-deploy-with-outputs-expected.json create mode 100755 packages/aws-cdk/test/integ/cli/test-cdk-deploy-wildcard-with-outputs.sh create mode 100755 packages/aws-cdk/test/integ/cli/test-cdk-deploy-with-outputs.sh diff --git a/packages/aws-cdk/README.md b/packages/aws-cdk/README.md index c6146379dea85..75448eabfe8e8 100644 --- a/packages/aws-cdk/README.md +++ b/packages/aws-cdk/README.md @@ -158,9 +158,67 @@ Example of overwriting the topic name from a previous deployment. $ cdk deploy --parameters "ParametersStack:TopicNameParam=blahagain" --force ``` -⚠️ Parameters will be applied to all stacks if a stack name is not specified or `*` is provided. Parameters provided to Stacks that do not make use of the parameter will not successfully deploy. +⚠️ Parameters will be applied to all stacks if a stack name is not specified or `*` is provided. +Parameters provided to Stacks that do not make use of the parameter will not successfully deploy. -⚠️ Parameters do not propagate to NestedStacks. These must be sent with the constructor. See Nested Stack [documentation](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudformation.NestedStack.html) +⚠️ Parameters do not propagate to NestedStacks. These must be sent with the constructor. +See Nested Stack [documentation](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudformation.NestedStack.html) + +##### Outputs + +Write stack outputs from deployments into a file. When your stack finishes deploying, all stack outputs +will be written to the output file as JSON. + +Usage of output in a CDK stack +```typescript +const fn = new lambda.Function(this, "fn", { + handler: "index.handler", + code: lambda.Code.fromInline(`exports.handler = \${handler.toString()}`), + runtime: lambda.Runtime.NODEJS_10_X +}); + +new cdk.CfnOutput(this, 'FunctionArn', { + value: fn.functionArn, +}); +``` + +Specify an outputs file to write to by supplying the `--outputs-file` parameter + +```console +$ cdk deploy --outputs-file outputs.json +``` + +When the stack finishes deployment, `outputs.json` would look like this: +```json +{ + "MyStack": { + "FunctionArn": "arn:aws:lambda:us-east-1:123456789012:function:MyStack-fn5FF616E3-G632ITHSP5HK" + } +} +``` + +⚠️ The `key` of the outputs corresponds to the logical ID of the `CfnOutput`. +Read more about identifiers in the CDK [here](https://docs.aws.amazon.com/cdk/latest/guide/identifiers.html) + +If multiple stacks are being deployed or the wild card `*` is used to deploy all stacks, all outputs +are written to the same output file where each stack artifact ID is a key in the JSON file + + +```console +$ cdk deploy '*' --outputs-file "/Users/code/myproject/outputs.json" +``` + +Example `outputs.json` after deployment of multiple stacks +```json +{ + "MyStack": { + "FunctionArn": "arn:aws:lambda:us-east-1:123456789012:function:MyStack-fn5FF616E3-G632ITHSP5HK" + }, + "AnotherStack": { + "VPCId": "vpc-z0mg270fee16693f" + } +} +``` #### `cdk destroy` Deletes a stack from it's environment. This will cause the resources in the stack to be destroyed (unless they were diff --git a/packages/aws-cdk/bin/cdk.ts b/packages/aws-cdk/bin/cdk.ts index 672d676b0d455..0fca5f06b3c8a 100644 --- a/packages/aws-cdk/bin/cdk.ts +++ b/packages/aws-cdk/bin/cdk.ts @@ -71,6 +71,7 @@ async function parseCommandLineArguments() { .option('execute', { type: 'boolean', desc: 'Whether to execute ChangeSet (--no-execute will NOT execute the ChangeSet)', default: true }) .option('force', { alias: 'f', type: 'boolean', desc: 'Always deploy stack even if templates are identical', default: false }) .option('parameters', { type: 'array', desc: 'Additional parameters passed to CloudFormation at deploy time (STACK:KEY=VALUE)', nargs: 1, requiresArg: true, default: {} }) + .option('outputs-file', { type: 'string', alias: 'O', desc: 'Path to file where stack outputs will be written as JSON', requiresArg: true }) ) .command('destroy [STACKS..]', 'Destroy the stack(s) named STACKS', yargs => yargs .option('exclusively', { type: 'boolean', alias: 'e', desc: 'Only destroy requested stacks, don\'t include dependees' }) @@ -238,7 +239,8 @@ async function initCommandLine() { sdk: aws, execute: args.execute, force: args.force, - parameters: parameterMap + parameters: parameterMap, + outputsFile: args.outputsFile }); case 'destroy': diff --git a/packages/aws-cdk/lib/cdk-toolkit.ts b/packages/aws-cdk/lib/cdk-toolkit.ts index 1bfa81a6eedd0..dea29b910345f 100644 --- a/packages/aws-cdk/lib/cdk-toolkit.ts +++ b/packages/aws-cdk/lib/cdk-toolkit.ts @@ -100,6 +100,9 @@ export class CdkToolkit { } } + const stackOutputs: { [key: string]: any } = { }; + const outputsFile = options.outputsFile; + for (const stack of stacks) { if (stacks.length !== 1) { highlight(stack.displayName); } if (!stack.environment) { @@ -170,6 +173,8 @@ export class CdkToolkit { if (Object.keys(result.outputs).length > 0) { print('\nOutputs:'); + + stackOutputs[stack.stackName] = result.outputs; } for (const name of Object.keys(result.outputs)) { @@ -183,6 +188,17 @@ export class CdkToolkit { } catch (e) { error('\n ❌ %s failed: %s', colors.bold(stack.displayName), e); throw e; + } finally { + // If an outputs file has been specified, create the file path and write stack outputs to it once. + // Outputs are written after all stacks have been deployed. If a stack deployment fails, + // all of the outputs from successfully deployed stacks before the failure will still be written. + if (outputsFile) { + fs.ensureFileSync(outputsFile); + fs.writeJson(outputsFile, stackOutputs, { + spaces: 2, + encoding: 'utf8' + }); + } } } } @@ -337,6 +353,12 @@ export interface DeployOptions { * @default {} */ parameters?: { [name: string]: string | undefined }; + + /** + * Path to file where stack outputs will be written after a successful deploy as JSON + * @default - Outputs are not written to any file + */ + outputsFile?: string; } export interface DestroyOptions { diff --git a/packages/aws-cdk/test/integ/cli/app/app.js b/packages/aws-cdk/test/integ/cli/app/app.js index e4ca9ce7f39c5..b1b1294cc9d81 100644 --- a/packages/aws-cdk/test/integ/cli/app/app.js +++ b/packages/aws-cdk/test/integ/cli/app/app.js @@ -61,6 +61,34 @@ class OtherParameterStack extends cdk.Stack { } } +class OutputsStack extends cdk.Stack { + constructor(parent, id, props) { + super(parent, id, props); + + const topic = new sns.Topic(this, 'MyOutput', { + topicName: '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: 'MyOtherTopic' + }); + + new cdk.CfnOutput(this, 'TopicName', { + value: topic.topicName + }); + } +} + class IamStack extends cdk.Stack { constructor(parent, id, props) { super(parent, id, props); @@ -208,6 +236,9 @@ 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 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`); const providing = new ProvidingStack(app, `${stackPrefix}-order-providing`); diff --git a/packages/aws-cdk/test/integ/cli/cdk-deploy-wildcard-with-outputs-expected.json b/packages/aws-cdk/test/integ/cli/cdk-deploy-wildcard-with-outputs-expected.json new file mode 100644 index 0000000000000..66a2ec3ed0071 --- /dev/null +++ b/packages/aws-cdk/test/integ/cli/cdk-deploy-wildcard-with-outputs-expected.json @@ -0,0 +1,8 @@ +{ + "cdk-toolkit-integration-outputs-test-1": { + "TopicName": "MyTopic" + }, + "cdk-toolkit-integration-outputs-test-2": { + "TopicName": "MyOtherTopic" + } +} \ No newline at end of file diff --git a/packages/aws-cdk/test/integ/cli/cdk-deploy-with-outputs-expected.json b/packages/aws-cdk/test/integ/cli/cdk-deploy-with-outputs-expected.json new file mode 100644 index 0000000000000..7e5a38d1d975f --- /dev/null +++ b/packages/aws-cdk/test/integ/cli/cdk-deploy-with-outputs-expected.json @@ -0,0 +1,5 @@ +{ + "cdk-toolkit-integration-outputs-test-1": { + "TopicName": "MyTopic" + } +} \ No newline at end of file diff --git a/packages/aws-cdk/test/integ/cli/common.bash b/packages/aws-cdk/test/integ/cli/common.bash index 690ef418f6ca5..ebf653fe4c9b9 100644 --- a/packages/aws-cdk/test/integ/cli/common.bash +++ b/packages/aws-cdk/test/integ/cli/common.bash @@ -93,6 +93,8 @@ function cleanup() { cleanup_stack ${STACK_NAME_PREFIX}-test-2 cleanup_stack ${STACK_NAME_PREFIX}-iam-test cleanup_stack ${STACK_NAME_PREFIX}-with-nested-stack + cleanup_stack ${STACK_NAME_PREFIX}-outputs-test-1 + cleanup_stack ${STACK_NAME_PREFIX}-outputs-test-2 } function setup() { diff --git a/packages/aws-cdk/test/integ/cli/test-cdk-deploy-wildcard-with-outputs.sh b/packages/aws-cdk/test/integ/cli/test-cdk-deploy-wildcard-with-outputs.sh new file mode 100755 index 0000000000000..09e22f2015140 --- /dev/null +++ b/packages/aws-cdk/test/integ/cli/test-cdk-deploy-wildcard-with-outputs.sh @@ -0,0 +1,28 @@ +#!/bin/bash +set -euo pipefail +scriptdir=$(cd $(dirname $0) && pwd) +source ${scriptdir}/common.bash +# ---------------------------------------------------------- + +setup + +outputs_file=${integ_test_dir}/outputs/outputs.json +expected_outputs=${scriptdir}/cdk-deploy-wildcard-with-outputs-expected.json + +# deploy all outputs stacks +cdk deploy ${STACK_NAME_PREFIX}-outputs-test-\* --outputs-file ${outputs_file} +echo "Stacks deployed successfully" + +# verify generated outputs file +generated_outputs_file="$(cat ${outputs_file})" +expected_outputs_file="$(cat ${expected_outputs})" +if [[ "${generated_outputs_file}" != "${expected_outputs_file}" ]]; then + fail "unexpected outputs. Expected: ${expected_outputs_file} Actual: ${generated_outputs_file}" +fi + +# destroy +rm ${outputs_file} +cdk destroy -f ${STACK_NAME_PREFIX}-outputs-test-1 +cdk destroy -f ${STACK_NAME_PREFIX}-outputs-test-2 + +echo "✅ success" diff --git a/packages/aws-cdk/test/integ/cli/test-cdk-deploy-with-outputs.sh b/packages/aws-cdk/test/integ/cli/test-cdk-deploy-with-outputs.sh new file mode 100755 index 0000000000000..da90c0e14c43d --- /dev/null +++ b/packages/aws-cdk/test/integ/cli/test-cdk-deploy-with-outputs.sh @@ -0,0 +1,26 @@ +#!/bin/bash +set -euo pipefail +scriptdir=$(cd $(dirname $0) && pwd) +source ${scriptdir}/common.bash +# ---------------------------------------------------------- + +setup + +outputs_file=${integ_test_dir}/outputs/outputs.json +expected_outputs=${scriptdir}/cdk-deploy-with-outputs-expected.json + +cdk deploy -v ${STACK_NAME_PREFIX}-outputs-test-1 --outputs-file ${outputs_file} +echo "Stack deployed successfully" + +# verify generated outputs file +generated_outputs_file="$(cat ${outputs_file})" +expected_outputs_file="$(cat ${expected_outputs})" +if [[ "${generated_outputs_file}" != "${expected_outputs_file}" ]]; then + fail "unexpected outputs. Expected: ${expected_outputs_file} Actual: ${generated_outputs_file}" +fi + +# destroy +rm ${outputs_file} +cdk destroy -f ${STACK_NAME_PREFIX}-outputs-test-1 + +echo "✅ success" diff --git a/packages/aws-cdk/test/integ/cli/test-cdk-ls.sh b/packages/aws-cdk/test/integ/cli/test-cdk-ls.sh index b37e99bd2825c..05476f3b8d854 100755 --- a/packages/aws-cdk/test/integ/cli/test-cdk-ls.sh +++ b/packages/aws-cdk/test/integ/cli/test-cdk-ls.sh @@ -15,6 +15,8 @@ ${STACK_NAME_PREFIX}-iam-test ${STACK_NAME_PREFIX}-lambda ${STACK_NAME_PREFIX}-missing-ssm-parameter ${STACK_NAME_PREFIX}-order-providing +${STACK_NAME_PREFIX}-outputs-test-1 +${STACK_NAME_PREFIX}-outputs-test-2 ${STACK_NAME_PREFIX}-param-test-1 ${STACK_NAME_PREFIX}-param-test-2 ${STACK_NAME_PREFIX}-test-1 From a711c0167de8c41796ee20a0b85b763bdfa4a643 Mon Sep 17 00:00:00 2001 From: Nicolai Lang Date: Thu, 2 Apr 2020 00:43:31 +0200 Subject: [PATCH 43/53] fix(acm-certificatemanager): DnsValidatedCertificateHandler support for `SubjectAlternativeNames` (#7050) - [x] added support for certificates with `SubjectAlternativNames` by creating a Dns Record in Route53 for distinct entries in `DomainValidationOptions` (packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/lib/index.js) - [x] added unittests fixes #4659 --- .../lib/index.js | 46 ++-- .../test/handler.test.js | 202 ++++++++++++++++++ ...oad-balanced-fargate-service.expected.json | 18 +- 3 files changed, 240 insertions(+), 26 deletions(-) diff --git a/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/lib/index.js b/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/lib/index.js index ab112a3b248f0..866e9405b049e 100644 --- a/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/lib/index.js +++ b/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/lib/index.js @@ -99,15 +99,24 @@ const requestCertificate = async function(requestId, domainName, subjectAlternat console.log('Waiting for ACM to provide DNS records for validation...'); - let record; - for (let attempt = 0; attempt < maxAttempts && !record; attempt++) { + let records; + for (let attempt = 0; attempt < maxAttempts && !records; attempt++) { const { Certificate } = await acm.describeCertificate({ CertificateArn: reqCertResponse.CertificateArn }).promise(); const options = Certificate.DomainValidationOptions || []; - if (options.length > 0 && options[0].ResourceRecord) { - record = options[0].ResourceRecord; + // some alternative names will produce the same validation record + // as the main domain (eg. example.com + *.example.com) + // filtering duplicates to avoid errors with adding the same record + // to the route53 zone twice + const unique = options + .map((val) => val.ResourceRecord) + .reduce((acc, cur) => { + acc[cur.Name] = cur; + return acc; + }, {}); + records = Object.keys(unique).sort().map(key => unique[key]); } else { // Exponential backoff with jitter based on 200ms base // component of backoff fixed to ensure minimum total wait time on @@ -116,25 +125,28 @@ const requestCertificate = async function(requestId, domainName, subjectAlternat await sleep(random() * base * 50 + base * 150); } } - if (!record) { + if (!records) { throw new Error(`Response from describeCertificate did not contain DomainValidationOptions after ${maxAttempts} attempts.`) } - console.log(`Upserting DNS record into zone ${hostedZoneId}: ${record.Name} ${record.Type} ${record.Value}`); + console.log(`Upserting ${records.length} DNS records into zone ${hostedZoneId}:`); const changeBatch = await route53.changeResourceRecordSets({ ChangeBatch: { - Changes: [{ - Action: 'UPSERT', - ResourceRecordSet: { - Name: record.Name, - Type: record.Type, - TTL: 60, - ResourceRecords: [{ - Value: record.Value - }] - } - }] + Changes: records.map((record) => { + console.log(`${record.Name} ${record.Type} ${record.Value}`) + return { + Action: 'UPSERT', + ResourceRecordSet: { + Name: record.Name, + Type: record.Type, + TTL: 60, + ResourceRecords: [{ + Value: record.Value + }] + } + }; + }), }, HostedZoneId: hostedZoneId }).promise(); diff --git a/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/test/handler.test.js b/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/test/handler.test.js index 5b3378e93b524..3e93f09680a91 100644 --- a/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/test/handler.test.js +++ b/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/test/handler.test.js @@ -13,10 +13,13 @@ describe('DNS Validated Certificate Handler', () => { let origLog = console.log; const testRequestId = 'f4ef1b10-c39a-44e3-99c0-fbf7e53c3943'; const testDomainName = 'test.example.com'; + const testSubjectAlternativeName = 'foo.example.com'; const testHostedZoneId = '/hostedzone/Z3P5QSUBK4POTI'; const testCertificateArn = 'arn:aws:acm:region:123456789012:certificate/12345678-1234-1234-1234-123456789012'; const testRRName = '_3639ac514e785e898d2646601fa951d5.example.com'; const testRRValue = '_x2.acm-validations.aws'; + const testAltRRName = '_3639ac514e785e898d2646601fa951d5.foo.example.com'; + const testAltRRValue = '_x3.acm-validations.aws'; const spySleep = sinon.spy(function(ms) { return Promise.resolve(); }); @@ -145,6 +148,205 @@ describe('DNS Validated Certificate Handler', () => { }); }); + test('Create operation with `SubjectAlternativeNames` requests a certificate with validation records for all options', () => { + const requestCertificateFake = sinon.fake.resolves({ + CertificateArn: testCertificateArn, + }); + + const describeCertificateFake = sinon.stub(); + describeCertificateFake.onFirstCall().resolves({ + Certificate: { + CertificateArn: testCertificateArn + } + }); + describeCertificateFake.resolves({ + Certificate: { + CertificateArn: testCertificateArn, + DomainValidationOptions: [ + { + ValidationStatus: 'SUCCESS', + ResourceRecord: { + Name: testRRName, + Type: 'CNAME', + Value: testRRValue + } + }, { + ValidationStatus: 'SUCCESS', + ResourceRecord: { + Name: testAltRRName, + Type: 'CNAME', + Value: testAltRRValue + } + } + ] + } + }); + + const changeResourceRecordSetsFake = sinon.fake.resolves({ + ChangeInfo: { + Id: 'bogus' + } + }); + + AWS.mock('ACM', 'requestCertificate', requestCertificateFake); + AWS.mock('ACM', 'describeCertificate', describeCertificateFake); + AWS.mock('Route53', 'changeResourceRecordSets', changeResourceRecordSetsFake); + + const request = nock(ResponseURL).put('/', body => { + return body.Status === 'SUCCESS'; + }).reply(200); + + return LambdaTester(handler.certificateRequestHandler) + .event({ + RequestType: 'Create', + RequestId: testRequestId, + ResourceProperties: { + DomainName: testDomainName, + SubjectAlternativeNames: [testSubjectAlternativeName], + HostedZoneId: testHostedZoneId, + Region: 'us-east-1', + } + }) + .expectResolve(() => { + sinon.assert.calledWith(requestCertificateFake, sinon.match({ + DomainName: testDomainName, + ValidationMethod: 'DNS', + SubjectAlternativeNames: [testSubjectAlternativeName] + })); + sinon.assert.calledWith(changeResourceRecordSetsFake, sinon.match({ + ChangeBatch: { + Changes: [ + { + Action: 'UPSERT', + ResourceRecordSet: { + Name: testRRName, + Type: 'CNAME', + TTL: 60, + ResourceRecords: [{ + Value: testRRValue + }] + } + }, { + Action: 'UPSERT', + ResourceRecordSet: { + Name: testAltRRName, + Type: 'CNAME', + TTL: 60, + ResourceRecords: [{ + Value: testAltRRValue + }] + } + } + ] + }, + HostedZoneId: testHostedZoneId + })); + expect(request.isDone()).toBe(true); + }); + }); + + test('Create operation with `SubjectAlternativeNames` requests a certificate for all options without duplicates', () => { + const requestCertificateFake = sinon.fake.resolves({ + CertificateArn: testCertificateArn, + }); + + const describeCertificateFake = sinon.stub(); + describeCertificateFake.onFirstCall().resolves({ + Certificate: { + CertificateArn: testCertificateArn + } + }); + describeCertificateFake.resolves({ + Certificate: { + CertificateArn: testCertificateArn, + DomainValidationOptions: [ + { + ValidationStatus: 'SUCCESS', + ResourceRecord: { + Name: testRRName, + Type: 'CNAME', + Value: testRRValue + } + }, { + ValidationStatus: 'SUCCESS', + ResourceRecord: { + Name: testAltRRName, + Type: 'CNAME', + Value: testAltRRValue + } + }, { + ValidationStatus: 'SUCCESS', + ResourceRecord: { + Name: testRRName, + Type: 'CNAME', + Value: testRRValue + } + } + ] + } + }); + + const changeResourceRecordSetsFake = sinon.fake.resolves({ + ChangeInfo: { + Id: 'bogus' + } + }); + + AWS.mock('ACM', 'requestCertificate', requestCertificateFake); + AWS.mock('ACM', 'describeCertificate', describeCertificateFake); + AWS.mock('Route53', 'changeResourceRecordSets', changeResourceRecordSetsFake); + + const request = nock(ResponseURL).put('/', body => { + return body.Status === 'SUCCESS'; + }).reply(200); + + return LambdaTester(handler.certificateRequestHandler) + .event({ + RequestType: 'Create', + RequestId: testRequestId, + ResourceProperties: { + DomainName: testDomainName, + HostedZoneId: testHostedZoneId, + Region: 'us-east-1', + } + }) + .expectResolve(() => { + sinon.assert.calledWith(requestCertificateFake, sinon.match({ + DomainName: testDomainName, + ValidationMethod: 'DNS' + })); + sinon.assert.calledWith(changeResourceRecordSetsFake, sinon.match({ + ChangeBatch: { + Changes: [ + { + Action: 'UPSERT', + ResourceRecordSet: { + Name: testRRName, + Type: 'CNAME', + TTL: 60, + ResourceRecords: [{ + Value: testRRValue + }] + } + }, { + Action: 'UPSERT', + ResourceRecordSet: { + Name: testAltRRName, + Type: 'CNAME', + TTL: 60, + ResourceRecords: [{ + Value: testAltRRValue + }] + } + } + ] + }, + HostedZoneId: testHostedZoneId + })); + expect(request.isDone()).toBe(true); + }); + }); + test('Create operation fails after more than 60s if certificate has no DomainValidationOptions', () => { handler.withRandom(() => 0); const requestCertificateFake = sinon.fake.resolves({ diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.load-balanced-fargate-service.expected.json b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.load-balanced-fargate-service.expected.json index ba5017dd9e617..d01d8b9bfd6d9 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.load-balanced-fargate-service.expected.json +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/integ.load-balanced-fargate-service.expected.json @@ -545,7 +545,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParameters01b2187f99280c53b7d58040d494b5d051e1e253601fc32dee62ba56712db247S3Bucket3747EA0C" + "Ref": "AssetParameters19e461d2ff1a5b90438fed6ceee4c197d7efee8712a6f76d85b501ab20bfb1a2S3BucketFCCD3A76" }, "S3Key": { "Fn::Join": [ @@ -558,7 +558,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters01b2187f99280c53b7d58040d494b5d051e1e253601fc32dee62ba56712db247S3VersionKey13E25E1F" + "Ref": "AssetParameters19e461d2ff1a5b90438fed6ceee4c197d7efee8712a6f76d85b501ab20bfb1a2S3VersionKey07AF06B6" } ] } @@ -571,7 +571,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters01b2187f99280c53b7d58040d494b5d051e1e253601fc32dee62ba56712db247S3VersionKey13E25E1F" + "Ref": "AssetParameters19e461d2ff1a5b90438fed6ceee4c197d7efee8712a6f76d85b501ab20bfb1a2S3VersionKey07AF06B6" } ] } @@ -865,17 +865,17 @@ } }, "Parameters": { - "AssetParameters01b2187f99280c53b7d58040d494b5d051e1e253601fc32dee62ba56712db247S3Bucket3747EA0C": { + "AssetParameters19e461d2ff1a5b90438fed6ceee4c197d7efee8712a6f76d85b501ab20bfb1a2S3BucketFCCD3A76": { "Type": "String", - "Description": "S3 bucket for asset \"01b2187f99280c53b7d58040d494b5d051e1e253601fc32dee62ba56712db247\"" + "Description": "S3 bucket for asset \"19e461d2ff1a5b90438fed6ceee4c197d7efee8712a6f76d85b501ab20bfb1a2\"" }, - "AssetParameters01b2187f99280c53b7d58040d494b5d051e1e253601fc32dee62ba56712db247S3VersionKey13E25E1F": { + "AssetParameters19e461d2ff1a5b90438fed6ceee4c197d7efee8712a6f76d85b501ab20bfb1a2S3VersionKey07AF06B6": { "Type": "String", - "Description": "S3 key for asset version \"01b2187f99280c53b7d58040d494b5d051e1e253601fc32dee62ba56712db247\"" + "Description": "S3 key for asset version \"19e461d2ff1a5b90438fed6ceee4c197d7efee8712a6f76d85b501ab20bfb1a2\"" }, - "AssetParameters01b2187f99280c53b7d58040d494b5d051e1e253601fc32dee62ba56712db247ArtifactHashFB4438F1": { + "AssetParameters19e461d2ff1a5b90438fed6ceee4c197d7efee8712a6f76d85b501ab20bfb1a2ArtifactHash652C125C": { "Type": "String", - "Description": "Artifact hash for asset \"01b2187f99280c53b7d58040d494b5d051e1e253601fc32dee62ba56712db247\"" + "Description": "Artifact hash for asset \"19e461d2ff1a5b90438fed6ceee4c197d7efee8712a6f76d85b501ab20bfb1a2\"" } } } From d6ecf44e84cb326bcbfe48583fdae66829a86adb Mon Sep 17 00:00:00 2001 From: Shiv Lakshminarayan Date: Wed, 1 Apr 2020 16:52:12 -0700 Subject: [PATCH 44/53] feat(kinesis): streams are encrypted by default (#7102) Currently, the default configuration for a stream is to be unencrypted. This change uses the KMS master key and enables encryption on Streams by default. Stream encryption is not supported in `cn-north-1` and `cn-northwest-1` regions so there's a condition that sets the default in those regions to unencrypted. **Why is this not a breaking change** Modifying the encryption settings on a Stream does not require interruption. Adding/removing the `StreamEncryption` properties will enable/disable the encryption on the stream accordingly without interruption --- packages/@aws-cdk/aws-kinesis/README.md | 10 +- packages/@aws-cdk/aws-kinesis/lib/stream.ts | 39 +- .../@aws-cdk/aws-kinesis/test/test.stream.ts | 1320 ++++++++++------- .../test/integ.kinesis.expected.json | 36 +- .../test/integ.kinesiswithdlq.expected.json | 36 +- 5 files changed, 855 insertions(+), 586 deletions(-) diff --git a/packages/@aws-cdk/aws-kinesis/README.md b/packages/@aws-cdk/aws-kinesis/README.md index d805856111752..e04c868643231 100644 --- a/packages/@aws-cdk/aws-kinesis/README.md +++ b/packages/@aws-cdk/aws-kinesis/README.md @@ -41,7 +41,7 @@ new Stream(this, "MyFirstStream", { ``` You can also specify properties such as `shardCount` to indicate how many shards the stream should choose and a `retentionPeriod` -to specify how many logn the data in the shards should remain accessible. +to specify how long the data in the shards should remain accessible. Read more at [Creating and Managing Streams](https://docs.aws.amazon.com/streams/latest/dev/working-with-streams.html) ```ts @@ -52,19 +52,15 @@ new Stream(this, "MyFirstStream", { }); ``` -Streams are not encrypted by default. - ### Encryption [Stream encryption](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-kinesis-stream-streamencryption.html) enables server-side encryption using an AWS KMS key for a specified stream. -You can enable encryption on your stream with the master key owned by Kinesis Data Streams by specifying the `encryption` property. +Encryption is enabled by default on your stream with the master key owned by Kinesis Data Streams in regions where it is supported. ```ts -new Stream(this, 'MyEncryptedStream', { - encryption: StreamEncryption.MANAGED -}); +new Stream(this, 'MyEncryptedStream'); ``` You can enable encryption on your stream with a user-managed key by specifying the `encryption` property. diff --git a/packages/@aws-cdk/aws-kinesis/lib/stream.ts b/packages/@aws-cdk/aws-kinesis/lib/stream.ts index f6a683449c09d..646e824ec0e49 100644 --- a/packages/@aws-cdk/aws-kinesis/lib/stream.ts +++ b/packages/@aws-cdk/aws-kinesis/lib/stream.ts @@ -1,6 +1,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; -import { Construct, Duration, IResource, Resource, Stack } from '@aws-cdk/core'; +import { Aws, CfnCondition, Construct, Duration, Fn, IResource, Resource, Stack } from '@aws-cdk/core'; +import { IResolvable } from 'constructs'; import { CfnStream } from './kinesis.generated'; /** @@ -201,7 +202,9 @@ export interface StreamProps { * If you choose KMS, you can specify a KMS key via `encryptionKey`. If * encryption key is not specified, a key will automatically be created. * - * @default - StreamEncryption.KMS if encryptionKey is specified, or StreamEncryption.UNENCRYPTED otherwise + * @default - StreamEncryption.KMS if encrypted Streams are supported in the region + * or StreamEncryption.UNENCRYPTED otherwise. + * StreamEncryption.KMS if an encryption key is supplied through the encryptionKey property */ readonly encryption?: StreamEncryption; @@ -210,8 +213,9 @@ export interface StreamProps { * * The 'encryption' property must be set to "Kms". * - * @default - If encryption is set to "KMS" and this property is undefined, a - * new KMS key will be created and associated with this stream. + * @default - Kinesis Data Streams master key ('/alias/aws/kinesis'). + * If encryption is set to StreamEncryption.KMS and this property is undefined, a new KMS key + * will be created and associated with this stream. */ readonly encryptionKey?: kms.IKey; } @@ -290,13 +294,36 @@ export class Stream extends StreamBase { * user's configuration. */ private parseEncryption(props: StreamProps): { - streamEncryption?: CfnStream.StreamEncryptionProperty, + streamEncryption?: CfnStream.StreamEncryptionProperty | IResolvable encryptionKey?: kms.IKey } { + // if encryption properties are not set, default to KMS in regions where KMS is available + if (!props.encryption && !props.encryptionKey) { + + const conditionName = 'AwsCdkKinesisEncryptedStreamsUnsupportedRegions'; + const existing = Stack.of(this).node.tryFindChild(conditionName); + + // create a single condition for the Stack + if (!existing) { + new CfnCondition(Stack.of(this), conditionName, { + expression: Fn.conditionOr( + Fn.conditionEquals(Aws.REGION, 'cn-north-1'), + Fn.conditionEquals(Aws.REGION, 'cn-northwest-1') + ) + }); + } + + return { + streamEncryption: Fn.conditionIf(conditionName, + Aws.NO_VALUE, + { EncryptionType: 'KMS', KeyId: 'alias/aws/kinesis'}) + }; + } + // default based on whether encryption key is specified const encryptionType = props.encryption ?? - (props.encryptionKey ? StreamEncryption.KMS : StreamEncryption.UNENCRYPTED); + (props.encryptionKey ? StreamEncryption.KMS : StreamEncryption.UNENCRYPTED); // if encryption key is set, encryption must be set to KMS. if (encryptionType !== StreamEncryption.KMS && props.encryptionKey) { diff --git a/packages/@aws-cdk/aws-kinesis/test/test.stream.ts b/packages/@aws-cdk/aws-kinesis/test/test.stream.ts index b229bc669808e..bcdf18dd8438a 100644 --- a/packages/@aws-cdk/aws-kinesis/test/test.stream.ts +++ b/packages/@aws-cdk/aws-kinesis/test/test.stream.ts @@ -14,14 +14,122 @@ export = { new Stream(stack, 'MyStream'); expect(stack).toMatch({ - "Resources": { - "MyStream5C050E93": { - "Type": "AWS::Kinesis::Stream", - "Properties": { - "RetentionPeriodHours": 24, - "ShardCount": 1 + Resources: { + MyStream5C050E93: { + Type: 'AWS::Kinesis::Stream', + Properties: { + ShardCount: 1, + RetentionPeriodHours: 24, + StreamEncryption: { + 'Fn::If': [ + 'AwsCdkKinesisEncryptedStreamsUnsupportedRegions', + { + Ref: 'AWS::NoValue' + }, + { + EncryptionType: 'KMS', + KeyId: 'alias/aws/kinesis' + } + ] + } + } + } + }, + Conditions: { + AwsCdkKinesisEncryptedStreamsUnsupportedRegions: { + 'Fn::Or': [ + { + 'Fn::Equals': [ + { + Ref: 'AWS::Region' + }, + 'cn-north-1' + ] + }, + { + 'Fn::Equals': [ + { + Ref: 'AWS::Region' + }, + 'cn-northwest-1' + ] + } + ] + } + } + }); + + test.done(); + }, + + 'multiple default streams only have one condition for encryption'(test: Test) { + const stack = new Stack(); + + new Stream(stack, 'MyStream'); + new Stream(stack, 'MyOtherStream'); + + expect(stack).toMatch({ + Resources: { + MyStream5C050E93: { + Type: 'AWS::Kinesis::Stream', + Properties: { + ShardCount: 1, + RetentionPeriodHours: 24, + StreamEncryption: { + 'Fn::If': [ + 'AwsCdkKinesisEncryptedStreamsUnsupportedRegions', + { + Ref: 'AWS::NoValue' + }, + { + EncryptionType: 'KMS', + KeyId: 'alias/aws/kinesis' + } + ] + } + } + }, + MyOtherStream86FCC9CE: { + Type: 'AWS::Kinesis::Stream', + Properties: { + ShardCount: 1, + RetentionPeriodHours: 24, + StreamEncryption: { + 'Fn::If': [ + 'AwsCdkKinesisEncryptedStreamsUnsupportedRegions', + { + Ref: 'AWS::NoValue' + }, + { + EncryptionType: 'KMS', + KeyId: 'alias/aws/kinesis' + } + ] + } } } + }, + Conditions: { + AwsCdkKinesisEncryptedStreamsUnsupportedRegions: { + 'Fn::Or': [ + { + 'Fn::Equals': [ + { + Ref: 'AWS::Region' + }, + 'cn-north-1' + ] + }, + { + 'Fn::Equals': [ + { + Ref: 'AWS::Region' + }, + 'cn-northwest-1' + ] + } + ] + } } }); @@ -40,7 +148,7 @@ export = { test.done(); }, - "uses explicit shard count"(test: Test) { + 'uses explicit shard count'(test: Test) { const stack = new Stack(); new Stream(stack, 'MyStream', { @@ -48,41 +156,109 @@ export = { }); expect(stack).toMatch({ - "Resources": { - "MyStream5C050E93": { - "Type": "AWS::Kinesis::Stream", - "Properties": { - "RetentionPeriodHours": 24, - "ShardCount": 2 + Resources: { + MyStream5C050E93: { + Type: 'AWS::Kinesis::Stream', + Properties: { + ShardCount: 2, + RetentionPeriodHours: 24, + StreamEncryption: { + 'Fn::If': [ + 'AwsCdkKinesisEncryptedStreamsUnsupportedRegions', + { + Ref: 'AWS::NoValue' + }, + { + EncryptionType: 'KMS', + KeyId: 'alias/aws/kinesis' + } + ] + } } } + }, + Conditions: { + AwsCdkKinesisEncryptedStreamsUnsupportedRegions: { + 'Fn::Or': [ + { + 'Fn::Equals': [ + { + Ref: 'AWS::Region' + }, + 'cn-north-1' + ] + }, + { + 'Fn::Equals': [ + { + Ref: 'AWS::Region' + }, + 'cn-northwest-1' + ] + } + ] + } } }); test.done(); }, - "uses explicit retention period"(test: Test) { + 'uses explicit retention period'(test: Test) { const stack = new Stack(); - new Stream(stack, "MyStream", { + new Stream(stack, 'MyStream', { retentionPeriod: Duration.hours(168) }); expect(stack).toMatch({ - "Resources": { - "MyStream5C050E93": { - "Type": "AWS::Kinesis::Stream", - "Properties": { - "RetentionPeriodHours": 168, - "ShardCount": 1 + Resources: { + MyStream5C050E93: { + Type: 'AWS::Kinesis::Stream', + Properties: { + ShardCount: 1, + RetentionPeriodHours: 168, + StreamEncryption: { + 'Fn::If': [ + 'AwsCdkKinesisEncryptedStreamsUnsupportedRegions', + { + Ref: 'AWS::NoValue' + }, + { + EncryptionType: 'KMS', + KeyId: 'alias/aws/kinesis' + } + ] + } } } + }, + Conditions: { + AwsCdkKinesisEncryptedStreamsUnsupportedRegions: { + 'Fn::Or': [ + { + 'Fn::Equals': [ + { + Ref: 'AWS::Region' + }, + 'cn-north-1' + ] + }, + { + 'Fn::Equals': [ + { + Ref: 'AWS::Region' + }, + 'cn-northwest-1' + ] + } + ] + } } }); test.done(); }, - "retention period must be between 24 and 168 hours"(test: Test) { + 'retention period must be between 24 and 168 hours'(test: Test) { test.throws(() => { new Stream(new Stack(), 'MyStream', { retentionPeriod: Duration.hours(169) @@ -90,9 +266,9 @@ export = { }, /retentionPeriod must be between 24 and 168 hours. Received 169/); test.throws(() => { - new Stream(new Stack(), 'MyStream', { - retentionPeriod: Duration.hours(23) - }); + new Stream(new Stack(), 'MyStream', { + retentionPeriod: Duration.hours(23) + }); }, /retentionPeriod must be between 24 and 168 hours. Received 23/); test.done(); @@ -109,15 +285,15 @@ export = { // THEN expect(stack).toMatch({ - "Resources": { - "MyStream5C050E93": { - "Type": "AWS::Kinesis::Stream", - "Properties": { - "ShardCount": 1, - "RetentionPeriodHours": 24, - "StreamEncryption": { - "EncryptionType": "KMS", - "KeyId": "alias/aws/kinesis" + Resources: { + MyStream5C050E93: { + Type: 'AWS::Kinesis::Stream', + Properties: { + ShardCount: 1, + RetentionPeriodHours: 24, + StreamEncryption: { + EncryptionType: 'KMS', + KeyId: 'alias/aws/kinesis' } } } @@ -138,7 +314,8 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::Kinesis::Stream', { + expect(stack).to( + haveResource('AWS::Kinesis::Stream', { ShardCount: 1, RetentionPeriodHours: 24, StreamEncryption: { @@ -153,7 +330,7 @@ export = { test.done(); }, - "auto-creates KMS key if encryption type is KMS but no key is provided"(test: Test) { + 'auto-creates KMS key if encryption type is KMS but no key is provided'(test: Test) { const stack = new Stack(); new Stream(stack, 'MyStream', { @@ -161,71 +338,68 @@ export = { }); expect(stack).toMatch({ - "Resources": { - "MyStreamKey76F3300E": { - "Type": "AWS::KMS::Key", - "Properties": { - "Description": "Created by MyStream", - "KeyPolicy": { - "Statement": [ + Resources: { + MyStreamKey76F3300E: { + Type: 'AWS::KMS::Key', + Properties: { + Description: 'Created by MyStream', + KeyPolicy: { + Statement: [ { - "Action": [ - "kms:Create*", - "kms:Describe*", - "kms:Enable*", - "kms:List*", - "kms:Put*", - "kms:Update*", - "kms:Revoke*", - "kms:Disable*", - "kms:Get*", - "kms:Delete*", - "kms:ScheduleKeyDeletion", - "kms:CancelKeyDeletion", - "kms:GenerateDataKey", - "kms:TagResource", - "kms:UntagResource" + Action: [ + 'kms:Create*', + 'kms:Describe*', + 'kms:Enable*', + 'kms:List*', + 'kms:Put*', + 'kms:Update*', + 'kms:Revoke*', + 'kms:Disable*', + 'kms:Get*', + 'kms:Delete*', + 'kms:ScheduleKeyDeletion', + 'kms:CancelKeyDeletion', + 'kms:GenerateDataKey', + 'kms:TagResource', + 'kms:UntagResource' ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::Join": [ - "", + Effect: 'Allow', + Principal: { + AWS: { + 'Fn::Join': [ + '', [ - "arn:", + 'arn:', { - "Ref": "AWS::Partition" + Ref: 'AWS::Partition' }, - ":iam::", + ':iam::', { - "Ref": "AWS::AccountId" + Ref: 'AWS::AccountId' }, - ":root" + ':root' ] ] } }, - "Resource": "*" + Resource: '*' } ], - "Version": "2012-10-17" + Version: '2012-10-17' } }, - "DeletionPolicy": "Retain", - "UpdateReplacePolicy": "Retain" + DeletionPolicy: 'Retain', + UpdateReplacePolicy: 'Retain' }, - "MyStream5C050E93": { - "Type": "AWS::Kinesis::Stream", - "Properties": { - "RetentionPeriodHours": 24, - "ShardCount": 1, - "StreamEncryption": { - "EncryptionType": "KMS", - "KeyId": { - "Fn::GetAtt": [ - "MyStreamKey76F3300E", - "Arn" - ] + MyStream5C050E93: { + Type: 'AWS::Kinesis::Stream', + Properties: { + RetentionPeriodHours: 24, + ShardCount: 1, + StreamEncryption: { + EncryptionType: 'KMS', + KeyId: { + 'Fn::GetAtt': ['MyStreamKey76F3300E', 'Arn'] } } } @@ -235,7 +409,7 @@ export = { test.done(); }, - "uses explicit KMS key if encryption type is KMS and a key is provided"(test: Test) { + 'uses explicit KMS key if encryption type is KMS and a key is provided'(test: Test) { const stack = new Stack(); const explicitKey = new kms.Key(stack, 'ExplicitKey', { @@ -248,71 +422,68 @@ export = { }); expect(stack).toMatch({ - "Resources": { - "ExplicitKey7DF42F37": { - "Type": "AWS::KMS::Key", - "Properties": { - "Description": "Explicit Key", - "KeyPolicy": { - "Statement": [ + Resources: { + ExplicitKey7DF42F37: { + Type: 'AWS::KMS::Key', + Properties: { + Description: 'Explicit Key', + KeyPolicy: { + Statement: [ { - "Action": [ - "kms:Create*", - "kms:Describe*", - "kms:Enable*", - "kms:List*", - "kms:Put*", - "kms:Update*", - "kms:Revoke*", - "kms:Disable*", - "kms:Get*", - "kms:Delete*", - "kms:ScheduleKeyDeletion", - "kms:CancelKeyDeletion", - "kms:GenerateDataKey", - "kms:TagResource", - "kms:UntagResource" + Action: [ + 'kms:Create*', + 'kms:Describe*', + 'kms:Enable*', + 'kms:List*', + 'kms:Put*', + 'kms:Update*', + 'kms:Revoke*', + 'kms:Disable*', + 'kms:Get*', + 'kms:Delete*', + 'kms:ScheduleKeyDeletion', + 'kms:CancelKeyDeletion', + 'kms:GenerateDataKey', + 'kms:TagResource', + 'kms:UntagResource' ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::Join": [ - "", + Effect: 'Allow', + Principal: { + AWS: { + 'Fn::Join': [ + '', [ - "arn:", + 'arn:', { - "Ref": "AWS::Partition" + Ref: 'AWS::Partition' }, - ":iam::", + ':iam::', { - "Ref": "AWS::AccountId" + Ref: 'AWS::AccountId' }, - ":root" + ':root' ] ] } }, - "Resource": "*" + Resource: '*' } ], - "Version": "2012-10-17" + Version: '2012-10-17' } }, - "DeletionPolicy": "Retain", - "UpdateReplacePolicy": "Retain" + DeletionPolicy: 'Retain', + UpdateReplacePolicy: 'Retain' }, - "MyStream5C050E93": { - "Type": "AWS::Kinesis::Stream", - "Properties": { - "RetentionPeriodHours": 24, - "ShardCount": 1, - "StreamEncryption": { - "EncryptionType": "KMS", - "KeyId": { - "Fn::GetAtt": [ - "ExplicitKey7DF42F37", - "Arn" - ] + MyStream5C050E93: { + Type: 'AWS::Kinesis::Stream', + Properties: { + RetentionPeriodHours: 24, + ShardCount: 1, + StreamEncryption: { + EncryptionType: 'KMS', + KeyId: { + 'Fn::GetAtt': ['ExplicitKey7DF42F37', 'Arn'] } } } @@ -322,139 +493,123 @@ export = { test.done(); }, - "permissions": { - "with encryption": { - "grantRead creates and attaches a policy with read only access to Stream and EncryptionKey"(test: Test) { + permissions: { + 'with encryption': { + 'grantRead creates and attaches a policy with read only access to Stream and EncryptionKey'(test: Test) { const stack = new Stack(); const stream = new Stream(stack, 'MyStream', { encryption: StreamEncryption.KMS }); - const user = new iam.User(stack, "MyUser"); + const user = new iam.User(stack, 'MyUser'); stream.grantRead(user); expect(stack).toMatch({ - "Resources": { - "MyStreamKey76F3300E": { - "Type": "AWS::KMS::Key", - "Properties": { - "Description": "Created by MyStream", - "KeyPolicy": { - "Statement": [ + Resources: { + MyStreamKey76F3300E: { + Type: 'AWS::KMS::Key', + Properties: { + KeyPolicy: { + Statement: [ { - "Action": [ - "kms:Create*", - "kms:Describe*", - "kms:Enable*", - "kms:List*", - "kms:Put*", - "kms:Update*", - "kms:Revoke*", - "kms:Disable*", - "kms:Get*", - "kms:Delete*", - "kms:ScheduleKeyDeletion", - "kms:CancelKeyDeletion", - "kms:GenerateDataKey", - "kms:TagResource", - "kms:UntagResource" + Action: [ + 'kms:Create*', + 'kms:Describe*', + 'kms:Enable*', + 'kms:List*', + 'kms:Put*', + 'kms:Update*', + 'kms:Revoke*', + 'kms:Disable*', + 'kms:Get*', + 'kms:Delete*', + 'kms:ScheduleKeyDeletion', + 'kms:CancelKeyDeletion', + 'kms:GenerateDataKey', + 'kms:TagResource', + 'kms:UntagResource' ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::Join": [ - "", + Effect: 'Allow', + Principal: { + AWS: { + 'Fn::Join': [ + '', [ - "arn:", + 'arn:', { - "Ref": "AWS::Partition" + Ref: 'AWS::Partition' }, - ":iam::", + ':iam::', { - "Ref": "AWS::AccountId" + Ref: 'AWS::AccountId' }, - ":root" + ':root' ] ] } }, - "Resource": "*" + Resource: '*' }, { - "Action": "kms:Decrypt", - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "MyUserDC45028B", - "Arn" - ] + Action: 'kms:Decrypt', + Effect: 'Allow', + Principal: { + AWS: { + 'Fn::GetAtt': ['MyUserDC45028B', 'Arn'] } }, - "Resource": "*" + Resource: '*' } ], - "Version": "2012-10-17" - } + Version: '2012-10-17' + }, + Description: 'Created by MyStream' }, - "DeletionPolicy": "Retain", - "UpdateReplacePolicy": "Retain" + UpdateReplacePolicy: 'Retain', + DeletionPolicy: 'Retain' }, - "MyStream5C050E93": { - "Type": "AWS::Kinesis::Stream", - "Properties": { - "RetentionPeriodHours": 24, - "ShardCount": 1, - "StreamEncryption": { - "EncryptionType": "KMS", - "KeyId": { - "Fn::GetAtt": [ - "MyStreamKey76F3300E", - "Arn" - ] + MyStream5C050E93: { + Type: 'AWS::Kinesis::Stream', + Properties: { + ShardCount: 1, + RetentionPeriodHours: 24, + StreamEncryption: { + EncryptionType: 'KMS', + KeyId: { + 'Fn::GetAtt': ['MyStreamKey76F3300E', 'Arn'] } } } }, - "MyUserDC45028B": { - "Type": "AWS::IAM::User" + MyUserDC45028B: { + Type: 'AWS::IAM::User' }, - "MyUserDefaultPolicy7B897426": { - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyDocument": { - "Statement": [ + MyUserDefaultPolicy7B897426: { + Type: 'AWS::IAM::Policy', + Properties: { + PolicyDocument: { + Statement: [ { - "Action": [ - "kinesis:DescribeStream", - "kinesis:GetRecords", - "kinesis:GetShardIterator" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "MyStream5C050E93", - "Arn" - ] + Action: ['kinesis:DescribeStream', 'kinesis:GetRecords', 'kinesis:GetShardIterator'], + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': ['MyStream5C050E93', 'Arn'] } }, { - "Action": "kms:Decrypt", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "MyStreamKey76F3300E", - "Arn" - ] + Action: 'kms:Decrypt', + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': ['MyStreamKey76F3300E', 'Arn'] } } ], - "Version": "2012-10-17" + Version: '2012-10-17' }, - "PolicyName": "MyUserDefaultPolicy7B897426", - "Users": [ + PolicyName: 'MyUserDefaultPolicy7B897426', + Users: [ { - "Ref": "MyUserDC45028B" + Ref: 'MyUserDC45028B' } ] } @@ -464,145 +619,121 @@ export = { test.done(); }, - "grantWrite creates and attaches a policy with write only access to Stream and EncryptionKey"(test: Test) { + 'grantWrite creates and attaches a policy with write only access to Stream and EncryptionKey'(test: Test) { const stack = new Stack(); const stream = new Stream(stack, 'MyStream', { encryption: StreamEncryption.KMS }); - const user = new iam.User(stack, "MyUser"); + const user = new iam.User(stack, 'MyUser'); stream.grantWrite(user); expect(stack).toMatch({ - "Resources": { - "MyStreamKey76F3300E": { - "Type": "AWS::KMS::Key", - "Properties": { - "Description": "Created by MyStream", - "KeyPolicy": { - "Statement": [ + Resources: { + MyStreamKey76F3300E: { + Type: 'AWS::KMS::Key', + Properties: { + KeyPolicy: { + Statement: [ { - "Action": [ - "kms:Create*", - "kms:Describe*", - "kms:Enable*", - "kms:List*", - "kms:Put*", - "kms:Update*", - "kms:Revoke*", - "kms:Disable*", - "kms:Get*", - "kms:Delete*", - "kms:ScheduleKeyDeletion", - "kms:CancelKeyDeletion", - "kms:GenerateDataKey", - "kms:TagResource", - "kms:UntagResource" + Action: [ + 'kms:Create*', + 'kms:Describe*', + 'kms:Enable*', + 'kms:List*', + 'kms:Put*', + 'kms:Update*', + 'kms:Revoke*', + 'kms:Disable*', + 'kms:Get*', + 'kms:Delete*', + 'kms:ScheduleKeyDeletion', + 'kms:CancelKeyDeletion', + 'kms:GenerateDataKey', + 'kms:TagResource', + 'kms:UntagResource' ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::Join": [ - "", + Effect: 'Allow', + Principal: { + AWS: { + 'Fn::Join': [ + '', [ - "arn:", + 'arn:', { - "Ref": "AWS::Partition" + Ref: 'AWS::Partition' }, - ":iam::", + ':iam::', { - "Ref": "AWS::AccountId" + Ref: 'AWS::AccountId' }, - ":root" + ':root' ] ] } }, - "Resource": "*" + Resource: '*' }, { - "Action": [ - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "MyUserDC45028B", - "Arn" - ] + Action: ['kms:Encrypt', 'kms:ReEncrypt*', 'kms:GenerateDataKey*'], + Effect: 'Allow', + Principal: { + AWS: { + 'Fn::GetAtt': ['MyUserDC45028B', 'Arn'] } }, - "Resource": "*" + Resource: '*' } ], - "Version": "2012-10-17" - } + Version: '2012-10-17' + }, + Description: 'Created by MyStream' }, - "DeletionPolicy": "Retain", - "UpdateReplacePolicy": "Retain" + UpdateReplacePolicy: 'Retain', + DeletionPolicy: 'Retain' }, - "MyStream5C050E93": { - "Type": "AWS::Kinesis::Stream", - "Properties": { - "RetentionPeriodHours": 24, - "ShardCount": 1, - "StreamEncryption": { - "EncryptionType": "KMS", - "KeyId": { - "Fn::GetAtt": [ - "MyStreamKey76F3300E", - "Arn" - ] + MyStream5C050E93: { + Type: 'AWS::Kinesis::Stream', + Properties: { + ShardCount: 1, + RetentionPeriodHours: 24, + StreamEncryption: { + EncryptionType: 'KMS', + KeyId: { + 'Fn::GetAtt': ['MyStreamKey76F3300E', 'Arn'] } } } }, - "MyUserDC45028B": { - "Type": "AWS::IAM::User" + MyUserDC45028B: { + Type: 'AWS::IAM::User' }, - "MyUserDefaultPolicy7B897426": { - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyDocument": { - "Statement": [ + MyUserDefaultPolicy7B897426: { + Type: 'AWS::IAM::Policy', + Properties: { + PolicyDocument: { + Statement: [ { - "Action": [ - "kinesis:DescribeStream", - "kinesis:PutRecord", - "kinesis:PutRecords" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "MyStream5C050E93", - "Arn" - ] + Action: ['kinesis:DescribeStream', 'kinesis:PutRecord', 'kinesis:PutRecords'], + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': ['MyStream5C050E93', 'Arn'] } }, { - "Action": [ - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*", - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "MyStreamKey76F3300E", - "Arn" - ] + Action: ['kms:Encrypt', 'kms:ReEncrypt*', 'kms:GenerateDataKey*'], + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': ['MyStreamKey76F3300E', 'Arn'] } } ], - "Version": "2012-10-17" + Version: '2012-10-17' }, - "PolicyName": "MyUserDefaultPolicy7B897426", - "Users": [ + PolicyName: 'MyUserDefaultPolicy7B897426', + Users: [ { - "Ref": "MyUserDC45028B" + Ref: 'MyUserDC45028B' } ] } @@ -612,149 +743,121 @@ export = { test.done(); }, - "grantReadWrite creates and attaches a policy with access to Stream and EncryptionKey"(test: Test) { + 'grantReadWrite creates and attaches a policy with access to Stream and EncryptionKey'(test: Test) { const stack = new Stack(); const stream = new Stream(stack, 'MyStream', { encryption: StreamEncryption.KMS }); - const user = new iam.User(stack, "MyUser"); + const user = new iam.User(stack, 'MyUser'); stream.grantReadWrite(user); expect(stack).toMatch({ - "Resources": { - "MyStreamKey76F3300E": { - "Type": "AWS::KMS::Key", - "Properties": { - "Description": "Created by MyStream", - "KeyPolicy": { - "Statement": [ + Resources: { + MyStreamKey76F3300E: { + Type: 'AWS::KMS::Key', + Properties: { + Description: 'Created by MyStream', + KeyPolicy: { + Statement: [ { - "Action": [ - "kms:Create*", - "kms:Describe*", - "kms:Enable*", - "kms:List*", - "kms:Put*", - "kms:Update*", - "kms:Revoke*", - "kms:Disable*", - "kms:Get*", - "kms:Delete*", - "kms:ScheduleKeyDeletion", - "kms:CancelKeyDeletion", - "kms:GenerateDataKey", - "kms:TagResource", - "kms:UntagResource" + Action: [ + 'kms:Create*', + 'kms:Describe*', + 'kms:Enable*', + 'kms:List*', + 'kms:Put*', + 'kms:Update*', + 'kms:Revoke*', + 'kms:Disable*', + 'kms:Get*', + 'kms:Delete*', + 'kms:ScheduleKeyDeletion', + 'kms:CancelKeyDeletion', + 'kms:GenerateDataKey', + 'kms:TagResource', + 'kms:UntagResource' ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::Join": [ - "", + Effect: 'Allow', + Principal: { + AWS: { + 'Fn::Join': [ + '', [ - "arn:", + 'arn:', { - "Ref": "AWS::Partition" + Ref: 'AWS::Partition' }, - ":iam::", + ':iam::', { - "Ref": "AWS::AccountId" + Ref: 'AWS::AccountId' }, - ":root" + ':root' ] ] } }, - "Resource": "*" + Resource: '*' }, { - "Action": [ - "kms:Decrypt", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::GetAtt": [ - "MyUserDC45028B", - "Arn" - ] + Action: ['kms:Decrypt', 'kms:Encrypt', 'kms:ReEncrypt*', 'kms:GenerateDataKey*'], + Effect: 'Allow', + Principal: { + AWS: { + 'Fn::GetAtt': ['MyUserDC45028B', 'Arn'] } }, - "Resource": "*" + Resource: '*' } ], - "Version": "2012-10-17" + Version: '2012-10-17' } }, - "DeletionPolicy": "Retain", - "UpdateReplacePolicy": "Retain" + DeletionPolicy: 'Retain', + UpdateReplacePolicy: 'Retain' }, - "MyStream5C050E93": { - "Type": "AWS::Kinesis::Stream", - "Properties": { - "RetentionPeriodHours": 24, - "ShardCount": 1, - "StreamEncryption": { - "EncryptionType": "KMS", - "KeyId": { - "Fn::GetAtt": [ - "MyStreamKey76F3300E", - "Arn" - ] + MyStream5C050E93: { + Type: 'AWS::Kinesis::Stream', + Properties: { + RetentionPeriodHours: 24, + ShardCount: 1, + StreamEncryption: { + EncryptionType: 'KMS', + KeyId: { + 'Fn::GetAtt': ['MyStreamKey76F3300E', 'Arn'] } } } }, - "MyUserDC45028B": { - "Type": "AWS::IAM::User" + MyUserDC45028B: { + Type: 'AWS::IAM::User' }, - "MyUserDefaultPolicy7B897426": { - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyDocument": { - "Statement": [ + MyUserDefaultPolicy7B897426: { + Type: 'AWS::IAM::Policy', + Properties: { + PolicyDocument: { + Statement: [ { - "Action": [ - "kinesis:DescribeStream", - "kinesis:GetRecords", - "kinesis:GetShardIterator", - "kinesis:PutRecord", - "kinesis:PutRecords" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "MyStream5C050E93", - "Arn" - ] + Action: ['kinesis:DescribeStream', 'kinesis:GetRecords', 'kinesis:GetShardIterator', 'kinesis:PutRecord', 'kinesis:PutRecords'], + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': ['MyStream5C050E93', 'Arn'] } }, { - "Action": [ - "kms:Decrypt", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "MyStreamKey76F3300E", - "Arn" - ] + Action: ['kms:Decrypt', 'kms:Encrypt', 'kms:ReEncrypt*', 'kms:GenerateDataKey*'], + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': ['MyStreamKey76F3300E', 'Arn'] } } ], - "Version": "2012-10-17" + Version: '2012-10-17' }, - "PolicyName": "MyUserDefaultPolicy7B897426", - "Users": [ + PolicyName: 'MyUserDefaultPolicy7B897426', + Users: [ { - "Ref": "MyUserDC45028B" + Ref: 'MyUserDC45028B' } ] } @@ -765,166 +868,245 @@ export = { test.done(); } }, - "with no encryption": { - "grantRead creates and associates a policy with read only access to Stream"(test: Test) { + 'with no encryption': { + 'grantRead creates and associates a policy with read only access to Stream'(test: Test) { const stack = new Stack(); const stream = new Stream(stack, 'MyStream'); - const user = new iam.User(stack, "MyUser"); + const user = new iam.User(stack, 'MyUser'); stream.grantRead(user); expect(stack).toMatch({ - "Resources": { - "MyStream5C050E93": { - "Type": "AWS::Kinesis::Stream", - "Properties": { - "RetentionPeriodHours": 24, - "ShardCount": 1 + Resources: { + MyStream5C050E93: { + Type: 'AWS::Kinesis::Stream', + Properties: { + ShardCount: 1, + RetentionPeriodHours: 24, + StreamEncryption: { + 'Fn::If': [ + 'AwsCdkKinesisEncryptedStreamsUnsupportedRegions', + { + Ref: 'AWS::NoValue' + }, + { + EncryptionType: 'KMS', + KeyId: 'alias/aws/kinesis' + } + ] + } } }, - "MyUserDC45028B": { - "Type": "AWS::IAM::User" + MyUserDC45028B: { + Type: 'AWS::IAM::User' }, - "MyUserDefaultPolicy7B897426": { - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyDocument": { - "Statement": [ + MyUserDefaultPolicy7B897426: { + Type: 'AWS::IAM::Policy', + Properties: { + PolicyDocument: { + Statement: [ { - "Action": [ - "kinesis:DescribeStream", - "kinesis:GetRecords", - "kinesis:GetShardIterator" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "MyStream5C050E93", - "Arn" - ] + Action: ['kinesis:DescribeStream', 'kinesis:GetRecords', 'kinesis:GetShardIterator'], + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': ['MyStream5C050E93', 'Arn'] } } ], - "Version": "2012-10-17" + Version: '2012-10-17' }, - "PolicyName": "MyUserDefaultPolicy7B897426", - "Users": [ + PolicyName: 'MyUserDefaultPolicy7B897426', + Users: [ { - "Ref": "MyUserDC45028B" + Ref: 'MyUserDC45028B' } ] } } + }, + Conditions: { + AwsCdkKinesisEncryptedStreamsUnsupportedRegions: { + 'Fn::Or': [ + { + 'Fn::Equals': [ + { + Ref: 'AWS::Region' + }, + 'cn-north-1' + ] + }, + { + 'Fn::Equals': [ + { + Ref: 'AWS::Region' + }, + 'cn-northwest-1' + ] + } + ] + } } }); test.done(); }, - "grantWrite creates and attaches a policy with write only access to Stream"(test: Test) { + 'grantWrite creates and attaches a policy with write only access to Stream'(test: Test) { const stack = new Stack(); const stream = new Stream(stack, 'MyStream'); - const user = new iam.User(stack, "MyUser"); + const user = new iam.User(stack, 'MyUser'); stream.grantWrite(user); expect(stack).toMatch({ - "Resources": { - "MyStream5C050E93": { - "Type": "AWS::Kinesis::Stream", - "Properties": { - "RetentionPeriodHours": 24, - "ShardCount": 1 + Resources: { + MyStream5C050E93: { + Type: 'AWS::Kinesis::Stream', + Properties: { + ShardCount: 1, + RetentionPeriodHours: 24, + StreamEncryption: { + 'Fn::If': [ + 'AwsCdkKinesisEncryptedStreamsUnsupportedRegions', + { + Ref: 'AWS::NoValue' + }, + { + EncryptionType: 'KMS', + KeyId: 'alias/aws/kinesis' + } + ] + } } }, - "MyUserDC45028B": { - "Type": "AWS::IAM::User" + MyUserDC45028B: { + Type: 'AWS::IAM::User' }, - "MyUserDefaultPolicy7B897426": { - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyDocument": { - "Statement": [ + MyUserDefaultPolicy7B897426: { + Type: 'AWS::IAM::Policy', + Properties: { + PolicyDocument: { + Statement: [ { - "Action": [ - "kinesis:DescribeStream", - "kinesis:PutRecord", - "kinesis:PutRecords" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "MyStream5C050E93", - "Arn" - ] + Action: ['kinesis:DescribeStream', 'kinesis:PutRecord', 'kinesis:PutRecords'], + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': ['MyStream5C050E93', 'Arn'] } } ], - "Version": "2012-10-17" + Version: '2012-10-17' }, - "PolicyName": "MyUserDefaultPolicy7B897426", - "Users": [ + PolicyName: 'MyUserDefaultPolicy7B897426', + Users: [ { - "Ref": "MyUserDC45028B" + Ref: 'MyUserDC45028B' } ] } } + }, + Conditions: { + AwsCdkKinesisEncryptedStreamsUnsupportedRegions: { + 'Fn::Or': [ + { + 'Fn::Equals': [ + { + Ref: 'AWS::Region' + }, + 'cn-north-1' + ] + }, + { + 'Fn::Equals': [ + { + Ref: 'AWS::Region' + }, + 'cn-northwest-1' + ] + } + ] + } } }); test.done(); }, - "greatReadWrite creates and attaches a policy with write only access to Stream"(test: Test) { + 'greatReadWrite creates and attaches a policy with write only access to Stream'(test: Test) { const stack = new Stack(); const stream = new Stream(stack, 'MyStream'); - const user = new iam.User(stack, "MyUser"); + const user = new iam.User(stack, 'MyUser'); stream.grantReadWrite(user); expect(stack).toMatch({ - "Resources": { - "MyStream5C050E93": { - "Type": "AWS::Kinesis::Stream", - "Properties": { - "RetentionPeriodHours": 24, - "ShardCount": 1 + Resources: { + MyStream5C050E93: { + Type: 'AWS::Kinesis::Stream', + Properties: { + ShardCount: 1, + RetentionPeriodHours: 24, + StreamEncryption: { + 'Fn::If': [ + 'AwsCdkKinesisEncryptedStreamsUnsupportedRegions', + { + Ref: 'AWS::NoValue' + }, + { + EncryptionType: 'KMS', + KeyId: 'alias/aws/kinesis' + } + ] + } } }, - "MyUserDC45028B": { - "Type": "AWS::IAM::User" + MyUserDC45028B: { + Type: 'AWS::IAM::User' }, - "MyUserDefaultPolicy7B897426": { - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyDocument": { - "Statement": [ + MyUserDefaultPolicy7B897426: { + Type: 'AWS::IAM::Policy', + Properties: { + PolicyDocument: { + Statement: [ { - "Action": [ - "kinesis:DescribeStream", - "kinesis:GetRecords", - "kinesis:GetShardIterator", - "kinesis:PutRecord", - "kinesis:PutRecords" - ], - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "MyStream5C050E93", - "Arn" - ] + Action: ['kinesis:DescribeStream', 'kinesis:GetRecords', 'kinesis:GetShardIterator', 'kinesis:PutRecord', 'kinesis:PutRecords'], + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': ['MyStream5C050E93', 'Arn'] } } ], - "Version": "2012-10-17" + Version: '2012-10-17' }, - "PolicyName": "MyUserDefaultPolicy7B897426", - "Users": [ + PolicyName: 'MyUserDefaultPolicy7B897426', + Users: [ { - "Ref": "MyUserDC45028B" + Ref: 'MyUserDC45028B' } ] } } + }, + Conditions: { + AwsCdkKinesisEncryptedStreamsUnsupportedRegions: { + 'Fn::Or': [ + { + 'Fn::Equals': [ + { + Ref: 'AWS::Region' + }, + 'cn-north-1' + ] + }, + { + 'Fn::Equals': [ + { + Ref: 'AWS::Region' + }, + 'cn-northwest-1' + ] + } + ] + } } }); @@ -932,8 +1114,8 @@ export = { } } }, - "cross-stack permissions": { - "no encryption"(test: Test) { + 'cross-stack permissions': { + 'no encryption'(test: Test) { const app = new App(); const stackA = new Stack(app, 'stackA'); const streamFromStackA = new Stream(stackA, 'MyStream'); @@ -943,60 +1125,56 @@ export = { streamFromStackA.grantRead(user); expect(stackA).toMatch({ - "Resources": { - "MyStream5C050E93": { - "Type": "AWS::Kinesis::Stream", - "Properties": { - "RetentionPeriodHours": 24, - "ShardCount": 1 + Resources: { + MyStream5C050E93: { + Type: 'AWS::Kinesis::Stream', + Properties: { + ShardCount: 1, + RetentionPeriodHours: 24, + StreamEncryption: { + 'Fn::If': [ + 'AwsCdkKinesisEncryptedStreamsUnsupportedRegions', + { + Ref: 'AWS::NoValue' + }, + { + EncryptionType: 'KMS', + KeyId: 'alias/aws/kinesis' + } + ] + } } } }, - "Outputs": { - "ExportsOutputFnGetAttMyStream5C050E93Arn4ABF30CD": { - "Value": { - "Fn::GetAtt": [ - "MyStream5C050E93", - "Arn" - ] - }, - "Export": { - "Name": "stackA:ExportsOutputFnGetAttMyStream5C050E93Arn4ABF30CD" - } - } - } - }); - - expect(stackB).toMatch({ - "Resources": { - "UserWhoNeedsAccessF8959C3D": { - "Type": "AWS::IAM::User" - }, - "UserWhoNeedsAccessDefaultPolicy6A9EB530": { - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyDocument": { - "Statement": [ + Conditions: { + AwsCdkKinesisEncryptedStreamsUnsupportedRegions: { + 'Fn::Or': [ + { + 'Fn::Equals': [ { - "Action": [ - "kinesis:DescribeStream", - "kinesis:GetRecords", - "kinesis:GetShardIterator" - ], - "Effect": "Allow", - "Resource": { - "Fn::ImportValue": "stackA:ExportsOutputFnGetAttMyStream5C050E93Arn4ABF30CD" - } - } - ], - "Version": "2012-10-17" + Ref: 'AWS::Region' + }, + 'cn-north-1' + ] }, - "PolicyName": "UserWhoNeedsAccessDefaultPolicy6A9EB530", - "Users": [ - { - "Ref": "UserWhoNeedsAccessF8959C3D" - } - ] + { + 'Fn::Equals': [ + { + Ref: 'AWS::Region' + }, + 'cn-northwest-1' + ] + } + ] + } + }, + Outputs: { + ExportsOutputFnGetAttMyStream5C050E93Arn4ABF30CD: { + Value: { + 'Fn::GetAtt': ['MyStream5C050E93', 'Arn'] + }, + Export: { + Name: 'stackA:ExportsOutputFnGetAttMyStream5C050E93Arn4ABF30CD' } } } @@ -1004,7 +1182,7 @@ export = { test.done(); }, - "fails with encryption due to cyclic dependency"(test: Test) { + 'fails with encryption due to cyclic dependency'(test: Test) { const app = new App(); const stackA = new Stack(app, 'stackA'); const streamFromStackA = new Stream(stackA, 'MyStream', { diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesis.expected.json b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesis.expected.json index a9599215e68d1..d95daaa759c3d 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesis.expected.json +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesis.expected.json @@ -101,8 +101,42 @@ "Type": "AWS::Kinesis::Stream", "Properties": { "ShardCount": 1, - "RetentionPeriodHours": 24 + "RetentionPeriodHours": 24, + "StreamEncryption": { + "Fn::If": [ + "AwsCdkKinesisEncryptedStreamsUnsupportedRegions", + { + "Ref": "AWS::NoValue" + }, + { + "EncryptionType": "KMS", + "KeyId": "alias/aws/kinesis" + } + ] + } } } + }, + "Conditions": { + "AwsCdkKinesisEncryptedStreamsUnsupportedRegions": { + "Fn::Or": [ + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "cn-north-1" + ] + }, + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "cn-northwest-1" + ] + } + ] + } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesiswithdlq.expected.json b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesiswithdlq.expected.json index c53057168c9d0..f524c95bd7f22 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesiswithdlq.expected.json +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/integ.kinesiswithdlq.expected.json @@ -126,7 +126,19 @@ "Type": "AWS::Kinesis::Stream", "Properties": { "ShardCount": 1, - "RetentionPeriodHours": 24 + "RetentionPeriodHours": 24, + "StreamEncryption": { + "Fn::If": [ + "AwsCdkKinesisEncryptedStreamsUnsupportedRegions", + { + "Ref": "AWS::NoValue" + }, + { + "EncryptionType": "KMS", + "KeyId": "alias/aws/kinesis" + } + ] + } } }, "Q63C6E3AB": { @@ -152,5 +164,27 @@ "Ref": "Q63C6E3AB" } } + }, + "Conditions": { + "AwsCdkKinesisEncryptedStreamsUnsupportedRegions": { + "Fn::Or": [ + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "cn-north-1" + ] + }, + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "cn-northwest-1" + ] + } + ] + } } } \ No newline at end of file From c97e63b54f9dd373f7f51a8cf5d2f3eef422255a Mon Sep 17 00:00:00 2001 From: Shiv Lakshminarayan Date: Thu, 2 Apr 2020 03:22:59 -0700 Subject: [PATCH 45/53] chore(cli): fix integration tests for cdk deploy with outputs (#7134) The outputs file that's created from using the `--outputs-file` option are keyed on the stack id. However, this was dependent on a prefix. Expected files were written against a prefix, but they can change. This broke integration tests in a scenario where stack prefix didn't align with the encoded expected outputs. To address this issue, the testing strategy was adjusted to use the expected outputs files as a template, substitute in the prefix and compare them with actual outputs. --- ...deploy-wildcard-with-outputs-expected.json | 8 -------- ...oy-wildcard-with-outputs-expected.template | 8 ++++++++ .../cli/cdk-deploy-with-outputs-expected.json | 5 ----- .../cdk-deploy-with-outputs-expected.template | 5 +++++ .../test-cdk-deploy-wildcard-with-outputs.sh | 16 ++++++++++++--- .../integ/cli/test-cdk-deploy-with-outputs.sh | 20 ++++++++++++++----- 6 files changed, 41 insertions(+), 21 deletions(-) delete mode 100644 packages/aws-cdk/test/integ/cli/cdk-deploy-wildcard-with-outputs-expected.json create mode 100644 packages/aws-cdk/test/integ/cli/cdk-deploy-wildcard-with-outputs-expected.template delete mode 100644 packages/aws-cdk/test/integ/cli/cdk-deploy-with-outputs-expected.json create mode 100644 packages/aws-cdk/test/integ/cli/cdk-deploy-with-outputs-expected.template diff --git a/packages/aws-cdk/test/integ/cli/cdk-deploy-wildcard-with-outputs-expected.json b/packages/aws-cdk/test/integ/cli/cdk-deploy-wildcard-with-outputs-expected.json deleted file mode 100644 index 66a2ec3ed0071..0000000000000 --- a/packages/aws-cdk/test/integ/cli/cdk-deploy-wildcard-with-outputs-expected.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "cdk-toolkit-integration-outputs-test-1": { - "TopicName": "MyTopic" - }, - "cdk-toolkit-integration-outputs-test-2": { - "TopicName": "MyOtherTopic" - } -} \ No newline at end of file diff --git a/packages/aws-cdk/test/integ/cli/cdk-deploy-wildcard-with-outputs-expected.template b/packages/aws-cdk/test/integ/cli/cdk-deploy-wildcard-with-outputs-expected.template new file mode 100644 index 0000000000000..6097801be8035 --- /dev/null +++ b/packages/aws-cdk/test/integ/cli/cdk-deploy-wildcard-with-outputs-expected.template @@ -0,0 +1,8 @@ +{ + "%STACK_NAME_PREFIX%-outputs-test-1": { + "TopicName": "MyTopic" + }, + "%STACK_NAME_PREFIX%-outputs-test-2": { + "TopicName": "MyOtherTopic" + } +} \ No newline at end of file diff --git a/packages/aws-cdk/test/integ/cli/cdk-deploy-with-outputs-expected.json b/packages/aws-cdk/test/integ/cli/cdk-deploy-with-outputs-expected.json deleted file mode 100644 index 7e5a38d1d975f..0000000000000 --- a/packages/aws-cdk/test/integ/cli/cdk-deploy-with-outputs-expected.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "cdk-toolkit-integration-outputs-test-1": { - "TopicName": "MyTopic" - } -} \ No newline at end of file diff --git a/packages/aws-cdk/test/integ/cli/cdk-deploy-with-outputs-expected.template b/packages/aws-cdk/test/integ/cli/cdk-deploy-with-outputs-expected.template new file mode 100644 index 0000000000000..972c4eaa725ff --- /dev/null +++ b/packages/aws-cdk/test/integ/cli/cdk-deploy-with-outputs-expected.template @@ -0,0 +1,5 @@ +{ + "%STACK_NAME_PREFIX%-outputs-test-1": { + "TopicName": "MyTopic" + } +} diff --git a/packages/aws-cdk/test/integ/cli/test-cdk-deploy-wildcard-with-outputs.sh b/packages/aws-cdk/test/integ/cli/test-cdk-deploy-wildcard-with-outputs.sh index 09e22f2015140..b77a489955e97 100755 --- a/packages/aws-cdk/test/integ/cli/test-cdk-deploy-wildcard-with-outputs.sh +++ b/packages/aws-cdk/test/integ/cli/test-cdk-deploy-wildcard-with-outputs.sh @@ -6,8 +6,18 @@ source ${scriptdir}/common.bash setup +# create directory in /tmp +outputs_folder=${integ_test_dir}/outputs +mkdir -p ${outputs_folder} + +# set up outputs outputs_file=${integ_test_dir}/outputs/outputs.json -expected_outputs=${scriptdir}/cdk-deploy-wildcard-with-outputs-expected.json +expected_file=${integ_test_dir}/outputs/expected.json +touch $expected_file + +# add prefixes as stacks are keyed on their stack name in the outputs file +expected_outputs=${scriptdir}/cdk-deploy-wildcard-with-outputs-expected.template +sed "s|%STACK_NAME_PREFIX%|$STACK_NAME_PREFIX|g" "$expected_outputs" > "$expected_file" # deploy all outputs stacks cdk deploy ${STACK_NAME_PREFIX}-outputs-test-\* --outputs-file ${outputs_file} @@ -15,13 +25,13 @@ echo "Stacks deployed successfully" # verify generated outputs file generated_outputs_file="$(cat ${outputs_file})" -expected_outputs_file="$(cat ${expected_outputs})" +expected_outputs_file="$(cat ${expected_file})" if [[ "${generated_outputs_file}" != "${expected_outputs_file}" ]]; then fail "unexpected outputs. Expected: ${expected_outputs_file} Actual: ${generated_outputs_file}" fi # destroy -rm ${outputs_file} +rm -rf ${outputs_folder} cdk destroy -f ${STACK_NAME_PREFIX}-outputs-test-1 cdk destroy -f ${STACK_NAME_PREFIX}-outputs-test-2 diff --git a/packages/aws-cdk/test/integ/cli/test-cdk-deploy-with-outputs.sh b/packages/aws-cdk/test/integ/cli/test-cdk-deploy-with-outputs.sh index da90c0e14c43d..cd135f06c28f3 100755 --- a/packages/aws-cdk/test/integ/cli/test-cdk-deploy-with-outputs.sh +++ b/packages/aws-cdk/test/integ/cli/test-cdk-deploy-with-outputs.sh @@ -6,21 +6,31 @@ source ${scriptdir}/common.bash setup -outputs_file=${integ_test_dir}/outputs/outputs.json -expected_outputs=${scriptdir}/cdk-deploy-with-outputs-expected.json +# create directory in /tmp +outputs_folder=${integ_test_dir}/outputs +mkdir -p ${outputs_folder} -cdk deploy -v ${STACK_NAME_PREFIX}-outputs-test-1 --outputs-file ${outputs_file} +# set up outputs +outputs_file=${outputs_folder}/outputs.json +expected_file=${outputs_folder}/expected.json +touch $expected_file + +# add prefixes as stacks are keyed on their stack name in the outputs file +expected_outputs=${scriptdir}/cdk-deploy-with-outputs-expected.template +sed "s|%STACK_NAME_PREFIX%|$STACK_NAME_PREFIX|g" "$expected_outputs" > "$expected_file" + +cdk deploy ${STACK_NAME_PREFIX}-outputs-test-1 --outputs-file ${outputs_file} echo "Stack deployed successfully" # verify generated outputs file generated_outputs_file="$(cat ${outputs_file})" -expected_outputs_file="$(cat ${expected_outputs})" +expected_outputs_file="$(cat ${expected_file})" if [[ "${generated_outputs_file}" != "${expected_outputs_file}" ]]; then fail "unexpected outputs. Expected: ${expected_outputs_file} Actual: ${generated_outputs_file}" fi # destroy -rm ${outputs_file} +rm -rf ${outputs_folder} cdk destroy -f ${STACK_NAME_PREFIX}-outputs-test-1 echo "✅ success" From ca2585c99e1f81d45b8bf835638f65a311fbbf9a Mon Sep 17 00:00:00 2001 From: Michael Dimoudis Date: Thu, 2 Apr 2020 22:16:23 +1100 Subject: [PATCH 46/53] feat(lambda): .net core 3.1 runtime (#7105) Closes https://github.com/aws/aws-cdk/issues/7104 --- packages/@aws-cdk/aws-lambda/lib/runtime.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/@aws-cdk/aws-lambda/lib/runtime.ts b/packages/@aws-cdk/aws-lambda/lib/runtime.ts index bb175074aca0d..ffa111ca4509b 100644 --- a/packages/@aws-cdk/aws-lambda/lib/runtime.ts +++ b/packages/@aws-cdk/aws-lambda/lib/runtime.ts @@ -113,6 +113,11 @@ export class Runtime { */ public static readonly DOTNET_CORE_2_1 = new Runtime('dotnetcore2.1', RuntimeFamily.DOTNET_CORE); + /** + * The .NET Core 3.1 runtime (dotnetcore3.1) + */ + public static readonly DOTNET_CORE_3_1 = new Runtime('dotnetcore3.1', RuntimeFamily.DOTNET_CORE); + /** * The Go 1.x runtime (go1.x) */ From 6358698e3487adb331ce8a0835d43c6c71112ffe Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Thu, 2 Apr 2020 15:07:54 +0200 Subject: [PATCH 47/53] chore: missing awaits (#7138) Add some awaits that were missing. --- packages/aws-cdk/lib/cdk-toolkit.ts | 2 +- packages/aws-cdk/test/api/sdk-provider.test.ts | 2 +- packages/aws-cdk/test/cdk-toolkit.test.ts | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/aws-cdk/lib/cdk-toolkit.ts b/packages/aws-cdk/lib/cdk-toolkit.ts index dea29b910345f..52c670cb1b321 100644 --- a/packages/aws-cdk/lib/cdk-toolkit.ts +++ b/packages/aws-cdk/lib/cdk-toolkit.ts @@ -194,7 +194,7 @@ export class CdkToolkit { // all of the outputs from successfully deployed stacks before the failure will still be written. if (outputsFile) { fs.ensureFileSync(outputsFile); - fs.writeJson(outputsFile, stackOutputs, { + await fs.writeJson(outputsFile, stackOutputs, { spaces: 2, encoding: 'utf8' }); diff --git a/packages/aws-cdk/test/api/sdk-provider.test.ts b/packages/aws-cdk/test/api/sdk-provider.test.ts index e1099dedc6481..68e8d99721f7d 100644 --- a/packages/aws-cdk/test/api/sdk-provider.test.ts +++ b/packages/aws-cdk/test/api/sdk-provider.test.ts @@ -136,7 +136,7 @@ describe('CLI compatible credentials loading', () => { test('different account throws', async () => { const provider = await SdkProvider.withAwsCliCompatibleDefaults({ ...defaultCredOptions, profile: 'boo' }); - expect(provider.forEnvironment(`${uid}some_account_#`, 'def', Mode.ForReading)).rejects.toThrow('Need to perform AWS calls'); + await expect(provider.forEnvironment(`${uid}some_account_#`, 'def', Mode.ForReading)).rejects.toThrow('Need to perform AWS calls'); }); }); diff --git a/packages/aws-cdk/test/cdk-toolkit.test.ts b/packages/aws-cdk/test/cdk-toolkit.test.ts index 5fc3f10b99f20..3da42f0710b1f 100644 --- a/packages/aws-cdk/test/cdk-toolkit.test.ts +++ b/packages/aws-cdk/test/cdk-toolkit.test.ts @@ -7,7 +7,7 @@ import { MockSDK } from './util/mock-sdk'; describe('deploy', () => { describe('makes correct CloudFormation calls', () => { - test('without options', () => { + test('without options', async () => { // GIVEN const toolkit = new CdkToolkit({ appStacks: new TestAppStacks(), @@ -18,10 +18,10 @@ describe('deploy', () => { }); // WHEN - toolkit.deploy({ stackNames: ['Test-Stack-A', 'Test-Stack-B'], sdk: new MockSDK() }); + await toolkit.deploy({ stackNames: ['Test-Stack-A', 'Test-Stack-B'], sdk: new MockSDK() }); }); - test('with sns notification arns', () => { + test('with sns notification arns', async () => { // GIVEN const notificationArns = ['arn:aws:sns:::cfn-notifications', 'arn:aws:sns:::my-cool-topic']; const toolkit = new CdkToolkit({ @@ -33,7 +33,7 @@ describe('deploy', () => { }); // WHEN - toolkit.deploy({ + await toolkit.deploy({ stackNames: ['Test-Stack-A', 'Test-Stack-B'], notificationArns, sdk: new MockSDK() From 3925d9aee3b408a3b2160bff5306cb80a0a9a3ab Mon Sep 17 00:00:00 2001 From: Christoph Gysin Date: Thu, 2 Apr 2020 18:58:14 +0300 Subject: [PATCH 48/53] feat: Support passing AssetOptions (#7099) feat: Support passing AssetOptions --- packages/@aws-cdk/aws-s3-deployment/README.md | 5 ++ .../@aws-cdk/aws-s3-deployment/lib/source.ts | 7 ++- .../@aws-cdk/aws-s3-deployment/package.json | 1 + .../test/test.bucket-deployment.ts | 63 +++++++++++++++++++ 4 files changed, 74 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/aws-s3-deployment/README.md b/packages/@aws-cdk/aws-s3-deployment/README.md index 5b99c88ad8202..7e13e466e51e5 100644 --- a/packages/@aws-cdk/aws-s3-deployment/README.md +++ b/packages/@aws-cdk/aws-s3-deployment/README.md @@ -60,6 +60,11 @@ The following source types are supported for bucket deployments: - Local directory: `s3deploy.Source.asset('/path/to/local/directory')` - Another bucket: `s3deploy.Source.bucket(bucket, zipObjectKey)` +To create a source from a single file, you can pass `AssetOptions` to exclude +all but a single file: + + - Single file: `s3deploy.Source.asset('/path/to/local/directory', { exclude: ['**', '!onlyThisFile.txt'] })` + ## Retain on Delete By default, the contents of the destination bucket will be deleted when the diff --git a/packages/@aws-cdk/aws-s3-deployment/lib/source.ts b/packages/@aws-cdk/aws-s3-deployment/lib/source.ts index 86eae270fcf94..4d50c6de16e36 100644 --- a/packages/@aws-cdk/aws-s3-deployment/lib/source.ts +++ b/packages/@aws-cdk/aws-s3-deployment/lib/source.ts @@ -51,14 +51,17 @@ export class Source { * Uses a local asset as the deployment source. * @param path The path to a local .zip file or a directory */ - public static asset(path: string): ISource { + public static asset(path: string, options?: s3_assets.AssetOptions): ISource { return { bind(context: cdk.Construct): SourceConfig { let id = 1; while (context.node.tryFindChild(`Asset${id}`)) { id++; } - const asset = new s3_assets.Asset(context, `Asset${id}`, { path }); + const asset = new s3_assets.Asset(context, `Asset${id}`, { + path, + ...options, + }); if (!asset.isZipArchive) { throw new Error(`Asset path must be either a .zip file or a directory`); } diff --git a/packages/@aws-cdk/aws-s3-deployment/package.json b/packages/@aws-cdk/aws-s3-deployment/package.json index e12f42ffe89b7..7f174c57b4f40 100644 --- a/packages/@aws-cdk/aws-s3-deployment/package.json +++ b/packages/@aws-cdk/aws-s3-deployment/package.json @@ -95,6 +95,7 @@ }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { + "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-cloudformation": "0.0.0", "@aws-cdk/aws-cloudfront": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", diff --git a/packages/@aws-cdk/aws-s3-deployment/test/test.bucket-deployment.ts b/packages/@aws-cdk/aws-s3-deployment/test/test.bucket-deployment.ts index 47753923a84dd..6b6b5cacb5bcf 100644 --- a/packages/@aws-cdk/aws-s3-deployment/test/test.bucket-deployment.ts +++ b/packages/@aws-cdk/aws-s3-deployment/test/test.bucket-deployment.ts @@ -206,6 +206,69 @@ export = { test.done(); }, + 'honors passed asset options'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'Dest'); + + // WHEN + new s3deploy.BucketDeployment(stack, 'Deploy', { + sources: [s3deploy.Source.asset(path.join(__dirname, 'my-website'), { + exclude: ['*', '!index.html'], + })], + destinationBucket: bucket, + }); + + // THEN + expect(stack).to(haveResource('Custom::CDKBucketDeployment', { + "ServiceToken": { + "Fn::GetAtt": [ + "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C81C01536", + "Arn" + ] + }, + "SourceBucketNames": [{ + "Ref": "AssetParameterse9b696b2a8a1f93ea8b8a9ce1e4dd4727f9243eba984e50411ca95c6b03d26b6S3Bucket1A1EC3E9" + }], + "SourceObjectKeys": [{ + "Fn::Join": [ + "", + [ + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameterse9b696b2a8a1f93ea8b8a9ce1e4dd4727f9243eba984e50411ca95c6b03d26b6S3VersionKeyE46A4824" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameterse9b696b2a8a1f93ea8b8a9ce1e4dd4727f9243eba984e50411ca95c6b03d26b6S3VersionKeyE46A4824" + } + ] + } + ] + } + ] + ] + }], + "DestinationBucketName": { + "Ref": "DestC383B82A" + } + })); + test.done(); + }, 'retainOnDelete can be used to retain files when resource is deleted'(test: Test) { // GIVEN const stack = new cdk.Stack(); From 684468e60a68e98c591e1e4fbb7bfe6afc6854d0 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 2 Apr 2020 16:35:52 +0000 Subject: [PATCH 49/53] chore(deps-dev): bump fast-check from 1.24.0 to 1.24.1 (#7127) Bumps [fast-check](https://github.com/dubzzz/fast-check) from 1.24.0 to 1.24.1. - [Release notes](https://github.com/dubzzz/fast-check/releases) - [Changelog](https://github.com/dubzzz/fast-check/blob/master/CHANGELOG.md) - [Commits](https://github.com/dubzzz/fast-check/compare/v1.24.0...v1.24.1) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- packages/@aws-cdk/app-delivery/package.json | 2 +- packages/@aws-cdk/aws-applicationautoscaling/package.json | 2 +- packages/@aws-cdk/aws-autoscaling-common/package.json | 2 +- packages/@aws-cdk/cloudformation-diff/package.json | 2 +- packages/@aws-cdk/core/package.json | 2 +- yarn.lock | 8 ++++---- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/@aws-cdk/app-delivery/package.json b/packages/@aws-cdk/app-delivery/package.json index 78c53e9098fd0..2462f7630091c 100644 --- a/packages/@aws-cdk/app-delivery/package.json +++ b/packages/@aws-cdk/app-delivery/package.json @@ -56,7 +56,7 @@ "@types/nodeunit": "^0.0.30", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", - "fast-check": "^1.24.0", + "fast-check": "^1.24.1", "nodeunit": "^0.11.3", "pkglint": "0.0.0" }, diff --git a/packages/@aws-cdk/aws-applicationautoscaling/package.json b/packages/@aws-cdk/aws-applicationautoscaling/package.json index 90ce9862b5291..f40775f45562f 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/package.json +++ b/packages/@aws-cdk/aws-applicationautoscaling/package.json @@ -66,7 +66,7 @@ "@types/nodeunit": "^0.0.30", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "fast-check": "^1.24.0", + "fast-check": "^1.24.1", "nodeunit": "^0.11.3", "pkglint": "0.0.0" }, diff --git a/packages/@aws-cdk/aws-autoscaling-common/package.json b/packages/@aws-cdk/aws-autoscaling-common/package.json index d1e4b4ded3f6d..7fddbe8b9185e 100644 --- a/packages/@aws-cdk/aws-autoscaling-common/package.json +++ b/packages/@aws-cdk/aws-autoscaling-common/package.json @@ -62,7 +62,7 @@ "@types/nodeunit": "^0.0.30", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", - "fast-check": "^1.24.0", + "fast-check": "^1.24.1", "nodeunit": "^0.11.3", "pkglint": "0.0.0" }, diff --git a/packages/@aws-cdk/cloudformation-diff/package.json b/packages/@aws-cdk/cloudformation-diff/package.json index 02983b3de8aba..9cdd9a0c2a163 100644 --- a/packages/@aws-cdk/cloudformation-diff/package.json +++ b/packages/@aws-cdk/cloudformation-diff/package.json @@ -42,7 +42,7 @@ "@types/string-width": "^4.0.1", "@types/table": "^4.0.7", "cdk-build-tools": "0.0.0", - "fast-check": "^1.24.0", + "fast-check": "^1.24.1", "jest": "^24.9.0", "pkglint": "0.0.0", "ts-jest": "^25.3.0" diff --git a/packages/@aws-cdk/core/package.json b/packages/@aws-cdk/core/package.json index 1b25a836bff3d..f96d69d1962cd 100644 --- a/packages/@aws-cdk/core/package.json +++ b/packages/@aws-cdk/core/package.json @@ -140,7 +140,7 @@ "@types/nodeunit": "^0.0.30", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "fast-check": "^1.24.0", + "fast-check": "^1.24.1", "lodash": "^4.17.15", "nodeunit": "^0.11.3", "pkglint": "0.0.0" diff --git a/yarn.lock b/yarn.lock index a5a7b2c8391b1..dfa992e8cde88 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5332,10 +5332,10 @@ falafel@^2.1.0: isarray "^2.0.1" object-keys "^1.0.6" -fast-check@^1.24.0: - version "1.24.0" - resolved "https://registry.yarnpkg.com/fast-check/-/fast-check-1.24.0.tgz#55b8c990fc529a65412ed6c43a9ae52974dd8f0b" - integrity sha512-GnEs2bUHKMXRbVdNiccsGM3O38wl2NfZkAfGwU7bGTOZBN5xzjGjXzh4uvN4NR/mwqoaoEkcZ+LE5Yedc5RIeA== +fast-check@^1.24.1: + version "1.24.1" + resolved "https://registry.yarnpkg.com/fast-check/-/fast-check-1.24.1.tgz#42a153e664122b1a2defdaea4e9b8311635fa7e7" + integrity sha512-ECF5LDbt4F8sJyTDI62fRLn0BdHDAdBacxlEsxaYbtqwbsdWofoYZUSaUp9tJrLsqCQ8jG28SkNvPZpDfNo3tw== dependencies: pure-rand "^2.0.0" tslib "^1.10.0" From a9028449753d4f19c9f35f9fb385bd71e602b924 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 2 Apr 2020 17:18:36 +0000 Subject: [PATCH 50/53] chore(deps): bump aws-sdk from 2.650.0 to 2.651.0 (#7125) Bumps [aws-sdk](https://github.com/aws/aws-sdk-js) from 2.650.0 to 2.651.0. - [Release notes](https://github.com/aws/aws-sdk-js/releases) - [Changelog](https://github.com/aws/aws-sdk-js/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-js/compare/v2.650.0...v2.651.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- packages/@aws-cdk/aws-cloudfront/package.json | 2 +- packages/@aws-cdk/aws-cloudtrail/package.json | 2 +- packages/@aws-cdk/aws-codebuild/package.json | 2 +- packages/@aws-cdk/aws-codecommit/package.json | 2 +- packages/@aws-cdk/aws-dynamodb/package.json | 2 +- packages/@aws-cdk/aws-eks/package.json | 2 +- packages/@aws-cdk/aws-events-targets/package.json | 2 +- packages/@aws-cdk/aws-lambda/package.json | 2 +- packages/@aws-cdk/aws-route53/package.json | 2 +- packages/@aws-cdk/aws-sqs/package.json | 2 +- packages/@aws-cdk/custom-resources/package.json | 2 +- packages/aws-cdk/package.json | 2 +- packages/cdk-assets/package.json | 2 +- yarn.lock | 8 ++++---- 14 files changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/@aws-cdk/aws-cloudfront/package.json b/packages/@aws-cdk/aws-cloudfront/package.json index b05fafeca0386..36e582de74618 100644 --- a/packages/@aws-cdk/aws-cloudfront/package.json +++ b/packages/@aws-cdk/aws-cloudfront/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.650.0", + "aws-sdk": "^2.651.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudtrail/package.json b/packages/@aws-cdk/aws-cloudtrail/package.json index 49471d23ba425..a93a972fdab45 100644 --- a/packages/@aws-cdk/aws-cloudtrail/package.json +++ b/packages/@aws-cdk/aws-cloudtrail/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.650.0", + "aws-sdk": "^2.651.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-codebuild/package.json b/packages/@aws-cdk/aws-codebuild/package.json index 21d9dadf3568c..3c62ab06b87d2 100644 --- a/packages/@aws-cdk/aws-codebuild/package.json +++ b/packages/@aws-cdk/aws-codebuild/package.json @@ -70,7 +70,7 @@ "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.650.0", + "aws-sdk": "^2.651.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-codecommit/package.json b/packages/@aws-cdk/aws-codecommit/package.json index 786d9651bd6e1..4bd363826eeb5 100644 --- a/packages/@aws-cdk/aws-codecommit/package.json +++ b/packages/@aws-cdk/aws-codecommit/package.json @@ -70,7 +70,7 @@ "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.650.0", + "aws-sdk": "^2.651.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-dynamodb/package.json b/packages/@aws-cdk/aws-dynamodb/package.json index afa22e9fd6fc9..4d77f6eb19bb1 100644 --- a/packages/@aws-cdk/aws-dynamodb/package.json +++ b/packages/@aws-cdk/aws-dynamodb/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/jest": "^25.1.4", - "aws-sdk": "^2.650.0", + "aws-sdk": "^2.651.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-eks/package.json b/packages/@aws-cdk/aws-eks/package.json index 71f984564b2a7..d0969dd16ec4f 100644 --- a/packages/@aws-cdk/aws-eks/package.json +++ b/packages/@aws-cdk/aws-eks/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.650.0", + "aws-sdk": "^2.651.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-events-targets/package.json b/packages/@aws-cdk/aws-events-targets/package.json index a78ee6b6cce4c..70e3b7143e3cb 100644 --- a/packages/@aws-cdk/aws-events-targets/package.json +++ b/packages/@aws-cdk/aws-events-targets/package.json @@ -86,7 +86,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-codecommit": "0.0.0", - "aws-sdk": "^2.650.0", + "aws-sdk": "^2.651.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-lambda/package.json b/packages/@aws-cdk/aws-lambda/package.json index dd14974012e44..0a129f1555c87 100644 --- a/packages/@aws-cdk/aws-lambda/package.json +++ b/packages/@aws-cdk/aws-lambda/package.json @@ -71,7 +71,7 @@ "@types/lodash": "^4.14.149", "@types/nodeunit": "^0.0.30", "@types/sinon": "^9.0.0", - "aws-sdk": "^2.650.0", + "aws-sdk": "^2.651.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-route53/package.json b/packages/@aws-cdk/aws-route53/package.json index 40a5c45b79b0e..f69e353d80de2 100644 --- a/packages/@aws-cdk/aws-route53/package.json +++ b/packages/@aws-cdk/aws-route53/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.650.0", + "aws-sdk": "^2.651.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-sqs/package.json b/packages/@aws-cdk/aws-sqs/package.json index 46533f90f6a9f..bfbedd298f292 100644 --- a/packages/@aws-cdk/aws-sqs/package.json +++ b/packages/@aws-cdk/aws-sqs/package.json @@ -65,7 +65,7 @@ "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.650.0", + "aws-sdk": "^2.651.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/custom-resources/package.json b/packages/@aws-cdk/custom-resources/package.json index b4d1a33ebb874..c35aa198af949 100644 --- a/packages/@aws-cdk/custom-resources/package.json +++ b/packages/@aws-cdk/custom-resources/package.json @@ -73,7 +73,7 @@ "@types/aws-lambda": "^8.10.39", "@types/fs-extra": "^8.1.0", "@types/sinon": "^9.0.0", - "aws-sdk": "^2.650.0", + "aws-sdk": "^2.651.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index 65ce2cd610eda..3f24ea5b36ed9 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -69,7 +69,7 @@ "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/region-info": "0.0.0", "archiver": "^3.1.1", - "aws-sdk": "^2.650.0", + "aws-sdk": "^2.651.0", "camelcase": "^5.3.1", "cdk-assets": "0.0.0", "colors": "^1.4.0", diff --git a/packages/cdk-assets/package.json b/packages/cdk-assets/package.json index 5064c412125b7..59da5b01cc309 100644 --- a/packages/cdk-assets/package.json +++ b/packages/cdk-assets/package.json @@ -44,7 +44,7 @@ "dependencies": { "@aws-cdk/cdk-assets-schema": "0.0.0", "archiver": "^3.1.1", - "aws-sdk": "^2.650.0", + "aws-sdk": "^2.651.0", "glob": "^7.1.6", "yargs": "^15.3.1" }, diff --git a/yarn.lock b/yarn.lock index dfa992e8cde88..d7e84e930d5e2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2808,10 +2808,10 @@ aws-sdk-mock@^5.1.0: sinon "^9.0.1" traverse "^0.6.6" -aws-sdk@^2.637.0, aws-sdk@^2.650.0: - version "2.650.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.650.0.tgz#edf995cf2805c918d7470a652f1316ae902c5aa4" - integrity sha512-MlTKXeRSe4IXXqnulAiXZccpTgDafs3ofYIQv/7ApR+oQUFsq96RHwe8MdW9N1cXn7fz302jLXUAykj4boR3DA== +aws-sdk@^2.637.0, aws-sdk@^2.651.0: + version "2.651.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.651.0.tgz#0a62f4b68b6a416d65fa9a88833f52d5e483a605" + integrity sha512-ZPZIRj4EkZSpeuLsNKV799lj5itcCH3adZheWfXTp2IPf48C+ScYh3QaEmPd2HoneUkjo41znJjcORrLN8lWaw== dependencies: buffer "4.9.1" events "1.1.1" From b7127107eabce6265c4649c25fd7f1c27a8ada97 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 2 Apr 2020 19:09:12 +0000 Subject: [PATCH 51/53] chore(deps-dev): bump @types/jest from 25.1.4 to 25.1.5 (#7147) Bumps [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) from 25.1.4 to 25.1.5. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- packages/@aws-cdk/assert/package.json | 2 +- packages/@aws-cdk/aws-dynamodb/package.json | 2 +- packages/@aws-cdk/aws-sam/package.json | 2 +- .../@aws-cdk/cdk-assets-schema/package.json | 2 +- .../@aws-cdk/cloudformation-diff/package.json | 2 +- packages/@aws-cdk/cx-api/package.json | 2 +- .../@monocdk-experiment/assert/package.json | 2 +- .../rewrite-imports/package.json | 2 +- packages/aws-cdk/package.json | 2 +- packages/cdk-assets/package.json | 2 +- packages/cdk-dasm/package.json | 2 +- packages/decdk/package.json | 2 +- tools/cdk-build-tools/package.json | 2 +- tools/cfn2ts/package.json | 2 +- yarn.lock | 54 +++++++++---------- 15 files changed, 41 insertions(+), 41 deletions(-) diff --git a/packages/@aws-cdk/assert/package.json b/packages/@aws-cdk/assert/package.json index a30d4045fcddb..27f8a37948722 100644 --- a/packages/@aws-cdk/assert/package.json +++ b/packages/@aws-cdk/assert/package.json @@ -29,7 +29,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^25.1.4", + "@types/jest": "^25.1.5", "cdk-build-tools": "0.0.0", "jest": "^24.9.0", "pkglint": "0.0.0", diff --git a/packages/@aws-cdk/aws-dynamodb/package.json b/packages/@aws-cdk/aws-dynamodb/package.json index 4d77f6eb19bb1..e14d02e6b2ddb 100644 --- a/packages/@aws-cdk/aws-dynamodb/package.json +++ b/packages/@aws-cdk/aws-dynamodb/package.json @@ -63,7 +63,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/jest": "^25.1.4", + "@types/jest": "^25.1.5", "aws-sdk": "^2.651.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-sam/package.json b/packages/@aws-cdk/aws-sam/package.json index 2c46a3aa4a0ab..903319a6cba05 100644 --- a/packages/@aws-cdk/aws-sam/package.json +++ b/packages/@aws-cdk/aws-sam/package.json @@ -64,7 +64,7 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/jest": "^25.1.4", + "@types/jest": "^25.1.5", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "jest": "^24.9.0", diff --git a/packages/@aws-cdk/cdk-assets-schema/package.json b/packages/@aws-cdk/cdk-assets-schema/package.json index 4f1557f13f080..7a14fc02759a7 100644 --- a/packages/@aws-cdk/cdk-assets-schema/package.json +++ b/packages/@aws-cdk/cdk-assets-schema/package.json @@ -66,7 +66,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^25.1.4", + "@types/jest": "^25.1.5", "cdk-build-tools": "0.0.0", "jest": "^24.9.0", "pkglint": "0.0.0" diff --git a/packages/@aws-cdk/cloudformation-diff/package.json b/packages/@aws-cdk/cloudformation-diff/package.json index 9cdd9a0c2a163..680fb7f70ef5b 100644 --- a/packages/@aws-cdk/cloudformation-diff/package.json +++ b/packages/@aws-cdk/cloudformation-diff/package.json @@ -38,7 +38,7 @@ "table": "^5.4.6" }, "devDependencies": { - "@types/jest": "^25.1.4", + "@types/jest": "^25.1.5", "@types/string-width": "^4.0.1", "@types/table": "^4.0.7", "cdk-build-tools": "0.0.0", diff --git a/packages/@aws-cdk/cx-api/package.json b/packages/@aws-cdk/cx-api/package.json index 10bf7fa6d98a4..c49e5b937deed 100644 --- a/packages/@aws-cdk/cx-api/package.json +++ b/packages/@aws-cdk/cx-api/package.json @@ -66,7 +66,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^25.1.4", + "@types/jest": "^25.1.5", "@types/mock-fs": "^4.10.0", "@types/semver": "^7.1.0", "cdk-build-tools": "0.0.0", diff --git a/packages/@monocdk-experiment/assert/package.json b/packages/@monocdk-experiment/assert/package.json index eac564b2299ba..6cdbb51d56b7c 100644 --- a/packages/@monocdk-experiment/assert/package.json +++ b/packages/@monocdk-experiment/assert/package.json @@ -41,7 +41,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^25.1.4", + "@types/jest": "^25.1.5", "cdk-build-tools": "0.0.0", "jest": "^24.9.0", "pkglint": "0.0.0", diff --git a/packages/@monocdk-experiment/rewrite-imports/package.json b/packages/@monocdk-experiment/rewrite-imports/package.json index 0b76ed6bacea8..39905687588c7 100644 --- a/packages/@monocdk-experiment/rewrite-imports/package.json +++ b/packages/@monocdk-experiment/rewrite-imports/package.json @@ -32,7 +32,7 @@ }, "devDependencies": { "@types/glob": "^7.1.1", - "@types/jest": "^25.1.4", + "@types/jest": "^25.1.5", "@types/node": "^10.17.18", "cdk-build-tools": "0.0.0", "pkglint": "0.0.0" diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index 3f24ea5b36ed9..1821fe69c6361 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -44,7 +44,7 @@ "@types/archiver": "^3.1.0", "@types/fs-extra": "^8.1.0", "@types/glob": "^7.1.1", - "@types/jest": "^25.1.4", + "@types/jest": "^25.1.5", "@types/minimatch": "^3.0.3", "@types/mockery": "^1.4.29", "@types/node": "^10.17.18", diff --git a/packages/cdk-assets/package.json b/packages/cdk-assets/package.json index 59da5b01cc309..875cd0accfe60 100644 --- a/packages/cdk-assets/package.json +++ b/packages/cdk-assets/package.json @@ -30,7 +30,7 @@ "devDependencies": { "@types/archiver": "^3.1.0", "@types/glob": "^7.1.1", - "@types/jest": "^25.1.4", + "@types/jest": "^25.1.5", "@types/mock-fs": "^4.10.0", "@types/node": "^10.17.18", "@types/yargs": "^15.0.4", diff --git a/packages/cdk-dasm/package.json b/packages/cdk-dasm/package.json index 6874f0ec85c6c..ac30dbc5781f6 100644 --- a/packages/cdk-dasm/package.json +++ b/packages/cdk-dasm/package.json @@ -30,7 +30,7 @@ "yaml": "1.8.3" }, "devDependencies": { - "@types/jest": "^25.1.4", + "@types/jest": "^25.1.5", "@types/yaml": "1.2.0", "jest": "^24.9.0" }, diff --git a/packages/decdk/package.json b/packages/decdk/package.json index d717d4b3776cc..699baf235f0cf 100644 --- a/packages/decdk/package.json +++ b/packages/decdk/package.json @@ -178,7 +178,7 @@ }, "devDependencies": { "@types/fs-extra": "^8.1.0", - "@types/jest": "^25.1.4", + "@types/jest": "^25.1.5", "@types/yaml": "1.2.0", "@types/yargs": "^15.0.4", "jest": "^24.9.0", diff --git a/tools/cdk-build-tools/package.json b/tools/cdk-build-tools/package.json index 757b7b6cb17a3..64cdf997e0bcf 100644 --- a/tools/cdk-build-tools/package.json +++ b/tools/cdk-build-tools/package.json @@ -32,7 +32,7 @@ "license": "Apache-2.0", "devDependencies": { "@types/fs-extra": "^8.1.0", - "@types/jest": "^25.1.4", + "@types/jest": "^25.1.5", "@types/yargs": "^15.0.4", "pkglint": "0.0.0" }, diff --git a/tools/cfn2ts/package.json b/tools/cfn2ts/package.json index a499da1cf4ffc..5935617f3127b 100644 --- a/tools/cfn2ts/package.json +++ b/tools/cfn2ts/package.json @@ -37,7 +37,7 @@ }, "devDependencies": { "@types/fs-extra": "^8.1.0", - "@types/jest": "^25.1.4", + "@types/jest": "^25.1.5", "@types/yargs": "^15.0.4", "cdk-build-tools": "0.0.0", "jest": "^24.9.0", diff --git a/yarn.lock b/yarn.lock index d7e84e930d5e2..634bec317bec5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2156,13 +2156,13 @@ "@types/istanbul-lib-coverage" "*" "@types/istanbul-lib-report" "*" -"@types/jest@^25.1.4": - version "25.1.4" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-25.1.4.tgz#9e9f1e59dda86d3fd56afce71d1ea1b331f6f760" - integrity sha512-QDDY2uNAhCV7TMCITrxz+MRk1EizcsevzfeS6LykIlq2V1E5oO4wXG8V2ZEd9w7Snxeeagk46YbMgZ8ESHx3sw== +"@types/jest@^25.1.5": + version "25.1.5" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-25.1.5.tgz#3c3c078b3cd19c6403e21277f1cfdc0ce5ebf9a9" + integrity sha512-FBmb9YZHoEOH56Xo/PIYtfuyTL0IzJLM3Hy0Sqc82nn5eqqXgefKcl/eMgChM8eSGVfoDee8cdlj7K74T8a6Yg== dependencies: - jest-diff "^25.1.0" - pretty-format "^25.1.0" + jest-diff "25.1.0" + pretty-format "25.1.0" "@types/json-schema@^7.0.3": version "7.0.4" @@ -7033,6 +7033,16 @@ jest-config@^25.2.4: pretty-format "^25.2.3" realpath-native "^2.0.0" +jest-diff@25.1.0: + version "25.1.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-25.1.0.tgz#58b827e63edea1bc80c1de952b80cec9ac50e1ad" + integrity sha512-nepXgajT+h017APJTreSieh4zCqnSHEJ1iT8HDlewu630lSJ4Kjjr9KNzm+kzGwwcpsDE6Snx1GJGzzsefaEHw== + dependencies: + chalk "^3.0.0" + diff-sequences "^25.1.0" + jest-get-type "^25.1.0" + pretty-format "^25.1.0" + jest-diff@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.9.0.tgz#931b7d0d5778a1baf7452cb816e325e3724055da" @@ -7043,16 +7053,6 @@ jest-diff@^24.9.0: jest-get-type "^24.9.0" pretty-format "^24.9.0" -jest-diff@^25.1.0: - version "25.1.0" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-25.1.0.tgz#58b827e63edea1bc80c1de952b80cec9ac50e1ad" - integrity sha512-nepXgajT+h017APJTreSieh4zCqnSHEJ1iT8HDlewu630lSJ4Kjjr9KNzm+kzGwwcpsDE6Snx1GJGzzsefaEHw== - dependencies: - chalk "^3.0.0" - diff-sequences "^25.1.0" - jest-get-type "^25.1.0" - pretty-format "^25.1.0" - jest-diff@^25.2.3: version "25.2.3" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-25.2.3.tgz#54d601a0a754ef26e808a8c8dbadd278c215aa3f" @@ -10164,6 +10164,16 @@ prelude-ls@~1.1.2: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= +pretty-format@25.1.0: + version "25.1.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-25.1.0.tgz#ed869bdaec1356fc5ae45de045e2c8ec7b07b0c8" + integrity sha512-46zLRSGLd02Rp+Lhad9zzuNZ+swunitn8zIpfD2B4OPCRLXbM87RJT2aBLBWYOznNUML/2l/ReMyWNC80PJBUQ== + dependencies: + "@jest/types" "^25.1.0" + ansi-regex "^5.0.0" + ansi-styles "^4.0.0" + react-is "^16.12.0" + pretty-format@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.9.0.tgz#12fac31b37019a4eea3c11aa9a959eb7628aa7c9" @@ -10174,17 +10184,7 @@ pretty-format@^24.9.0: ansi-styles "^3.2.0" react-is "^16.8.4" -pretty-format@^25.1.0: - version "25.1.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-25.1.0.tgz#ed869bdaec1356fc5ae45de045e2c8ec7b07b0c8" - integrity sha512-46zLRSGLd02Rp+Lhad9zzuNZ+swunitn8zIpfD2B4OPCRLXbM87RJT2aBLBWYOznNUML/2l/ReMyWNC80PJBUQ== - dependencies: - "@jest/types" "^25.1.0" - ansi-regex "^5.0.0" - ansi-styles "^4.0.0" - react-is "^16.12.0" - -pretty-format@^25.2.3: +pretty-format@^25.1.0, pretty-format@^25.2.3: version "25.2.3" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-25.2.3.tgz#ba6e9603a0d80fa2e470b1fed55de1f9bfd81421" integrity sha512-IP4+5UOAVGoyqC/DiomOeHBUKN6q00gfyT2qpAsRH64tgOKB2yF7FHJXC18OCiU0/YFierACup/zdCOWw0F/0w== From b0a90243b07c415ff6807f3262ccdb643e5ff9d8 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 2 Apr 2020 19:50:45 +0000 Subject: [PATCH 52/53] chore(deps): bump aws-sdk from 2.651.0 to 2.652.0 (#7149) Bumps [aws-sdk](https://github.com/aws/aws-sdk-js) from 2.651.0 to 2.652.0. - [Release notes](https://github.com/aws/aws-sdk-js/releases) - [Changelog](https://github.com/aws/aws-sdk-js/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-js/compare/v2.651.0...v2.652.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- packages/@aws-cdk/aws-cloudfront/package.json | 2 +- packages/@aws-cdk/aws-cloudtrail/package.json | 2 +- packages/@aws-cdk/aws-codebuild/package.json | 2 +- packages/@aws-cdk/aws-codecommit/package.json | 2 +- packages/@aws-cdk/aws-dynamodb/package.json | 2 +- packages/@aws-cdk/aws-eks/package.json | 2 +- packages/@aws-cdk/aws-events-targets/package.json | 2 +- packages/@aws-cdk/aws-lambda/package.json | 2 +- packages/@aws-cdk/aws-route53/package.json | 2 +- packages/@aws-cdk/aws-sqs/package.json | 2 +- packages/@aws-cdk/custom-resources/package.json | 2 +- packages/aws-cdk/package.json | 2 +- packages/cdk-assets/package.json | 2 +- yarn.lock | 8 ++++---- 14 files changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/@aws-cdk/aws-cloudfront/package.json b/packages/@aws-cdk/aws-cloudfront/package.json index 36e582de74618..d10e71a419246 100644 --- a/packages/@aws-cdk/aws-cloudfront/package.json +++ b/packages/@aws-cdk/aws-cloudfront/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.651.0", + "aws-sdk": "^2.652.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudtrail/package.json b/packages/@aws-cdk/aws-cloudtrail/package.json index a93a972fdab45..079ec381d9220 100644 --- a/packages/@aws-cdk/aws-cloudtrail/package.json +++ b/packages/@aws-cdk/aws-cloudtrail/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.651.0", + "aws-sdk": "^2.652.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-codebuild/package.json b/packages/@aws-cdk/aws-codebuild/package.json index 3c62ab06b87d2..5793fbf04ecae 100644 --- a/packages/@aws-cdk/aws-codebuild/package.json +++ b/packages/@aws-cdk/aws-codebuild/package.json @@ -70,7 +70,7 @@ "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.651.0", + "aws-sdk": "^2.652.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-codecommit/package.json b/packages/@aws-cdk/aws-codecommit/package.json index 4bd363826eeb5..fc0518288595e 100644 --- a/packages/@aws-cdk/aws-codecommit/package.json +++ b/packages/@aws-cdk/aws-codecommit/package.json @@ -70,7 +70,7 @@ "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.651.0", + "aws-sdk": "^2.652.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-dynamodb/package.json b/packages/@aws-cdk/aws-dynamodb/package.json index e14d02e6b2ddb..d809174c1da89 100644 --- a/packages/@aws-cdk/aws-dynamodb/package.json +++ b/packages/@aws-cdk/aws-dynamodb/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/jest": "^25.1.5", - "aws-sdk": "^2.651.0", + "aws-sdk": "^2.652.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-eks/package.json b/packages/@aws-cdk/aws-eks/package.json index d0969dd16ec4f..80887d4d9b4e7 100644 --- a/packages/@aws-cdk/aws-eks/package.json +++ b/packages/@aws-cdk/aws-eks/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.651.0", + "aws-sdk": "^2.652.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-events-targets/package.json b/packages/@aws-cdk/aws-events-targets/package.json index 70e3b7143e3cb..cfc4e6460fc44 100644 --- a/packages/@aws-cdk/aws-events-targets/package.json +++ b/packages/@aws-cdk/aws-events-targets/package.json @@ -86,7 +86,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-codecommit": "0.0.0", - "aws-sdk": "^2.651.0", + "aws-sdk": "^2.652.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-lambda/package.json b/packages/@aws-cdk/aws-lambda/package.json index 0a129f1555c87..8a007eb05d661 100644 --- a/packages/@aws-cdk/aws-lambda/package.json +++ b/packages/@aws-cdk/aws-lambda/package.json @@ -71,7 +71,7 @@ "@types/lodash": "^4.14.149", "@types/nodeunit": "^0.0.30", "@types/sinon": "^9.0.0", - "aws-sdk": "^2.651.0", + "aws-sdk": "^2.652.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-route53/package.json b/packages/@aws-cdk/aws-route53/package.json index f69e353d80de2..3a8b5e80f8425 100644 --- a/packages/@aws-cdk/aws-route53/package.json +++ b/packages/@aws-cdk/aws-route53/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.651.0", + "aws-sdk": "^2.652.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-sqs/package.json b/packages/@aws-cdk/aws-sqs/package.json index bfbedd298f292..a273ce8f75c78 100644 --- a/packages/@aws-cdk/aws-sqs/package.json +++ b/packages/@aws-cdk/aws-sqs/package.json @@ -65,7 +65,7 @@ "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.651.0", + "aws-sdk": "^2.652.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/custom-resources/package.json b/packages/@aws-cdk/custom-resources/package.json index c35aa198af949..9c2f04f1bd49b 100644 --- a/packages/@aws-cdk/custom-resources/package.json +++ b/packages/@aws-cdk/custom-resources/package.json @@ -73,7 +73,7 @@ "@types/aws-lambda": "^8.10.39", "@types/fs-extra": "^8.1.0", "@types/sinon": "^9.0.0", - "aws-sdk": "^2.651.0", + "aws-sdk": "^2.652.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index 1821fe69c6361..93da8f66277ef 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -69,7 +69,7 @@ "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/region-info": "0.0.0", "archiver": "^3.1.1", - "aws-sdk": "^2.651.0", + "aws-sdk": "^2.652.0", "camelcase": "^5.3.1", "cdk-assets": "0.0.0", "colors": "^1.4.0", diff --git a/packages/cdk-assets/package.json b/packages/cdk-assets/package.json index 875cd0accfe60..0c669cae7c72c 100644 --- a/packages/cdk-assets/package.json +++ b/packages/cdk-assets/package.json @@ -44,7 +44,7 @@ "dependencies": { "@aws-cdk/cdk-assets-schema": "0.0.0", "archiver": "^3.1.1", - "aws-sdk": "^2.651.0", + "aws-sdk": "^2.652.0", "glob": "^7.1.6", "yargs": "^15.3.1" }, diff --git a/yarn.lock b/yarn.lock index 634bec317bec5..1f2d8f4ea274e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2808,10 +2808,10 @@ aws-sdk-mock@^5.1.0: sinon "^9.0.1" traverse "^0.6.6" -aws-sdk@^2.637.0, aws-sdk@^2.651.0: - version "2.651.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.651.0.tgz#0a62f4b68b6a416d65fa9a88833f52d5e483a605" - integrity sha512-ZPZIRj4EkZSpeuLsNKV799lj5itcCH3adZheWfXTp2IPf48C+ScYh3QaEmPd2HoneUkjo41znJjcORrLN8lWaw== +aws-sdk@^2.637.0, aws-sdk@^2.652.0: + version "2.652.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.652.0.tgz#00a4dd3a4ce588448895c42d25e967f2a23b487c" + integrity sha512-THMlf3CX/IKMh+jizDQ+XCf5LSp1x+rIl+4uIRJjMj+zHNes7zJy3DSkuu5gux5aG5x4God996vPdCus+F22JA== dependencies: buffer "4.9.1" events "1.1.1" From de8e670159065e1c1fe6d69a51c1596755dcbcc6 Mon Sep 17 00:00:00 2001 From: Katie Normandin <51719777+knorms101@users.noreply.github.com> Date: Thu, 2 Apr 2020 17:39:42 -0400 Subject: [PATCH 53/53] feat(aws-codebuild): add from codebuild image option (#7117) feat: add from codebuild image option Addresses comment [here](https://github.com/aws/aws-cdk/issues/2606#issuecomment-606114708). --- packages/@aws-cdk/aws-codebuild/README.md | 3 ++- packages/@aws-cdk/aws-codebuild/lib/project.ts | 14 ++++++++++++++ .../aws-codebuild/test/test.codebuild.ts | 17 +++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-codebuild/README.md b/packages/@aws-cdk/aws-codebuild/README.md index d3c5e533221c5..279c42eceed61 100644 --- a/packages/@aws-cdk/aws-codebuild/README.md +++ b/packages/@aws-cdk/aws-codebuild/README.md @@ -188,7 +188,7 @@ can use the `environment` property to customize the build environment: The CodeBuild library supports both Linux and Windows images via the `LinuxBuildImage` and `WindowsBuildImage` classes, respectively. -You can either specify one of the predefined Windows/Linux images by using one +You can specify one of the predefined Windows/Linux images by using one of the constants such as `WindowsBuildImage.WINDOWS_BASE_2_0` or `LinuxBuildImage.STANDARD_2_0`. @@ -200,6 +200,7 @@ Alternatively, you can specify a custom image using one of the static methods on ECR repository. * Use `.fromAsset(directory)` to use an image created from a local asset. +* Use `.fromCodeBuildImageId(id)` to reference a pre-defined, CodeBuild-provided Docker image. The following example shows how to define an image from a Docker asset: diff --git a/packages/@aws-cdk/aws-codebuild/lib/project.ts b/packages/@aws-cdk/aws-codebuild/lib/project.ts index e0efb49a6ee0c..34fee6f8bec57 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/project.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/project.ts @@ -1345,6 +1345,20 @@ export class LinuxBuildImage implements IBuildImage { }); } + /** + * Uses a Docker image provided by CodeBuild. + * + * @returns A Docker image provided by CodeBuild. + * + * @see https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-available.html + * + * @param id The image identifier + * @example 'aws/codebuild/standard:4.0' + */ + public static fromCodeBuildImageId(id: string): IBuildImage { + return LinuxBuildImage.codeBuildImage(id); + } + private static codeBuildImage(name: string): IBuildImage { return new LinuxBuildImage({ imageId: name, diff --git a/packages/@aws-cdk/aws-codebuild/test/test.codebuild.ts b/packages/@aws-cdk/aws-codebuild/test/test.codebuild.ts index 9127e324d83ed..b97b87b0d5fac 100644 --- a/packages/@aws-cdk/aws-codebuild/test/test.codebuild.ts +++ b/packages/@aws-cdk/aws-codebuild/test/test.codebuild.ts @@ -1369,6 +1369,23 @@ export = { test.done(); }, + 'fromCodebuildImage'(test: Test) { + const stack = new cdk.Stack(); + new codebuild.PipelineProject(stack, 'Project', { + environment: { + buildImage: codebuild.LinuxBuildImage.fromCodeBuildImageId('aws/codebuild/standard:4.0') + }, + }); + + expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { + "Environment": { + "Image": "aws/codebuild/standard:4.0", + }, + })); + + test.done(); + }, + 'ARM image': { 'AMAZON_LINUX_2_ARM': { 'has type ARM_CONTAINER and default ComputeType LARGE'(test: Test) {