From 23028906df8e16b9b456f42ef3d611630d6a65be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=91=A8=F0=9F=8F=BC=E2=80=8D=F0=9F=92=BB=20Romain=20M?= =?UTF-8?q?arcadier-Muller?= Date: Fri, 21 Jun 2019 14:51:36 +0200 Subject: [PATCH 1/6] fix(stepfunctions): Downscope SageMaker permissions Previous implementation was using the `SageMakerFullAccess` managed policy, which grants extensive permissions to the SageMaker job. Instead, this commit makes it set permissions very specifically to what the requirement entities are, and only resorts to the `*` resource when the entities are provided by an input to the StepFunction. --- .../lib/sagemaker-task-base-types.ts | 154 ++++++- .../lib/sagemaker-train-task.ts | 76 +++- .../aws-stepfunctions-tasks/package.json | 6 +- .../test/integ.sagemaker.expected.json | 399 ++++++++++++++++++ .../test/integ.sagemaker.ts | 28 ++ .../test/sagemaker-training-job.test.ts | 43 +- .../@aws-cdk/aws-stepfunctions/lib/fields.ts | 11 +- .../aws-stepfunctions/lib/json-path.ts | 4 +- .../@aws-cdk/cdk/lib/private/token-map.ts | 2 +- packages/@aws-cdk/cdk/lib/token.ts | 15 +- 10 files changed, 701 insertions(+), 37 deletions(-) create mode 100644 packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.sagemaker.expected.json create mode 100644 packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.sagemaker.ts diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-task-base-types.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-task-base-types.ts index 9648b4bac4928..66c723a68667a 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-task-base-types.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-task-base-types.ts @@ -1,5 +1,9 @@ import ec2 = require('@aws-cdk/aws-ec2'); +import ecr = require('@aws-cdk/aws-ecr'); +import iam = require('@aws-cdk/aws-iam'); import kms = require('@aws-cdk/aws-kms'); +import s3 = require('@aws-cdk/aws-s3'); +import sfn = require('@aws-cdk/aws-stepfunctions'); import { Duration } from '@aws-cdk/cdk'; // @@ -24,7 +28,7 @@ export interface AlgorithmSpecification { /** * Registry path of the Docker image that contains the training algorithm. */ - readonly trainingImage?: string; + readonly trainingImage?: IDockerImage; /** * Input mode that the algorithm supports. @@ -125,7 +129,7 @@ export interface S3DataSource { /** * S3 Uri */ - readonly s3Uri: string; + readonly s3Location: IS3Location; } /** @@ -140,7 +144,7 @@ export interface OutputDataConfig { /** * Identifies the S3 path where you want Amazon SageMaker to store the model artifacts. */ - readonly s3OutputPath: string; + readonly s3OutputLocation: IS3Location; } export interface StoppingCondition { @@ -169,7 +173,7 @@ export interface ResourceConfig { /** * KMS key that Amazon SageMaker uses to encrypt data on the storage volume attached to the ML compute instance(s) that run the training job. */ - readonly volumeKmsKeyId?: kms.IKey; + readonly volumeEncryptionKey?: kms.IKey; /** * Size of the ML storage volume that you want to provision. @@ -218,6 +222,148 @@ export interface MetricDefinition { readonly regex: string; } +/** + * Specifies a location in a S3 Bucket. + * + * @experimental + */ +export interface IS3Location { + /** The URI of the location in S3 */ + readonly uri: string; + + /** Grants read permissions to the S3 location. */ + grantRead(grantee: iam.IGrantable): void; + /** Grants write permissions to the S3 location. */ + grantWrite(grantee: iam.IGrantable): void; +} + +/** + * Constructs `IS3Location` objects. + */ +export class S3Location { + /** + * An `IS3Location` built with a determined bucket and key prefix. + * + * @param bucket is the bucket where the objects are to be stored. + * @param keyPrefix is the key prefix used by the location. + */ + public static inBucket(bucket: s3.IBucket, keyPrefix: string): IS3Location { + return { + uri: bucket.urlForObject(keyPrefix), + grantRead: (grantee) => bucket.grantRead(grantee, keyPrefix + '*'), + grantWrite: (grantee) => bucket.grantWrite(grantee, keyPrefix + '*'), + }; + } + + /** + * An `IS3Location` determined fully by a JSON Path from the task input. + * + * Due to the dynamic nature of those locations, the IAM grants that will be set by `grantRead` and `grantWrite` + * apply to the `*` resource. + * + * @param expression the JSON expression resolving to an S3 location URI. + */ + public static fromJsonExpression(expression: string): IS3Location { + return { + uri: sfn.Data.stringAt(expression), + grantRead: grantee => grantee.grantPrincipal.addToPolicy(new iam.PolicyStatement({ + actions: ['s3:GetObject', `s3:ListBucket`], + resources: ['*'] + })), + grantWrite: grantee => grantee.grantPrincipal.addToPolicy(new iam.PolicyStatement({ + actions: ['s3:PutObject'], + resources: ['*'] + })), + }; + } + + private constructor() { } +} + +export interface IDockerImage { + readonly name: string; + grantRead(grantee: iam.IGrantable): void; +} + +/** + * Specifies options for accessing images in ECR. + */ +export interface EcrImageOptions { + /** + * The tag to use for this ECR Image. This option is mutually exclusive with `digest`. + */ + readonly tag?: string; + + /** + * The digest to use for this ECR Image. This option is mutually exclusive with `tag`. + */ + readonly digest?: string; +} + +/** + * Creates `IDockerImage` instances. + */ +export class DockerImage { + /** + * Reference a Docker image stored in an ECR repository. + * + * @param repo the ECR repository where the image is hosted. + * @param opts an optional `tag` or `digest` to use. + */ + public static inEcr(repo: ecr.IRepository, opts: EcrImageOptions = {}): IDockerImage { + if (opts.tag && opts.digest) { + throw new Error(`The tag and digest options are mutually exclusive, but both were specified`); + } + const suffix = opts.tag + ? `:${opts.tag}` + : opts.digest + ? `@${opts.digest}` + : ''; + return { + name: repo.repositoryUri + suffix, + grantRead: repo.grantPull.bind(repo), + }; + } + + /** + * Reference a Docker image which URI is obtained from the task's input. + * + * @param expression the JSON path expression with the task input. + * @param enableEcrAccess whether ECR access should be permitted (set to `false` if the image will never be in ECR). + */ + public static fromJsonExpression(expression: string, enableEcrAccess = true): IDockerImage { + return this.fromImageUri(sfn.Data.stringAt(expression), enableEcrAccess); + } + + /** + * Reference a Docker image by it's URI. + * + * When referencing ECR images, prefer using `inEcr`. + * + * @param uri the URI to the docker image. + * @param enableEcrAccess whether ECR access should be permitted (set to `true` if the image is located in an ECR + * repository). + */ + public static fromImageUri(uri: string, enableEcrAccess = false): IDockerImage { + return { + name: uri, + grantRead(grantee) { + if (!enableEcrAccess) { return; } + grantee.grantPrincipal.addToPolicy(new iam.PolicyStatement({ + actions: [ + 'ecr:BatchCheckLayerAvailability', + 'ecr:GetDownloadUrlForLayer', + 'ecr:BatchGetImage' + ], + resources: ['*'] + })); + }, + }; + } + + private constructor() { } +} + /** * S3 Data Type. */ diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-train-task.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-train-task.ts index 40a9ee928cd7e..833c70d6a4d6b 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-train-task.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-train-task.ts @@ -8,7 +8,7 @@ import { AlgorithmSpecification, Channel, InputMode, OutputDataConfig, ResourceC /** * @experimental */ -export interface SagemakerTrainProps { +export interface SagemakerTrainTaskProps { /** * Training Job Name. @@ -16,7 +16,12 @@ export interface SagemakerTrainProps { readonly trainingJobName: string; /** - * Role for thte Training Job. + * Role for the Training Job. The role must be granted all necessary permissions for the SageMaker training job to + * be able to operate. + * + * See https://docs.aws.amazon.com/fr_fr/sagemaker/latest/dg/sagemaker-roles.html#sagemaker-roles-createtrainingjob-perms + * + * @default - a role with appropriate permissions will be created. */ readonly role?: iam.IRole; @@ -71,7 +76,7 @@ export interface SagemakerTrainProps { /** * Class representing the SageMaker Create Training Job task. */ -export class SagemakerTrainTask implements ec2.IConnectable, sfn.IStepFunctionsTask { +export class SagemakerTrainTask implements iam.IGrantable, ec2.IConnectable, sfn.IStepFunctionsTask { /** * Allows specify security group connections for instances of this fleet. @@ -105,7 +110,7 @@ export class SagemakerTrainTask implements ec2.IConnectable, sfn.IStepFunctionsT */ private readonly stoppingCondition: StoppingCondition; - constructor(scope: Construct, private readonly props: SagemakerTrainProps) { + constructor(scope: Construct, private readonly props: SagemakerTrainTaskProps) { // set the default resource config if not defined. this.resourceConfig = props.resourceConfig || { @@ -122,11 +127,55 @@ export class SagemakerTrainTask implements ec2.IConnectable, sfn.IStepFunctionsT // set the sagemaker role or create new one this.role = props.role || new iam.Role(scope, 'SagemakerRole', { assumedBy: new iam.ServicePrincipal('sagemaker.amazonaws.com'), - managedPolicies: [ - iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonSageMakerFullAccess') - ] + inlinePolicies: { + CreateTrainingJob: new iam.PolicyDocument({ + statements: [ + new iam.PolicyStatement({ + actions: [ + 'cloudwatch:PutMetricData', + 'logs:CreateLogStream', + 'logs:PutLogEvents', + 'logs:CreateLogGroup', + 'logs:DescribeLogStreams', + 'ecr:GetAuthorizationToken', + ...props.vpcConfig + ? [ + 'ec2:CreateNetworkInterface', + 'ec2:CreateNetworkInterfacePermission', + 'ec2:DeleteNetworkInterface', + 'ec2:DeleteNetworkInterfacePermission', + 'ec2:DescribeNetworkInterfaces', + 'ec2:DescribeVpcs', + 'ec2:DescribeDhcpOptions', + 'ec2:DescribeSubnets', + 'ec2:DescribeSecurityGroups', + ] + : [], + ], + resources: ['*'], // Those permissions cannot be resource-scoped + }) + ] + }), + } }); + for (const input of props.inputDataConfig) { + input.dataSource.s3DataSource.s3Location.grantRead(this.role); + } + props.outputDataConfig.s3OutputLocation.grantWrite(this.role); + + if (props.outputDataConfig.encryptionKey) { + props.outputDataConfig.encryptionKey.grantEncrypt(this.role); + } + + if (props.algorithmSpecification.trainingImage) { + props.algorithmSpecification.trainingImage.grantRead(this.role); + } + + if (props.resourceConfig && props.resourceConfig.volumeEncryptionKey) { + props.resourceConfig.volumeEncryptionKey.grant(this.role, 'kms:CreateGrant'); + } + // set the input mode to 'File' if not defined this.algorithmSpecification = ( props.algorithmSpecification.trainingInputMode ) ? ( props.algorithmSpecification ) : @@ -148,6 +197,10 @@ export class SagemakerTrainTask implements ec2.IConnectable, sfn.IStepFunctionsT } } + public get grantPrincipal(): iam.IPrincipal { + return this.role; + } + public bind(task: sfn.Task): sfn.StepFunctionsTaskConfig { return { resourceArn: 'arn:aws:states:::sagemaker:createTrainingJob' + (this.props.synchronous ? '.sync' : ''), @@ -190,7 +243,7 @@ export class SagemakerTrainTask implements ec2.IConnectable, sfn.IStepFunctionsT ChannelName: channel.channelName, DataSource: { S3DataSource: { - S3Uri: channel.dataSource.s3DataSource.s3Uri, + S3Uri: channel.dataSource.s3DataSource.s3Location.uri, S3DataType: channel.dataSource.s3DataSource.s3DataType, ...(channel.dataSource.s3DataSource.s3DataDistributionType) ? { S3DataDistributionType: channel.dataSource.s3DataSource.s3DataDistributionType} : {}, @@ -209,7 +262,7 @@ export class SagemakerTrainTask implements ec2.IConnectable, sfn.IStepFunctionsT private renderOutputDataConfig(config: OutputDataConfig): {[key: string]: any} { return { OutputDataConfig: { - S3OutputPath: config.s3OutputPath, + S3OutputPath: config.s3OutputLocation.uri, ...(config.encryptionKey) ? { KmsKeyId: config.encryptionKey.keyArn } : {}, } }; @@ -221,7 +274,7 @@ export class SagemakerTrainTask implements ec2.IConnectable, sfn.IStepFunctionsT InstanceCount: config.instanceCount, InstanceType: 'ml.' + config.instanceType, VolumeSizeInGB: config.volumeSizeInGB, - ...(config.volumeKmsKeyId) ? { VolumeKmsKeyId: config.volumeKmsKeyId.keyArn } : {}, + ...(config.volumeEncryptionKey) ? { VolumeKmsKeyId: config.volumeEncryptionKey.keyArn } : {}, } }; } @@ -260,7 +313,8 @@ export class SagemakerTrainTask implements ec2.IConnectable, sfn.IStepFunctionsT stack.formatArn({ service: 'sagemaker', resource: 'training-job', - resourceName: '*' + // If the job name comes from input, we cannot target the policy to a particular ARN prefix reliably... + resourceName: sfn.Data.isJsonPath(this.props.trainingJobName) ? '*' : `${this.props.trainingJobName}*` }) ], }), diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/package.json b/packages/@aws-cdk/aws-stepfunctions-tasks/package.json index 184e0e7e16baf..2cc37cd22bfd2 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/package.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/package.json @@ -80,10 +80,12 @@ "dependencies": { "@aws-cdk/aws-cloudwatch": "^0.35.0", "@aws-cdk/aws-ec2": "^0.35.0", + "@aws-cdk/aws-ecr": "^0.35.0", "@aws-cdk/aws-ecs": "^0.35.0", "@aws-cdk/aws-iam": "^0.35.0", "@aws-cdk/aws-kms": "^0.35.0", "@aws-cdk/aws-lambda": "^0.35.0", + "@aws-cdk/aws-s3": "^0.35.0", "@aws-cdk/aws-sns": "^0.35.0", "@aws-cdk/aws-sqs": "^0.35.0", "@aws-cdk/aws-stepfunctions": "^0.35.0", @@ -93,10 +95,12 @@ "peerDependencies": { "@aws-cdk/aws-cloudwatch": "^0.35.0", "@aws-cdk/aws-ec2": "^0.35.0", + "@aws-cdk/aws-ecr": "^0.35.0", "@aws-cdk/aws-ecs": "^0.35.0", "@aws-cdk/aws-iam": "^0.35.0", "@aws-cdk/aws-kms": "^0.35.0", "@aws-cdk/aws-lambda": "^0.35.0", + "@aws-cdk/aws-s3": "^0.35.0", "@aws-cdk/aws-sns": "^0.35.0", "@aws-cdk/aws-sqs": "^0.35.0", "@aws-cdk/aws-stepfunctions": "^0.35.0", @@ -106,4 +110,4 @@ "node": ">= 8.10.0" }, "stability": "experimental" -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.sagemaker.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.sagemaker.expected.json new file mode 100644 index 0000000000000..55c8ee820af8b --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.sagemaker.expected.json @@ -0,0 +1,399 @@ +{ + "Resources": { + "EncryptionKey1B843E66": { + "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" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + }, + { + "Action": [ + "kms:Decrypt", + "kms:DescribeKey" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "SagemakerRole5FDB64E1", + "Arn" + ] + } + }, + "Resource": "*" + }, + { + "Action": [ + "kms:Encrypt", + "kms:ReEncrypt*", + "kms:GenerateDataKey*" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "SagemakerRole5FDB64E1", + "Arn" + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + } + }, + "DeletionPolicy": "Delete" + }, + "TrainingData3FDB6D34": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "KMSMasterKeyID": { + "Fn::GetAtt": [ + "EncryptionKey1B843E66", + "Arn" + ] + }, + "SSEAlgorithm": "aws:kms" + } + } + ] + } + }, + "DeletionPolicy": "Delete" + }, + "SagemakerRole5FDB64E1": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "sagemaker.", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + } + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "cloudwatch:PutMetricData", + "logs:CreateLogStream", + "logs:PutLogEvents", + "logs:CreateLogGroup", + "logs:DescribeLogStreams", + "ecr:GetAuthorizationToken" + ], + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "CreateTrainingJob" + } + ] + } + }, + "SagemakerRoleDefaultPolicy9DD21C3C": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:GetObject*", + "s3:GetBucket*", + "s3:List*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "TrainingData3FDB6D34", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "TrainingData3FDB6D34", + "Arn" + ] + }, + "/data/*" + ] + ] + } + ] + }, + { + "Action": [ + "kms:Decrypt", + "kms:DescribeKey" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "EncryptionKey1B843E66", + "Arn" + ] + } + }, + { + "Action": [ + "s3:DeleteObject*", + "s3:PutObject*", + "s3:Abort*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "TrainingData3FDB6D34", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "TrainingData3FDB6D34", + "Arn" + ] + }, + "/result/*" + ] + ] + } + ] + }, + { + "Action": [ + "kms:Encrypt", + "kms:ReEncrypt*", + "kms:GenerateDataKey*" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "EncryptionKey1B843E66", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "SagemakerRoleDefaultPolicy9DD21C3C", + "Roles": [ + { + "Ref": "SagemakerRole5FDB64E1" + } + ] + } + }, + "StateMachineRoleB840431D": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "states.", + { + "Ref": "AWS::Region" + }, + ".amazonaws.com" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "StateMachineRoleDefaultPolicyDF1E6607": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "sagemaker:CreateTrainingJob", + "sagemaker:DescribeTrainingJob", + "sagemaker:StopTrainingJob" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":sagemaker:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":training-job/MyTrainingJob*" + ] + ] + } + }, + { + "Action": "sagemaker:ListTags", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": "iam:PassRole", + "Condition": { + "StringEquals": { + "iam:PassedToService": "sagemaker.amazonaws.com" + } + }, + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "SagemakerRole5FDB64E1", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "StateMachineRoleDefaultPolicyDF1E6607", + "Roles": [ + { + "Ref": "StateMachineRoleB840431D" + } + ] + } + }, + "StateMachine2E01A3A5": { + "Type": "AWS::StepFunctions::StateMachine", + "Properties": { + "DefinitionString": { + "Fn::Join": [ + "", + [ + "{\"StartAt\":\"TrainTask\",\"States\":{\"TrainTask\":{\"End\":true,\"Parameters\":{\"TrainingJobName\":\"MyTrainingJob\",\"RoleArn\":\"", + { + "Fn::GetAtt": [ + "SagemakerRole5FDB64E1", + "Arn" + ] + }, + "\",\"AlgorithmSpecification\":{\"TrainingInputMode\":\"File\"},\"InputDataConfig\":[{\"ChannelName\":\"InputData\",\"DataSource\":{\"S3DataSource\":{\"S3Uri\":\"https://s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "TrainingData3FDB6D34" + }, + "/data/\",\"S3DataType\":\"S3Prefix\"}}}],\"OutputDataConfig\":{\"S3OutputPath\":\"https://s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "TrainingData3FDB6D34" + }, + "/result/\"},\"ResourceConfig\":{\"InstanceCount\":1,\"InstanceType\":\"ml.m4.xlarge\",\"VolumeSizeInGB\":10},\"StoppingCondition\":{\"MaxRuntimeInSeconds\":3600}},\"Type\":\"Task\",\"Resource\":\"arn:aws:states:::sagemaker:createTrainingJob\"}}}" + ] + ] + }, + "RoleArn": { + "Fn::GetAtt": [ + "StateMachineRoleB840431D", + "Arn" + ] + } + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.sagemaker.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.sagemaker.ts new file mode 100644 index 0000000000000..8052bac59bef4 --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.sagemaker.ts @@ -0,0 +1,28 @@ +import { Key } from '@aws-cdk/aws-kms'; +import { Bucket, BucketEncryption } from '@aws-cdk/aws-s3'; +import { StateMachine, Task } from '@aws-cdk/aws-stepfunctions'; +import { App, RemovalPolicy, Stack } from '@aws-cdk/cdk'; +import { S3Location, SagemakerTrainTask } from '../lib'; + +const app = new App(); +const stack = new Stack(app, 'integ-stepfunctions-sagemaker'); + +const encryptionKey = new Key(stack, 'EncryptionKey', { + removalPolicy: RemovalPolicy.Destroy, +}); +const trainingData = new Bucket(stack, 'TrainingData', { + encryption: BucketEncryption.KMS, + encryptionKey, + removalPolicy: RemovalPolicy.Destroy, +}); + +new StateMachine(stack, 'StateMachine', { + definition: new Task(stack, 'TrainTask', { + task: new SagemakerTrainTask(stack, { + algorithmSpecification: {}, + inputDataConfig: [{ channelName: 'InputData', dataSource: { s3DataSource: { s3Location: S3Location.inBucket(trainingData, 'data/') } } }], + outputDataConfig: { s3OutputLocation: S3Location.inBucket(trainingData, 'result/') }, + trainingJobName: 'MyTrainingJob', + }) + }) +}); diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker-training-job.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker-training-job.test.ts index b0840bd8b5e16..83dedec9dec9f 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker-training-job.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker-training-job.test.ts @@ -2,9 +2,12 @@ import '@aws-cdk/assert/jest'; import ec2 = require('@aws-cdk/aws-ec2'); import iam = require('@aws-cdk/aws-iam'); import kms = require('@aws-cdk/aws-kms'); +import s3 = require('@aws-cdk/aws-s3'); import sfn = require('@aws-cdk/aws-stepfunctions'); + import cdk = require('@aws-cdk/cdk'); import tasks = require('../lib'); +import { S3Location } from '../lib'; let stack: cdk.Stack; @@ -25,13 +28,13 @@ test('create basic training job', () => { channelName: 'train', dataSource: { s3DataSource: { - s3Uri: "s3://mybucket/mytrainpath" + s3Location: S3Location.inBucket(s3.Bucket.fromBucketName(stack, 'InputBucket', 'mybucket'), 'mytrainpath') } } } ], outputDataConfig: { - s3OutputPath: 's3://mybucket/myoutputpath' + s3OutputLocation: S3Location.inBucket(s3.Bucket.fromBucketName(stack, 'OutputBucket', 'mybucket'), 'myoutputpath') }, })}); @@ -51,13 +54,17 @@ test('create basic training job', () => { DataSource: { S3DataSource: { S3DataType: 'S3Prefix', - S3Uri: 's3://mybucket/mytrainpath' + S3Uri: { + 'Fn::Join': ['', ['https://s3.', { Ref: 'AWS::Region'}, '.', { Ref: 'AWS::URLSuffix' }, '/mybucket/mytrainpath']] + } } } } ], OutputDataConfig: { - S3OutputPath: 's3://mybucket/myoutputpath' + S3OutputPath: { + 'Fn::Join': ['', ['https://s3.', { Ref: 'AWS::Region' }, '.', { Ref: 'AWS::URLSuffix' }, '/mybucket/myoutputpath']] + } }, ResourceConfig: { InstanceCount: 1, @@ -112,7 +119,7 @@ test('create complex training job', () => { dataSource: { s3DataSource: { s3DataType: tasks.S3DataType.S3_PREFIX, - s3Uri: "s3://mybucket/mytrainpath", + s3Location: S3Location.inBucket(s3.Bucket.fromBucketName(stack, 'InputBucketA', 'mybucket'), 'mytrainpath'), } } }, @@ -124,20 +131,20 @@ test('create complex training job', () => { dataSource: { s3DataSource: { s3DataType: tasks.S3DataType.S3_PREFIX, - s3Uri: "s3://mybucket/mytestpath", + s3Location: S3Location.inBucket(s3.Bucket.fromBucketName(stack, 'InputBucketB', 'mybucket'), 'mytestpath'), } } } ], outputDataConfig: { - s3OutputPath: 's3://mybucket/myoutputpath', + s3OutputLocation: S3Location.inBucket(s3.Bucket.fromBucketName(stack, 'OutputBucket', 'mybucket'), 'myoutputpath'), encryptionKey: kmsKey }, resourceConfig: { instanceCount: 1, instanceType: new ec2.InstanceTypePair(ec2.InstanceClass.P3, ec2.InstanceSize.XLARGE2), volumeSizeInGB: 50, - volumeKmsKeyId: kmsKey, + volumeEncryptionKey: kmsKey, }, stoppingCondition: { maxRuntime: cdk.Duration.hours(1) @@ -179,7 +186,9 @@ test('create complex training job', () => { DataSource: { S3DataSource: { S3DataType: 'S3Prefix', - S3Uri: 's3://mybucket/mytrainpath' + S3Uri: { + 'Fn::Join': ['', ['https://s3.', { Ref: 'AWS::Region'}, '.', { Ref: 'AWS::URLSuffix' }, '/mybucket/mytrainpath']] + } } } }, @@ -191,13 +200,17 @@ test('create complex training job', () => { DataSource: { S3DataSource: { S3DataType: 'S3Prefix', - S3Uri: 's3://mybucket/mytestpath' + S3Uri: { + 'Fn::Join': ['', ['https://s3.', { Ref: 'AWS::Region'}, '.', { Ref: 'AWS::URLSuffix' }, '/mybucket/mytestpath']] + } } } } ], OutputDataConfig: { - S3OutputPath: 's3://mybucket/myoutputpath', + S3OutputPath: { + 'Fn::Join': ['', ['https://s3.', { Ref: 'AWS::Region' }, '.', { Ref: 'AWS::URLSuffix' }, '/mybucket/myoutputpath']] + }, KmsKeyId: { "Fn::GetAtt": [ "Key961B73FD", "Arn" ] }, }, ResourceConfig: { @@ -245,13 +258,13 @@ test('pass param to training job', () => { dataSource: { s3DataSource: { s3DataType: tasks.S3DataType.S3_PREFIX, - s3Uri: sfn.Data.stringAt('$.S3Bucket') + s3Location: S3Location.fromJsonExpression('$.S3Bucket') } } } ], outputDataConfig: { - s3OutputPath: 's3://mybucket/myoutputpath' + s3OutputLocation: S3Location.inBucket(s3.Bucket.fromBucketName(stack, 'Bucket', 'mybucket'), 'myoutputpath'), }, resourceConfig: { instanceCount: 1, @@ -287,7 +300,9 @@ test('pass param to training job', () => { } ], 'OutputDataConfig': { - S3OutputPath: 's3://mybucket/myoutputpath' + S3OutputPath: { + 'Fn::Join': ['', ['https://s3.', { Ref: 'AWS::Region' }, '.', { Ref: 'AWS::URLSuffix' }, '/mybucket/myoutputpath']] + } }, 'ResourceConfig': { InstanceCount: 1, diff --git a/packages/@aws-cdk/aws-stepfunctions/lib/fields.ts b/packages/@aws-cdk/aws-stepfunctions/lib/fields.ts index c6d1890e2512f..c70f6a1947d60 100644 --- a/packages/@aws-cdk/aws-stepfunctions/lib/fields.ts +++ b/packages/@aws-cdk/aws-stepfunctions/lib/fields.ts @@ -1,5 +1,5 @@ -import { Token } from "@aws-cdk/cdk"; -import { findReferencedPaths, JsonPathToken, renderObject } from "./json-path"; +import { Token } from '@aws-cdk/cdk'; +import { findReferencedPaths, JsonPathToken, renderObject } from './json-path'; /** * Extract a field from the State Machine data that gets passed around between states @@ -39,6 +39,11 @@ export class Data { return new JsonPathToken('$').toString(); } + public static isJsonPath(value: any): boolean { + const decoded = Token.decode(value); + return decoded != null && JsonPathToken.isJsonPathToken(decoded); + } + private constructor() { } } @@ -134,4 +139,4 @@ function validateContextPath(path: string) { if (!path.startsWith('$$.')) { throw new Error("Context JSON path values must start with '$$.'"); } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-stepfunctions/lib/json-path.ts b/packages/@aws-cdk/aws-stepfunctions/lib/json-path.ts index e9f07fa2f7a4a..222770cc4f587 100644 --- a/packages/@aws-cdk/aws-stepfunctions/lib/json-path.ts +++ b/packages/@aws-cdk/aws-stepfunctions/lib/json-path.ts @@ -3,7 +3,7 @@ import { captureStackTrace, IResolvable, IResolveContext, Token, Tokenization } const JSON_PATH_TOKEN_SYMBOL = Symbol.for('@aws-cdk/aws-stepfunctions.JsonPathToken'); export class JsonPathToken implements IResolvable { - public static isJsonPathToken(x: any): x is JsonPathToken { + public static isJsonPathToken(x: IResolvable): x is JsonPathToken { return (x as any)[JSON_PATH_TOKEN_SYMBOL] === true; } @@ -224,4 +224,4 @@ function jsonPathNumber(x: number): string | undefined { function pathFromToken(token: IResolvable | undefined) { return token && (JsonPathToken.isJsonPathToken(token) ? token.path : undefined); -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/cdk/lib/private/token-map.ts b/packages/@aws-cdk/cdk/lib/private/token-map.ts index 5e006b55b9dae..aee79012cd794 100644 --- a/packages/@aws-cdk/cdk/lib/private/token-map.ts +++ b/packages/@aws-cdk/cdk/lib/private/token-map.ts @@ -75,7 +75,7 @@ export class TokenMap { * Lookup a token from an encoded value */ public tokenFromEncoding(x: any): IResolvable | undefined { - if (typeof 'x' === 'string') { return this.lookupString(x); } + if (typeof x === 'string') { return this.lookupString(x); } if (Array.isArray(x)) { return this.lookupList(x); } if (Token.isUnresolved(x)) { return x; } return undefined; diff --git a/packages/@aws-cdk/cdk/lib/token.ts b/packages/@aws-cdk/cdk/lib/token.ts index e5c5127873943..b67729411849e 100644 --- a/packages/@aws-cdk/cdk/lib/token.ts +++ b/packages/@aws-cdk/cdk/lib/token.ts @@ -35,6 +35,19 @@ export class Token { return unresolved(obj); } + /** + * Retrieves the `IResolvable` for of an encoded token. + * + * @param encodedToken an encoded Token. + * + * @returns the resolvable object for the given encoded token, or `undefined` if `encodedToken` is not an encoded + * token (`Token.isUnresolved(encodedToken)` is `false`), or the token is a `string` composed of the + * concatenation of multiple tokens and/or literals. + */ + public static decode(encodedToken: any): IResolvable | undefined { + return TokenMap.instance().tokenFromEncoding(encodedToken); + } + /** * Return a reversible string representation of this token * @@ -150,4 +163,4 @@ export interface EncodingOptions { export function isResolvableObject(x: any): x is IResolvable { return typeof(x) === 'object' && x !== null && typeof x.resolve === 'function'; -} \ No newline at end of file +} From 32cd58052904e722bc8d6c688e87eb5e4fc48b61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=91=A8=F0=9F=8F=BC=E2=80=8D=F0=9F=92=BB=20Romain=20M?= =?UTF-8?q?arcadier-Muller?= Date: Fri, 21 Jun 2019 15:50:06 +0200 Subject: [PATCH 2/6] Remove new Token method --- .../lib/sagemaker-train-task.ts | 2 +- packages/@aws-cdk/aws-stepfunctions/lib/fields.ts | 7 +++---- .../@aws-cdk/aws-stepfunctions/lib/json-path.ts | 2 +- packages/@aws-cdk/cdk/lib/token.ts | 13 ------------- 4 files changed, 5 insertions(+), 19 deletions(-) diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-train-task.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-train-task.ts index 833c70d6a4d6b..fd2c82c63c8b7 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-train-task.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-train-task.ts @@ -314,7 +314,7 @@ export class SagemakerTrainTask implements iam.IGrantable, ec2.IConnectable, sfn service: 'sagemaker', resource: 'training-job', // If the job name comes from input, we cannot target the policy to a particular ARN prefix reliably... - resourceName: sfn.Data.isJsonPath(this.props.trainingJobName) ? '*' : `${this.props.trainingJobName}*` + resourceName: sfn.Data.isJsonPathString(this.props.trainingJobName) ? '*' : `${this.props.trainingJobName}*` }) ], }), diff --git a/packages/@aws-cdk/aws-stepfunctions/lib/fields.ts b/packages/@aws-cdk/aws-stepfunctions/lib/fields.ts index c70f6a1947d60..0120cb2562fdf 100644 --- a/packages/@aws-cdk/aws-stepfunctions/lib/fields.ts +++ b/packages/@aws-cdk/aws-stepfunctions/lib/fields.ts @@ -1,5 +1,5 @@ import { Token } from '@aws-cdk/cdk'; -import { findReferencedPaths, JsonPathToken, renderObject } from './json-path'; +import { findReferencedPaths, jsonPathString, JsonPathToken, renderObject } from './json-path'; /** * Extract a field from the State Machine data that gets passed around between states @@ -39,9 +39,8 @@ export class Data { return new JsonPathToken('$').toString(); } - public static isJsonPath(value: any): boolean { - const decoded = Token.decode(value); - return decoded != null && JsonPathToken.isJsonPathToken(decoded); + public static isJsonPathString(value: string): boolean { + return !!jsonPathString(value); } private constructor() { diff --git a/packages/@aws-cdk/aws-stepfunctions/lib/json-path.ts b/packages/@aws-cdk/aws-stepfunctions/lib/json-path.ts index 222770cc4f587..0f4ff6e023823 100644 --- a/packages/@aws-cdk/aws-stepfunctions/lib/json-path.ts +++ b/packages/@aws-cdk/aws-stepfunctions/lib/json-path.ts @@ -191,7 +191,7 @@ function renderBoolean(key: string, value: boolean): {[key: string]: boolean} { * * Otherwise return undefined. */ -function jsonPathString(x: string): string | undefined { +export function jsonPathString(x: string): string | undefined { const fragments = Tokenization.reverseString(x); const jsonPathTokens = fragments.tokens.filter(JsonPathToken.isJsonPathToken); diff --git a/packages/@aws-cdk/cdk/lib/token.ts b/packages/@aws-cdk/cdk/lib/token.ts index b67729411849e..a9314a3ee7476 100644 --- a/packages/@aws-cdk/cdk/lib/token.ts +++ b/packages/@aws-cdk/cdk/lib/token.ts @@ -35,19 +35,6 @@ export class Token { return unresolved(obj); } - /** - * Retrieves the `IResolvable` for of an encoded token. - * - * @param encodedToken an encoded Token. - * - * @returns the resolvable object for the given encoded token, or `undefined` if `encodedToken` is not an encoded - * token (`Token.isUnresolved(encodedToken)` is `false`), or the token is a `string` composed of the - * concatenation of multiple tokens and/or literals. - */ - public static decode(encodedToken: any): IResolvable | undefined { - return TokenMap.instance().tokenFromEncoding(encodedToken); - } - /** * Return a reversible string representation of this token * From 604dd3e144dbbff880aa676cebb8ab036b86ca75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=91=A8=F0=9F=8F=BC=E2=80=8D=F0=9F=92=BB=20Romain=20M?= =?UTF-8?q?arcadier-Muller?= Date: Tue, 2 Jul 2019 11:16:30 +0200 Subject: [PATCH 3/6] PR feedback --- .../lib/sagemaker-task-base-types.ts | 222 +-- .../lib/sagemaker-train-task.ts | 23 +- .../aws-stepfunctions-tasks/package.json | 2 + .../test/integ.sagemaker.ts | 10 +- .../test/sagemaker-training-job.test.ts | 12 +- packages/decdk/package-lock.json | 1236 +---------------- tools/awslint/package-lock.json | 2 +- tools/cdk-build-tools/package-lock.json | 2 +- 8 files changed, 160 insertions(+), 1349 deletions(-) diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-task-base-types.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-task-base-types.ts index 5d9d840964bdb..1eecfd62db8d5 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-task-base-types.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-task-base-types.ts @@ -1,10 +1,13 @@ import ec2 = require('@aws-cdk/aws-ec2'); import ecr = require('@aws-cdk/aws-ecr'); +import { DockerImageAsset, DockerImageAssetProps } from '@aws-cdk/aws-ecr-assets'; import iam = require('@aws-cdk/aws-iam'); import kms = require('@aws-cdk/aws-kms'); import s3 = require('@aws-cdk/aws-s3'); import sfn = require('@aws-cdk/aws-stepfunctions'); -import { Duration } from '@aws-cdk/core'; +import { Construct, Duration } from '@aws-cdk/core'; + +export interface ISageMakerTask extends sfn.IStepFunctionsTask, iam.IGrantable {} // // Create Training Job types @@ -28,7 +31,7 @@ export interface AlgorithmSpecification { /** * Registry path of the Docker image that contains the training algorithm. */ - readonly trainingImage?: IDockerImage; + readonly trainingImage?: DockerImage; /** * Input mode that the algorithm supports. @@ -129,7 +132,7 @@ export interface S3DataSource { /** * S3 Uri */ - readonly s3Location: IS3Location; + readonly s3Location: S3Location; } /** @@ -144,7 +147,7 @@ export interface OutputDataConfig { /** * Identifies the S3 path where you want Amazon SageMaker to store the model artifacts. */ - readonly s3OutputLocation: IS3Location; + readonly s3OutputLocation: S3Location; } export interface StoppingCondition { @@ -222,37 +225,22 @@ export interface MetricDefinition { readonly regex: string; } -/** - * Specifies a location in a S3 Bucket. - * - * @experimental - */ -export interface IS3Location { - /** The URI of the location in S3 */ +export interface S3LocationConfig { readonly uri: string; - - /** Grants read permissions to the S3 location. */ - grantRead(grantee: iam.IGrantable): void; - /** Grants write permissions to the S3 location. */ - grantWrite(grantee: iam.IGrantable): void; } /** * Constructs `IS3Location` objects. */ -export class S3Location { +export abstract class S3Location { /** * An `IS3Location` built with a determined bucket and key prefix. * * @param bucket is the bucket where the objects are to be stored. * @param keyPrefix is the key prefix used by the location. */ - public static inBucket(bucket: s3.IBucket, keyPrefix: string): IS3Location { - return { - uri: bucket.urlForObject(keyPrefix), - grantRead: (grantee) => bucket.grantRead(grantee, keyPrefix + '*'), - grantWrite: (grantee) => bucket.grantWrite(grantee, keyPrefix + '*'), - }; + public static fromBucket(bucket: s3.IBucket, keyPrefix: string): S3Location { + return new StandardS3Location({ bucket, keyPrefix, uri: bucket.urlForObject(keyPrefix) }); } /** @@ -263,76 +251,71 @@ export class S3Location { * * @param expression the JSON expression resolving to an S3 location URI. */ - public static fromJsonExpression(expression: string): IS3Location { - return { - uri: sfn.Data.stringAt(expression), - grantRead: grantee => grantee.grantPrincipal.addToPolicy(new iam.PolicyStatement({ - actions: ['s3:GetObject', `s3:ListBucket`], - resources: ['*'] - })), - grantWrite: grantee => grantee.grantPrincipal.addToPolicy(new iam.PolicyStatement({ - actions: ['s3:PutObject'], - resources: ['*'] - })), - }; + public static fromJsonExpression(expression: string): S3Location { + return new StandardS3Location({ uri: sfn.Data.stringAt(expression) }); } - private constructor() { } -} - -export interface IDockerImage { - readonly name: string; - grantRead(grantee: iam.IGrantable): void; + /** + * Called when the S3Location is bound to a StepFunctions task. + */ + public abstract bind(task: ISageMakerTask, opts: S3LocationBindOptions): S3LocationConfig; } /** - * Specifies options for accessing images in ECR. + * Options for binding an S3 Location. */ -export interface EcrImageOptions { +export interface S3LocationBindOptions { /** - * The tag to use for this ECR Image. This option is mutually exclusive with `digest`. + * Allow reading from the S3 Location. + * + * @default false */ - readonly tag?: string; + readonly forReading?: boolean; /** - * The digest to use for this ECR Image. This option is mutually exclusive with `tag`. + * Allow writing to the S3 Location. + * + * @default false */ - readonly digest?: string; + readonly forWriting?: boolean; +} + +/** + * Configuration for a using Docker image. + * + * @experimental + */ +export interface DockerImageConfig { + /** + * The fully qualified URI of the Docker image. + */ + readonly imageUri: string; } /** * Creates `IDockerImage` instances. + * + * @experimental */ -export class DockerImage { +export abstract class DockerImage { /** * Reference a Docker image stored in an ECR repository. * - * @param repo the ECR repository where the image is hosted. - * @param opts an optional `tag` or `digest` to use. + * @param repository the ECR repository where the image is hosted. + * @param tag an optional `tag` */ - public static inEcr(repo: ecr.IRepository, opts: EcrImageOptions = {}): IDockerImage { - if (opts.tag && opts.digest) { - throw new Error(`The tag and digest options are mutually exclusive, but both were specified`); - } - const suffix = opts.tag - ? `:${opts.tag}` - : opts.digest - ? `@${opts.digest}` - : ''; - return { - name: repo.repositoryUri + suffix, - grantRead: repo.grantPull.bind(repo), - }; + public static fromEcrRepository(repository: ecr.IRepository, tag: string = 'latest'): DockerImage { + return new StandardDockerImage({ repository, imageUri: repository.repositoryUriForTag(tag) }); } /** * Reference a Docker image which URI is obtained from the task's input. * - * @param expression the JSON path expression with the task input. - * @param enableEcrAccess whether ECR access should be permitted (set to `false` if the image will never be in ECR). + * @param expression the JSON path expression with the task input. + * @param allowAnyEcrImagePull whether ECR access should be permitted (set to `false` if the image will never be in ECR). */ - public static fromJsonExpression(expression: string, enableEcrAccess = true): IDockerImage { - return this.fromImageUri(sfn.Data.stringAt(expression), enableEcrAccess); + public static fromJsonExpression(expression: string, allowAnyEcrImagePull = true): DockerImage { + return new StandardDockerImage({ imageUri: expression, allowAnyEcrImagePull }); } /** @@ -340,28 +323,28 @@ export class DockerImage { * * When referencing ECR images, prefer using `inEcr`. * - * @param uri the URI to the docker image. - * @param enableEcrAccess whether ECR access should be permitted (set to `true` if the image is located in an ECR - * repository). + * @param imageUri the URI to the docker image. */ - public static fromImageUri(uri: string, enableEcrAccess = false): IDockerImage { - return { - name: uri, - grantRead(grantee) { - if (!enableEcrAccess) { return; } - grantee.grantPrincipal.addToPolicy(new iam.PolicyStatement({ - actions: [ - 'ecr:BatchCheckLayerAvailability', - 'ecr:GetDownloadUrlForLayer', - 'ecr:BatchGetImage' - ], - resources: ['*'] - })); - }, - }; + public static fromRegistry(imageUri: string): DockerImage { + return new StandardDockerImage({ imageUri }); } - private constructor() { } + /** + * Reference a Docker image that is provided as an Asset in the current app. + * + * @param scope the scope in which to create the Asset. + * @param id the ID for the asset in the construct tree. + * @param props the configuration props of the asset. + */ + public static fromAsset(scope: Construct, id: string, props: DockerImageAssetProps): DockerImage { + const asset = new DockerImageAsset(scope, id, props); + return new StandardDockerImage({ repository: asset.repository, imageUri: asset.imageUri }); + } + + /** + * Called when the image is used by a SageMaker task. + */ + public abstract bind(task: ISageMakerTask): DockerImageConfig; } /** @@ -618,3 +601,70 @@ export enum AssembleWith { LINE = 'Line' } + +class StandardDockerImage extends DockerImage { + private readonly allowAnyEcrImagePull: boolean; + private readonly imageUri: string; + private readonly repository?: ecr.IRepository; + + constructor(opts: { allowAnyEcrImagePull?: boolean, imageUri: string, repository?: ecr.IRepository }) { + super(); + + this.allowAnyEcrImagePull = !!opts.allowAnyEcrImagePull; + this.imageUri = opts.imageUri; + this.repository = opts.repository; + } + + public bind(task: ISageMakerTask): DockerImageConfig { + if (this.repository) { + this.repository.grantPull(task); + } + if (this.allowAnyEcrImagePull) { + task.grantPrincipal.addToPolicy(new iam.PolicyStatement({ + actions: [ + 'ecr:BatchCheckLayerAvailability', + 'ecr:GetDownloadUrlForLayer', + 'ecr:BatchGetImage', + ], + resources: ['*'] + })); + } + return { + imageUri: this.imageUri, + }; + } +} + +class StandardS3Location extends S3Location { + private readonly bucket?: s3.IBucket; + private readonly keyGlob: string; + private readonly uri: string; + + constructor(opts: { bucket?: s3.IBucket, keyPrefix?: string, uri: string }) { + super(); + this.bucket = opts.bucket; + this.keyGlob = `${opts.keyPrefix || ''}*`; + this.uri = opts.uri; + } + + public bind(task: ISageMakerTask, opts: S3LocationBindOptions): S3LocationConfig { + if (this.bucket) { + if (opts.forReading) { + this.bucket.grantRead(task, this.keyGlob); + } + if (opts.forWriting) { + this.bucket.grantWrite(task, this.keyGlob); + } + } else { + const actions = new Array(); + if (opts.forReading) { + actions.push('s3:GetObject', 's3:ListBucket'); + } + if (opts.forWriting) { + actions.push('s3:PutObject'); + } + task.grantPrincipal.addToPolicy(new iam.PolicyStatement({ actions, resources: ['*'], })); + } + return { uri: this.uri }; + } +} diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-train-task.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-train-task.ts index 74a9db9a27eed..5145c74cb2ee5 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-train-task.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-train-task.ts @@ -90,6 +90,8 @@ export class SagemakerTrainTask implements iam.IGrantable, ec2.IConnectable, sfn */ public readonly role: iam.IRole; + public readonly grantPrincipal: iam.IPrincipal; + /** * The Algorithm Specification */ @@ -125,7 +127,7 @@ export class SagemakerTrainTask implements iam.IGrantable, ec2.IConnectable, sfn }; // set the sagemaker role or create new one - this.role = props.role || new iam.Role(scope, 'SagemakerRole', { + this.grantPrincipal = this.role = props.role || new iam.Role(scope, 'SagemakerRole', { assumedBy: new iam.ServicePrincipal('sagemaker.amazonaws.com'), inlinePolicies: { CreateTrainingJob: new iam.PolicyDocument({ @@ -159,19 +161,10 @@ export class SagemakerTrainTask implements iam.IGrantable, ec2.IConnectable, sfn } }); - for (const input of props.inputDataConfig) { - input.dataSource.s3DataSource.s3Location.grantRead(this.role); - } - props.outputDataConfig.s3OutputLocation.grantWrite(this.role); - if (props.outputDataConfig.encryptionKey) { props.outputDataConfig.encryptionKey.grantEncrypt(this.role); } - if (props.algorithmSpecification.trainingImage) { - props.algorithmSpecification.trainingImage.grantRead(this.role); - } - if (props.resourceConfig && props.resourceConfig.volumeEncryptionKey) { props.resourceConfig.volumeEncryptionKey.grant(this.role, 'kms:CreateGrant'); } @@ -197,10 +190,6 @@ export class SagemakerTrainTask implements iam.IGrantable, ec2.IConnectable, sfn } } - public get grantPrincipal(): iam.IPrincipal { - return this.role; - } - public bind(task: sfn.Task): sfn.StepFunctionsTaskConfig { return { resourceArn: 'arn:aws:states:::sagemaker:createTrainingJob' + (this.props.synchronous ? '.sync' : ''), @@ -228,7 +217,7 @@ export class SagemakerTrainTask implements iam.IGrantable, ec2.IConnectable, sfn return { AlgorithmSpecification: { TrainingInputMode: spec.trainingInputMode, - ...(spec.trainingImage) ? { TrainingImage: spec.trainingImage } : {}, + ...(spec.trainingImage) ? { TrainingImage: spec.trainingImage.bind(this).imageUri } : {}, ...(spec.algorithmName) ? { AlgorithmName: spec.algorithmName } : {}, ...(spec.metricDefinitions) ? { MetricDefinitions: spec.metricDefinitions @@ -243,7 +232,7 @@ export class SagemakerTrainTask implements iam.IGrantable, ec2.IConnectable, sfn ChannelName: channel.channelName, DataSource: { S3DataSource: { - S3Uri: channel.dataSource.s3DataSource.s3Location.uri, + S3Uri: channel.dataSource.s3DataSource.s3Location.bind(this, { forReading: true }).uri, S3DataType: channel.dataSource.s3DataSource.s3DataType, ...(channel.dataSource.s3DataSource.s3DataDistributionType) ? { S3DataDistributionType: channel.dataSource.s3DataSource.s3DataDistributionType} : {}, @@ -262,7 +251,7 @@ export class SagemakerTrainTask implements iam.IGrantable, ec2.IConnectable, sfn private renderOutputDataConfig(config: OutputDataConfig): {[key: string]: any} { return { OutputDataConfig: { - S3OutputPath: config.s3OutputLocation.uri, + S3OutputPath: config.s3OutputLocation.bind(this, { forWriting: true }).uri, ...(config.encryptionKey) ? { KmsKeyId: config.encryptionKey.keyArn } : {}, } }; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/package.json b/packages/@aws-cdk/aws-stepfunctions-tasks/package.json index 62a39dd210810..5574837d0e1c8 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/package.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/package.json @@ -78,6 +78,7 @@ "pkglint": "^0.36.1" }, "dependencies": { + "@aws-cdk/assets": "^0.36.1", "@aws-cdk/aws-cloudwatch": "^0.36.1", "@aws-cdk/aws-ec2": "^0.36.1", "@aws-cdk/aws-ecr": "^0.36.1", @@ -94,6 +95,7 @@ }, "homepage": "https://github.com/awslabs/aws-cdk", "peerDependencies": { + "@aws-cdk/assets": "^0.36.1", "@aws-cdk/aws-cloudwatch": "^0.36.1", "@aws-cdk/aws-ec2": "^0.36.1", "@aws-cdk/aws-ecr": "^0.36.1", diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.sagemaker.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.sagemaker.ts index 8052bac59bef4..8a72022d0f959 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.sagemaker.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/integ.sagemaker.ts @@ -1,27 +1,27 @@ import { Key } from '@aws-cdk/aws-kms'; import { Bucket, BucketEncryption } from '@aws-cdk/aws-s3'; import { StateMachine, Task } from '@aws-cdk/aws-stepfunctions'; -import { App, RemovalPolicy, Stack } from '@aws-cdk/cdk'; +import { App, RemovalPolicy, Stack } from '@aws-cdk/core'; import { S3Location, SagemakerTrainTask } from '../lib'; const app = new App(); const stack = new Stack(app, 'integ-stepfunctions-sagemaker'); const encryptionKey = new Key(stack, 'EncryptionKey', { - removalPolicy: RemovalPolicy.Destroy, + removalPolicy: RemovalPolicy.DESTROY, }); const trainingData = new Bucket(stack, 'TrainingData', { encryption: BucketEncryption.KMS, encryptionKey, - removalPolicy: RemovalPolicy.Destroy, + removalPolicy: RemovalPolicy.DESTROY, }); new StateMachine(stack, 'StateMachine', { definition: new Task(stack, 'TrainTask', { task: new SagemakerTrainTask(stack, { algorithmSpecification: {}, - inputDataConfig: [{ channelName: 'InputData', dataSource: { s3DataSource: { s3Location: S3Location.inBucket(trainingData, 'data/') } } }], - outputDataConfig: { s3OutputLocation: S3Location.inBucket(trainingData, 'result/') }, + inputDataConfig: [{ channelName: 'InputData', dataSource: { s3DataSource: { s3Location: S3Location.fromBucket(trainingData, 'data/') } } }], + outputDataConfig: { s3OutputLocation: S3Location.fromBucket(trainingData, 'result/') }, trainingJobName: 'MyTrainingJob', }) }) diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker-training-job.test.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker-training-job.test.ts index 8231099775321..43dff4d3f54a4 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker-training-job.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/sagemaker-training-job.test.ts @@ -27,13 +27,13 @@ test('create basic training job', () => { channelName: 'train', dataSource: { s3DataSource: { - s3Location: S3Location.inBucket(s3.Bucket.fromBucketName(stack, 'InputBucket', 'mybucket'), 'mytrainpath') + s3Location: S3Location.fromBucket(s3.Bucket.fromBucketName(stack, 'InputBucket', 'mybucket'), 'mytrainpath') } } } ], outputDataConfig: { - s3OutputLocation: S3Location.inBucket(s3.Bucket.fromBucketName(stack, 'OutputBucket', 'mybucket'), 'myoutputpath') + s3OutputLocation: S3Location.fromBucket(s3.Bucket.fromBucketName(stack, 'OutputBucket', 'mybucket'), 'myoutputpath') }, })}); @@ -118,7 +118,7 @@ test('create complex training job', () => { dataSource: { s3DataSource: { s3DataType: tasks.S3DataType.S3_PREFIX, - s3Location: S3Location.inBucket(s3.Bucket.fromBucketName(stack, 'InputBucketA', 'mybucket'), 'mytrainpath'), + s3Location: S3Location.fromBucket(s3.Bucket.fromBucketName(stack, 'InputBucketA', 'mybucket'), 'mytrainpath'), } } }, @@ -130,13 +130,13 @@ test('create complex training job', () => { dataSource: { s3DataSource: { s3DataType: tasks.S3DataType.S3_PREFIX, - s3Location: S3Location.inBucket(s3.Bucket.fromBucketName(stack, 'InputBucketB', 'mybucket'), 'mytestpath'), + s3Location: S3Location.fromBucket(s3.Bucket.fromBucketName(stack, 'InputBucketB', 'mybucket'), 'mytestpath'), } } } ], outputDataConfig: { - s3OutputLocation: S3Location.inBucket(s3.Bucket.fromBucketName(stack, 'OutputBucket', 'mybucket'), 'myoutputpath'), + s3OutputLocation: S3Location.fromBucket(s3.Bucket.fromBucketName(stack, 'OutputBucket', 'mybucket'), 'myoutputpath'), encryptionKey: kmsKey }, resourceConfig: { @@ -263,7 +263,7 @@ test('pass param to training job', () => { } ], outputDataConfig: { - s3OutputLocation: S3Location.inBucket(s3.Bucket.fromBucketName(stack, 'Bucket', 'mybucket'), 'myoutputpath'), + s3OutputLocation: S3Location.fromBucket(s3.Bucket.fromBucketName(stack, 'Bucket', 'mybucket'), 'myoutputpath'), }, resourceConfig: { instanceCount: 1, diff --git a/packages/decdk/package-lock.json b/packages/decdk/package-lock.json index 1820b362f42af..be342d9d4fb6c 100644 --- a/packages/decdk/package-lock.json +++ b/packages/decdk/package-lock.json @@ -1,1220 +1,9 @@ { "name": "decdk", - "version": "0.36.0", + "version": "0.36.1", "lockfileVersion": 1, "requires": true, "dependencies": { - "@aws-cdk/alexa-ask": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/alexa-ask/-/alexa-ask-0.36.0.tgz", - "integrity": "sha512-Ac+Ov+ikeBnc7L7nngHPRx4HnkpM1MdzC4BRIcWumnhSSGXera3bjLnLRhH7SZKok4o33hsZPkUmUcHRrsl1Vg==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/app-delivery": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/app-delivery/-/app-delivery-0.36.0.tgz", - "integrity": "sha512-tHOPu9DRTtKuLgE47ba0JP697W7ciBMNsvT1n2TjQvTA8tDUbix0T7vfzBk+ivAzScv8JWQEkenCoYcH7T7dxA==", - "requires": { - "@aws-cdk/aws-cloudformation": "^0.36.0", - "@aws-cdk/aws-codebuild": "^0.36.0", - "@aws-cdk/aws-codepipeline": "^0.36.0", - "@aws-cdk/aws-codepipeline-actions": "^0.36.0", - "@aws-cdk/aws-events": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/core": "^0.36.0", - "@aws-cdk/cx-api": "^0.36.0" - } - }, - "@aws-cdk/assets": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/assets/-/assets-0.36.0.tgz", - "integrity": "sha512-hqb3wGnwgsJAtcWzzvu4CmPAMZpbyyj8zkEnqxWUI0LkZGJlC6Yy6+La1CjpAxwOB3DkavcPp8+riNpVnn2pzQ==", - "requires": { - "@aws-cdk/core": "^0.36.0", - "@aws-cdk/cx-api": "^0.36.0", - "minimatch": "^3.0.4" - }, - "dependencies": { - "balanced-match": { - "version": "1.0.0", - "bundled": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "concat-map": { - "version": "0.0.1", - "bundled": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "requires": { - "brace-expansion": "^1.1.7" - } - } - } - }, - "@aws-cdk/aws-amazonmq": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-amazonmq/-/aws-amazonmq-0.36.0.tgz", - "integrity": "sha512-KchfPcx2aY33MdOHj+celf4Cjfj98H+1sB3Wo5xQ3ZgZSiV7vo0t525COeucdQAgLckWwEJtN2rl2our3fQv7w==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-amplify": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-amplify/-/aws-amplify-0.36.0.tgz", - "integrity": "sha512-gRMLf+sHPJiLoJDPevpyAlkie5A2UVlhyJG6LzaWt2W6jrphNOTVjqftCcOC+KthdsxLyy1IVVmod2wYKLHBjg==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-apigateway": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-apigateway/-/aws-apigateway-0.36.0.tgz", - "integrity": "sha512-/BeE0R9K0a3FDzFInnpc0ZmBoadOoiVLnRINl8lSbZqBFGdAX0AQwxn1v4QniJpkoidyQ3uEjv70mq70rAJVFg==", - "requires": { - "@aws-cdk/aws-elasticloadbalancingv2": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-lambda": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-applicationautoscaling": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-applicationautoscaling/-/aws-applicationautoscaling-0.36.0.tgz", - "integrity": "sha512-S0XvFsHe3IL2pwlGxj5RRt/L+YBMPZ2VPTKEIHOz5j1Dv/3N/5rzqY6/l3rmq191S8NCGBqgv0JXbRnqui/ugA==", - "requires": { - "@aws-cdk/aws-autoscaling-common": "^0.36.0", - "@aws-cdk/aws-cloudwatch": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-appmesh": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-appmesh/-/aws-appmesh-0.36.0.tgz", - "integrity": "sha512-B3h14znXak0wGUoWmWw8qVcfKoX8F1NhAdTHf3nCr8GdL4Fu1F7Zivs7Y1ejFPHniq3eEIA6vp8BIdhMV03SFw==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-appstream": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-appstream/-/aws-appstream-0.36.0.tgz", - "integrity": "sha512-GGME8m4XJjYgiYyrz6l+pYrWbXX1m7ZP7dUvnlS3iP4sjR9gk0S4e4quiBoyeAuxUWlhJLtVzAG7XT9kLHiiEA==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-appsync": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-appsync/-/aws-appsync-0.36.0.tgz", - "integrity": "sha512-29lSRYnTW0qcFV7gPX6TatgZHUyw84z9rnxex+iEEJ5o7ZdOgMe4cDC3jtcqeGIxVWvN+q6LG3yUB596Pt6cTA==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-athena": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-athena/-/aws-athena-0.36.0.tgz", - "integrity": "sha512-pPVbV4vdU/NI2InIa4uZZ1f1CvPWt3VJTF+q4k6GUFUL0vJu/MCXn3E/XK2FmbBdQEGXBXskERpkblxgEGFiqQ==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-autoscaling": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-autoscaling/-/aws-autoscaling-0.36.0.tgz", - "integrity": "sha512-X1MyOgYhohaIjAGcWiY1etaMmPWpBQe5V5QflVVmkl6JlEQ7GfRCDh/ICg807jlCUHLgLzxhBzqgry93WYZnbw==", - "requires": { - "@aws-cdk/aws-autoscaling-common": "^0.36.0", - "@aws-cdk/aws-cloudwatch": "^0.36.0", - "@aws-cdk/aws-ec2": "^0.36.0", - "@aws-cdk/aws-elasticloadbalancing": "^0.36.0", - "@aws-cdk/aws-elasticloadbalancingv2": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-sns": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-autoscaling-common": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-autoscaling-common/-/aws-autoscaling-common-0.36.0.tgz", - "integrity": "sha512-UIuPF9ojcjmviqn/W0j53UwTiu1B98HPihRALqyO4TVpJWIDGUH5QoFJEVZFE6O/xB1AeyaHUVNGwi1Iq+hc8w==", - "requires": { - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-autoscaling-hooktargets": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-autoscaling-hooktargets/-/aws-autoscaling-hooktargets-0.36.0.tgz", - "integrity": "sha512-/Pkfk4CErhigorOkXVtgOFSl0gppQhRYcFIKxXK1L4LO5bTQCBQz88raGDaIpx6LnwjqSSYOj/UkEPfn5IAHPQ==", - "requires": { - "@aws-cdk/aws-autoscaling": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-lambda": "^0.36.0", - "@aws-cdk/aws-sns": "^0.36.0", - "@aws-cdk/aws-sns-subscriptions": "^0.36.0", - "@aws-cdk/aws-sqs": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-autoscalingplans": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-autoscalingplans/-/aws-autoscalingplans-0.36.0.tgz", - "integrity": "sha512-sHaQJ2yMM94ZvCP6HPMTIDEQp7fiPcMd2ixvFVIJgI5+rokKUAHCT7bTM6zfLEzWM0Z90Tomwon9T/MivHQVrA==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-batch": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-batch/-/aws-batch-0.36.0.tgz", - "integrity": "sha512-ggQTmoihylpA/xkMXmvP3wM3NjwTDyZTofsiTc4B6rH97TZUun7bHJ1alqqIAuPL2OXunfSsp3eCRyIVfq7vGQ==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-budgets": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-budgets/-/aws-budgets-0.36.0.tgz", - "integrity": "sha512-alp17fv4TmpCjkxN/Id7w2KYXKIRW5iBuNXSa8e5Fd58yffGNv9smR+nM8Cph9GKcjt3yWajMwYWUtwFCILaaQ==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-certificatemanager": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-certificatemanager/-/aws-certificatemanager-0.36.0.tgz", - "integrity": "sha512-A5v8Wn2RXR0TauKldZoAPPC9IvsbT9eUDvZ1CqlxOd8r0Y8PzW+8Df1lFqg2jCDw/FF1Nsss0v/JnHLHusfU3w==", - "requires": { - "@aws-cdk/aws-cloudformation": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-lambda": "^0.36.0", - "@aws-cdk/aws-route53": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-cloud9": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-cloud9/-/aws-cloud9-0.36.0.tgz", - "integrity": "sha512-1g+04G5IBtraOwZJ43RCxm3FYEvAXdHrM6DH/CUjAEktG1WsUCo52A7nh3v04qUkf1q08qf26K6dP+wuMelYRA==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-cloudformation": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-cloudformation/-/aws-cloudformation-0.36.0.tgz", - "integrity": "sha512-rX5gC0Jhnx04tHnKgJ19waN23+dr8EM3l9bE1Npa4W9ab+5qmrCMJJGyoQRB/mKzdf+j2qxoP4MiBUdLOXG5Iw==", - "requires": { - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-lambda": "^0.36.0", - "@aws-cdk/aws-sns": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-cloudfront": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-cloudfront/-/aws-cloudfront-0.36.0.tgz", - "integrity": "sha512-Z0rjSqO4DlS0qbsG2qFTXFBNJrsFKnEU4ZMKRiJqU5eN6qPzogpt4FAy0fBMaaO4fY2IyNRGJxQeOp6CAxlPkA==", - "requires": { - "@aws-cdk/aws-certificatemanager": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-kms": "^0.36.0", - "@aws-cdk/aws-lambda": "^0.36.0", - "@aws-cdk/aws-s3": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-cloudtrail": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-cloudtrail/-/aws-cloudtrail-0.36.0.tgz", - "integrity": "sha512-eQhHcddqAkfsely5ZayDSSIL4CjVXTTr3S0xauXOUdxvXX9gm8FAIS5kgRZWDUnRDDQYScO38mZgiFmL2Il7vw==", - "requires": { - "@aws-cdk/aws-events": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-kms": "^0.36.0", - "@aws-cdk/aws-logs": "^0.36.0", - "@aws-cdk/aws-s3": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-cloudwatch": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-cloudwatch/-/aws-cloudwatch-0.36.0.tgz", - "integrity": "sha512-nWuGnK24/9A+rVJw+RiVGUklzS1+7kXi7I2rqojH0iPU/6qrcd4IEHpRAx/1eKYbMnI0KJMDQOw2mEGWuYss9g==", - "requires": { - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-cloudwatch-actions": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-cloudwatch-actions/-/aws-cloudwatch-actions-0.36.0.tgz", - "integrity": "sha512-93wTnjlvkMhUQ3Lfkfmk2VOXpVZeGQTUBmIYXEH6FayQ094pzJ0I1NZeATUUF4zmO9QU7fsDTPpZct1pgChtoQ==", - "requires": { - "@aws-cdk/aws-applicationautoscaling": "^0.36.0", - "@aws-cdk/aws-autoscaling": "^0.36.0", - "@aws-cdk/aws-cloudwatch": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-sns": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-codebuild": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-codebuild/-/aws-codebuild-0.36.0.tgz", - "integrity": "sha512-DzzrZAlQc2CK1HME/jNpxv7WSDg/ANvCCCxN7RUruVPttY/eGQQAZE2g8bs5uLJiSicQskmxq1U+dAcgcYXpSg==", - "requires": { - "@aws-cdk/assets": "^0.36.0", - "@aws-cdk/aws-cloudwatch": "^0.36.0", - "@aws-cdk/aws-codecommit": "^0.36.0", - "@aws-cdk/aws-ec2": "^0.36.0", - "@aws-cdk/aws-ecr": "^0.36.0", - "@aws-cdk/aws-ecr-assets": "^0.36.0", - "@aws-cdk/aws-events": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-kms": "^0.36.0", - "@aws-cdk/aws-s3": "^0.36.0", - "@aws-cdk/aws-s3-assets": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-codecommit": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-codecommit/-/aws-codecommit-0.36.0.tgz", - "integrity": "sha512-y6eIa39X0z5aI6Wg7Hjn38HUi8NCSE6A8+GZTxsO+FWtNxj9r1wDuHHON5In6Wb5sGvp+bYiW9dPVIULPysxUQ==", - "requires": { - "@aws-cdk/aws-events": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-codedeploy": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-codedeploy/-/aws-codedeploy-0.36.0.tgz", - "integrity": "sha512-m8tFGajSXg9wAWvx8nn6ve2kw7mBPBZsG2UeNsIYrvvGOcBL1YzvBzNb97IoPSZNgHdHf3dOkvfBYorlbT6J/A==", - "requires": { - "@aws-cdk/aws-autoscaling": "^0.36.0", - "@aws-cdk/aws-cloudwatch": "^0.36.0", - "@aws-cdk/aws-elasticloadbalancing": "^0.36.0", - "@aws-cdk/aws-elasticloadbalancingv2": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-lambda": "^0.36.0", - "@aws-cdk/aws-s3": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-codepipeline": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-codepipeline/-/aws-codepipeline-0.36.0.tgz", - "integrity": "sha512-/HW2+nhqTzeIk64JGH3VqEnuiN+Vll9uzbt+LXHieMMl5Tf/Aw+12rhEEncZnQrx2V9y+on0ODGJ7yHe56JwMw==", - "requires": { - "@aws-cdk/aws-events": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-kms": "^0.36.0", - "@aws-cdk/aws-s3": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-codepipeline-actions": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-codepipeline-actions/-/aws-codepipeline-actions-0.36.0.tgz", - "integrity": "sha512-YG/x2eGCfIZBC/JfoVyxW1YLi/sAPhseGr9usLJopSFj9LKi09IvN/VlAWow1W+0Y7xCC6dnIstjv3R/QpaGvQ==", - "requires": { - "@aws-cdk/aws-cloudformation": "^0.36.0", - "@aws-cdk/aws-codebuild": "^0.36.0", - "@aws-cdk/aws-codecommit": "^0.36.0", - "@aws-cdk/aws-codedeploy": "^0.36.0", - "@aws-cdk/aws-codepipeline": "^0.36.0", - "@aws-cdk/aws-ec2": "^0.36.0", - "@aws-cdk/aws-ecr": "^0.36.0", - "@aws-cdk/aws-ecs": "^0.36.0", - "@aws-cdk/aws-events": "^0.36.0", - "@aws-cdk/aws-events-targets": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-lambda": "^0.36.0", - "@aws-cdk/aws-s3": "^0.36.0", - "@aws-cdk/aws-sns": "^0.36.0", - "@aws-cdk/aws-sns-subscriptions": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-cognito": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-cognito/-/aws-cognito-0.36.0.tgz", - "integrity": "sha512-PtjCloaw7uMEVtKxA/NhWEPlUBk/+xefs6gxstaLj6iDTKgVdNxa2Wb2l6qn7+JPQscHt4BXjSPCt30aj+OGrQ==", - "requires": { - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-lambda": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-config": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-config/-/aws-config-0.36.0.tgz", - "integrity": "sha512-I3DLqIsmAntsegDMmhy+WlvPPwMJlcnfRK85x1KT6pZx0Weywq92GJIEIfOSyltmILAAL/ho1dfw2X99Uom+Iw==", - "requires": { - "@aws-cdk/aws-events": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-lambda": "^0.36.0", - "@aws-cdk/aws-sns": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-datapipeline": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-datapipeline/-/aws-datapipeline-0.36.0.tgz", - "integrity": "sha512-/R7pHQpDLRDMY9n8PZwV3I6nySKYhz67VyU6mAZR0WkOt1XhJwitZtvTejbwueEZRNhvYw7gb77lfJ5sJ9LVfg==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-dax": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-dax/-/aws-dax-0.36.0.tgz", - "integrity": "sha512-Erxj5c3yCgLDRJGsrXVW8XHAjwda0ZlaM9jDttmoepjRkjBMEPgkWdbu0RaW+W2eAGjJzOJ9mKhTpQczfaPQ/w==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-directoryservice": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-directoryservice/-/aws-directoryservice-0.36.0.tgz", - "integrity": "sha512-Z5gIX4YEuaWhunawWyRrlFHDPfkv9NLH0IUgrgg8DxDXerthfM/U3NyfFgkQUmaR6TzuI/nlXpcZkVVSNgyYrA==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-dlm": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-dlm/-/aws-dlm-0.36.0.tgz", - "integrity": "sha512-y/yQuehSoq/W5SoDm1twzxSkGXd9mb8ATOoPl+Q6YrwjMgoyKphm2dcG6i/HG6ztWhOr1lUOFE6tjJtbrdLhcg==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-dms": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-dms/-/aws-dms-0.36.0.tgz", - "integrity": "sha512-FgU9wVQ+jV2h1Rdypcyddww3hEeH4QTlWwognkgYz76mq+wTvrovW/0nkIGC+31Qsamp3S0HMh44EB8d0Aee8g==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-docdb": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-docdb/-/aws-docdb-0.36.0.tgz", - "integrity": "sha512-wZd53GGsvZYGo9+IoE2hgH6NtJ1+5Lq5FCF+jaLo+nu+WEOZvqPmUuWgDkjBkfM55I9+CHcwo7UaCA/iwizKKw==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-dynamodb": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-dynamodb/-/aws-dynamodb-0.36.0.tgz", - "integrity": "sha512-bb3NHaSMCqVXZiBPxsYhIBi6sHt+HLOVogNWNsWVIryk1nlKFLtRJYkqO3SdRRFIy59xiGzTDyNm2lsDwlrA6w==", - "requires": { - "@aws-cdk/aws-applicationautoscaling": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-dynamodb-global": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-dynamodb-global/-/aws-dynamodb-global-0.36.0.tgz", - "integrity": "sha512-PImt0fTLUpMhrUdeanIO5MWYZKSX0SoKIdryLWZy5wcdmQwDKDvotNHOfmjEe/Zu6aeSghcjUtokBnwtZBobAA==", - "requires": { - "@aws-cdk/aws-cloudformation": "^0.36.0", - "@aws-cdk/aws-dynamodb": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-lambda": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-ec2": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-ec2/-/aws-ec2-0.36.0.tgz", - "integrity": "sha512-/eDBrUpBS6SyIjLH1fHPJ1N+2qk2YrhCLcqIzU2vVPBwSlvYj3A6K+2gONcvpMRht1dK+pxYyOhwjFJYZ472Mw==", - "requires": { - "@aws-cdk/aws-cloudwatch": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-ssm": "^0.36.0", - "@aws-cdk/core": "^0.36.0", - "@aws-cdk/cx-api": "^0.36.0" - } - }, - "@aws-cdk/aws-ecr": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-ecr/-/aws-ecr-0.36.0.tgz", - "integrity": "sha512-25miz74k1HrmJ3h9lGXsSt5ql37rVANIQT7Lpis1F67oe/teBTppEO2ShKI5TDeyI5j++uMUF8XfWACfe/k93g==", - "requires": { - "@aws-cdk/aws-events": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-ecr-assets": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-ecr-assets/-/aws-ecr-assets-0.36.0.tgz", - "integrity": "sha512-9alcq59rYIs5iN1zEqWx+vG7pkir4im7MeGdGX7674ut3501Usa7XAQe0FWGXWTdhz1gVfahjx5H918L9+IdSg==", - "requires": { - "@aws-cdk/assets": "^0.36.0", - "@aws-cdk/aws-cloudformation": "^0.36.0", - "@aws-cdk/aws-ecr": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-lambda": "^0.36.0", - "@aws-cdk/aws-s3": "^0.36.0", - "@aws-cdk/core": "^0.36.0", - "@aws-cdk/cx-api": "^0.36.0" - } - }, - "@aws-cdk/aws-ecs": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-ecs/-/aws-ecs-0.36.0.tgz", - "integrity": "sha512-+xQgqNPMtqGdwiEQI7s80FsnwWmpgXdfioY+Kg2zwC8U528qeq6SlUz7jvVqxl6/BME7HaBmNZeUIJ02RYw9yg==", - "requires": { - "@aws-cdk/aws-applicationautoscaling": "^0.36.0", - "@aws-cdk/aws-autoscaling": "^0.36.0", - "@aws-cdk/aws-autoscaling-hooktargets": "^0.36.0", - "@aws-cdk/aws-certificatemanager": "^0.36.0", - "@aws-cdk/aws-cloudformation": "^0.36.0", - "@aws-cdk/aws-cloudwatch": "^0.36.0", - "@aws-cdk/aws-ec2": "^0.36.0", - "@aws-cdk/aws-ecr": "^0.36.0", - "@aws-cdk/aws-ecr-assets": "^0.36.0", - "@aws-cdk/aws-elasticloadbalancing": "^0.36.0", - "@aws-cdk/aws-elasticloadbalancingv2": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-lambda": "^0.36.0", - "@aws-cdk/aws-logs": "^0.36.0", - "@aws-cdk/aws-route53": "^0.36.0", - "@aws-cdk/aws-route53-targets": "^0.36.0", - "@aws-cdk/aws-secretsmanager": "^0.36.0", - "@aws-cdk/aws-servicediscovery": "^0.36.0", - "@aws-cdk/aws-sns": "^0.36.0", - "@aws-cdk/aws-sqs": "^0.36.0", - "@aws-cdk/aws-ssm": "^0.36.0", - "@aws-cdk/core": "^0.36.0", - "@aws-cdk/cx-api": "^0.36.0" - } - }, - "@aws-cdk/aws-ecs-patterns": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-ecs-patterns/-/aws-ecs-patterns-0.36.0.tgz", - "integrity": "sha512-i7nyD/Z1k8dmOxyg27tvAfDJEvIerJYiG6R7YOR0yyLKT+LsyUrzjeOxqTBuvpP6GYdT9KCISq3KkCmmSYjF4A==", - "requires": { - "@aws-cdk/aws-applicationautoscaling": "^0.36.0", - "@aws-cdk/aws-certificatemanager": "^0.36.0", - "@aws-cdk/aws-ec2": "^0.36.0", - "@aws-cdk/aws-ecs": "^0.36.0", - "@aws-cdk/aws-elasticloadbalancingv2": "^0.36.0", - "@aws-cdk/aws-events": "^0.36.0", - "@aws-cdk/aws-events-targets": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-route53": "^0.36.0", - "@aws-cdk/aws-route53-targets": "^0.36.0", - "@aws-cdk/aws-sqs": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-efs": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-efs/-/aws-efs-0.36.0.tgz", - "integrity": "sha512-NHBsxilyhbZbyp54xJ4t4lsgCJTkRcALupcrqjiQrVOfAhPWO9QGoKbcOqpfIeDaEHEmgySrh5tzuJTGiSf3aw==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-eks": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-eks/-/aws-eks-0.36.0.tgz", - "integrity": "sha512-l4iFmLYs+zyeWcly8VAkdQ44U5yojT2gL+X7coHd9pBK14cp9+wHPzoty17VnDjffxbSw3AMXDkn6kElyTGE3Q==", - "requires": { - "@aws-cdk/aws-autoscaling": "^0.36.0", - "@aws-cdk/aws-ec2": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-elasticache": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-elasticache/-/aws-elasticache-0.36.0.tgz", - "integrity": "sha512-OXscek4BeLgh270n4X5nswA+OJQzvDaPaOYduk0H65so5zSd9z4N01MgaUqQQbnnJsScTtIjJBDdCZTplpajrA==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-elasticbeanstalk": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-elasticbeanstalk/-/aws-elasticbeanstalk-0.36.0.tgz", - "integrity": "sha512-BJeWnEsMM5hgOz3pof9Ad3XFUzyZ99DvqkkEHUY4xy+GtJeFwwHZ/5FQVexQ10n8X72C4+4rLqdoAj2YjsTbPQ==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-elasticloadbalancing": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-elasticloadbalancing/-/aws-elasticloadbalancing-0.36.0.tgz", - "integrity": "sha512-Na/0fzHBWgmtOhipDtBjwktmW/HgM2JDzZbzeAV/3vilAReydJqKPGqeMC84H2uOWsHx3v7p7KlpOIjjt9Qglw==", - "requires": { - "@aws-cdk/aws-ec2": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-elasticloadbalancingv2": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-elasticloadbalancingv2/-/aws-elasticloadbalancingv2-0.36.0.tgz", - "integrity": "sha512-Zwu6bK4D6R1RuUdfoDqtHq5zT7Z3tfHvfJD2F1dUQo1l9MhxEog2aKHpkLEDQQYfrAjSGVRjHpdVibgZYx1rGw==", - "requires": { - "@aws-cdk/aws-certificatemanager": "^0.36.0", - "@aws-cdk/aws-cloudwatch": "^0.36.0", - "@aws-cdk/aws-ec2": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-s3": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-elasticsearch": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-elasticsearch/-/aws-elasticsearch-0.36.0.tgz", - "integrity": "sha512-em1Lhx2AXPytOwusQlkcQix+ePrZIy5alcGY4OQ9p9MPeEKBFGTSl8cf+tODg7kp0PDTRSAclReBy5XaeluT8w==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-emr": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-emr/-/aws-emr-0.36.0.tgz", - "integrity": "sha512-ytud/4/J/MSM9BnUnMHN1hsmUU2P/oYIeSed5euKVyAqWfKd/OMssOe4QOlC/drbZeg2NkAfMLzBWNt7xM8rHw==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-events": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-events/-/aws-events-0.36.0.tgz", - "integrity": "sha512-8HpgNCt1OXcPX27oWrXZ4SdJWpd6OTqmO2EvwlCUm5wJkDih+eeM6HFfNw6tPEj7qosM8L6to5AyxN4vnplnLw==", - "requires": { - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-events-targets": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-events-targets/-/aws-events-targets-0.36.0.tgz", - "integrity": "sha512-Sw8V5EUnbVtAkWddZu1Bu7DQhQX6nA2gvBMlyQG391ghmxxD9QWMliLo7jTGnaYrG7GDdZ9ajr4yEV2b8BbrsQ==", - "requires": { - "@aws-cdk/aws-cloudformation": "^0.36.0", - "@aws-cdk/aws-codebuild": "^0.36.0", - "@aws-cdk/aws-codepipeline": "^0.36.0", - "@aws-cdk/aws-ec2": "^0.36.0", - "@aws-cdk/aws-ecs": "^0.36.0", - "@aws-cdk/aws-events": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-lambda": "^0.36.0", - "@aws-cdk/aws-sns": "^0.36.0", - "@aws-cdk/aws-sns-subscriptions": "^0.36.0", - "@aws-cdk/aws-sqs": "^0.36.0", - "@aws-cdk/aws-stepfunctions": "^0.36.0", - "@aws-cdk/core": "^0.36.0", - "@aws-cdk/custom-resources": "^0.36.0" - } - }, - "@aws-cdk/aws-fsx": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-fsx/-/aws-fsx-0.36.0.tgz", - "integrity": "sha512-nphX1y6doRwAc0IrX/EVyHpgQue3WhqXm677va97bmFmy043yyAz3PuDH+Y9cya2JYYf9nTQrCfEeXdpYFFJ9Q==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-gamelift": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-gamelift/-/aws-gamelift-0.36.0.tgz", - "integrity": "sha512-aNqCzm4QrUOlLExbjr+Gt3gY3U12zjpsTt/XRvxJ/gqTSwvYAju0fAwTmhz12sJqGtF9INK+mYDO/Bv1WTQ6/Q==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-glue": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-glue/-/aws-glue-0.36.0.tgz", - "integrity": "sha512-oB8YZ/OyAsfT9ha76kZ85UXEMXIj+OgG1iXHWMoyvTk0xrDJwVgZe8zI4swyf8oeu+1OXgZnl9UvkJAWOG4H7w==", - "requires": { - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-kms": "^0.36.0", - "@aws-cdk/aws-s3": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-greengrass": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-greengrass/-/aws-greengrass-0.36.0.tgz", - "integrity": "sha512-Nqjwx7AjDwk917WKYlDp3aUGQfpF/MlBWhMmOJJroKJgJl9zAlWRs7Cr5lg0H+ILiLpWopaSpfBG1ROAUzLYNg==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-guardduty": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-guardduty/-/aws-guardduty-0.36.0.tgz", - "integrity": "sha512-bMdbITh7eZ9w+gk41lY2sKCSy/E0FovJDxeEJ9dKI/m7rF1z1sz1a5ZOywrgVRS8YldXO9hPuhNeqWnJnpwv8w==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-iam": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-iam/-/aws-iam-0.36.0.tgz", - "integrity": "sha512-yXb8hVeJPC7pWi4A/UIf9dSm+VRZkGRkrLeM61cSjZOL9ulbz4MHqeS9YIL5ELqIKv0VzJmTuQLIWXO2dc4wAw==", - "requires": { - "@aws-cdk/core": "^0.36.0", - "@aws-cdk/region-info": "^0.36.0" - } - }, - "@aws-cdk/aws-inspector": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-inspector/-/aws-inspector-0.36.0.tgz", - "integrity": "sha512-wDJ7d88Bhy7AbJHV8DXSTf49Eyn1jfN6riTV4HTPhIpWQQDd8qATnUKhL3EPDIK9iOU3IDvDchmnAXLV2wRZFQ==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-iot": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-iot/-/aws-iot-0.36.0.tgz", - "integrity": "sha512-o4N8bjlnh0oHFroIu3Gbg3fbFic01ffFMuT4vgjVbS97ZlU7S2epbJ4ZsJrOVpmfnslW7X2uYkSGDZPIACGKdA==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-iot1click": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-iot1click/-/aws-iot1click-0.36.0.tgz", - "integrity": "sha512-zbeZ0RhmYMBvJ9A8DuCfA38U7bR1wNVGwI8E9s/YW5OKcIH/MTwtV3IteNV+HPyd+IaM7mVF5OK6QhCftgRqTA==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-iotanalytics": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-iotanalytics/-/aws-iotanalytics-0.36.0.tgz", - "integrity": "sha512-uUYRWEo+B51GEwFpVaw6dWE1LZNiu8KDXmFDh/HzdR4C72cB9hMrI0LdOV2bTxC2EMtogagWToGUg0+lMjL2+g==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-iotthingsgraph": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-iotthingsgraph/-/aws-iotthingsgraph-0.36.0.tgz", - "integrity": "sha512-m4cUnsbVRI0lJubLNtFgeaXr5OX1j3u+EorYPtc02lB0n/nE+KJG2Pdsx0R3JyAGdQKD8Srpoh8RRXVOoqeyqg==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-kinesis": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-kinesis/-/aws-kinesis-0.36.0.tgz", - "integrity": "sha512-QoSUFHrNq6ZFFXXnzJg7F6AR8bwdDd3aicW7qizzrexEh+Nsz/Unzzlr9VqV6lqmgbePPOqcbMrSCWFUaToSkA==", - "requires": { - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-kms": "^0.36.0", - "@aws-cdk/aws-logs": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-kinesisanalytics": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-kinesisanalytics/-/aws-kinesisanalytics-0.36.0.tgz", - "integrity": "sha512-UiDNtLO6+y+Aoezd0Wkb6XYgQhba5bB97awMp8TOK4pidIcesn8Yo7bAzs+cSwu1xIEOYS9PtJRxc6c04Sm7Ww==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-kinesisfirehose": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-kinesisfirehose/-/aws-kinesisfirehose-0.36.0.tgz", - "integrity": "sha512-Mw7dQ6IVkPlxTm8jyedS1gmskrKc6WOZgTd6TTCpg7/6a09lm5JC6r0VUcBd6jD9Tln+oeuyH+/ppczuCN9n1A==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-kms": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-kms/-/aws-kms-0.36.0.tgz", - "integrity": "sha512-09ubtkI7MxjwmtbuMHzI79JIFwVaqAP0h60PShLYR7UAvKQYeumvk6//Ix8d40TNDxlNBe+QEATdbD2FSK9vTg==", - "requires": { - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-lambda": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-lambda/-/aws-lambda-0.36.0.tgz", - "integrity": "sha512-MR28qP57gF29MxlBbnfhEAjPIYUp1mi7BUTGGD7zIwMd0LBpPafj85i1Q5ubc6ZDC1l155lWsY/JlDFSYCJytA==", - "requires": { - "@aws-cdk/aws-cloudwatch": "^0.36.0", - "@aws-cdk/aws-ec2": "^0.36.0", - "@aws-cdk/aws-events": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-logs": "^0.36.0", - "@aws-cdk/aws-s3": "^0.36.0", - "@aws-cdk/aws-s3-assets": "^0.36.0", - "@aws-cdk/aws-sqs": "^0.36.0", - "@aws-cdk/core": "^0.36.0", - "@aws-cdk/cx-api": "^0.36.0" - } - }, - "@aws-cdk/aws-lambda-event-sources": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-lambda-event-sources/-/aws-lambda-event-sources-0.36.0.tgz", - "integrity": "sha512-f3kdgEOHQ8uPjDSCV2UsMk3NQHr/Phtb3PfQejPSNHjSm4+JL/myYp/YmHxcxUlHyaZcs1s2t+VMSmqBz5BRtA==", - "requires": { - "@aws-cdk/aws-apigateway": "^0.36.0", - "@aws-cdk/aws-dynamodb": "^0.36.0", - "@aws-cdk/aws-events": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-kinesis": "^0.36.0", - "@aws-cdk/aws-lambda": "^0.36.0", - "@aws-cdk/aws-s3": "^0.36.0", - "@aws-cdk/aws-s3-notifications": "^0.36.0", - "@aws-cdk/aws-sns": "^0.36.0", - "@aws-cdk/aws-sns-subscriptions": "^0.36.0", - "@aws-cdk/aws-sqs": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-logs": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-logs/-/aws-logs-0.36.0.tgz", - "integrity": "sha512-1UhCuGgA9fGMCI0ILVbf6TnMDv5hcKk2cIfnEH31hVvXQyBB23GolcUmhqtQK2bwxprtgcgpYPGApY5BztVAmg==", - "requires": { - "@aws-cdk/aws-cloudwatch": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-logs-destinations": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-logs-destinations/-/aws-logs-destinations-0.36.0.tgz", - "integrity": "sha512-oKVqIwD5lg8WsK/Ko76tb4Z2pSzHCfQ2LqeUbaTChMOtlIMB8M1zE5cXzDR/SkrFOaMVCdBffnM2x4KnzWUE5g==", - "requires": { - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-kinesis": "^0.36.0", - "@aws-cdk/aws-lambda": "^0.36.0", - "@aws-cdk/aws-logs": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-mediastore": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-mediastore/-/aws-mediastore-0.36.0.tgz", - "integrity": "sha512-9TS97XUwir8QTY9pr86qXnB4VqNb4u4K1fsb+WuTdPWYCeberAJNgfyfHfYzIMedQO1rfqaxPPs8OGyIh35/lw==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-msk": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-msk/-/aws-msk-0.36.0.tgz", - "integrity": "sha512-8eqgeYoL07eX3wYS8HhIG0j+pBEiBEdiUFakti1xFk37gWq5LjCB+IGInjm0dCCSchQ4h9cbUrM8qQyIKafgDg==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-neptune": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-neptune/-/aws-neptune-0.36.0.tgz", - "integrity": "sha512-QpQbpEdAyHLkLUB1McPvuqc6M2MVpKUT3GqGGY0ia7kZncdl8hy/iF+IY7553TjyjdIJSCHwTHvH7n0KAqi79A==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-opsworks": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-opsworks/-/aws-opsworks-0.36.0.tgz", - "integrity": "sha512-3RS1alXZn8eqq8vJAXl65p8Q7CMQErHfHnZGpIyLxn+5Fn/hEZp6GozylKla1HsvVA8ylu/DsvxxllkYTJsF3Q==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-opsworkscm": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-opsworkscm/-/aws-opsworkscm-0.36.0.tgz", - "integrity": "sha512-6rbzwTAcYgu976E6+SEySlT2f0Oq11wHPhhxUSXiSf8uJcxDcU/R7YTSIzBFgLyH8EJwFMAfjQup1xomvG+Jig==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-pinpoint": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-pinpoint/-/aws-pinpoint-0.36.0.tgz", - "integrity": "sha512-N0xazPmXTTMFkB8B2uyMGdDK3gIf9i+DNLA2uNvzXHJrGhbVXxN6wzq8rmtnw4rNvYrIHtAMPwBwmPqhu/1ahA==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-pinpointemail": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-pinpointemail/-/aws-pinpointemail-0.36.0.tgz", - "integrity": "sha512-GsSTRaj6IftWTa1/ZvLObMKbsBmfW3NIcQmcUzHd9mGfUs1LbaSahhdBtHn9Al7TJf2ko9MtTR6LTAEUtLf+AA==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-ram": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-ram/-/aws-ram-0.36.0.tgz", - "integrity": "sha512-jAyiP3EbZek9Wp6cn6N82KryyVDHzRRGClGs+J4zHQASkRD2lvxb74qIc8FQNHivqzzKM9ror1Iva/NSw5YONg==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-rds": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-rds/-/aws-rds-0.36.0.tgz", - "integrity": "sha512-MMvgDpPXIr3VjCfRNX6qAzvlnLluQcNDEmPrq6LY/q0DMuCKYLiwtrNuVD41kIJ9B4mcxGGMJFzo6r7oi6i0Pw==", - "requires": { - "@aws-cdk/aws-cloudwatch": "^0.36.0", - "@aws-cdk/aws-ec2": "^0.36.0", - "@aws-cdk/aws-events": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-kms": "^0.36.0", - "@aws-cdk/aws-lambda": "^0.36.0", - "@aws-cdk/aws-logs": "^0.36.0", - "@aws-cdk/aws-sam": "^0.36.0", - "@aws-cdk/aws-secretsmanager": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-redshift": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-redshift/-/aws-redshift-0.36.0.tgz", - "integrity": "sha512-KrkXrUfBBX7SxOCVYFLXI0hBMgLMHy8aL0H4UvAauHwYfXpkdRnpKTLfG7rKJf4rahcQODJWW+RnknY1/Ft3jw==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-robomaker": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-robomaker/-/aws-robomaker-0.36.0.tgz", - "integrity": "sha512-XnytszQ/0SJCSS+8wyhc4/9UHflqx+nf0E061VCxjT1oo9iICGOflvVUnTpAf04hw2HcBSCtu5xsOSRmJ/8HEA==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-route53": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-route53/-/aws-route53-0.36.0.tgz", - "integrity": "sha512-pcM6caNgnaXSYi6x3PgH+DC4+pPYj1ZFzPvASUVKsnVQD7rWU0XebgeHTFveNCJxrHg9fQKp853UUf3p5SYz+Q==", - "requires": { - "@aws-cdk/aws-ec2": "^0.36.0", - "@aws-cdk/aws-logs": "^0.36.0", - "@aws-cdk/core": "^0.36.0", - "@aws-cdk/cx-api": "^0.36.0" - } - }, - "@aws-cdk/aws-route53-targets": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-route53-targets/-/aws-route53-targets-0.36.0.tgz", - "integrity": "sha512-vW7QV4R2JcJqXHT6xTC51GnC7Whq7b0XLcibw90wdQ+KGtYbMUK3RhSN5YjYGQNL4QO5AyfYrIrVRxc+pvZuFw==", - "requires": { - "@aws-cdk/aws-cloudfront": "^0.36.0", - "@aws-cdk/aws-elasticloadbalancingv2": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-route53": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-route53resolver": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-route53resolver/-/aws-route53resolver-0.36.0.tgz", - "integrity": "sha512-lTsGM6IWnjjoRavsZ8R9OcUZnQICtPM6c2RG99rFHhNFvfHQbSz50LCREa00mZ2auEmUBCn5VLI7URHvGjJ8xA==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-s3": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-s3/-/aws-s3-0.36.0.tgz", - "integrity": "sha512-c6ObcIZpui6o+gLLjDpNrBlPB0sDLQLUVEVVFyBGPgV/wUQnSHzNfTgtO5xR/oVTx7b58eU/hLlJ8DEJvcIEXA==", - "requires": { - "@aws-cdk/aws-events": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-kms": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-s3-assets": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-s3-assets/-/aws-s3-assets-0.36.0.tgz", - "integrity": "sha512-McJHmtYaKzyp9kH3KazHX4YF0iklmp/ly91W3QrjWZ+Vsks3YiFcW3T9AbEF7VThGHR2BqvnRGol0Kc2ACatgA==", - "requires": { - "@aws-cdk/assets": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-s3": "^0.36.0", - "@aws-cdk/core": "^0.36.0", - "@aws-cdk/cx-api": "^0.36.0" - } - }, - "@aws-cdk/aws-s3-deployment": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-s3-deployment/-/aws-s3-deployment-0.36.0.tgz", - "integrity": "sha512-rVwB9rfZ9GzYMtxBszo6c8NvQcEMShFYz9fhSBgrdYtKx37L7k+jVV+c5T0KBwCgTWfhGwd4kfIAqEEZ7dPN7Q==", - "requires": { - "@aws-cdk/aws-cloudformation": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-lambda": "^0.36.0", - "@aws-cdk/aws-s3": "^0.36.0", - "@aws-cdk/aws-s3-assets": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-s3-notifications": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-s3-notifications/-/aws-s3-notifications-0.36.0.tgz", - "integrity": "sha512-NRawu99mSE8uPBvF7sdVU9ekBTJKVbfpC0ETVNHPt5JVJrOpm5hwPgaXvtWnILFBmzVptdUh3TsVv1QHe6ZHUg==", - "requires": { - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-lambda": "^0.36.0", - "@aws-cdk/aws-s3": "^0.36.0", - "@aws-cdk/aws-sns": "^0.36.0", - "@aws-cdk/aws-sqs": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-sagemaker": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-sagemaker/-/aws-sagemaker-0.36.0.tgz", - "integrity": "sha512-P7GZ4S1LVikbuhyFsUyGWywhOmi0Tyqs9K4eNH6RXO6RUIWliY7ARjrAzGfD/r2pUSEiw7OHmtJzRl+Hn515Rw==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-sam": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-sam/-/aws-sam-0.36.0.tgz", - "integrity": "sha512-si0FBW6UCB+MtmW2AnIOoGM5wR2t2V2Xk25h1twdDlyIfeLqP1bGMA/aSS+691xml+2FhC541xSLsffg6IU3aA==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-sdb": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-sdb/-/aws-sdb-0.36.0.tgz", - "integrity": "sha512-e+t3Y1yoOi7EsupQEDGVRpbLuJ2ypyLds2iovnTFzSyRgDtIjeQVLiwj54UCI5uVYmA1KnSAV574Afvs71lpAw==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-secretsmanager": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-secretsmanager/-/aws-secretsmanager-0.36.0.tgz", - "integrity": "sha512-vvD0h+KiGr74tD6k9ykz8AKMmW7t7ryUFJV8fqmyId9BdStld98z9lwAXA8B1Ele91OGaA08LxS+TBZ5SDWzBQ==", - "requires": { - "@aws-cdk/aws-ec2": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-kms": "^0.36.0", - "@aws-cdk/aws-lambda": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-servicecatalog": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-servicecatalog/-/aws-servicecatalog-0.36.0.tgz", - "integrity": "sha512-mHszIFYHQlEKXVIRIHkMpp6cCpR+JDYXMAWp3xn8mLP9u4qfK4jU7ZDYrdIH9RQHDAIKMBJJ328BUfSx4+MYNg==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-servicediscovery": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-servicediscovery/-/aws-servicediscovery-0.36.0.tgz", - "integrity": "sha512-Zdb5spM1vREaQroJSsO0wz2EVfJCgqemoFYKvpOnEoBv8aQuzEz/ufNLXG80+/hMWcWbNFqVgOTT6ZLoGLrvNg==", - "requires": { - "@aws-cdk/aws-ec2": "^0.36.0", - "@aws-cdk/aws-elasticloadbalancingv2": "^0.36.0", - "@aws-cdk/aws-route53": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-ses": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-ses/-/aws-ses-0.36.0.tgz", - "integrity": "sha512-Fomdr4T8pTM1sEVG9HJAQKqzQw8NQ7RoZ7L8HaNT4YtYBFWsW7rkaWBGGzT4ZTvE5T1KfvBhwkkd+gUrdkaOOQ==", - "requires": { - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-kms": "^0.36.0", - "@aws-cdk/aws-lambda": "^0.36.0", - "@aws-cdk/aws-s3": "^0.36.0", - "@aws-cdk/aws-sns": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-sns": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-sns/-/aws-sns-0.36.0.tgz", - "integrity": "sha512-TsSrseID7weI3pjBTvQYR9bVSA3a3LJcZhiW13ztagu0J3ntpgyoCLT0mbgdur2W+waQh/gFyWZOYle2VXs75w==", - "requires": { - "@aws-cdk/aws-cloudwatch": "^0.36.0", - "@aws-cdk/aws-events": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-sns-subscriptions": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-sns-subscriptions/-/aws-sns-subscriptions-0.36.0.tgz", - "integrity": "sha512-lyBb8SMK8NqWfo3uSVmFQu3D0QYqmNAYdzsaz5pUReFsNfjS0fR7B/MqreGiNjX1ww5XUv+Sbx4ehSemSaAhTg==", - "requires": { - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-lambda": "^0.36.0", - "@aws-cdk/aws-sns": "^0.36.0", - "@aws-cdk/aws-sqs": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-sqs": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-sqs/-/aws-sqs-0.36.0.tgz", - "integrity": "sha512-Qb4SHgJUU4z9cg5O5IjKQUD7bSJjkO2ooBKg/N45k29Zkyn/3PEq7AgC3I3Fj7EmmeT0Gvnc1DXHdGnL+IBPvA==", - "requires": { - "@aws-cdk/aws-cloudwatch": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-kms": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-ssm": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-ssm/-/aws-ssm-0.36.0.tgz", - "integrity": "sha512-/VaImBixUTDuRLuWnZZ7EcaSTgHtPjlQTpsD/Ay7iyxQ1X4MgntBpnAbTYYC/jY0YLelCE/sd/X3753RMRax3A==", - "requires": { - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/core": "^0.36.0", - "@aws-cdk/cx-api": "^0.36.0" - } - }, - "@aws-cdk/aws-stepfunctions": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-stepfunctions/-/aws-stepfunctions-0.36.0.tgz", - "integrity": "sha512-dMhGJs4pgxKewOHWxZe4sqmBXOVHax3Vh2Eb9cigLWg7VIV2/+ir79IcpaYZs0MCdeTTAgUNOBQuJxbbVp3z5A==", - "requires": { - "@aws-cdk/aws-cloudwatch": "^0.36.0", - "@aws-cdk/aws-events": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-stepfunctions-tasks": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-stepfunctions-tasks/-/aws-stepfunctions-tasks-0.36.0.tgz", - "integrity": "sha512-uAUzbmvSkUgZOfk1wYSSRW6aqHBgszcRspScheC6bV0wdeLKYEiS3vGGwp3/lm4JJKnazESt4klKyl1SFxhg3Q==", - "requires": { - "@aws-cdk/aws-cloudwatch": "^0.36.0", - "@aws-cdk/aws-ec2": "^0.36.0", - "@aws-cdk/aws-ecs": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-kms": "^0.36.0", - "@aws-cdk/aws-lambda": "^0.36.0", - "@aws-cdk/aws-sns": "^0.36.0", - "@aws-cdk/aws-sqs": "^0.36.0", - "@aws-cdk/aws-stepfunctions": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-transfer": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-transfer/-/aws-transfer-0.36.0.tgz", - "integrity": "sha512-8Qr35gmUETl15x5eDrEhwgMdnhdTsUfd7/jT6CucVWZ+fMUKG8/WgQ2aint6vmTO8Yi6Zw99FWJg/h2ldBRTKw==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-waf": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-waf/-/aws-waf-0.36.0.tgz", - "integrity": "sha512-8JhmYbl5QuwsJrrrLbQ8dXS3vWrJ16SYtQaWFmb5Q9Ew1tY0GS0bD6m5dbBL6YKdQRuoJFqIlltakAnmPWZICA==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-wafregional": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-wafregional/-/aws-wafregional-0.36.0.tgz", - "integrity": "sha512-zzXSDvRuKYUjysEqGoJlSizJj5R9x/xwRn+Dgp/SAXAu0wlkwFK3W/FwYET8UPSeMmBD9Jid/EI1R+Y3buk5Ag==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/aws-workspaces": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-workspaces/-/aws-workspaces-0.36.0.tgz", - "integrity": "sha512-hqd4TFsxFwHZcGBpbfdU2K3C8hHiszpWI+Ss2l97/wZZIb81bd2OM8W/r0GtCamKcJIM6LbuAp7STYZ+fSt/cQ==", - "requires": { - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/cfnspec": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/cfnspec/-/cfnspec-0.36.0.tgz", - "integrity": "sha512-sDnCciuiEQZxrfoaqlJhq+GcnYKaQSbhI0cFg883WGD5RPkHWRaMx+MyBWoGCVeFxVAJnIcLM1qqsvVqpJ8RqA==", - "requires": { - "md5": "^2.2.1" - } - }, - "@aws-cdk/core": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/core/-/core-0.36.0.tgz", - "integrity": "sha512-5oEVetyivHEJAA5NVozUy/kaLRL2nOYdklGIlSWdCrrYp7TZ75wDi3WYf6IKwCI5eUX3zylBgj91gn7OWQ+krg==", - "requires": { - "@aws-cdk/cx-api": "^0.36.0" - } - }, - "@aws-cdk/custom-resources": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/custom-resources/-/custom-resources-0.36.0.tgz", - "integrity": "sha512-cgLBo/lwQfDCNcrl4lM3FopJIkdrv/BcmnfK7s14iwD60Qz9NlzOolI5ppbr9DOdImjlbUYA/4VCGtOf1fPD3w==", - "requires": { - "@aws-cdk/aws-cloudformation": "^0.36.0", - "@aws-cdk/aws-iam": "^0.36.0", - "@aws-cdk/aws-lambda": "^0.36.0", - "@aws-cdk/aws-sns": "^0.36.0", - "@aws-cdk/core": "^0.36.0" - } - }, - "@aws-cdk/cx-api": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/cx-api/-/cx-api-0.36.0.tgz", - "integrity": "sha512-MWNqLbDAyWMLtlr1/E8i4ul9JwVtES7SNJSrM3J2hTiPYFsL7FEKoy6W0l8ooutPgNGyC8W4B08jNvBSbPnEWA==", - "requires": { - "semver": "^6.1.1" - }, - "dependencies": { - "semver": { - "version": "6.1.1", - "bundled": true - } - } - }, - "@aws-cdk/region-info": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/region-info/-/region-info-0.36.0.tgz", - "integrity": "sha512-FyEr0lWs9SisTSpAGiAuxKFeAhImH2CQDeBoYgVoPLs7dlj9pfPHZhRjFV4IqwKV8gf4mGUCyXAQNOoMn11XfQ==" - }, "@babel/code-frame": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", @@ -2158,11 +947,6 @@ "supports-color": "^5.3.0" } }, - "charenc": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", - "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=" - }, "ci-info": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", @@ -2303,11 +1087,6 @@ "which": "^1.2.9" } }, - "crypt": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", - "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=" - }, "cssom": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.6.tgz", @@ -3660,7 +2439,8 @@ "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true }, "is-callable": { "version": "1.1.4", @@ -4925,16 +3705,6 @@ "object-visit": "^1.0.0" } }, - "md5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz", - "integrity": "sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=", - "requires": { - "charenc": "~0.0.1", - "crypt": "~0.0.1", - "is-buffer": "~1.1.1" - } - }, "mem": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", diff --git a/tools/awslint/package-lock.json b/tools/awslint/package-lock.json index 306eac2146f2c..935de3ab33608 100644 --- a/tools/awslint/package-lock.json +++ b/tools/awslint/package-lock.json @@ -1,6 +1,6 @@ { "name": "awslint", - "version": "0.36.0", + "version": "0.36.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/tools/cdk-build-tools/package-lock.json b/tools/cdk-build-tools/package-lock.json index 713e7e63cfe24..cfe2a45878297 100644 --- a/tools/cdk-build-tools/package-lock.json +++ b/tools/cdk-build-tools/package-lock.json @@ -1,6 +1,6 @@ { "name": "cdk-build-tools", - "version": "0.36.0", + "version": "0.36.1", "lockfileVersion": 1, "requires": true, "dependencies": { From e014fde2b16ae5f52a46e1b891ef2ec30c337708 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=91=A8=F0=9F=8F=BC=E2=80=8D=F0=9F=92=BB=20Romain=20M?= =?UTF-8?q?arcadier-Muller?= Date: Tue, 2 Jul 2019 12:52:28 +0200 Subject: [PATCH 4/6] Add some experimental markings --- .../lib/sagemaker-task-base-types.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-task-base-types.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-task-base-types.ts index 1eecfd62db8d5..b577b92813d7a 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-task-base-types.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-task-base-types.ts @@ -225,12 +225,17 @@ export interface MetricDefinition { readonly regex: string; } +/** + * @experimental + */ export interface S3LocationConfig { readonly uri: string; } /** * Constructs `IS3Location` objects. + * + * @experimental */ export abstract class S3Location { /** @@ -263,6 +268,8 @@ export abstract class S3Location { /** * Options for binding an S3 Location. + * + * @experimental */ export interface S3LocationBindOptions { /** From b408b4b349905d1507d42ca363527630f0709091 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=91=A8=F0=9F=8F=BC=E2=80=8D=F0=9F=92=BB=20Romain=20M?= =?UTF-8?q?arcadier-Muller?= Date: Tue, 2 Jul 2019 12:52:28 +0200 Subject: [PATCH 5/6] Add some experimental markings --- .../lib/sagemaker-task-base-types.ts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-task-base-types.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-task-base-types.ts index b577b92813d7a..b120dd0e4351d 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-task-base-types.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-task-base-types.ts @@ -150,6 +150,9 @@ export interface OutputDataConfig { readonly s3OutputLocation: S3Location; } +/** + * @experimental + */ export interface StoppingCondition { /** * The maximum length of time, in seconds, that the training or compilation job can run. @@ -157,6 +160,9 @@ export interface StoppingCondition { readonly maxRuntime?: Duration; } +/** + * @experimental + */ export interface ResourceConfig { /** @@ -356,6 +362,8 @@ export abstract class DockerImage { /** * S3 Data Type. + * + * @experimental */ export enum S3DataType { /** @@ -376,6 +384,8 @@ export enum S3DataType { /** * S3 Data Distribution Type. + * + * @experimental */ export enum S3DataDistributionType { /** @@ -391,6 +401,8 @@ export enum S3DataDistributionType { /** * Define the format of the input data. + * + * @experimental */ export enum RecordWrapperType { /** @@ -406,6 +418,8 @@ export enum RecordWrapperType { /** * Input mode that the algorithm supports. + * + * @experimental */ export enum InputMode { /** @@ -421,6 +435,8 @@ export enum InputMode { /** * Compression type of the data. + * + * @experimental */ export enum CompressionType { /** @@ -552,6 +568,8 @@ export interface TransformResources { /** * Specifies the number of records to include in a mini-batch for an HTTP inference request. + * + * @experimental */ export enum BatchStrategy { @@ -568,6 +586,8 @@ export enum BatchStrategy { /** * Method to use to split the transform job's data files into smaller batches. + * + * @experimental */ export enum SplitType { @@ -594,6 +614,8 @@ export enum SplitType { /** * How to assemble the results of the transform job as a single S3 object. + * + * @experimental */ export enum AssembleWith { From 24842a6dbf14cb72e85a4bc77a6fa5dad617f548 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=91=A8=F0=9F=8F=BC=E2=80=8D=F0=9F=92=BB=20Romain=20M?= =?UTF-8?q?arcadier-Muller?= Date: Tue, 2 Jul 2019 16:23:00 +0200 Subject: [PATCH 6/6] More experimental marking --- .../aws-stepfunctions-tasks/lib/sagemaker-train-task.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-train-task.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-train-task.ts index 5145c74cb2ee5..61807c1adcab5 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-train-task.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/sagemaker-train-task.ts @@ -75,6 +75,8 @@ export interface SagemakerTrainTaskProps { /** * Class representing the SageMaker Create Training Job task. + * + * @experimental */ export class SagemakerTrainTask implements iam.IGrantable, ec2.IConnectable, sfn.IStepFunctionsTask {