diff --git a/.dependabot/config.yml b/.dependabot/config.yml index 21dc263e33a15..c54ea38a24f81 100644 --- a/.dependabot/config.yml +++ b/.dependabot/config.yml @@ -14,9 +14,6 @@ update_configs: dependency_name: "@jsii/*" - match: dependency_name: "codemaker" - - match: - dependency_name: "semver" - match: dependency_name: "@types/node" version_requirement: ">=11.0.0-0" - diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index bd3aa67159221..09c7300a66754 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,5 +1,5 @@ ### Commit Message -COMMIT TITLE HERE (copy from PR title, keep in sync) +COMMIT/PR TITLE HERE (must follow conventionalcommits.org) COMMIT MESSAGE HERE ### End Commit Message diff --git a/CHANGELOG.md b/CHANGELOG.md index af8b4bfe02d1e..04288d73cf9f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,30 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.36.0](https://github.com/aws/aws-cdk/compare/v1.35.0...v1.36.0) (2020-04-28) + + +### ⚠ BREAKING CHANGES + +* **stepfunctions-tasks:** `payload` in RunLambdaTask is now of type `TaskInput` and has a default of the state input instead of the empty object. +You can migrate your current assignment to payload by supplying it to the `TaskInput.fromObject()` API + +### Features + +* **apigateway:** gateway responses ([#7441](https://github.com/aws/aws-cdk/issues/7441)) ([b0a65c1](https://github.com/aws/aws-cdk/commit/b0a65c1b7bb4532722adf20a10f653fff88d152a)), closes [#7071](https://github.com/aws/aws-cdk/issues/7071) +* **aws-ecs:** add support for IPC and PID Mode for EC2 Task Definitions ([1ee629e](https://github.com/aws/aws-cdk/commit/1ee629e418fccec30b8a94e43682ed2c47ddd8da)), closes [#7186](https://github.com/aws/aws-cdk/issues/7186) + + +### Bug Fixes + +* **apigateway:** authorizer is not attached to RestApi across projects ([#7596](https://github.com/aws/aws-cdk/issues/7596)) ([1423c53](https://github.com/aws/aws-cdk/commit/1423c53fec4172ba21946ca6d33f63fc7a9d8337)), closes [#7377](https://github.com/aws/aws-cdk/issues/7377) +* **cli:** can't bootstrap environment not in app ([9566cca](https://github.com/aws/aws-cdk/commit/9566cca8c77b99922e8214567b87fa5680fe06ef)) +* **cli:** context keys specified in `cdk.json` get moved to `cdk.context.json` ([022eb66](https://github.com/aws/aws-cdk/commit/022eb66b85abba46c1a4d980259f440c31036d57)), closes [#7399](https://github.com/aws/aws-cdk/issues/7399) +* **dynamodb:** grant() is not available on ITable ([#7618](https://github.com/aws/aws-cdk/issues/7618)) ([3b0a397](https://github.com/aws/aws-cdk/commit/3b0a3977e153e5a6a17967dfab360926712bff9e)), closes [#7473](https://github.com/aws/aws-cdk/issues/7473) +* **dynamodb:** grantXxx() does not grant in replication regions ([98429e0](https://github.com/aws/aws-cdk/commit/98429e019e347459c74cccf3bb99994e58341377)), closes [#7362](https://github.com/aws/aws-cdk/issues/7362) +* **eks:** version update completes prematurely ([#7526](https://github.com/aws/aws-cdk/issues/7526)) ([307c8b0](https://github.com/aws/aws-cdk/commit/307c8b021d5c00c1d675f4ce3cba8004a6a4a0a8)), closes [#7457](https://github.com/aws/aws-cdk/issues/7457) +* **stepfunctions-tasks:** cannot specify part of execution data or task context as input to the `RunLambda` service integration ([#7428](https://github.com/aws/aws-cdk/issues/7428)) ([a1d9884](https://github.com/aws/aws-cdk/commit/a1d98845a209e7ed650d8adaaa1a724a3109b6a2)), closes [#7371](https://github.com/aws/aws-cdk/issues/7371) + ## [1.35.0](https://github.com/aws/aws-cdk/compare/v1.34.1...v1.35.0) (2020-04-23) @@ -15,6 +39,7 @@ All notable changes to this project will be documented in this file. See [standa ### Features +* **backup:** Vault, Plan and Selection ([#7074](https://github.com/aws/aws-cdk/issues/7074)) ([c8aa92d](https://github.com/aws/aws-cdk/commit/c8aa92d1a0b87afc380fecaf91fc1048a74f670f)) * **cfnspec:** cloudformation spec v13.0.0 ([#7504](https://github.com/aws/aws-cdk/issues/7504)) ([6903869](https://github.com/aws/aws-cdk/commit/6903869def944f8100c8eef51dd7145c181984e2)) * **cloudtrail:** Lambda Function data events ([4a70138](https://github.com/aws/aws-cdk/commit/4a70138faf2e863be37a66bec23ed29a784b486a)) * **cognito:** user pool domain ([#7224](https://github.com/aws/aws-cdk/issues/7224)) ([feadd6c](https://github.com/aws/aws-cdk/commit/feadd6cb643b415ae002191ba2cb4622221a5af6)), closes [#6787](https://github.com/aws/aws-cdk/issues/6787) @@ -25,8 +50,6 @@ All notable changes to this project will be documented in this file. See [standa * **assets:** infrequent "ValidationError: S3 error: Access Denied" ([#7556](https://github.com/aws/aws-cdk/issues/7556)) ([00c9deb](https://github.com/aws/aws-cdk/commit/00c9deb975fe794eef9003cd26a6453abc514928)), closes [#6430](https://github.com/aws/aws-cdk/issues/6430) [#7553](https://github.com/aws/aws-cdk/issues/7553) * **route53:** cannot add tags to `HostedZone` ([#7531](https://github.com/aws/aws-cdk/issues/7531)) ([2729804](https://github.com/aws/aws-cdk/commit/272980492dc6b98d71ce9c3b23cab38f656dc632)), closes [#7445](https://github.com/aws/aws-cdk/issues/7445) - - * **efs:** drop Efs prefix from all exported types ([#7481](https://github.com/aws/aws-cdk/issues/7481)) ([ddd47cd](https://github.com/aws/aws-cdk/commit/ddd47cd7e0735424d2e47891c32e4b7813035067)) ## [1.34.1](https://github.com/aws/aws-cdk/compare/v1.34.0...v1.34.1) (2020-04-22) diff --git a/lerna.json b/lerna.json index 539c1710776a4..f7264bb852729 100644 --- a/lerna.json +++ b/lerna.json @@ -10,5 +10,5 @@ "tools/*" ], "rejectCycles": "true", - "version": "1.35.0" + "version": "1.36.0" } diff --git a/packages/@aws-cdk/app-delivery/package.json b/packages/@aws-cdk/app-delivery/package.json index e254ea13cfd79..2dcc6cfca15fa 100644 --- a/packages/@aws-cdk/app-delivery/package.json +++ b/packages/@aws-cdk/app-delivery/package.json @@ -57,7 +57,7 @@ "@types/nodeunit": "^0.0.30", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", - "fast-check": "^1.24.1", + "fast-check": "^1.24.2", "nodeunit": "^0.11.3", "pkglint": "0.0.0" }, diff --git a/packages/@aws-cdk/aws-apigateway/README.md b/packages/@aws-cdk/aws-apigateway/README.md index cfb752b3891a8..d8361d290767a 100644 --- a/packages/@aws-cdk/aws-apigateway/README.md +++ b/packages/@aws-cdk/aws-apigateway/README.md @@ -33,6 +33,7 @@ running on AWS Lambda, or any web application. - [Access Logging](#access-logging) - [Cross Origin Resource Sharing (CORS)](cross-origin-resource-sharing-cors) - [Endpoint Configuration](#endpoint-configuration) +- [Gateway Response](#gateway-response) - [APIGateway v2](#apigateway-v2) ## Defining APIs @@ -867,6 +868,32 @@ By performing this association, we can invoke the API gateway using the followin https://{rest-api-id}-{vpce-id}.execute-api.{region}.amazonaws.com/{stage} ``` +## Gateway response + +If the Rest API fails to process an incoming request, it returns to the client an error response without forwarding the +request to the integration backend. API Gateway has a set of standard response messages that are sent to the client for +each type of error. These error responses can be configured on the Rest API. The list of Gateway responses that can be +configured can be found [here](https://docs.aws.amazon.com/apigateway/latest/developerguide/supported-gateway-response-types.html). +Learn more about [Gateway +Responses](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-gatewayResponse-definition.html). + +The following code configures a Gateway Response when the response is 'access denied': + +```ts +const api = new apigateway.RestApi(this, 'books-api'); +api.addGatewayResponse('test-response', { + type: ResponseType.ACCESS_DENIED, + statusCode: '500', + responseHeaders: { + 'Access-Control-Allow-Origin': "test.com", + 'test-key': 'test-value' + }, + templates: { + 'application/json': '{ "message": $context.error.messageString, "statusCode": "488", "type": "$context.error.responseType" }' + } +}); +``` + ## APIGateway v2 APIGateway v2 APIs are now moved to its own package named `aws-apigatewayv2`. For backwards compatibility, existing diff --git a/packages/@aws-cdk/aws-apigateway/lib/gateway-response.ts b/packages/@aws-cdk/aws-apigateway/lib/gateway-response.ts new file mode 100644 index 0000000000000..62957167fa881 --- /dev/null +++ b/packages/@aws-cdk/aws-apigateway/lib/gateway-response.ts @@ -0,0 +1,210 @@ +import { Construct, IResource, Resource } from '@aws-cdk/core'; +import { CfnGatewayResponse } from './apigateway.generated'; +import { IRestApi } from './restapi'; + +/** + * Represents gateway response resource. + */ +export interface IGatewayResponse extends IResource { +} + +/** + * Properties for a new gateway response. + */ +export interface GatewayResponseProps extends GatewayResponseOptions { + /** + * Rest api resource to target. + */ + readonly restApi: IRestApi; +} + +/** + * Options to add gateway response. + */ +export interface GatewayResponseOptions { + /** + * Response type to associate with gateway response. + * @see https://docs.aws.amazon.com/apigateway/latest/developerguide/supported-gateway-response-types.html + */ + readonly type: ResponseType; + + /** + * Http status code for response. + * @default - standard http status code for the response type. + */ + readonly statusCode?: string; + + /** + * Custom headers parameters for response. + * @default - no headers + */ + readonly responseHeaders?: { [key: string]: string }; + + /** + * Custom templates to get mapped as response. + * @default - Response from api will be returned without applying any transformation. + */ + readonly templates?: { [key: string]: string }; + +} + +/** + * Configure the response received by clients, produced from the API Gateway backend. + * + * @resource AWS::ApiGateway::GatewayResponse + */ +export class GatewayResponse extends Resource implements IGatewayResponse { + constructor(scope: Construct, id: string, props: GatewayResponseProps) { + super(scope, id); + + const resource = new CfnGatewayResponse(this, 'Resource', { + restApiId: props.restApi.restApiId, + responseType: props.type.responseType, + responseParameters: this.buildResponseParameters(props.responseHeaders), + responseTemplates: props.templates, + statusCode: props.statusCode, + }); + + this.node.defaultChild = resource; + } + + private buildResponseParameters(responseHeaders?: { [key: string]: string }): { [key: string]: string } | undefined { + if (!responseHeaders) { + return undefined; + } + + const responseParameters: { [key: string]: string } = {}; + for (const [header, value] of Object.entries(responseHeaders)) { + responseParameters[`gatewayresponse.header.${header}`] = value; + } + return responseParameters; + } +} + +/** + * Supported types of gateway responses. + * @see https://docs.aws.amazon.com/apigateway/latest/developerguide/supported-gateway-response-types.html + */ +export class ResponseType { + /** + * The gateway response for authorization failure. + */ + public static readonly ACCESS_DENIED = new ResponseType('ACCESS_DENIED'); + + /** + * The gateway response for an invalid API configuration. + */ + public static readonly API_CONFIGURATION_ERROR = new ResponseType('API_CONFIGURATION_ERROR'); + + /** + * The gateway response when a custom or Amazon Cognito authorizer failed to authenticate the caller. + */ + public static readonly AUTHORIZER_FAILURE = new ResponseType('AUTHORIZER_FAILURE'); + + /** + * The gateway response for failing to connect to a custom or Amazon Cognito authorizer. + */ + public static readonly AUTHORIZER_CONFIGURATION_ERROR = new ResponseType('AUTHORIZER_CONFIGURATION_ERROR'); + + /** + * The gateway response when the request parameter cannot be validated according to an enabled request validator. + */ + public static readonly BAD_REQUEST_PARAMETERS = new ResponseType('BAD_REQUEST_PARAMETERS'); + + /** + * The gateway response when the request body cannot be validated according to an enabled request validator. + */ + public static readonly BAD_REQUEST_BODY = new ResponseType('BAD_REQUEST_BODY'); + + /** + * The default gateway response for an unspecified response type with the status code of 4XX. + */ + public static readonly DEFAULT_4XX = new ResponseType('DEFAULT_4XX'); + + /** + * The default gateway response for an unspecified response type with a status code of 5XX. + */ + public static readonly DEFAULT_5XX = new ResponseType('DEFAULT_5XX'); + + /** + * The gateway response for an AWS authentication token expired error. + */ + public static readonly EXPIRED_TOKEN = new ResponseType('EXPIRED_TOKEN'); + + /** + * The gateway response for an invalid AWS signature error. + */ + public static readonly INVALID_SIGNATURE = new ResponseType('INVALID_SIGNATURE'); + + /** + * The gateway response for an integration failed error. + */ + public static readonly INTEGRATION_FAILURE = new ResponseType('INTEGRATION_FAILURE'); + + /** + * The gateway response for an integration timed out error. + */ + public static readonly INTEGRATION_TIMEOUT = new ResponseType('INTEGRATION_TIMEOUT'); + + /** + * The gateway response for an invalid API key submitted for a method requiring an API key. + */ + public static readonly INVALID_API_KEY = new ResponseType('INVALID_API_KEY'); + + /** + * The gateway response for a missing authentication token error, + * including the cases when the client attempts to invoke an unsupported API method or resource. + */ + public static readonly MISSING_AUTHENTICATION_TOKEN = new ResponseType('MISSING_AUTHENTICATION_TOKEN'); + + /** + * The gateway response for the usage plan quota exceeded error. + */ + public static readonly QUOTA_EXCEEDED = new ResponseType('QUOTA_EXCEEDED'); + + /** + * The gateway response for the request too large error. + */ + public static readonly REQUEST_TOO_LARGE = new ResponseType('REQUEST_TOO_LARGE'); + + /** + * The gateway response when API Gateway cannot find the specified resource + * after an API request passes authentication and authorization. + */ + public static readonly RESOURCE_NOT_FOUND = new ResponseType('RESOURCE_NOT_FOUND'); + + /** + * The gateway response when usage plan, method, stage, or account level throttling limits exceeded. + */ + public static readonly THROTTLED = new ResponseType('THROTTLED'); + + /** + * The gateway response when the custom or Amazon Cognito authorizer failed to authenticate the caller. + */ + public static readonly UNAUTHORIZED = new ResponseType('UNAUTHORIZED'); + + /** + * The gateway response when a payload is of an unsupported media type, if strict passthrough behavior is enabled. + */ + public static readonly UNSUPPORTED_MEDIA_TYPE = new ResponseType('UNSUPPORTED_MEDIA_TYPE'); + + /** + * The gateway response when a request is blocked by AWS WAF. + */ + public static readonly WAF_FILTERED = new ResponseType('WAF_FILTERED'); + + /** A custom response type to suppport future cases. */ + public static of(type: string): ResponseType { + return new ResponseType(type.toUpperCase()); + } + + /** + * Valid value of response type. + */ + public readonly responseType: string; + + private constructor(type: string) { + this.responseType = type; + } + +} diff --git a/packages/@aws-cdk/aws-apigateway/lib/index.ts b/packages/@aws-cdk/aws-apigateway/lib/index.ts index fe71c1492ab21..a0b9c7529cde2 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/index.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/index.ts @@ -20,6 +20,7 @@ export * from './base-path-mapping'; export * from './cors'; export * from './authorizers'; export * from './access-log'; +export * from './gateway-response'; // AWS::ApiGateway CloudFormation Resources: export * from './apigateway.generated'; diff --git a/packages/@aws-cdk/aws-apigateway/lib/restapi.ts b/packages/@aws-cdk/aws-apigateway/lib/restapi.ts index 7807f18c98a50..5785574023b17 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/restapi.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/restapi.ts @@ -6,6 +6,7 @@ import { CfnAccount, CfnRestApi } from './apigateway.generated'; import { CorsOptions } from './cors'; import { Deployment } from './deployment'; import { DomainName, DomainNameOptions } from './domain-name'; +import { GatewayResponse, GatewayResponseOptions } from './gateway-response'; import { Integration } from './integration'; import { Method, MethodOptions } from './method'; import { Model, ModelOptions } from './model'; @@ -390,6 +391,16 @@ export class RestApi extends Resource implements IRestApi { this.methods.push(method); } + /** + * Adds a new gateway response. + */ + public addGatewayResponse(id: string, options: GatewayResponseOptions): GatewayResponse { + return new GatewayResponse(this, id, { + restApi: this, + ...options, + }); + } + /** * Performs validation of the REST API. */ diff --git a/packages/@aws-cdk/aws-apigateway/package.json b/packages/@aws-cdk/aws-apigateway/package.json index 5649b915feb0d..53b5862643f59 100644 --- a/packages/@aws-cdk/aws-apigateway/package.json +++ b/packages/@aws-cdk/aws-apigateway/package.json @@ -106,6 +106,7 @@ "exclude": [ "from-method:@aws-cdk/aws-apigateway.Resource", "duration-prop-type:@aws-cdk/aws-apigateway.QuotaSettings.period", + "duration-prop-type:@aws-cdk/aws-apigateway.ResponseType.INTEGRATION_TIMEOUT", "from-method:@aws-cdk/aws-apigateway.ApiKey", "ref-via-interface:@aws-cdk/aws-apigateway.ApiKeyProps.resources", "props-physical-name:@aws-cdk/aws-apigateway.DeploymentProps", @@ -116,6 +117,7 @@ "props-physical-name-type:@aws-cdk/aws-apigateway.StageProps.stageName", "props-physical-name:@aws-cdk/aws-apigateway.BasePathMappingProps", "props-physical-name:@aws-cdk/aws-apigateway.LambdaRestApiProps", + "props-physical-name:@aws-cdk/aws-apigateway.GatewayResponseProps", "construct-interface-extends-iconstruct:@aws-cdk/aws-apigateway.IModel", "resource-interface-extends-resource:@aws-cdk/aws-apigateway.IModel", "docs-public-apis:@aws-cdk/aws-apigateway.JsonSchema.definitions", diff --git a/packages/@aws-cdk/aws-apigateway/test/test.restapi.ts b/packages/@aws-cdk/aws-apigateway/test/test.restapi.ts index 97fac8ca999f4..6997bcf31b220 100644 --- a/packages/@aws-cdk/aws-apigateway/test/test.restapi.ts +++ b/packages/@aws-cdk/aws-apigateway/test/test.restapi.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, haveResourceLike, ResourcePart, SynthUtils } from '@aws-cdk/assert'; +import { ABSENT, expect, haveResource, haveResourceLike, ResourcePart, SynthUtils } from '@aws-cdk/assert'; import { GatewayVpcEndpoint } from '@aws-cdk/aws-ec2'; import { App, CfnElement, CfnResource, Stack } from '@aws-cdk/core'; import { Test } from 'nodeunit'; @@ -810,4 +810,99 @@ export = { test.done(); }, + + 'gateway response resource is created'(test: Test) { + // GIVEN + const stack = new Stack(); + + // WHEN + const api = new apigw.RestApi(stack, 'restapi', { + deploy: false, + cloudWatchRole: false, + }); + + api.root.addMethod('GET'); + api.addGatewayResponse('test-response', { + type: apigw.ResponseType.ACCESS_DENIED, + }); + + // THEN + expect(stack).to(haveResource('AWS::ApiGateway::GatewayResponse', { + ResponseType: 'ACCESS_DENIED', + RestApiId: stack.resolve(api.restApiId), + StatusCode: ABSENT, + ResponseParameters: ABSENT, + ResponseTemplates: ABSENT, + })); + + test.done(); + }, + + 'gateway response resource is created with parameters'(test: Test) { + // GIVEN + const stack = new Stack(); + + // WHEN + const api = new apigw.RestApi(stack, 'restapi', { + deploy: false, + cloudWatchRole: false, + }); + + api.root.addMethod('GET'); + api.addGatewayResponse('test-response', { + type: apigw.ResponseType.AUTHORIZER_FAILURE, + statusCode: '500', + responseHeaders: { + 'Access-Control-Allow-Origin': 'test.com', + 'test-key': 'test-value', + }, + }); + + // THEN + expect(stack).to(haveResource('AWS::ApiGateway::GatewayResponse', { + ResponseType: 'AUTHORIZER_FAILURE', + RestApiId: stack.resolve(api.restApiId), + StatusCode: '500', + ResponseParameters: { + 'gatewayresponse.header.Access-Control-Allow-Origin': 'test.com', + 'gatewayresponse.header.test-key': 'test-value', + }, + ResponseTemplates: ABSENT, + })); + + test.done(); + }, + + 'gateway response resource is created with templates'(test: Test) { + // GIVEN + const stack = new Stack(); + + // WHEN + const api = new apigw.RestApi(stack, 'restapi', { + deploy: false, + cloudWatchRole: false, + }); + + api.root.addMethod('GET'); + api.addGatewayResponse('test-response', { + type: apigw.ResponseType.AUTHORIZER_FAILURE, + statusCode: '500', + templates: { + 'application/json': '{ "message": $context.error.messageString, "statusCode": "488" }', + }, + }); + + // THEN + expect(stack).to(haveResource('AWS::ApiGateway::GatewayResponse', { + ResponseType: 'AUTHORIZER_FAILURE', + RestApiId: stack.resolve(api.restApiId), + StatusCode: '500', + ResponseParameters: ABSENT, + ResponseTemplates: { + 'application/json': '{ "message": $context.error.messageString, "statusCode": "488" }', + }, + })); + + test.done(); + }, }; diff --git a/packages/@aws-cdk/aws-applicationautoscaling/package.json b/packages/@aws-cdk/aws-applicationautoscaling/package.json index b91380d051677..991a30328d8e9 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/package.json +++ b/packages/@aws-cdk/aws-applicationautoscaling/package.json @@ -66,7 +66,7 @@ "@types/nodeunit": "^0.0.30", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "fast-check": "^1.24.1", + "fast-check": "^1.24.2", "nodeunit": "^0.11.3", "pkglint": "0.0.0" }, diff --git a/packages/@aws-cdk/aws-autoscaling-common/package.json b/packages/@aws-cdk/aws-autoscaling-common/package.json index 7aa3f95a2c0e7..229b78d1ed501 100644 --- a/packages/@aws-cdk/aws-autoscaling-common/package.json +++ b/packages/@aws-cdk/aws-autoscaling-common/package.json @@ -62,7 +62,7 @@ "@types/nodeunit": "^0.0.30", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", - "fast-check": "^1.24.1", + "fast-check": "^1.24.2", "nodeunit": "^0.11.3", "pkglint": "0.0.0" }, diff --git a/packages/@aws-cdk/aws-cloudfront/package.json b/packages/@aws-cdk/aws-cloudfront/package.json index b615c3d752311..3a95bc01880fb 100644 --- a/packages/@aws-cdk/aws-cloudfront/package.json +++ b/packages/@aws-cdk/aws-cloudfront/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.662.0", + "aws-sdk": "^2.665.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudtrail/package.json b/packages/@aws-cdk/aws-cloudtrail/package.json index 57a4717ed420d..33e2bf11afa3d 100644 --- a/packages/@aws-cdk/aws-cloudtrail/package.json +++ b/packages/@aws-cdk/aws-cloudtrail/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.662.0", + "aws-sdk": "^2.665.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-codebuild/README.md b/packages/@aws-cdk/aws-codebuild/README.md index 0b28d65d992e8..45268bafd0064 100644 --- a/packages/@aws-cdk/aws-codebuild/README.md +++ b/packages/@aws-cdk/aws-codebuild/README.md @@ -259,7 +259,9 @@ project as a AWS CloudWatch event rule target: // start build when a commit is pushed const targets = require('@aws-cdk/aws-events-targets'); -codeCommitRepository.onCommit('OnCommit', new targets.CodeBuildProject(project)); +codeCommitRepository.onCommit('OnCommit', { + target: new targets.CodeBuildProject(project), +}); ``` ### Using Project as an event source diff --git a/packages/@aws-cdk/aws-codebuild/package.json b/packages/@aws-cdk/aws-codebuild/package.json index ff417756adc4d..c6b6d494b03b5 100644 --- a/packages/@aws-cdk/aws-codebuild/package.json +++ b/packages/@aws-cdk/aws-codebuild/package.json @@ -70,7 +70,7 @@ "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.662.0", + "aws-sdk": "^2.665.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-codecommit/package.json b/packages/@aws-cdk/aws-codecommit/package.json index 0145879053ede..397c47ce1787e 100644 --- a/packages/@aws-cdk/aws-codecommit/package.json +++ b/packages/@aws-cdk/aws-codecommit/package.json @@ -70,7 +70,7 @@ "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.662.0", + "aws-sdk": "^2.665.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-dynamodb/lib/replica-handler/index.ts b/packages/@aws-cdk/aws-dynamodb/lib/replica-handler/index.ts index e60affefa6bfd..9764566a3c08d 100644 --- a/packages/@aws-cdk/aws-dynamodb/lib/replica-handler/index.ts +++ b/packages/@aws-cdk/aws-dynamodb/lib/replica-handler/index.ts @@ -1,16 +1,6 @@ /* tslint:disable no-console */ import { IsCompleteRequest, IsCompleteResponse, OnEventRequest, OnEventResponse } from '@aws-cdk/custom-resources/lib/provider-framework/types'; import { DynamoDB } from 'aws-sdk'; // eslint-disable-line import/no-extraneous-dependencies -import { execSync } from 'child_process'; - -let latestSdkInstalled = false; - -function installLatestSdk(): void { - console.log('Installing latest AWS SDK v2'); - // Both HOME and --prefix are needed here because /tmp is the only writable location - execSync('HOME=/tmp npm install aws-sdk@2 --production --no-package-lock --no-save --prefix /tmp'); - latestSdkInstalled = true; -} export async function onEventHandler(event: OnEventRequest): Promise { console.log('Event: %j', event); @@ -20,20 +10,7 @@ export async function onEventHandler(event: OnEventRequest): Promise { 'Users': [{ 'Ref': 'user2C2B57AE' }], }); }); + + test('grant for an imported table', () => { + // GIVEN + const stack = new Stack(); + const table = Table.fromTableName(stack, 'MyTable', 'my-table'); + const user = new iam.User(stack, 'user'); + + // WHEN + table.grant(user, 'dynamodb:*'); + + // THEN + expect(stack).toHaveResource('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: 'dynamodb:*', + Effect: 'Allow', + Resource: [ + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':dynamodb:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':table/my-table', + ], + ], + }, + { + Ref: 'AWS::NoValue', + }, + ], + }, + ], + Version: '2012-10-17', + }, + Users: [ + { + Ref: 'user2C2B57AE', + }, + ], + }); + }); }); describe('secondary indexes', () => { diff --git a/packages/@aws-cdk/aws-dynamodb/test/integ.global.expected.json b/packages/@aws-cdk/aws-dynamodb/test/integ.global.expected.json index b4e4db9156ec8..8db65da9e0a4c 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/integ.global.expected.json +++ b/packages/@aws-cdk/aws-dynamodb/test/integ.global.expected.json @@ -91,7 +91,7 @@ }, "/", { - "Ref": "AssetParametersc1289fc4cd3d56f60845ad47d38292003289b914d85114c8184c42f7c29cc37cS3BucketAF315054" + "Ref": "AssetParametersff9385d45e080dd6d7d73d81931d4eb97c31883610969bc8e00008b67f40ab68S3BucketF1B0B267" }, "/", { @@ -101,7 +101,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersc1289fc4cd3d56f60845ad47d38292003289b914d85114c8184c42f7c29cc37cS3VersionKey0BF5AB05" + "Ref": "AssetParametersff9385d45e080dd6d7d73d81931d4eb97c31883610969bc8e00008b67f40ab68S3VersionKey39DCF57D" } ] } @@ -114,7 +114,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersc1289fc4cd3d56f60845ad47d38292003289b914d85114c8184c42f7c29cc37cS3VersionKey0BF5AB05" + "Ref": "AssetParametersff9385d45e080dd6d7d73d81931d4eb97c31883610969bc8e00008b67f40ab68S3VersionKey39DCF57D" } ] } @@ -133,11 +133,11 @@ "referencetocdkdynamodbglobal20191121TableB640876BRef": { "Ref": "TableCD117FA1" }, - "referencetocdkdynamodbglobal20191121AssetParameters01d4c194f7ecc9749658a221ceb33b29ff0c4e9d202cb82d7126e6532458da2bS3Bucket3DE786D6Ref": { - "Ref": "AssetParameters01d4c194f7ecc9749658a221ceb33b29ff0c4e9d202cb82d7126e6532458da2bS3Bucket797A9731" + "referencetocdkdynamodbglobal20191121AssetParameters23c030d344d23d11a9deeaeca621a2fed8d153a4906d94da81b3cf75beb34260S3Bucket9DB95B91Ref": { + "Ref": "AssetParameters23c030d344d23d11a9deeaeca621a2fed8d153a4906d94da81b3cf75beb34260S3Bucket578442F1" }, - "referencetocdkdynamodbglobal20191121AssetParameters01d4c194f7ecc9749658a221ceb33b29ff0c4e9d202cb82d7126e6532458da2bS3VersionKey2E16D513Ref": { - "Ref": "AssetParameters01d4c194f7ecc9749658a221ceb33b29ff0c4e9d202cb82d7126e6532458da2bS3VersionKey32273025" + "referencetocdkdynamodbglobal20191121AssetParameters23c030d344d23d11a9deeaeca621a2fed8d153a4906d94da81b3cf75beb34260S3VersionKeyC55DE477Ref": { + "Ref": "AssetParameters23c030d344d23d11a9deeaeca621a2fed8d153a4906d94da81b3cf75beb34260S3VersionKey1B6BA461" }, "referencetocdkdynamodbglobal20191121AssetParameters5e49cf64d8027f48872790f80cdb76c5b836ecf9a70b71be1eb937a5c25a47c1S3Bucket6627F4A7Ref": { "Ref": "AssetParameters5e49cf64d8027f48872790f80cdb76c5b836ecf9a70b71be1eb937a5c25a47c1S3Bucket663A709C" @@ -150,17 +150,17 @@ } }, "Parameters": { - "AssetParameters01d4c194f7ecc9749658a221ceb33b29ff0c4e9d202cb82d7126e6532458da2bS3Bucket797A9731": { + "AssetParameters23c030d344d23d11a9deeaeca621a2fed8d153a4906d94da81b3cf75beb34260S3Bucket578442F1": { "Type": "String", - "Description": "S3 bucket for asset \"01d4c194f7ecc9749658a221ceb33b29ff0c4e9d202cb82d7126e6532458da2b\"" + "Description": "S3 bucket for asset \"23c030d344d23d11a9deeaeca621a2fed8d153a4906d94da81b3cf75beb34260\"" }, - "AssetParameters01d4c194f7ecc9749658a221ceb33b29ff0c4e9d202cb82d7126e6532458da2bS3VersionKey32273025": { + "AssetParameters23c030d344d23d11a9deeaeca621a2fed8d153a4906d94da81b3cf75beb34260S3VersionKey1B6BA461": { "Type": "String", - "Description": "S3 key for asset version \"01d4c194f7ecc9749658a221ceb33b29ff0c4e9d202cb82d7126e6532458da2b\"" + "Description": "S3 key for asset version \"23c030d344d23d11a9deeaeca621a2fed8d153a4906d94da81b3cf75beb34260\"" }, - "AssetParameters01d4c194f7ecc9749658a221ceb33b29ff0c4e9d202cb82d7126e6532458da2bArtifactHash54F789B6": { + "AssetParameters23c030d344d23d11a9deeaeca621a2fed8d153a4906d94da81b3cf75beb34260ArtifactHash57F1E9B3": { "Type": "String", - "Description": "Artifact hash for asset \"01d4c194f7ecc9749658a221ceb33b29ff0c4e9d202cb82d7126e6532458da2b\"" + "Description": "Artifact hash for asset \"23c030d344d23d11a9deeaeca621a2fed8d153a4906d94da81b3cf75beb34260\"" }, "AssetParameters5e49cf64d8027f48872790f80cdb76c5b836ecf9a70b71be1eb937a5c25a47c1S3Bucket663A709C": { "Type": "String", @@ -174,17 +174,17 @@ "Type": "String", "Description": "Artifact hash for asset \"5e49cf64d8027f48872790f80cdb76c5b836ecf9a70b71be1eb937a5c25a47c1\"" }, - "AssetParametersc1289fc4cd3d56f60845ad47d38292003289b914d85114c8184c42f7c29cc37cS3BucketAF315054": { + "AssetParametersff9385d45e080dd6d7d73d81931d4eb97c31883610969bc8e00008b67f40ab68S3BucketF1B0B267": { "Type": "String", - "Description": "S3 bucket for asset \"c1289fc4cd3d56f60845ad47d38292003289b914d85114c8184c42f7c29cc37c\"" + "Description": "S3 bucket for asset \"ff9385d45e080dd6d7d73d81931d4eb97c31883610969bc8e00008b67f40ab68\"" }, - "AssetParametersc1289fc4cd3d56f60845ad47d38292003289b914d85114c8184c42f7c29cc37cS3VersionKey0BF5AB05": { + "AssetParametersff9385d45e080dd6d7d73d81931d4eb97c31883610969bc8e00008b67f40ab68S3VersionKey39DCF57D": { "Type": "String", - "Description": "S3 key for asset version \"c1289fc4cd3d56f60845ad47d38292003289b914d85114c8184c42f7c29cc37c\"" + "Description": "S3 key for asset version \"ff9385d45e080dd6d7d73d81931d4eb97c31883610969bc8e00008b67f40ab68\"" }, - "AssetParametersc1289fc4cd3d56f60845ad47d38292003289b914d85114c8184c42f7c29cc37cArtifactHashDAE30A7E": { + "AssetParametersff9385d45e080dd6d7d73d81931d4eb97c31883610969bc8e00008b67f40ab68ArtifactHash1FBBCC08": { "Type": "String", - "Description": "Artifact hash for asset \"c1289fc4cd3d56f60845ad47d38292003289b914d85114c8184c42f7c29cc37c\"" + "Description": "Artifact hash for asset \"ff9385d45e080dd6d7d73d81931d4eb97c31883610969bc8e00008b67f40ab68\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-dynamodb/test/replica-provider.test.ts b/packages/@aws-cdk/aws-dynamodb/test/replica-provider.test.ts index 8ff6e6afc2ef4..cddd4c258689b 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/replica-provider.test.ts +++ b/packages/@aws-cdk/aws-dynamodb/test/replica-provider.test.ts @@ -20,15 +20,8 @@ const createEvent: OnEventRequest = { ResourceType: 'resource-type', }; -beforeEach(done => { - process.env.USE_NORMAL_SDK = 'true'; - done(); -}); - -afterEach(done => { - delete process.env.USE_NORMAL_SDK; +afterEach(() => { AWS.restore(); - done(); }); test('on event', async () => { diff --git a/packages/@aws-cdk/aws-ecs-patterns/README.md b/packages/@aws-cdk/aws-ecs-patterns/README.md index 24dff83b09908..71b3591ed6fdf 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/README.md +++ b/packages/@aws-cdk/aws-ecs-patterns/README.md @@ -60,6 +60,8 @@ You can omit `cluster` and `vpc` to let CDK create a new VPC with two AZs and cr You can customize the health check for your target group; otherwise it defaults to `HTTP` over port `80` hitting path `/`. +Fargate services will use the `LATEST` platform version by default, but you can override by providing a value for the `platformVersion` property in the constructor. + Additionally, if more than one application target group are needed, instantiate one of the following: * `ApplicationMultipleTargetGroupsEc2Service` diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-load-balanced-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-load-balanced-fargate-service.ts index 6451cafa4e828..baa8a191410dc 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-load-balanced-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-load-balanced-fargate-service.ts @@ -1,4 +1,4 @@ -import { FargateService, FargateTaskDefinition } from '@aws-cdk/aws-ecs'; +import { FargatePlatformVersion, FargateService, FargateTaskDefinition } from '@aws-cdk/aws-ecs'; import { Construct } from '@aws-cdk/core'; import { ApplicationLoadBalancedServiceBase, ApplicationLoadBalancedServiceBaseProps } from '../base/application-load-balanced-service-base'; @@ -64,6 +64,17 @@ export interface ApplicationLoadBalancedFargateServiceProps extends ApplicationL * @default false */ readonly assignPublicIp?: boolean; + + /** + * The platform version on which to run your service. + * + * If one is not specified, the LATEST platform version is used by default. For more information, see + * [AWS Fargate Platform Versions](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/platform_versions.html) + * in the Amazon Elastic Container Service Developer Guide. + * + * @default Latest + */ + readonly platformVersion?: FargatePlatformVersion; } /** @@ -139,6 +150,7 @@ export class ApplicationLoadBalancedFargateService extends ApplicationLoadBalanc propagateTags: props.propagateTags, enableECSManagedTags: props.enableECSManagedTags, cloudMapOptions: props.cloudMapOptions, + platformVersion: props.platformVersion, }); this.addServiceAsTarget(this.service); } diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-multiple-target-groups-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-multiple-target-groups-fargate-service.ts index 67534a50af8e0..c38b262d845e3 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-multiple-target-groups-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-multiple-target-groups-fargate-service.ts @@ -1,4 +1,4 @@ -import { FargateService, FargateTaskDefinition } from '@aws-cdk/aws-ecs'; +import { FargatePlatformVersion, FargateService, FargateTaskDefinition } from '@aws-cdk/aws-ecs'; import { ApplicationTargetGroup } from '@aws-cdk/aws-elasticloadbalancingv2'; import { Construct } from '@aws-cdk/core'; import { ApplicationMultipleTargetGroupsServiceBase, @@ -67,6 +67,17 @@ export interface ApplicationMultipleTargetGroupsFargateServiceProps extends Appl * @default false */ readonly assignPublicIp?: boolean; + + /** + * The platform version on which to run your service. + * + * If one is not specified, the LATEST platform version is used by default. For more information, see + * [AWS Fargate Platform Versions](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/platform_versions.html) + * in the Amazon Elastic Container Service Developer Guide. + * + * @default Latest + */ + readonly platformVersion?: FargatePlatformVersion; } /** @@ -165,6 +176,7 @@ export class ApplicationMultipleTargetGroupsFargateService extends ApplicationMu propagateTags: props.propagateTags, enableECSManagedTags: props.enableECSManagedTags, cloudMapOptions: props.cloudMapOptions, + platformVersion: props.platformVersion, }); } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/network-load-balanced-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/network-load-balanced-fargate-service.ts index 1d54d74189649..c86e279ab2ea1 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/network-load-balanced-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/network-load-balanced-fargate-service.ts @@ -1,4 +1,4 @@ -import { FargateService, FargateTaskDefinition } from '@aws-cdk/aws-ecs'; +import { FargatePlatformVersion, FargateService, FargateTaskDefinition } from '@aws-cdk/aws-ecs'; import { Construct } from '@aws-cdk/core'; import { NetworkLoadBalancedServiceBase, NetworkLoadBalancedServiceBaseProps } from '../base/network-load-balanced-service-base'; @@ -64,6 +64,17 @@ export interface NetworkLoadBalancedFargateServiceProps extends NetworkLoadBalan * @default false */ readonly assignPublicIp?: boolean; + + /** + * The platform version on which to run your service. + * + * If one is not specified, the LATEST platform version is used by default. For more information, see + * [AWS Fargate Platform Versions](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/platform_versions.html) + * in the Amazon Elastic Container Service Developer Guide. + * + * @default Latest + */ + readonly platformVersion?: FargatePlatformVersion; } /** @@ -135,6 +146,7 @@ export class NetworkLoadBalancedFargateService extends NetworkLoadBalancedServic propagateTags: props.propagateTags, enableECSManagedTags: props.enableECSManagedTags, cloudMapOptions: props.cloudMapOptions, + platformVersion: props.platformVersion, }); this.addServiceAsTarget(this.service); } diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/network-multiple-target-groups-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/network-multiple-target-groups-fargate-service.ts index e80923cd8f870..7b268027e3b55 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/network-multiple-target-groups-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/network-multiple-target-groups-fargate-service.ts @@ -1,4 +1,4 @@ -import { FargateService, FargateTaskDefinition } from '@aws-cdk/aws-ecs'; +import { FargatePlatformVersion, FargateService, FargateTaskDefinition } from '@aws-cdk/aws-ecs'; import { NetworkTargetGroup } from '@aws-cdk/aws-elasticloadbalancingv2'; import { Construct } from '@aws-cdk/core'; import { NetworkMultipleTargetGroupsServiceBase, @@ -67,6 +67,17 @@ export interface NetworkMultipleTargetGroupsFargateServiceProps extends NetworkM * @default false */ readonly assignPublicIp?: boolean; + + /** + * The platform version on which to run your service. + * + * If one is not specified, the LATEST platform version is used by default. For more information, see + * [AWS Fargate Platform Versions](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/platform_versions.html) + * in the Amazon Elastic Container Service Developer Guide. + * + * @default Latest + */ + readonly platformVersion?: FargatePlatformVersion; } /** @@ -165,6 +176,7 @@ export class NetworkMultipleTargetGroupsFargateService extends NetworkMultipleTa propagateTags: props.propagateTags, enableECSManagedTags: props.enableECSManagedTags, cloudMapOptions: props.cloudMapOptions, + platformVersion: props.platformVersion, }); } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/queue-processing-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/queue-processing-fargate-service.ts index 62cc2724308e2..a7da98ed1fbfc 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/queue-processing-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/queue-processing-fargate-service.ts @@ -1,4 +1,4 @@ -import { FargateService, FargateTaskDefinition } from '@aws-cdk/aws-ecs'; +import { FargatePlatformVersion, FargateService, FargateTaskDefinition } from '@aws-cdk/aws-ecs'; import { Construct } from '@aws-cdk/core'; import { QueueProcessingServiceBase, QueueProcessingServiceBaseProps } from '../base/queue-processing-service-base'; @@ -48,6 +48,17 @@ export interface QueueProcessingFargateServiceProps extends QueueProcessingServi * @default 512 */ readonly memoryLimitMiB?: number; + + /** + * The platform version on which to run your service. + * + * If one is not specified, the LATEST platform version is used by default. For more information, see + * [AWS Fargate Platform Versions](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/platform_versions.html) + * in the Amazon Elastic Container Service Developer Guide. + * + * @default Latest + */ + readonly platformVersion?: FargatePlatformVersion; } /** @@ -92,6 +103,7 @@ export class QueueProcessingFargateService extends QueueProcessingServiceBase { serviceName: props.serviceName, propagateTags: props.propagateTags, enableECSManagedTags: props.enableECSManagedTags, + platformVersion: props.platformVersion, }); this.configureAutoscalingForService(this.service); this.grantPermissionsToService(this.service); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service-v2.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service-v2.ts index 0e80eef094f24..becc38e6a9fd1 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service-v2.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service-v2.ts @@ -1,6 +1,6 @@ import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; import { Vpc } from '@aws-cdk/aws-ec2'; -import { AwsLogDriver, Cluster, ContainerImage, FargateTaskDefinition, PropagatedTagSource, Protocol } from '@aws-cdk/aws-ecs'; +import * as ecs from '@aws-cdk/aws-ecs'; import { CompositePrincipal, Role, ServicePrincipal } from '@aws-cdk/aws-iam'; import { Duration, Stack } from '@aws-cdk/core'; import { Test } from 'nodeunit'; @@ -12,13 +12,13 @@ export = { // GIVEN const stack = new Stack(); const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); // WHEN new ApplicationMultipleTargetGroupsFargateService(stack, 'Service', { cluster, taskImageOptions: { - image: ContainerImage.fromRegistry('test'), + image: ecs.ContainerImage.fromRegistry('test'), }, }); @@ -86,13 +86,13 @@ export = { // GIVEN const stack = new Stack(); const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); // WHEN new ApplicationMultipleTargetGroupsFargateService(stack, 'Service', { cluster, taskImageOptions: { - image: ContainerImage.fromRegistry('test'), + image: ecs.ContainerImage.fromRegistry('test'), containerName: 'hello', containerPorts: [80, 90], enableLogging: false, @@ -100,7 +100,7 @@ export = { TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', }, - logDriver: new AwsLogDriver({ + logDriver: new ecs.AwsLogDriver({ streamPrefix: 'TestStream', }), family: 'Ec2TaskDef', @@ -121,7 +121,8 @@ export = { desiredCount: 3, enableECSManagedTags: true, healthCheckGracePeriod: Duration.millis(2000), - propagateTags: PropagatedTagSource.SERVICE, + platformVersion: ecs.FargatePlatformVersion.VERSION1_4, + propagateTags: ecs.PropagatedTagSource.SERVICE, serviceName: 'myService', targetGroups: [ { @@ -131,7 +132,7 @@ export = { containerPort: 90, pathPattern: 'a/b/c', priority: 10, - protocol: Protocol.TCP, + protocol: ecs.Protocol.TCP, }, ], }); @@ -179,6 +180,7 @@ export = { ], }, }, + PlatformVersion: ecs.FargatePlatformVersion.VERSION1_4, PropagateTags: 'SERVICE', ServiceName: 'myService', })); @@ -251,9 +253,9 @@ export = { // GIVEN const stack = new Stack(); const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - const taskDefinition = new FargateTaskDefinition(stack, 'FargateTaskDef'); + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); // THEN test.throws(() => { @@ -270,15 +272,15 @@ export = { // GIVEN const stack = new Stack(); const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - const taskDefinition = new FargateTaskDefinition(stack, 'Ec2TaskDef'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'Ec2TaskDef'); // THEN test.throws(() => { new ApplicationMultipleTargetGroupsFargateService(stack, 'Service', { cluster, taskImageOptions: { - image: ContainerImage.fromRegistry('test'), + image: ecs.ContainerImage.fromRegistry('test'), }, taskDefinition, }); @@ -291,7 +293,7 @@ export = { // GIVEN const stack = new Stack(); const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); // THEN test.throws(() => { @@ -309,13 +311,13 @@ export = { // GIVEN const stack = new Stack(); const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); // WHEN new NetworkMultipleTargetGroupsFargateService(stack, 'Service', { cluster, taskImageOptions: { - image: ContainerImage.fromRegistry('test'), + image: ecs.ContainerImage.fromRegistry('test'), }, }); @@ -383,13 +385,13 @@ export = { // GIVEN const stack = new Stack(); const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); // WHEN new NetworkMultipleTargetGroupsFargateService(stack, 'Service', { cluster, taskImageOptions: { - image: ContainerImage.fromRegistry('test'), + image: ecs.ContainerImage.fromRegistry('test'), containerName: 'hello', containerPorts: [80, 90], enableLogging: false, @@ -397,7 +399,7 @@ export = { TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', }, - logDriver: new AwsLogDriver({ + logDriver: new ecs.AwsLogDriver({ streamPrefix: 'TestStream', }), family: 'Ec2TaskDef', @@ -418,7 +420,7 @@ export = { desiredCount: 3, enableECSManagedTags: true, healthCheckGracePeriod: Duration.millis(2000), - propagateTags: PropagatedTagSource.SERVICE, + propagateTags: ecs.PropagatedTagSource.SERVICE, serviceName: 'myService', targetGroups: [ { @@ -545,9 +547,9 @@ export = { // GIVEN const stack = new Stack(); const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - const taskDefinition = new FargateTaskDefinition(stack, 'FargateTaskDef'); + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); // THEN test.throws(() => { @@ -564,15 +566,15 @@ export = { // GIVEN const stack = new Stack(); const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - const taskDefinition = new FargateTaskDefinition(stack, 'Ec2TaskDef'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'Ec2TaskDef'); // THEN test.throws(() => { new NetworkMultipleTargetGroupsFargateService(stack, 'Service', { cluster, taskImageOptions: { - image: ContainerImage.fromRegistry('test'), + image: ecs.ContainerImage.fromRegistry('test'), }, taskDefinition, }); @@ -585,7 +587,7 @@ export = { // GIVEN const stack = new Stack(); const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); // THEN test.throws(() => { diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service.ts index be9400b26198e..b0b8a21705ddb 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service.ts @@ -228,6 +228,24 @@ export = { test.done(); }, + 'setting platform version'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + platformVersion: ecs.FargatePlatformVersion.VERSION1_4, + }); + // THEN + expect(stack).to(haveResource('AWS::ECS::Service', { + PlatformVersion: ecs.FargatePlatformVersion.VERSION1_4, + })); + test.done(); + }, + 'test load balanced service with family defined'(test: Test) { // GIVEN const stack = new cdk.Stack(); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts index 7c36af95ff7e0..c37c7f349b496 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts @@ -225,6 +225,7 @@ export = { maxScalingCapacity: 5, serviceName: 'fargate-test-service', family: 'fargate-task-family', + platformVersion: ecs.FargatePlatformVersion.VERSION1_4, }); // THEN - QueueWorker is of FARGATE launch type, an SQS queue is created and all optional properties are set. @@ -232,6 +233,7 @@ export = { DesiredCount: 2, LaunchType: 'FARGATE', ServiceName: 'fargate-test-service', + PlatformVersion: ecs.FargatePlatformVersion.VERSION1_4, })); expect(stack).to(haveResource('AWS::SQS::Queue', { QueueName: 'fargate-test-sqs-queue' })); diff --git a/packages/@aws-cdk/aws-ecs/lib/base/task-definition.ts b/packages/@aws-cdk/aws-ecs/lib/base/task-definition.ts index a2cd88a0897ca..bf2bbe535210b 100644 --- a/packages/@aws-cdk/aws-ecs/lib/base/task-definition.ts +++ b/packages/@aws-cdk/aws-ecs/lib/base/task-definition.ts @@ -146,6 +146,24 @@ export interface TaskDefinitionProps extends CommonTaskDefinitionProps { * @default - Memory used by task is not specified. */ readonly memoryMiB?: string; + + /** + * The IPC resource namespace to use for the containers in the task. + * + * Not supported in Fargate and Windows containers. + * + * @default - IpcMode used by the task is not specified + */ + readonly ipcMode?: IpcMode; + + /** + * The process namespace to use for the containers in the task. + * + * Not supported in Fargate and Windows containers. + * + * @default - PidMode used by the task is not specified + */ + readonly pidMode?: PidMode; } abstract class TaskDefinitionBase extends Resource implements ITaskDefinition { @@ -294,6 +312,8 @@ export class TaskDefinition extends TaskDefinitionBase { proxyConfiguration: props.proxyConfiguration ? props.proxyConfiguration.bind(this.stack, this) : undefined, cpu: props.cpu, memory: props.memoryMiB, + ipcMode: props.ipcMode, + pidMode: props.pidMode, }); if (props.placementConstraints) { @@ -522,6 +542,44 @@ export enum NetworkMode { NAT = 'nat' } +/** + * The IPC resource namespace to use for the containers in the task. + */ +export enum IpcMode { + /** + * If none is specified, then IPC resources within the containers of a task are private and not + * shared with other containers in a task or on the container instance + */ + NONE = 'none', + + /** + * If host is specified, then all containers within the tasks that specified the host IPC mode on + * the same container instance share the same IPC resources with the host Amazon EC2 instance. + */ + HOST = 'host', + + /** + * If task is specified, all containers within the specified task share the same IPC resources. + */ + TASK = 'task', +} + +/** + * The process namespace to use for the containers in the task. + */ +export enum PidMode { + /** + * If host is specified, then all containers within the tasks that specified the host PID mode + * on the same container instance share the same process namespace with the host Amazon EC2 instance. + */ + HOST = 'host', + + /** + * If task is specified, all containers within the specified task share the same process namespace. + */ + TASK = 'task', +} + /** * A data volume used in a task definition. * diff --git a/packages/@aws-cdk/aws-ecs/lib/ec2/ec2-task-definition.ts b/packages/@aws-cdk/aws-ecs/lib/ec2/ec2-task-definition.ts index 8fe6c6919519d..de25514330b33 100644 --- a/packages/@aws-cdk/aws-ecs/lib/ec2/ec2-task-definition.ts +++ b/packages/@aws-cdk/aws-ecs/lib/ec2/ec2-task-definition.ts @@ -1,5 +1,5 @@ import { Construct, Resource } from '@aws-cdk/core'; -import { CommonTaskDefinitionProps, Compatibility, ITaskDefinition, NetworkMode, TaskDefinition } from '../base/task-definition'; +import { CommonTaskDefinitionProps, Compatibility, IpcMode, ITaskDefinition, NetworkMode, PidMode, TaskDefinition } from '../base/task-definition'; import { PlacementConstraint } from '../placement'; /** @@ -23,6 +23,24 @@ export interface Ec2TaskDefinitionProps extends CommonTaskDefinitionProps { * @default - No placement constraints. */ readonly placementConstraints?: PlacementConstraint[]; + + /** + * The IPC resource namespace to use for the containers in the task. + * + * Not supported in Fargate and Windows containers. + * + * @default - IpcMode used by the task is not specified + */ + readonly ipcMode?: IpcMode; + + /** + * The process namespace to use for the containers in the task. + * + * Not supported in Fargate and Windows containers. + * + * @default - PidMode used by the task is not specified + */ + readonly pidMode?: PidMode; } /** @@ -60,6 +78,8 @@ export class Ec2TaskDefinition extends TaskDefinition implements IEc2TaskDefinit ...props, compatibility: Compatibility.EC2, placementConstraints: props.placementConstraints, + ipcMode: props.ipcMode, + pidMode: props.pidMode, }); } } diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.app-mesh-proxy-config.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.app-mesh-proxy-config.expected.json index c7a842ce03a5e..eb2c7c6250d64 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.app-mesh-proxy-config.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.app-mesh-proxy-config.expected.json @@ -837,6 +837,8 @@ } ], "Family": "awsecsintegTaskDef6FDFB69A", + "IpcMode": "host", + "PidMode": "task", "NetworkMode": "awsvpc", "ProxyConfiguration": { "ContainerName": "envoy", diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.app-mesh-proxy-config.ts b/packages/@aws-cdk/aws-ecs/test/ec2/integ.app-mesh-proxy-config.ts index 7e8feffe3557b..3e91af323831b 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.app-mesh-proxy-config.ts +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.app-mesh-proxy-config.ts @@ -23,7 +23,12 @@ const prox = ecs.ProxyConfigurations.appMeshProxyConfiguration({ egressIgnoredIPs: ['169.254.170.2', '169.254.169.254'], }, }); -const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { networkMode: ecs.NetworkMode.AWS_VPC, proxyConfiguration: prox }); +const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { + networkMode: ecs.NetworkMode.AWS_VPC, + proxyConfiguration: prox, + ipcMode: ecs.IpcMode.HOST, + pidMode: ecs.PidMode.TASK, +}); taskDefinition.addContainer('web', { image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.clb-host-nw.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.clb-host-nw.expected.json index ff68024d095e1..c26979330c088 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.clb-host-nw.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.clb-host-nw.expected.json @@ -858,6 +858,8 @@ } ], "Family": "awsecsintegTaskDef6FDFB69A", + "IpcMode": "host", + "PidMode": "task", "NetworkMode": "host", "RequiresCompatibilities": [ "EC2" diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.clb-host-nw.ts b/packages/@aws-cdk/aws-ecs/test/ec2/integ.clb-host-nw.ts index 60e66c9470038..915256db25141 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.clb-host-nw.ts +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.clb-host-nw.ts @@ -15,6 +15,8 @@ cluster.addCapacity('DefaultAutoScalingGroup', { const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef', { networkMode: ecs.NetworkMode.HOST, + ipcMode: ecs.IpcMode.HOST, + pidMode: ecs.PidMode.TASK, }); const container = taskDefinition.addContainer('web', { diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-task-definition.ts b/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-task-definition.ts index 42b665440de58..d6bee7ccea946 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-task-definition.ts +++ b/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-task-definition.ts @@ -40,6 +40,8 @@ export = { }), family: 'ecs-tasks', networkMode: ecs.NetworkMode.AWS_VPC, + ipcMode: ecs.IpcMode.HOST, + pidMode: ecs.PidMode.TASK, placementConstraints: [ecs.PlacementConstraint.memberOf('attribute:ecs.instance-type =~ t2.*')], taskRole: new iam.Role(stack, 'TaskRole', { assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), @@ -62,6 +64,8 @@ export = { }, Family: 'ecs-tasks', NetworkMode: 'awsvpc', + IpcMode: 'host', + PidMode: 'task', PlacementConstraints: [ { Expression: 'attribute:ecs.instance-type =~ t2.*', @@ -127,6 +131,36 @@ export = { test.done(); }, + 'correctly sets ipc mode'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', { + ipcMode: ecs.IpcMode.TASK, + }); + + // THEN + expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { + IpcMode: ecs.IpcMode.TASK, + })); + + test.done(); + }, + + 'correctly sets pid mode'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', { + pidMode: ecs.PidMode.HOST, + }); + + // THEN + expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { + PidMode: ecs.PidMode.HOST, + })); + + test.done(); + }, + 'correctly sets containers'(test: Test) { // GIVEN const stack = new cdk.Stack(); diff --git a/packages/@aws-cdk/aws-eks/package.json b/packages/@aws-cdk/aws-eks/package.json index 33143631c1ece..8b620ae2a5f9c 100644 --- a/packages/@aws-cdk/aws-eks/package.json +++ b/packages/@aws-cdk/aws-eks/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.662.0", + "aws-sdk": "^2.665.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-events-targets/package.json b/packages/@aws-cdk/aws-events-targets/package.json index e49e9e4801733..4d6a6597614be 100644 --- a/packages/@aws-cdk/aws-events-targets/package.json +++ b/packages/@aws-cdk/aws-events-targets/package.json @@ -86,7 +86,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-codecommit": "0.0.0", - "aws-sdk": "^2.662.0", + "aws-sdk": "^2.665.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-lambda/package.json b/packages/@aws-cdk/aws-lambda/package.json index 0e470f76207a5..7e8da91100715 100644 --- a/packages/@aws-cdk/aws-lambda/package.json +++ b/packages/@aws-cdk/aws-lambda/package.json @@ -71,7 +71,7 @@ "@types/lodash": "^4.14.150", "@types/nodeunit": "^0.0.30", "@types/sinon": "^9.0.0", - "aws-sdk": "^2.662.0", + "aws-sdk": "^2.665.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/@aws-cdk/aws-route53/package.json b/packages/@aws-cdk/aws-route53/package.json index ec0e01f5dfa65..d284ea47ed361 100644 --- a/packages/@aws-cdk/aws-route53/package.json +++ b/packages/@aws-cdk/aws-route53/package.json @@ -64,7 +64,7 @@ "devDependencies": { "@aws-cdk/assert": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.662.0", + "aws-sdk": "^2.665.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-sqs/package.json b/packages/@aws-cdk/aws-sqs/package.json index 1a1674b0ce4da..9cb94ee4fc9fc 100644 --- a/packages/@aws-cdk/aws-sqs/package.json +++ b/packages/@aws-cdk/aws-sqs/package.json @@ -65,7 +65,7 @@ "@aws-cdk/assert": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@types/nodeunit": "^0.0.30", - "aws-sdk": "^2.662.0", + "aws-sdk": "^2.665.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/README.md b/packages/@aws-cdk/aws-stepfunctions-tasks/README.md index 27519b0753cec..1d1237a8f8fae 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/README.md +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/README.md @@ -1,4 +1,4 @@ -# Tasks for AWS CloudWatch StepFunctions +# Tasks for AWS Step Functions --- @@ -9,4 +9,674 @@ --- -See the README of the `@aws-cdk/aws-stepfunctions` library. +[AWS Step Functions](https://docs.aws.amazon.com/step-functions/latest/dg/welcome.html) is a web service that enables you to coordinate the +components of distributed applications and microservices using visual workflows. +You build applications from individual components that each perform a discrete +function, or task, allowing you to scale and change applications quickly. + +A [Task](https://docs.aws.amazon.com/step-functions/latest/dg/amazon-states-language-task-state.html) state represents a single unit of work performed by a state machine. +All work in your state machine is performed by tasks. + +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +## Table Of Contents + +- [Task](#task) +- [Parameters](#task-parameters-from-the-state-json) +- [Evaluate Expression](#evaluate-expression) +- [Batch](#batch) + - [SubmitJob](#submitjob) +- [DynamoDB](#dynamodb) + - [GetItem](#getitem) + - [PutItem](#putitem) + - [DeleteItem](#deleteitem) + - [UpdateItem](#updateitem) +- [ECS](#ecs) + - [RunTask](#runtask) +- [EMR](#emr) + - [Create Cluster](#create-cluster) + - [Termination Protection](#termination-protection) + - [Terminate Cluster](#terminate-cluster) + - [Add Step](#add-step) + - [Cancel Step](#cancel-step) + - [Modify Instance Fleet](#modify-instance-fleet) + - [Modify Instance Group](#modify-instance-group) +- [Glue](#glue) +- [Lambda](#lambda) +- [SageMaker](#sagemaker) + - [Create Training Job](#create-training-job) + - [Create Transform Job](#create-transform-job) +- [SNS](#sns) +- [Step Functions](#step-functions) +- [SQS](#sqs) + +## Task + +A Task state represents a single unit of work performed by a state machine. In the +CDK, the exact work to be In the CDK, the exact work to be done is determined by +a class that implements `IStepFunctionsTask`. + +AWS Step Functions [integrates](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-service-integrations.html) with some AWS services so that you can call API +actions, and coordinate executions directly from the Amazon States Language in +Step Functions. You can directly call and pass parameters to the APIs of those +services. + +## Task parameters from the state JSON + +Most tasks take parameters. Parameter values can either be static, supplied directly +in the workflow definition (by specifying their values), or a value available at runtime +in the state machine's execution (either as its input or an output of a prior state). +Parameter values available at runtime can be specified via the `Data` class, +using methods such as `Data.stringAt()`. + +If so, the value is taken from the indicated location in the state JSON, +similar to (for example) `inputPath`. + +## Evaluate Expression + +Use the `EvaluateExpression` to perform simple operations referencing state paths. The +`expression` referenced in the task will be evaluated in a Lambda function +(`eval()`). This allows you to not have to write Lambda code for simple operations. + +Example: convert a wait time from milliseconds to seconds, concat this in a message and wait: + +```ts +const convertToSeconds = new sfn.Task(this, 'Convert to seconds', { + task: new tasks.EvaluateExpression({ expression: '$.waitMilliseconds / 1000' }), + resultPath: '$.waitSeconds' +}); + +const createMessage = new sfn.Task(this, 'Create message', { + // Note: this is a string inside a string. + task: new tasks.EvaluateExpression({ + expression: '`Now waiting ${$.waitSeconds} seconds...`', + runtime: lambda.Runtime.NODEJS_10_X, + }), + resultPath: '$.message' +}); + +const publishMessage = new sfn.Task(this, 'Publish message', { + task: new tasks.PublishToTopic(topic, { + message: sfn.TaskInput.fromDataAt('$.message'), + }), + resultPath: '$.sns' +}); + +const wait = new sfn.Wait(this, 'Wait', { + time: sfn.WaitTime.secondsPath('$.waitSeconds') +}); + +new sfn.StateMachine(this, 'StateMachine', { + definition: convertToSeconds + .next(createMessage) + .next(publishMessage) + .next(wait) +}); +``` + +The `EvaluateExpression` supports a `runtime` prop to specify the Lambda +runtime to use to evaluate the expression. Currently, the only runtime +supported is `lambda.Runtime.NODEJS_10_X`. + +## Batch + +Step Functions supports [Batch](https://docs.aws.amazon.com/step-functions/latest/dg/connect-batch.html) through the service integration pattern. + +### SubmitJob + +The [SubmitJob](https://docs.aws.amazon.com/batch/latest/APIReference/API_SubmitJob.html) API submits an AWS Batch job from a job definition. + +```ts +import batch = require('@aws-cdk/aws-batch'); + +const batchQueue = new batch.JobQueue(this, 'JobQueue', { + computeEnvironments: [ + { + order: 1, + computeEnvironment: new batch.ComputeEnvironment(this, 'ComputeEnv', { + computeResources: { vpc }, + }), + }, + ], +}); + +const batchJobDefinition = new batch.JobDefinition(this, 'JobDefinition', { + container: { + image: ecs.ContainerImage.fromAsset(path.resolve(__dirname, 'batchjob-image')), + }, +}); + +const task = new sfn.Task(this, 'Submit Job', { + task: new tasks.RunBatchJob({ + jobDefinition: batchJobDefinition, + jobName: 'MyJob', + jobQueue: batchQueue, + }), +}); +``` + +## DynamoDB + +You can call DynamoDB APIs from a `Task` state. +Read more about calling DynamoDB APIs [here](https://docs.aws.amazon.com/step-functions/latest/dg/connect-ddb.html) + +### GetItem + +The [GetItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html) operation returns a set of attributes for the item with the given primary key. + +```ts +new sfn.Task(this, 'Get Item', { + task: tasks.CallDynamoDB.getItem({ + partitionKey: { + name: 'messageId', + value: new tasks.DynamoAttributeValue().withS('message-007'), + }, + tableName: 'my-table', + }), +}); +``` + +### PutItem + +The [PutItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html) operation creates a new item, or replaces an old item with a new item. + +```ts +new sfn.Task(this, 'PutItem', { + task: tasks.CallDynamoDB.putItem({ + item: { + MessageId: new tasks.DynamoAttributeValue().withS('message-007'), + Text: new tasks.DynamoAttributeValue().withS(sfn.Data.stringAt('$.bar')), + TotalCount: new tasks.DynamoAttributeValue().withN('10'), + }, + tableName: 'my-table', + }), +}); +``` + +### DeleteItem + +The [DeleteItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DeleteItem.html) operation deletes a single item in a table by primary key. + +```ts +new sfn.Task(this, 'DeleteItem', { + task: tasks.CallDynamoDB.deleteItem({ + partitionKey: { + name: 'MessageId', + value: new tasks.DynamoAttributeValue().withS('message-007'), + }, + tableName: 'my-table', + }), + resultPath: 'DISCARD', +}); +``` + +### UpdateItem + +The [UpdateItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html) operation edits an existing item's attributes, or adds a new item +to the table if it does not already exist. + +```ts +const updateItemTask = new sfn.Task(this, 'UpdateItem', { + task: tasks.CallDynamoDB.updateItem({ + partitionKey: { + name: 'MessageId', + value: new tasks.DynamoAttributeValue().withS('message-007'), + }, + tableName: 'my-table', + expressionAttributeValues: { + ':val': new tasks.DynamoAttributeValue().withN(sfn.Data.stringAt('$.Item.TotalCount.N')), + ':rand': new tasks.DynamoAttributeValue().withN('20'), + }, + updateExpression: 'SET TotalCount = :val + :rand', + }), +}); +``` + +## ECS + +Step Functions supports [ECS/Fargate](https://docs.aws.amazon.com/step-functions/latest/dg/connect-ecs.html) through the service integration pattern. + +### RunTask + +[RunTask](https://docs.aws.amazon.com/step-functions/latest/dg/connect-ecs.html) starts a new task using the specified task definition. + +```ts +import ecs = require('@aws-cdk/aws-ecs'); + +// See examples in ECS library for initialization of 'cluster' and 'taskDefinition' + +new ecs.RunEcsFargateTask({ + cluster, + taskDefinition, + containerOverrides: [ + { + containerName: 'TheContainer', + environment: [ + { + name: 'CONTAINER_INPUT', + value: Data.stringAt('$.valueFromStateData'), + } + ] + } + ] +}); + +fargateTask.connections.allowToDefaultPort(rdsCluster, 'Read the database'); + +new sfn.Task(this, 'CallFargate', { + task: fargateTask +}); +``` + +## EMR + +Step Functions supports Amazon EMR through the service integration pattern. +The service integration APIs correspond to Amazon EMR APIs but differ in the +parameters that are used. + +[Read more](https://docs.aws.amazon.com/step-functions/latest/dg/connect-emr.html) about the differences when using these service integrations. + +### Create Cluster + +Creates and starts running a cluster (job flow). +Corresponds to the [`runJobFlow`](https://docs.aws.amazon.com/emr/latest/APIReference/API_RunJobFlow.html) API in EMR. + +```ts + +const clusterRole = new iam.Role(stack, 'ClusterRole', { + assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com'), +}); + +const serviceRole = new iam.Role(stack, 'ServiceRole', { + assumedBy: new iam.ServicePrincipal('elasticmapreduce.amazonaws.com'), +}); + +const autoScalingRole = new iam.Role(stack, 'AutoScalingRole', { + assumedBy: new iam.ServicePrincipal('elasticmapreduce.amazonaws.com'), +}); + +autoScalingRole.assumeRolePolicy?.addStatements( + new iam.PolicyStatement({ + effect: iam.Effect.ALLOW, + principals: [ + new iam.ServicePrincipal('application-autoscaling.amazonaws.com'), + ], + actions: [ + 'sts:AssumeRole', + ], + }); +) + +new sfn.Task(stack, 'Create Cluster', { + task: new tasks.EmrCreateCluster({ + instances: {}, + clusterRole, + name: sfn.TaskInput.fromDataAt('$.ClusterName').value, + serviceRole, + autoScalingRole, + integrationPattern: sfn.ServiceIntegrationPattern.FIRE_AND_FORGET, + }), +}); +``` + +### Termination Protection + +Locks a cluster (job flow) so the EC2 instances in the cluster cannot be +terminated by user intervention, an API call, or a job-flow error. + +Corresponds to the [`setTerminationProtection`](https://docs.aws.amazon.com/step-functions/latest/dg/connect-emr.html) API in EMR. + +```ts +new sfn.Task(stack, 'Task', { + task: new tasks.EmrSetClusterTerminationProtection({ + clusterId: 'ClusterId', + terminationProtected: false, + }), +}); +``` + +### Terminate Cluster + +Shuts down a cluster (job flow). +Corresponds to the [`terminateJobFlows`](https://docs.aws.amazon.com/emr/latest/APIReference/API_TerminateJobFlows.html) API in EMR. + +```ts +new sfn.Task(stack, 'Task', { + task: new tasks.EmrTerminateCluster({ + clusterId: 'ClusterId' + }), +}); +``` + +### Add Step + +Adds a new step to a running cluster. +Corresponds to the [`addJobFlowSteps`](https://docs.aws.amazon.com/emr/latest/APIReference/API_AddJobFlowSteps.html) API in EMR. + +```ts +new sfn.Task(stack, 'Task', { + task: new tasks.EmrAddStep({ + clusterId: 'ClusterId', + name: 'StepName', + jar: 'Jar', + actionOnFailure: tasks.ActionOnFailure.CONTINUE, + }), +}); +``` + +### Cancel Step + +Cancels a pending step in a running cluster. +Corresponds to the [`cancelSteps`](https://docs.aws.amazon.com/emr/latest/APIReference/API_CancelSteps.html) API in EMR. + +```ts +new sfn.Task(stack, 'Task', { + task: new tasks.EmrCancelStep({ + clusterId: 'ClusterId', + stepId: 'StepId', + }), +}); +``` + +### Modify Instance Fleet + +Modifies the target On-Demand and target Spot capacities for the instance +fleet with the specified InstanceFleetName. + +Corresponds to the [`modifyInstanceFleet`](https://docs.aws.amazon.com/emr/latest/APIReference/API_ModifyInstanceFleet.html) API in EMR. + +```ts +new sfn.Task(stack, 'Task', { + task: new tasks.EmrModifyInstanceFleetByName({ + clusterId: 'ClusterId', + instanceFleetName: 'InstanceFleetName', + targetOnDemandCapacity: 2, + targetSpotCapacity: 0, + }), +}); +``` + +### Modify Instance Group + +Modifies the number of nodes and configuration settings of an instance group. + +Corresponds to the [`modifyInstanceGroups`](https://docs.aws.amazon.com/emr/latest/APIReference/API_ModifyInstanceGroups.html) API in EMR. + +```ts +new sfn.Task(stack, 'Task', { + task: new tasks.EmrModifyInstanceGroupByName({ + clusterId: 'ClusterId', + instanceGroupName: sfn.Data.stringAt('$.InstanceGroupName'), + instanceGroup: { + instanceCount: 1, + }, + }), +}); +``` + +## Glue + +Step Functions supports [AWS Glue](https://docs.aws.amazon.com/step-functions/latest/dg/connect-glue.html) through the service integration pattern. + +You can call the [`StartJobRun`](https://docs.aws.amazon.com/glue/latest/dg/aws-glue-api-jobs-runs.html#aws-glue-api-jobs-runs-StartJobRun) API from a `Task` state. + +```ts +new sfn.Task(stack, 'Task', { + task: new tasks.RunGlueJobTask(jobName, { + arguments: { + key: 'value', + }, + timeout: cdk.Duration.minutes(30), + notifyDelayAfter: cdk.Duration.minutes(5), + }), +}); +``` + +## Lambda + +[Invoke](https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html) a Lambda function. + +You can specify the input to your Lambda function through the `payload` attribute. +By default, Step Functions invokes Lambda function with the state input (JSON path '$') +as the input. + +The following snippet invokes a Lambda Function with the state input as the payload +by referencing the `$` path. + +```ts +new sfn.Task(this, 'Invoke with state input'); +``` + +When a function is invoked, the Lambda service sends [these response +elements](https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html#API_Invoke_ResponseElements) +back. + +⚠️ The response from the Lambda function is in an attribute called `Payload` + +The following snippet invokes a Lambda Function by referencing the `$.Payload` path +to reference the output of a Lambda executed before it. + +```ts +new sfn.Task(this, 'Invoke with empty object as payload', { + task: new tasks.RunLambdaTask(myLambda, { + payload: sfn.TaskInput.fromObject({}) + }), +}); + +new sfn.Task(this, 'Invoke with payload field in the state input', { + task: new tasks.RunLambdaTask(myOtherLambda, { + payload: sfn.TaskInput.fromDataAt('$.Payload'), + }), +}); +``` + +The following snippet invokes a Lambda and sets the task output to only include +the Lambda function response. + +```ts +new sfn.Task(this, 'Invoke and set function response as task output', { + task: new tasks.RunLambdaTask(myLambda, { + payload: sfn.TaskInput.fromDataAt('$'), + }), + outputPath: '$.Payload', +}); +``` + +You can have Step Functions pause a task, and wait for an external process to +return a task token. Read more about the [callback pattern](https://docs.aws.amazon.com/step-functions/latest/dg/callback-task-sample-sqs.html#call-back-lambda-example) + +To use the callback pattern, set the `token` property on the task. Call the Step +Functions `SendTaskSuccess` or `SendTaskFailure` APIs with the token to +indicate that the task has completed and the state machine should resume execution. + +The following snippet invokes a Lambda with the task token as part of the input +to the Lambda. + +```ts + const task = new sfn.Task(stack, 'Invoke with callback', { + task: new tasks.RunLambdaTask(myLambda, { + integrationPattern: sfn.ServiceIntegrationPattern.WAIT_FOR_TASK_TOKEN, + payload: { + token: sfn.Context.taskToken, + input: sfn.TaskInput.fromDataAt('$.someField'), + } + }) + }); +``` + +⚠️ The task will pause until it receives that task token back with a `SendTaskSuccess` or `SendTaskFailure` +call. Learn more about [Callback with the Task +Token](https://docs.aws.amazon.com/step-functions/latest/dg/connect-to-resource.html#connect-wait-token). + +## SageMaker + +Step Functions supports [AWS SageMaker](https://docs.aws.amazon.com/step-functions/latest/dg/connect-sagemaker.html) through the service integration pattern. + +### Create Training Job + +You can call the [`CreateTrainingJob`](https://docs.aws.amazon.com/sagemaker/latest/dg/API_CreateTrainingJob.html) API from a `Task` state. + +```ts +new sfn.Task(stack, 'TrainSagemaker', { + task: new tasks.SagemakerTrainTask({ + trainingJobName: sfn.Data.stringAt('$.JobName'), + role, + algorithmSpecification: { + algorithmName: 'BlazingText', + trainingInputMode: tasks.InputMode.FILE, + }, + inputDataConfig: [ + { + channelName: 'train', + dataSource: { + s3DataSource: { + s3DataType: tasks.S3DataType.S3_PREFIX, + s3Location: tasks.S3Location.fromJsonExpression('$.S3Bucket'), + }, + }, + }, + ], + outputDataConfig: { + s3OutputLocation: tasks.S3Location.fromBucket(s3.Bucket.fromBucketName(stack, 'Bucket', 'mybucket'), 'myoutputpath'), + }, + resourceConfig: { + instanceCount: 1, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.P3, ec2.InstanceSize.XLARGE2), + volumeSizeInGB: 50, + }, + stoppingCondition: { + maxRuntime: cdk.Duration.hours(1), + }, + }), +}); +``` + +### Create Transform Job + +You can call the [`CreateTransformJob`](https://docs.aws.amazon.com/sagemaker/latest/dg/API_CreateTransformJob.html) API from a `Task` state. + +```ts +const transformJob = new tasks.SagemakerTransformTask( + transformJobName: "MyTransformJob", + modelName: "MyModelName", + role, + transformInput: { + transformDataSource: { + s3DataSource: { + s3Uri: 's3://inputbucket/train', + s3DataType: S3DataType.S3Prefix, + } + } + }, + transformOutput: { + s3OutputPath: 's3://outputbucket/TransformJobOutputPath', + }, + transformResources: { + instanceCount: 1, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.M4, ec2.InstanceSize.XLarge), +}); + +const task = new sfn.Task(this, 'Batch Inference', { + task: transformJob +}); +``` + +## SNS + +Step Functions supports [Amazon SNS](https://docs.aws.amazon.com/step-functions/latest/dg/connect-sns.html) through the service integration pattern. + +You can call the [`Publish`](https://docs.aws.amazon.com/sns/latest/api/API_Publish.html) API from a `Task` state to publish to an SNS topic. + +```ts +import sns = require('@aws-cdk/aws-sns'); + +// ... + +const topic = new sns.Topic(this, 'Topic'); + +// Use a field from the execution data as message. +const task1 = new sfn.Task(this, 'Publish1', { + task: new tasks.PublishToTopic(topic, { + integrationPattern: sfn.ServiceIntegrationPattern.FIRE_AND_FORGET, + message: TaskInput.fromDataAt('$.state.message'), + }) +}); + +// Combine a field from the execution data with +// a literal object. +const task2 = new sfn.Task(this, 'Publish2', { + task: new tasks.PublishToTopic(topic, { + message: TaskInput.fromObject({ + field1: 'somedata', + field2: Data.stringAt('$.field2'), + }) + }) +}); +``` + +## Step Functions + +You can manage [AWS Step Functions](https://docs.aws.amazon.com/step-functions/latest/dg/connect-stepfunctions.html) executions. + +AWS Step Functions supports it's own [`StartExecution`](https://docs.aws.amazon.com/step-functions/latest/apireference/API_StartExecution.html) API as a service integration. + +```ts +// Define a state machine with one Pass state +const child = new sfn.StateMachine(stack, 'ChildStateMachine', { + definition: sfn.Chain.start(new sfn.Pass(stack, 'PassState')), +}); + +// Include the state machine in a Task state with callback pattern +const task = new sfn.Task(stack, 'ChildTask', { + task: new tasks.ExecuteStateMachine(child, { + integrationPattern: sfn.ServiceIntegrationPattern.WAIT_FOR_TASK_TOKEN, + input: { + token: sfn.Context.taskToken, + foo: 'bar' + }, + name: 'MyExecutionName' + }) +}); + +// Define a second state machine with the Task state above +new sfn.StateMachine(stack, 'ParentStateMachine', { + definition: task +}); +``` + +## SQS + +Step Functions supports [Amazon SQS](https://docs.aws.amazon.com/step-functions/latest/dg/connect-sqs.html) + +You can call the [`SendMessage`](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html) API from a `Task` state +to send a message to an SQS queue. + +```ts +import sqs = require('@aws-cdk/aws-sqs'); + +// ... + +const queue = new sns.Queue(this, 'Queue'); + +// Use a field from the execution data as message. +const task1 = new sfn.Task(this, 'Send1', { + task: new tasks.SendToQueue(queue, { + messageBody: TaskInput.fromDataAt('$.message'), + // Only for FIFO queues + messageGroupId: '1234' + }) +}); + +// Combine a field from the execution data with +// a literal object. +const task2 = new sfn.Task(this, 'Send2', { + task: new tasks.SendToQueue(queue, { + messageBody: TaskInput.fromObject({ + field1: 'somedata', + field2: Data.stringAt('$.field2'), + }), + // Only for FIFO queues + messageGroupId: '1234' + }) +}); +``` diff --git a/packages/@aws-cdk/aws-stepfunctions/README.md b/packages/@aws-cdk/aws-stepfunctions/README.md index 78233bd085c17..21b3b62cc3fad 100644 --- a/packages/@aws-cdk/aws-stepfunctions/README.md +++ b/packages/@aws-cdk/aws-stepfunctions/README.md @@ -124,460 +124,11 @@ information, see the States Language spec. A `Task` represents some work that needs to be done. The exact work to be done is determine by a class that implements `IStepFunctionsTask`, a collection -of which can be found in the `@aws-cdk/aws-stepfunctions-tasks` package. A -couple of the tasks available are: - -* `tasks.InvokeActivity` -- start an Activity (Activities represent a work - queue that you poll on a compute fleet you manage yourself) -* `tasks.RunBatchJob` -- run a Batch job -* `tasks.RunLambdaTask` -- call Lambda as integrated service with magic ARN -* `tasks.RunGlueJobTask` -- call Glue Job as integrated service -* `tasks.PublishToTopic` -- publish a message to an SNS topic -* `tasks.SendToQueue` -- send a message to an SQS queue -* `tasks.RunEcsFargateTask`/`ecs.RunEcsEc2Task` -- run a container task, - depending on the type of capacity. -* `tasks.SagemakerTrainTask` -- run a SageMaker training job -* `tasks.SagemakerTransformTask` -- run a SageMaker transform job -* `tasks.StartExecution` -- call StartExecution to a state machine of Step Functions -* `tasks.EvaluateExpression` -- evaluate an expression referencing state paths -* `tasks.CallDynamoDB` -- call GetItem, PutItem, DeleteItem and UpdateItem APIs of DynamoDB - -Except `tasks.InvokeActivity`, the [service integration -pattern](https://docs.aws.amazon.com/step-functions/latest/dg/connect-to-resource.html) -(`integrationPattern`) is supposed to be provided as a parameter when customers want -to call integrated services within a Task state. The default value is `FIRE_AND_FORGET`. - -#### Task parameters from the state json - -Many tasks take parameters. The values for those can either be supplied -directly in the workflow definition (by specifying their values), or at -runtime by passing a value obtained from the static functions on `Data`, -such as `Data.stringAt()`. - -If so, the value is taken from the indicated location in the state JSON, -similar to (for example) `inputPath`. - -#### Lambda example - -[Invoke](https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html) a Lambda function. - -You can specify the input to your Lambda function through the `payload` attribute. -By default, Step Functions invokes Lambda function with the state input (JSON path '$') -as the input. - -The following snippet invokes a Lambda Function with the state input as the payload -by referencing the `$` path. +of which can be found in the `@aws-cdk/aws-stepfunctions-tasks` module. -```ts -new sfn.Task(this, 'Invoke with state input'); -``` - -When a function is invoked, the Lambda service sends [these response -elements](https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html#API_Invoke_ResponseElements) -back. - -⚠️ The response from the Lambda function is in an attribute called `Payload` - -The following snippet invokes a Lambda Function by referencing the `$.Payload` path -to reference the output of a Lambda executed before it. - -```ts -new sfn.Task(this, 'Invoke with empty object as payload', { - task: new tasks.RunLambdaTask(myLambda, { - payload: sfn.TaskInput.fromObject({}) - }), -}); - -new sfn.Task(this, 'Invoke with payload field in the state input', { - task: new tasks.RunLambdaTask(myOtherLambda, { - payload: sfn.TaskInput.fromDataAt('$.Payload'), - }), -}); -``` - -The following snippet invokes a Lambda and sets the task output to only include -the Lambda function response. - -```ts -new sfn.Task(this, 'Invoke and set function response as task output', { - task: new tasks.RunLambdaTask(myLambda, { - payload: sfn.TaskInput.fromDataAt('$'), - }), - outputPath: '$.Payload', -}); -``` - -You can have Step Functions pause a task, and wait for an external process to -return a task token. Read more about the [callback pattern](https://docs.aws.amazon.com/step-functions/latest/dg/callback-task-sample-sqs.html#call-back-lambda-example) - -To use the callback pattern, set the `token` property on the task. Call the Step -Functions `SendTaskSuccess` or `SendTaskFailure` APIs with the token to -indicate that the task has completed and the state machine should resume execution. - -The following snippet invokes a Lambda with the task token as part of the input -to the Lambda. - -```ts - const task = new sfn.Task(stack, 'Invoke with callback', { - task: new tasks.RunLambdaTask(myLambda, { - integrationPattern: sfn.ServiceIntegrationPattern.WAIT_FOR_TASK_TOKEN, - payload: { - token: sfn.Context.taskToken, - input: sfn.TaskInput.fromDataAt('$.someField'), - } - }) - }); -``` - -⚠️ The task will pause until it receives that task token back with a `SendTaskSuccess` or `SendTaskFailure` -call. Learn more about [Callback with the Task -Token](https://docs.aws.amazon.com/step-functions/latest/dg/connect-to-resource.html#connect-wait-token). - -#### Glue Job example - -```ts - const task = new sfn.Task(stack, 'ETL', { - task: new tasks.RunGlueJobTask(glueJobName, { - integrationPattern: sfn.ServiceIntegrationPattern.SYNC, - arguments: { - "--table-prefix": "myTable" - } - }) - }); -``` - -[Example CDK app](../aws-stepfunctions-tasks/test/integ.glue-task.ts) - -#### Batch example - -```ts -import batch = require('@aws-cdk/aws-batch'); - -const batchQueue = new batch.JobQueue(this, 'JobQueue', { - computeEnvironments: [ - { - order: 1, - computeEnvironment: new batch.ComputeEnvironment(this, 'ComputeEnv', { - computeResources: { vpc } - }) - } - ] -}); - -const batchJobDefinition = new batch.JobDefinition(this, 'JobDefinition', { - container: { - image: ecs.ContainerImage.fromAsset( - path.resolve(__dirname, 'batchjob-image') - ) - } -}); - -const task = new sfn.Task(this, 'Submit Job', { - task: new tasks.RunBatchJob({ - jobDefinition: batchJobDefinition, - jobName: 'MyJob', - jobQueue: batchQueue - }) -}); -``` - -#### SNS example - -```ts -import sns = require('@aws-cdk/aws-sns'); - -// ... - -const topic = new sns.Topic(this, 'Topic'); - -// Use a field from the execution data as message. -const task1 = new sfn.Task(this, 'Publish1', { - task: new tasks.PublishToTopic(topic, { - integrationPattern: sfn.ServiceIntegrationPattern.FIRE_AND_FORGET, - message: TaskInput.fromDataAt('$.state.message'), - }) -}); - -// Combine a field from the execution data with -// a literal object. -const task2 = new sfn.Task(this, 'Publish2', { - task: new tasks.PublishToTopic(topic, { - message: TaskInput.fromObject({ - field1: 'somedata', - field2: Data.stringAt('$.field2'), - }) - }) -}); -``` - -#### SQS example - -```ts -import sqs = require('@aws-cdk/aws-sqs'); - -// ... - -const queue = new sns.Queue(this, 'Queue'); - -// Use a field from the execution data as message. -const task1 = new sfn.Task(this, 'Send1', { - task: new tasks.SendToQueue(queue, { - messageBody: TaskInput.fromDataAt('$.message'), - // Only for FIFO queues - messageGroupId: '1234' - }) -}); - -// Combine a field from the execution data with -// a literal object. -const task2 = new sfn.Task(this, 'Send2', { - task: new tasks.SendToQueue(queue, { - messageBody: TaskInput.fromObject({ - field1: 'somedata', - field2: Data.stringAt('$.field2'), - }), - // Only for FIFO queues - messageGroupId: '1234' - }) -}); -``` - -#### ECS example - -```ts -import ecs = require('@aws-cdk/aws-ecs'); - -// See examples in ECS library for initialization of 'cluster' and 'taskDefinition' - -const fargateTask = new ecs.RunEcsFargateTask({ - cluster, - taskDefinition, - containerOverrides: [ - { - containerName: 'TheContainer', - environment: [ - { - name: 'CONTAINER_INPUT', - value: Data.stringAt('$.valueFromStateData') - } - ] - } - ] -}); - -fargateTask.connections.allowToDefaultPort(rdsCluster, 'Read the database'); - -const task = new sfn.Task(this, 'CallFargate', { - task: fargateTask -}); -``` - -#### SageMaker Transform example - -```ts -const transformJob = new tasks.SagemakerTransformTask( - transformJobName: "MyTransformJob", - modelName: "MyModelName", - role, - transformInput: { - transformDataSource: { - s3DataSource: { - s3Uri: 's3://inputbucket/train', - s3DataType: S3DataType.S3Prefix, - } - } - }, - transformOutput: { - s3OutputPath: 's3://outputbucket/TransformJobOutputPath', - }, - transformResources: { - instanceCount: 1, - instanceType: ec2.InstanceType.of(ec2.InstanceClass.M4, ec2.InstanceSize.XLarge), -}); - -const task = new sfn.Task(this, 'Batch Inference', { - task: transformJob -}); -``` - -#### Step Functions example - -```ts -// Define a state machine with one Pass state -const child = new sfn.StateMachine(stack, 'ChildStateMachine', { - definition: sfn.Chain.start(new sfn.Pass(stack, 'PassState')), -}); - -// Include the state machine in a Task state with callback pattern -const task = new sfn.Task(stack, 'ChildTask', { - task: new tasks.ExecuteStateMachine(child, { - integrationPattern: sfn.ServiceIntegrationPattern.WAIT_FOR_TASK_TOKEN, - input: { - token: sfn.Context.taskToken, - foo: 'bar' - }, - name: 'MyExecutionName' - }) -}); - -// Define a second state machine with the Task state above -new sfn.StateMachine(stack, 'ParentStateMachine', { - definition: task -}); -``` - -#### Eval example - -Use the `EvaluateExpression` to perform simple operations referencing state paths. The -`expression` referenced in the task will be evaluated in a Lambda function -(`eval()`). This allows you to not have to write Lambda code for simple operations. - -Example: convert a wait time from milliseconds to seconds, concat this in a message and wait: - -```ts -const convertToSeconds = new sfn.Task(this, 'Convert to seconds', { - task: new tasks.EvaluateExpression({ expression: '$.waitMilliseconds / 1000' }), - resultPath: '$.waitSeconds' -}); - -const createMessage = new sfn.Task(this, 'Create message', { - // Note: this is a string inside a string. - task: new tasks.EvaluateExpression({ expression: '`Now waiting ${$.waitSeconds} seconds...`'}), - resultPath: '$.message' -}); - -const publishMessage = new sfn.Task(this, 'Publish message', { - task: new tasks.PublishToTopic(topic, { - message: sfn.TaskInput.fromDataAt('$.message'), - }), - resultPath: '$.sns' -}); - -const wait = new sfn.Wait(this, 'Wait', { - time: sfn.WaitTime.secondsPath('$.waitSeconds') -}); - -new sfn.StateMachine(this, 'StateMachine', { - definition: convertToSeconds - .next(createMessage) - .next(publishMessage) - .next(wait) -}); -``` - -The `EvaluateExpression` supports a `runtime` prop to specify the Lambda -runtime to use to evaluate the expression. Currently, the only runtime -supported is `lambda.Runtime.NODEJS_10_X`. - -#### DynamoDB example - -##### PutItem - -```ts -const TABLE_NAME = 'Messages'; -const MESSAGE_ID = `1234`; -const firstNumber = 18; -const secondNumber = 24; - -const putItemTask = new sfn.Task(this, 'PutItem', { - task: tasks.CallDynamoDB.putItem({ - item: { - MessageId: new tasks.DynamoAttributeValue().withS(MESSAGE_ID), - Text: new tasks.DynamoAttributeValue().withS( - sfn.Data.stringAt('$.bar') - ), - TotalCount: new tasks.DynamoAttributeValue().withN(`${firstNumber}`) - }, - tableName: TABLE_NAME - }) -}); - -const definition = new sfn.Pass(this, 'Start', { - result: sfn.Result.fromObject({ bar: 'SomeValue' }) -}) - .next(putItemTask); - -const stateMachine = new sfn.StateMachine(this, 'StateMachine', { - definition -}); -``` - -##### GetItem - -```ts -const getItemTask = new sfn.Task(this, 'GetItem', { - task: tasks.CallDynamoDB.getItem({ - partitionKey: { - name: 'MessageId', - value: new tasks.DynamoAttributeValue().withS(MESSAGE_ID) - }, - tableName: TABLE_NAME - }) -}); - -const definition = new sfn.Pass(this, 'Start', { - result: sfn.Result.fromObject({ bar: 'SomeValue' }) -}) - .next(getItemTask); - -const stateMachine = new sfn.StateMachine(this, 'StateMachine', { - definition -}); -``` - -##### UpdateItem - -```ts -const updateItemTask = new sfn.Task(this, 'UpdateItem', { - task: tasks.CallDynamoDB.updateItem({ - partitionKey: { - name: 'MessageId', - value: new tasks.DynamoAttributeValue().withS(MESSAGE_ID) - }, - tableName: TABLE_NAME, - expressionAttributeValues: { - ':val': new tasks.DynamoAttributeValue().withN( - sfn.Data.stringAt('$.Item.TotalCount.N') - ), - ':rand': new tasks.DynamoAttributeValue().withN(`${secondNumber}`) - }, - updateExpression: 'SET TotalCount = :val + :rand' - }) -}); - -const definition = new sfn.Pass(this, 'Start', { - result: sfn.Result.fromObject({ bar: 'SomeValue' }) -}) - .next(updateItemTask); - -const stateMachine = new sfn.StateMachine(this, 'StateMachine', { - definition -}); -``` - -##### DeleteItem - -```ts -const deleteItemTask = new sfn.Task(this, 'DeleteItem', { - task: tasks.CallDynamoDB.deleteItem({ - partitionKey: { - name: 'MessageId', - value: new tasks.DynamoAttributeValue().withS(MESSAGE_ID) - }, - tableName: TABLE_NAME - }), - resultPath: 'DISCARD' -}); - -const definition = new sfn.Pass(this, 'Start', { - result: sfn.Result.fromObject({ bar: 'SomeValue' }) -}) - .next(deleteItemTask); - -const stateMachine = new sfn.StateMachine(this, 'StateMachine', { - definition -}); -``` +The tasks in the `@aws-cdk/aws-stepfunctions-tasks` module support the +[service integration pattern](https://docs.aws.amazon.com/step-functions/latest/dg/connect-to-resource.html) that integrates Step Functions with services +directly in the Amazon States language. ### Pass diff --git a/packages/@aws-cdk/aws-stepfunctions/lib/types.ts b/packages/@aws-cdk/aws-stepfunctions/lib/types.ts index f911e4611bc2e..a376ace3b24ea 100644 --- a/packages/@aws-cdk/aws-stepfunctions/lib/types.ts +++ b/packages/@aws-cdk/aws-stepfunctions/lib/types.ts @@ -36,7 +36,8 @@ export interface IChainable { /** * Predefined error strings - * Error names in Amazon States Language - https://docs.aws.amazon.com/step-functions/latest/dg/concepts-error-handling.html + * Error names in Amazon States Language - https://states-language.net/spec.html#appendix-a + * Error handling in Step Functions - https://docs.aws.amazon.com/step-functions/latest/dg/concepts-error-handling.html */ export class Errors { /** @@ -66,6 +67,12 @@ export class Errors { */ public static readonly RESULT_PATH_MATCH_FAILURE = 'States.ResultPathMatchFailure'; + /** + * Within a state’s “Parameters” field, the attempt to replace a field whose + * name ends in “.$” using a Path failed. + */ + public static readonly PARAMETER_PATH_FAILURE = 'States.ParameterPathFailure'; + /** * A branch of a Parallel state failed. */ diff --git a/packages/@aws-cdk/cloudformation-diff/package.json b/packages/@aws-cdk/cloudformation-diff/package.json index 94eb4b20482b1..6fd39a0790a1e 100644 --- a/packages/@aws-cdk/cloudformation-diff/package.json +++ b/packages/@aws-cdk/cloudformation-diff/package.json @@ -42,7 +42,7 @@ "@types/string-width": "^4.0.1", "@types/table": "^4.0.7", "cdk-build-tools": "0.0.0", - "fast-check": "^1.24.1", + "fast-check": "^1.24.2", "jest": "^25.4.0", "pkglint": "0.0.0", "ts-jest": "^25.4.0" diff --git a/packages/@aws-cdk/core/lib/private/prepare-app.ts b/packages/@aws-cdk/core/lib/private/prepare-app.ts index cb268a88b4069..6912f29a9fce5 100644 --- a/packages/@aws-cdk/core/lib/private/prepare-app.ts +++ b/packages/@aws-cdk/core/lib/private/prepare-app.ts @@ -1,5 +1,6 @@ import { ConstructOrder } from 'constructs'; -import { Construct } from '../construct-compat'; +import { CfnResource } from '../cfn-resource'; +import { Construct, IConstruct } from '../construct-compat'; import { Stack } from '../stack'; import { resolveReferences } from './refs'; @@ -18,6 +19,18 @@ export function prepareApp(root: Construct) { throw new Error('prepareApp must be called on the root node'); } + // apply dependencies between resources in depending subtrees + for (const dependency of root.node.dependencies) { + const targetCfnResources = findCfnResources(dependency.target); + const sourceCfnResources = findCfnResources(dependency.source); + + for (const target of targetCfnResources) { + for (const source of sourceCfnResources) { + source.addDependsOn(target); + } + } + } + // depth-first (children first) queue of nested stacks. We will pop a stack // from the head of this queue to prepare it's template asset. const queue = findAllNestedStacks(root); @@ -60,6 +73,13 @@ function findAllNestedStacks(root: Construct) { return result; } +/** + * Find all resources in a set of constructs + */ +function findCfnResources(root: IConstruct): CfnResource[] { + return root.node.findAll().filter(CfnResource.isCfnResource); +} + interface INestedStackPrivateApi { _prepareTemplateAsset(): boolean; } diff --git a/packages/@aws-cdk/core/lib/private/runtime-info.ts b/packages/@aws-cdk/core/lib/private/runtime-info.ts index 0c7fd70845ceb..ac3d33046a74e 100644 --- a/packages/@aws-cdk/core/lib/private/runtime-info.ts +++ b/packages/@aws-cdk/core/lib/private/runtime-info.ts @@ -1,6 +1,9 @@ import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import { major as nodeMajorVersion } from './node-version'; +// list of NPM scopes included in version reporting e.g. @aws-cdk and @aws-solutions-konstruk +const WHITELIST_SCOPES = ['@aws-cdk', '@aws-solutions-konstruk']; + /** * Returns a list of loaded modules and their versions. */ @@ -14,9 +17,16 @@ export function collectRuntimeInformation(): cxschema.RuntimeInfo { } } - // include only libraries that are in the @aws-cdk npm scope + // include only libraries that are in the whitelistLibraries list for (const name of Object.keys(libraries)) { - if (!name.startsWith('@aws-cdk/')) { + let foundMatch = false; + for (const scope of WHITELIST_SCOPES) { + if (name.startsWith(`${scope}/`)) { + foundMatch = true; + } + } + + if (!foundMatch) { delete libraries[name]; } } diff --git a/packages/@aws-cdk/core/lib/stack.ts b/packages/@aws-cdk/core/lib/stack.ts index ef60c79be3374..0f50050b22dd2 100644 --- a/packages/@aws-cdk/core/lib/stack.ts +++ b/packages/@aws-cdk/core/lib/stack.ts @@ -734,19 +734,6 @@ export class Stack extends Construct implements ITaggable { * Find all dependencies as well and add the appropriate DependsOn fields. */ protected prepare() { - // Resource dependencies - for (const dependency of this.node.dependencies) { - for (const target of findCfnResources([ dependency.target ])) { - for (const source of findCfnResources([ dependency.source ])) { - source.addDependsOn(target); - } - } - } - - if (this.tags.hasTags()) { - this.node.addMetadata(cxschema.ArtifactMetadataEntryType.STACK_TAGS, this.tags.renderTags()); - } - // if this stack is a roort (e.g. in unit tests), call `prepareApp` so that // we resolve cross-references and nested stack assets. if (!this.node.scope) { @@ -771,9 +758,6 @@ export class Stack extends Construct implements ITaggable { return; } - const deps = this.dependencies.map(s => s.artifactId); - const meta = this.collectMetadata(); - // backwards compatibility since originally artifact ID was always equal to // stack name the stackName attribute is optional and if it is not specified // the CLI will use the artifact ID as the stack name. we *could have* @@ -785,11 +769,21 @@ export class Stack extends Construct implements ITaggable { ? { } : { stackName: this.stackName }; + // nested stack tags are applied at the AWS::CloudFormation::Stack resource + // level and are not needed in the cloud assembly. + // TODO: move these to the cloud assembly artifact properties instead of metadata + if (this.tags.hasTags()) { + this.node.addMetadata(cxschema.ArtifactMetadataEntryType.STACK_TAGS, this.tags.renderTags()); + } + const properties: cxapi.AwsCloudFormationStackProperties = { templateFile: this.templateFile, ...stackNameProperty, }; + const deps = this.dependencies.map(s => s.artifactId); + const meta = this.collectMetadata(); + // add an artifact that represents this stack builder.addArtifact(this.artifactId, { type: cxschema.ArtifactType.AWS_CLOUDFORMATION_STACK, @@ -1054,17 +1048,6 @@ import { IResolvable } from './resolvable'; import { ITaggable, TagManager } from './tag-manager'; import { Token } from './token'; -/** - * Find all resources in a set of constructs - */ -function findCfnResources(roots: Iterable): CfnResource[] { - const ret = new Array(); - for (const root of roots) { - ret.push(...root.node.findAll().filter(CfnResource.isCfnResource)); - } - return ret; -} - interface StackDependency { stack: Stack; reasons: string[]; diff --git a/packages/@aws-cdk/core/package.json b/packages/@aws-cdk/core/package.json index 77a8adb5f1f5d..57232866cdd3b 100644 --- a/packages/@aws-cdk/core/package.json +++ b/packages/@aws-cdk/core/package.json @@ -141,7 +141,7 @@ "@types/nodeunit": "^0.0.30", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", - "fast-check": "^1.24.1", + "fast-check": "^1.24.2", "lodash": "^4.17.15", "nodeunit": "^0.11.3", "pkglint": "0.0.0" diff --git a/packages/@aws-cdk/core/test/test.runtime-info.ts b/packages/@aws-cdk/core/test/test.runtime-info.ts new file mode 100644 index 0000000000000..fe0752f90b931 --- /dev/null +++ b/packages/@aws-cdk/core/test/test.runtime-info.ts @@ -0,0 +1,34 @@ +import * as fs from 'fs'; +import { Test } from 'nodeunit'; +import * as os from 'os'; +import * as path from 'path'; +import { collectRuntimeInformation } from '../lib/private/runtime-info'; + +export = { + 'version reporting includes @aws-solutions-konstruk libraries'(test: Test) { + const pkgdir = fs.mkdtempSync(path.join(os.tmpdir(), 'runtime-info-konstruk-fixture')); + const mockVersion = '1.2.3'; + + fs.writeFileSync(path.join(pkgdir, 'index.js'), 'module.exports = \'this is foo\';'); + fs.writeFileSync(path.join(pkgdir, 'package.json'), JSON.stringify({ + name: '@aws-solutions-konstruk/foo', + version: mockVersion, + })); + + // eslint-disable-next-line @typescript-eslint/no-require-imports, import/no-extraneous-dependencies + require(pkgdir); + + const runtimeInfo = collectRuntimeInformation(); + + // eslint-disable-next-line @typescript-eslint/no-require-imports + const version = require('../package.json').version; + test.deepEqual(runtimeInfo.libraries , { + '@aws-cdk/core': version, + '@aws-cdk/cx-api': version, + '@aws-cdk/cloud-assembly-schema': version, + '@aws-solutions-konstruk/foo': mockVersion, + 'jsii-runtime': `node.js/${process.version}`, + }); + test.done(); + }, +}; diff --git a/packages/@aws-cdk/core/test/test.stack.ts b/packages/@aws-cdk/core/test/test.stack.ts index ae8f5d1322237..569ea65860d2c 100644 --- a/packages/@aws-cdk/core/test/test.stack.ts +++ b/packages/@aws-cdk/core/test/test.stack.ts @@ -1,6 +1,8 @@ import * as cxapi from '@aws-cdk/cx-api'; import { Test } from 'nodeunit'; -import { App, CfnCondition, CfnInclude, CfnOutput, CfnParameter, CfnResource, Construct, ConstructNode, Lazy, ScopedAws, Stack, validateString } from '../lib'; +import { + App, CfnCondition, CfnInclude, CfnOutput, CfnParameter, + CfnResource, Construct, ConstructNode, Lazy, ScopedAws, Stack, Tag, validateString } from '../lib'; import { Intrinsic } from '../lib/private/intrinsic'; import { PostResolveToken } from '../lib/util'; import { toCloudFormation } from './util'; @@ -828,6 +830,29 @@ export = { ]); test.done(); }, + + 'stack tags are reflected in the stack cloud assembly artifact'(test: Test) { + // GIVEN + const app = new App({ stackTraces: false }); + const stack1 = new Stack(app, 'stack1'); + const stack2 = new Stack(stack1, 'stack2'); + + // WHEN + Tag.add(app, 'foo', 'bar'); + + // THEN + const asm = app.synth(); + const expected = [ + { + type: 'aws:cdk:stack-tags', + data: [ { key: 'foo', value: 'bar' } ], + }, + ]; + + test.deepEqual(asm.getStackArtifact(stack1.artifactId).manifest.metadata, { '/stack1': expected }); + test.deepEqual(asm.getStackArtifact(stack2.artifactId).manifest.metadata, { '/stack1/stack2': expected }); + test.done(); + }, }; class StackWithPostProcessor extends Stack { diff --git a/packages/@aws-cdk/custom-resources/package.json b/packages/@aws-cdk/custom-resources/package.json index 7f93803384392..1a990f79b8dad 100644 --- a/packages/@aws-cdk/custom-resources/package.json +++ b/packages/@aws-cdk/custom-resources/package.json @@ -73,7 +73,7 @@ "@types/aws-lambda": "^8.10.39", "@types/fs-extra": "^8.1.0", "@types/sinon": "^9.0.0", - "aws-sdk": "^2.662.0", + "aws-sdk": "^2.665.0", "aws-sdk-mock": "^5.1.0", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", diff --git a/packages/aws-cdk/bin/cdk.ts b/packages/aws-cdk/bin/cdk.ts index 41e8336ced9c0..14ab1a2d04b98 100644 --- a/packages/aws-cdk/bin/cdk.ts +++ b/packages/aws-cdk/bin/cdk.ts @@ -51,7 +51,7 @@ async function parseCommandLineArguments() { .command([ 'synthesize [STACKS..]', 'synth [STACKS..]' ], 'Synthesizes and prints the CloudFormation template for this stack', yargs => yargs .option('exclusively', { type: 'boolean', alias: 'e', desc: 'Only synthesize requested stacks, don\'t include dependencies' })) .command('bootstrap [ENVIRONMENTS..]', 'Deploys the CDK toolkit stack into an AWS environment', yargs => yargs - .option('bootstrap-bucket-name', { type: 'string', alias: ['b', 'toolkit-bucket-name'], desc: 'The name of the CDK toolkit bucket', default: undefined }) + .option('bootstrap-bucket-name', { type: 'string', alias: ['b', 'toolkit-bucket-name'], desc: 'The name of the CDK toolkit bucket; bucket will be created and must not exist', default: undefined }) .option('bootstrap-kms-key-id', { type: 'string', desc: 'AWS KMS master key ID used for the SSE-KMS encryption', default: undefined }) .option('tags', { type: 'array', alias: 't', desc: 'Tags to add for the stack (KEY=VALUE)', nargs: 1, requiresArg: true, default: [] }) .option('execute', {type: 'boolean', desc: 'Whether to execute ChangeSet (--no-execute will NOT execute the ChangeSet)', default: true}) @@ -111,8 +111,11 @@ async function initCommandLine() { debug('CDK toolkit version:', version.DISPLAY_VERSION); debug('Command line arguments:', argv); + const configuration = new Configuration(argv); + await configuration.load(); + const sdkProvider = await SdkProvider.withAwsCliCompatibleDefaults({ - profile: argv.profile, + profile: configuration.settings.get(['profile']), ec2creds: argv.ec2creds, httpOptions: { proxyAddress: argv.proxy, @@ -120,9 +123,6 @@ async function initCommandLine() { }, }); - const configuration = new Configuration(argv); - await configuration.load(); - const cloudFormation = new CloudFormationDeployments({ sdkProvider }); const cloudExecutable = new CloudExecutable({ diff --git a/packages/aws-cdk/lib/settings.ts b/packages/aws-cdk/lib/settings.ts index 923c90d20afa7..93e37e9d3eab3 100644 --- a/packages/aws-cdk/lib/settings.ts +++ b/packages/aws-cdk/lib/settings.ts @@ -193,6 +193,7 @@ export class Settings { language: argv.language, pathMetadata: argv.pathMetadata, assetMetadata: argv.assetMetadata, + profile: argv.profile, plugin: argv.plugin, requireApproval: argv.requireApproval, toolkitStackName: argv.toolkitStackName, diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index a068a1507db57..b1f26fb45514e 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -68,7 +68,7 @@ "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/region-info": "0.0.0", "archiver": "^4.0.1", - "aws-sdk": "^2.662.0", + "aws-sdk": "^2.665.0", "camelcase": "^6.0.0", "cdk-assets": "0.0.0", "colors": "^1.4.0", diff --git a/packages/cdk-assets/lib/private/archive.ts b/packages/cdk-assets/lib/private/archive.ts index 2474e16d8b83d..802a9abac90fb 100644 --- a/packages/cdk-assets/lib/private/archive.ts +++ b/packages/cdk-assets/lib/private/archive.ts @@ -21,6 +21,12 @@ export function zipDirectory(directory: string, outputFile: string): Promise