diff --git a/.github/workflows/auto-approve-v2-merge-forward.yml b/.github/workflows/auto-approve-v2-merge-forward.yml new file mode 100644 index 0000000000000..96dd3d0837e6e --- /dev/null +++ b/.github/workflows/auto-approve-v2-merge-forward.yml @@ -0,0 +1,26 @@ +# Automatically approve PRs that merge master forward to v2-main +# +# Only does approvals! mergify takes care of the actual merge. +name: Auto-approve forward merges onto v2-main +on: + pull_request: + types: + - labeled + - opened + - ready_for_review + - reopened + - synchronize + - unlabeled + - unlocked + +jobs: + approve: + runs-on: ubuntu-latest + steps: + - uses: hmarr/auto-approve-action@v2.0.0 + if: > + github.event.pull_request.user.login == 'aws-cdk-automation' + && github.event.pull_request.base.ref == 'v2-main' + && contains(github.event.pull_request.labels.*.name, 'pr/forward-merge') + with: + github-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.mergify.yml b/.mergify.yml index ee41466232847..f91085a78d7a8 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -119,3 +119,20 @@ pull_request_rules: - "#changes-requested-reviews-by=0" - status-success~=AWS CodeBuild us-east-1 - status-success=validate-pr + - name: automatic merge of v2 forward merges + actions: + comment: + message: Forward merge successful! + merge: + method: merge + strict: smart+fasttrack + strict_method: merge + commit_message: title+body + conditions: + - label~=forward-merge + - -label~=(blocked|do-not-merge) + - -merged + - -closed + - author~=aws-cdk-automation + - "#approved-reviews-by>=1" + - status-success~=AWS CodeBuild us-east-1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 33bbd686b3017..c6e4036694ea6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,22 @@ 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.69.0](https://github.com/aws/aws-cdk/compare/v1.68.0...v1.69.0) (2020-10-19) + + +### Features + +* **apigatewayv2:** configure description for HttpApi ([#10863](https://github.com/aws/aws-cdk/issues/10863)) ([895372f](https://github.com/aws/aws-cdk/commit/895372fc8b027bd12d64450c429c04d8efdd27f4)) +* **pipelines:** temporarily disable self-mutation ([#10466](https://github.com/aws/aws-cdk/issues/10466)) ([8ffabb4](https://github.com/aws/aws-cdk/commit/8ffabb4325d2853f8650f991706eccfe233b2c74)) + + +### Bug Fixes + +* **apigateway:** cannot configure stage for SpecRestApi ([#10749](https://github.com/aws/aws-cdk/issues/10749)) ([62a2286](https://github.com/aws/aws-cdk/commit/62a2286f6dc46059160daa3c7466e712dad9f136)), closes [#10300](https://github.com/aws/aws-cdk/issues/10300) +* **apigateway:** lambda integration does not recognize allowTestInvoke ([#10828](https://github.com/aws/aws-cdk/issues/10828)) ([650c23f](https://github.com/aws/aws-cdk/commit/650c23f1fe9e87a7b1eb521faf57c7ed341d0eb6)), closes [#7605](https://github.com/aws/aws-cdk/issues/7605) [#7604](https://github.com/aws/aws-cdk/issues/7604) +* **cli:** `cdk context --reset ` does not work ([#10753](https://github.com/aws/aws-cdk/issues/10753)) ([2f3a167](https://github.com/aws/aws-cdk/commit/2f3a167797e60fd2df6c83bc2f3906ddc8eb8966)), closes [#3033](https://github.com/aws/aws-cdk/issues/3033) [#10619](https://github.com/aws/aws-cdk/issues/10619) +* **cli:** failure if account cache is malformed ([#10887](https://github.com/aws/aws-cdk/issues/10887)) ([9b2438a](https://github.com/aws/aws-cdk/commit/9b2438a6e78fc7a9622e79b1435ea6f8b76d98f7)) + ## [1.68.0](https://github.com/aws/aws-cdk/compare/v1.67.0...v1.68.0) (2020-10-15) diff --git a/build.sh b/build.sh index a17b80797c8ec..13d525731b16e 100755 --- a/build.sh +++ b/build.sh @@ -37,6 +37,11 @@ done export PATH=$(npm bin):$PATH export NODE_OPTIONS="--max-old-space-size=4096 ${NODE_OPTIONS:-}" +if ! [ -x "$(command -v yarn)" ]; then + echo "yarn is not installed. Install it from here- https://yarnpkg.com/en/docs/install." + exit 1 +fi + echo "=============================================================================================" echo "installing..." yarn install --frozen-lockfile --network-timeout 1000000 @@ -65,11 +70,6 @@ rm -rf $BUILD_INDICATOR export MERKLE_BUILD_CACHE=$(mktemp -d) trap "rm -rf $MERKLE_BUILD_CACHE" EXIT -if ! [ -x "$(command -v yarn)" ]; then - echo "yarn is not installed. Install it from here- https://yarnpkg.com/en/docs/install." - exit 1 -fi - echo "=============================================================================================" echo "building..." time lerna run $bail --stream $runtarget || fail diff --git a/lerna.json b/lerna.json index 7932a30853ba8..b19998dd19695 100644 --- a/lerna.json +++ b/lerna.json @@ -11,5 +11,5 @@ "tools/*" ], "rejectCycles": "true", - "version": "1.68.0" + "version": "1.69.0" } diff --git a/packages/@aws-cdk/alexa-ask/package.json b/packages/@aws-cdk/alexa-ask/package.json index 8435ce066a29c..26aaaf75630b6 100644 --- a/packages/@aws-cdk/alexa-ask/package.json +++ b/packages/@aws-cdk/alexa-ask/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "Alexa::ASK", diff --git a/packages/@aws-cdk/aws-accessanalyzer/package.json b/packages/@aws-cdk/aws-accessanalyzer/package.json index cba163f1e1914..530a3eddf7014 100644 --- a/packages/@aws-cdk/aws-accessanalyzer/package.json +++ b/packages/@aws-cdk/aws-accessanalyzer/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "compat": "cdk-compat", "build+test": "npm run build && npm test", - "build+test+package": "npm run build+test && npm run package" + "build+test+package": "npm run build+test && npm run package", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::AccessAnalyzer", diff --git a/packages/@aws-cdk/aws-acmpca/package.json b/packages/@aws-cdk/aws-acmpca/package.json index 7941394fee2af..c1b3fb93577e8 100644 --- a/packages/@aws-cdk/aws-acmpca/package.json +++ b/packages/@aws-cdk/aws-acmpca/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::ACMPCA", diff --git a/packages/@aws-cdk/aws-amazonmq/package.json b/packages/@aws-cdk/aws-amazonmq/package.json index 70b7db473e7fc..6bca2f8c0d800 100644 --- a/packages/@aws-cdk/aws-amazonmq/package.json +++ b/packages/@aws-cdk/aws-amazonmq/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::AmazonMQ", diff --git a/packages/@aws-cdk/aws-amplify/package.json b/packages/@aws-cdk/aws-amplify/package.json index 9d2fd24c60e62..4e220c8fc1faa 100644 --- a/packages/@aws-cdk/aws-amplify/package.json +++ b/packages/@aws-cdk/aws-amplify/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test": "npm run build && npm test", "build+test+package": "npm run build+test && npm run package", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::Amplify", diff --git a/packages/@aws-cdk/aws-apigateway/lib/base-path-mapping.ts b/packages/@aws-cdk/aws-apigateway/lib/base-path-mapping.ts index 6026fe3eaecd3..17fa52ee7005c 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/base-path-mapping.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/base-path-mapping.ts @@ -2,7 +2,7 @@ import { Resource, Token } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { CfnBasePathMapping } from './apigateway.generated'; import { IDomainName } from './domain-name'; -import { IRestApi, RestApi } from './restapi'; +import { IRestApi, RestApiBase } from './restapi'; import { Stage } from './stage'; export interface BasePathMappingOptions { @@ -55,7 +55,7 @@ export class BasePathMapping extends Resource { // if restApi is an owned API and it has a deployment stage, map all requests // to that stage. otherwise, the stage will have to be specified in the URL. - const stage = props.stage ?? (props.restApi instanceof RestApi + const stage = props.stage ?? (props.restApi instanceof RestApiBase ? props.restApi.deploymentStage : undefined); diff --git a/packages/@aws-cdk/aws-apigateway/lib/integrations/lambda.ts b/packages/@aws-cdk/aws-apigateway/lib/integrations/lambda.ts index c6a8ec04863c7..91c1c9da97d64 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/integrations/lambda.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/integrations/lambda.ts @@ -49,7 +49,7 @@ export class LambdaIntegration extends AwsIntegration { }); this.handler = handler; - this.enableTest = options.allowTestInvoke === undefined ? true : false; + this.enableTest = options.allowTestInvoke === undefined ? true : options.allowTestInvoke; } public bind(method: Method): IntegrationConfig { diff --git a/packages/@aws-cdk/aws-apigateway/package.json b/packages/@aws-cdk/aws-apigateway/package.json index 3a814eab431c2..5125418beaf8d 100644 --- a/packages/@aws-cdk/aws-apigateway/package.json +++ b/packages/@aws-cdk/aws-apigateway/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::ApiGateway", diff --git a/packages/@aws-cdk/aws-apigateway/test/test.domains.ts b/packages/@aws-cdk/aws-apigateway/test/test.domains.ts index 175b7c0c11dd2..1e611c4601cd4 100644 --- a/packages/@aws-cdk/aws-apigateway/test/test.domains.ts +++ b/packages/@aws-cdk/aws-apigateway/test/test.domains.ts @@ -443,4 +443,63 @@ export = { test.done(); }, + 'base path mapping configures stage for RestApi creation'(test: Test) { + // GIVEN + const stack = new Stack(); + new apigw.RestApi(stack, 'restApiWithStage', { + domainName: { + domainName: 'example.com', + certificate: acm.Certificate.fromCertificateArn(stack, 'cert', 'arn:aws:acm:us-east-1:1111111:certificate/11-3336f1-44483d-adc7-9cd375c5169d'), + endpointType: apigw.EndpointType.REGIONAL, + }, + }).root.addMethod('GET'); + + // THEN + expect(stack).to(haveResource('AWS::ApiGateway::BasePathMapping', { + 'DomainName': { + 'Ref': 'restApiWithStageCustomDomainC4749625', + }, + 'RestApiId': { + 'Ref': 'restApiWithStageD4F931D0', + }, + 'Stage': { + 'Ref': 'restApiWithStageDeploymentStageprodC82A6648', + }, + })); + + test.done(); + }, + + 'base path mapping configures stage for SpecRestApi creation'(test: Test) { + // GIVEN + const stack = new Stack(); + + const definition = { + key1: 'val1', + }; + + new apigw.SpecRestApi(stack, 'specRestApiWithStage', { + apiDefinition: apigw.ApiDefinition.fromInline(definition), + domainName: { + domainName: 'example.com', + certificate: acm.Certificate.fromCertificateArn(stack, 'cert', 'arn:aws:acm:us-east-1:1111111:certificate/11-3336f1-44483d-adc7-9cd375c5169d'), + endpointType: apigw.EndpointType.REGIONAL, + }, + }).root.addMethod('GET'); + + // THEN + expect(stack).to(haveResource('AWS::ApiGateway::BasePathMapping', { + 'DomainName': { + 'Ref': 'specRestApiWithStageCustomDomain8A36A5C9', + }, + 'RestApiId': { + 'Ref': 'specRestApiWithStageC1492575', + }, + 'Stage': { + 'Ref': 'specRestApiWithStageDeploymentStageprod2D3037ED', + }, + })); + + test.done(); + }, }; diff --git a/packages/@aws-cdk/aws-apigateway/test/test.lambda.ts b/packages/@aws-cdk/aws-apigateway/test/test.lambda.ts index abfe3e44b66f4..0519f62ee5a36 100644 --- a/packages/@aws-cdk/aws-apigateway/test/test.lambda.ts +++ b/packages/@aws-cdk/aws-apigateway/test/test.lambda.ts @@ -102,6 +102,44 @@ export = { test.done(); }, + '"allowTestInvoke" set to true allows calling the API from the test UI'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const fn = new lambda.Function(stack, 'Handler', { + runtime: lambda.Runtime.NODEJS_10_X, + code: lambda.Code.fromInline('foo'), + handler: 'index.handler', + }); + + const api = new apigateway.RestApi(stack, 'api'); + + // WHEN + const integ = new apigateway.LambdaIntegration(fn, { allowTestInvoke: true }); + api.root.addMethod('GET', integ); + + // THEN + expect(stack).to(haveResource('AWS::Lambda::Permission', { + SourceArn: { + 'Fn::Join': [ + '', + [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':execute-api:', + { Ref: 'AWS::Region' }, + ':', + { Ref: 'AWS::AccountId' }, + ':', + { Ref: 'apiC8550315' }, + '/test-invoke-stage/GET/', + ], + ], + }, + })); + + test.done(); + }, + '"proxy" can be used to disable proxy mode'(test: Test) { // GIVEN const stack = new cdk.Stack(); diff --git a/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts b/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts index 679163ebd3a01..ff75808b5a8d6 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/lib/http/api.ts @@ -85,6 +85,12 @@ export interface HttpApiProps { */ readonly apiName?: string; + /** + * The description of the API. + * @default - none + */ + readonly description?: string; + /** * An integration that will be configured on the catch-all route ($default). * @default - none @@ -267,6 +273,7 @@ export class HttpApi extends HttpApiBase { name: this.httpApiName, protocolType: 'HTTP', corsConfiguration, + description: props?.description, }; const resource = new CfnApi(this, 'Resource', apiProps); diff --git a/packages/@aws-cdk/aws-apigatewayv2/package.json b/packages/@aws-cdk/aws-apigatewayv2/package.json index 2a0063c86fd59..7c079b71baab1 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "compat": "cdk-compat", "build+test": "npm run build && npm test", - "build+test+package": "npm run build+test && npm run package" + "build+test+package": "npm run build+test && npm run package", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::ApiGatewayV2", diff --git a/packages/@aws-cdk/aws-apigatewayv2/test/http/api.test.ts b/packages/@aws-cdk/aws-apigatewayv2/test/http/api.test.ts index dd92c6dad441b..13ee4e120945d 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/test/http/api.test.ts +++ b/packages/@aws-cdk/aws-apigatewayv2/test/http/api.test.ts @@ -220,4 +220,17 @@ describe('HttpApi', () => { expect(countMetric.statistic).toEqual(statistic); }); }); + + test('description is set', () => { + const stack = new Stack(); + new HttpApi(stack, 'api', { + description: 'My Api', + }); + + expect(stack).toHaveResource('AWS::ApiGatewayV2::Api', { + Name: 'api', + ProtocolType: 'HTTP', + Description: 'My Api', + }); + }); }); diff --git a/packages/@aws-cdk/aws-appconfig/package.json b/packages/@aws-cdk/aws-appconfig/package.json index 138ac518ef269..d88d38fe78249 100644 --- a/packages/@aws-cdk/aws-appconfig/package.json +++ b/packages/@aws-cdk/aws-appconfig/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::AppConfig", diff --git a/packages/@aws-cdk/aws-appflow/package.json b/packages/@aws-cdk/aws-appflow/package.json index d589158afe5c4..446d4c0787e03 100644 --- a/packages/@aws-cdk/aws-appflow/package.json +++ b/packages/@aws-cdk/aws-appflow/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::AppFlow", diff --git a/packages/@aws-cdk/aws-applicationautoscaling/package.json b/packages/@aws-cdk/aws-applicationautoscaling/package.json index d0cfa2e654773..19c9121c033f0 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/package.json +++ b/packages/@aws-cdk/aws-applicationautoscaling/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::ApplicationAutoScaling", diff --git a/packages/@aws-cdk/aws-applicationinsights/package.json b/packages/@aws-cdk/aws-applicationinsights/package.json index 0d9cb18068cee..8b59f2cd18ea9 100644 --- a/packages/@aws-cdk/aws-applicationinsights/package.json +++ b/packages/@aws-cdk/aws-applicationinsights/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::ApplicationInsights", diff --git a/packages/@aws-cdk/aws-appmesh/package.json b/packages/@aws-cdk/aws-appmesh/package.json index 94a4d5d7fe0b5..89ba1dd23a157 100644 --- a/packages/@aws-cdk/aws-appmesh/package.json +++ b/packages/@aws-cdk/aws-appmesh/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::AppMesh", diff --git a/packages/@aws-cdk/aws-appstream/package.json b/packages/@aws-cdk/aws-appstream/package.json index d26317e17b8ad..da76fb0128a25 100644 --- a/packages/@aws-cdk/aws-appstream/package.json +++ b/packages/@aws-cdk/aws-appstream/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::AppStream", diff --git a/packages/@aws-cdk/aws-appsync/package.json b/packages/@aws-cdk/aws-appsync/package.json index 617831552c6ce..77fb13de689f3 100644 --- a/packages/@aws-cdk/aws-appsync/package.json +++ b/packages/@aws-cdk/aws-appsync/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::AppSync", diff --git a/packages/@aws-cdk/aws-athena/package.json b/packages/@aws-cdk/aws-athena/package.json index a33bffbb14686..d28bc676d18af 100644 --- a/packages/@aws-cdk/aws-athena/package.json +++ b/packages/@aws-cdk/aws-athena/package.json @@ -56,7 +56,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "keywords": [ "aws", diff --git a/packages/@aws-cdk/aws-autoscaling/package.json b/packages/@aws-cdk/aws-autoscaling/package.json index b84adf0699b09..29a782f24b356 100644 --- a/packages/@aws-cdk/aws-autoscaling/package.json +++ b/packages/@aws-cdk/aws-autoscaling/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::AutoScaling", diff --git a/packages/@aws-cdk/aws-autoscalingplans/package.json b/packages/@aws-cdk/aws-autoscalingplans/package.json index be56095ec1992..cbdfb6ba3cec3 100644 --- a/packages/@aws-cdk/aws-autoscalingplans/package.json +++ b/packages/@aws-cdk/aws-autoscalingplans/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::AutoScalingPlans", diff --git a/packages/@aws-cdk/aws-backup/package.json b/packages/@aws-cdk/aws-backup/package.json index 2fcc9c8b1582c..a264887259ecc 100644 --- a/packages/@aws-cdk/aws-backup/package.json +++ b/packages/@aws-cdk/aws-backup/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test": "npm run build && npm test", "build+test+package": "npm run build+test && npm run package", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::Backup", diff --git a/packages/@aws-cdk/aws-batch/package.json b/packages/@aws-cdk/aws-batch/package.json index 970872060bbbd..83a0722c1844c 100644 --- a/packages/@aws-cdk/aws-batch/package.json +++ b/packages/@aws-cdk/aws-batch/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::Batch", diff --git a/packages/@aws-cdk/aws-budgets/package.json b/packages/@aws-cdk/aws-budgets/package.json index 0d685503f4828..f59821a305b52 100644 --- a/packages/@aws-cdk/aws-budgets/package.json +++ b/packages/@aws-cdk/aws-budgets/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::Budgets", diff --git a/packages/@aws-cdk/aws-cassandra/package.json b/packages/@aws-cdk/aws-cassandra/package.json index 46adae57ddd00..c047c535fad5a 100644 --- a/packages/@aws-cdk/aws-cassandra/package.json +++ b/packages/@aws-cdk/aws-cassandra/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::Cassandra", diff --git a/packages/@aws-cdk/aws-ce/package.json b/packages/@aws-cdk/aws-ce/package.json index dff5201588b1f..b34e30b82ca4b 100644 --- a/packages/@aws-cdk/aws-ce/package.json +++ b/packages/@aws-cdk/aws-ce/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::CE", diff --git a/packages/@aws-cdk/aws-certificatemanager/package.json b/packages/@aws-cdk/aws-certificatemanager/package.json index 9985cf3e1d912..2c8dbf640c433 100644 --- a/packages/@aws-cdk/aws-certificatemanager/package.json +++ b/packages/@aws-cdk/aws-certificatemanager/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::CertificateManager", diff --git a/packages/@aws-cdk/aws-chatbot/package.json b/packages/@aws-cdk/aws-chatbot/package.json index f818ce933170e..c699af51544f5 100644 --- a/packages/@aws-cdk/aws-chatbot/package.json +++ b/packages/@aws-cdk/aws-chatbot/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::Chatbot", diff --git a/packages/@aws-cdk/aws-cloud9/package.json b/packages/@aws-cdk/aws-cloud9/package.json index de9042b93d715..636198593e417 100644 --- a/packages/@aws-cdk/aws-cloud9/package.json +++ b/packages/@aws-cdk/aws-cloud9/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::Cloud9", diff --git a/packages/@aws-cdk/aws-cloudformation/package.json b/packages/@aws-cdk/aws-cloudformation/package.json index 9c8edb74fb9c7..a7c731d4675c6 100644 --- a/packages/@aws-cdk/aws-cloudformation/package.json +++ b/packages/@aws-cdk/aws-cloudformation/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::CloudFormation" diff --git a/packages/@aws-cdk/aws-cloudfront/package.json b/packages/@aws-cdk/aws-cloudfront/package.json index 6c6813d752283..64fd49012e4da 100644 --- a/packages/@aws-cdk/aws-cloudfront/package.json +++ b/packages/@aws-cdk/aws-cloudfront/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::CloudFront", diff --git a/packages/@aws-cdk/aws-cloudtrail/package.json b/packages/@aws-cdk/aws-cloudtrail/package.json index bdddf764b1fe6..6d60bf80a6cf5 100644 --- a/packages/@aws-cdk/aws-cloudtrail/package.json +++ b/packages/@aws-cdk/aws-cloudtrail/package.json @@ -49,7 +49,8 @@ "integ": "cdk-integ", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::CloudTrail", diff --git a/packages/@aws-cdk/aws-cloudwatch/package.json b/packages/@aws-cdk/aws-cloudwatch/package.json index 094f36c166e4b..b22bfe7c5adb1 100644 --- a/packages/@aws-cdk/aws-cloudwatch/package.json +++ b/packages/@aws-cdk/aws-cloudwatch/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::CloudWatch", diff --git a/packages/@aws-cdk/aws-codeartifact/package.json b/packages/@aws-cdk/aws-codeartifact/package.json index 03d6b25e8412d..b34c43c558a78 100644 --- a/packages/@aws-cdk/aws-codeartifact/package.json +++ b/packages/@aws-cdk/aws-codeartifact/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::CodeArtifact", diff --git a/packages/@aws-cdk/aws-codebuild/package.json b/packages/@aws-cdk/aws-codebuild/package.json index b90117c6b9f15..25390ea5e64ae 100644 --- a/packages/@aws-cdk/aws-codebuild/package.json +++ b/packages/@aws-cdk/aws-codebuild/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::CodeBuild", diff --git a/packages/@aws-cdk/aws-codecommit/package.json b/packages/@aws-cdk/aws-codecommit/package.json index 6bc68e1268bd8..cb5bf1f4945be 100644 --- a/packages/@aws-cdk/aws-codecommit/package.json +++ b/packages/@aws-cdk/aws-codecommit/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::CodeCommit", diff --git a/packages/@aws-cdk/aws-codedeploy/package.json b/packages/@aws-cdk/aws-codedeploy/package.json index cc74f509cad79..ddc7c0302bc57 100644 --- a/packages/@aws-cdk/aws-codedeploy/package.json +++ b/packages/@aws-cdk/aws-codedeploy/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::CodeDeploy", diff --git a/packages/@aws-cdk/aws-codeguruprofiler/package.json b/packages/@aws-cdk/aws-codeguruprofiler/package.json index f9070a9688b1d..be1fb69d524d6 100644 --- a/packages/@aws-cdk/aws-codeguruprofiler/package.json +++ b/packages/@aws-cdk/aws-codeguruprofiler/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::CodeGuruProfiler", diff --git a/packages/@aws-cdk/aws-codegurureviewer/package.json b/packages/@aws-cdk/aws-codegurureviewer/package.json index ff4a52bd233d8..ab40869eed2a8 100644 --- a/packages/@aws-cdk/aws-codegurureviewer/package.json +++ b/packages/@aws-cdk/aws-codegurureviewer/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::CodeGuruReviewer", diff --git a/packages/@aws-cdk/aws-codepipeline/package.json b/packages/@aws-cdk/aws-codepipeline/package.json index 5e9054460f74d..88d5a0e340de3 100644 --- a/packages/@aws-cdk/aws-codepipeline/package.json +++ b/packages/@aws-cdk/aws-codepipeline/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::CodePipeline", diff --git a/packages/@aws-cdk/aws-codestar/package.json b/packages/@aws-cdk/aws-codestar/package.json index 5eeb0b43db158..b011eb00c9e60 100644 --- a/packages/@aws-cdk/aws-codestar/package.json +++ b/packages/@aws-cdk/aws-codestar/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test": "npm run build && npm test", "build+test+package": "npm run build+test && npm run package", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::CodeStar", diff --git a/packages/@aws-cdk/aws-codestarconnections/package.json b/packages/@aws-cdk/aws-codestarconnections/package.json index 76647d2d6375e..872b1eef71c7a 100644 --- a/packages/@aws-cdk/aws-codestarconnections/package.json +++ b/packages/@aws-cdk/aws-codestarconnections/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::CodeStarConnections", diff --git a/packages/@aws-cdk/aws-codestarnotifications/package.json b/packages/@aws-cdk/aws-codestarnotifications/package.json index ffbefc15ca846..97cfb682202cc 100644 --- a/packages/@aws-cdk/aws-codestarnotifications/package.json +++ b/packages/@aws-cdk/aws-codestarnotifications/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "compat": "cdk-compat", "build+test": "npm run build && npm test", - "build+test+package": "npm run build+test && npm run package" + "build+test+package": "npm run build+test && npm run package", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::CodeStarNotifications", diff --git a/packages/@aws-cdk/aws-cognito/package.json b/packages/@aws-cdk/aws-cognito/package.json index da7da1d44691c..df7f26c5591cc 100644 --- a/packages/@aws-cdk/aws-cognito/package.json +++ b/packages/@aws-cdk/aws-cognito/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::Cognito", diff --git a/packages/@aws-cdk/aws-config/package.json b/packages/@aws-cdk/aws-config/package.json index 8f23ddbcc604a..a29b1ced124bb 100644 --- a/packages/@aws-cdk/aws-config/package.json +++ b/packages/@aws-cdk/aws-config/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::Config", diff --git a/packages/@aws-cdk/aws-datapipeline/package.json b/packages/@aws-cdk/aws-datapipeline/package.json index 349c70d00ebfb..972bee3e20e85 100644 --- a/packages/@aws-cdk/aws-datapipeline/package.json +++ b/packages/@aws-cdk/aws-datapipeline/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::DataPipeline", diff --git a/packages/@aws-cdk/aws-dax/package.json b/packages/@aws-cdk/aws-dax/package.json index d2aba2cfb2787..4bd5a02d080d5 100644 --- a/packages/@aws-cdk/aws-dax/package.json +++ b/packages/@aws-cdk/aws-dax/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::DAX", diff --git a/packages/@aws-cdk/aws-detective/package.json b/packages/@aws-cdk/aws-detective/package.json index d99077efe02f7..fce28548ba5ff 100644 --- a/packages/@aws-cdk/aws-detective/package.json +++ b/packages/@aws-cdk/aws-detective/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::Detective", diff --git a/packages/@aws-cdk/aws-directoryservice/package.json b/packages/@aws-cdk/aws-directoryservice/package.json index 2625ba019a9c6..3db4839b33c51 100644 --- a/packages/@aws-cdk/aws-directoryservice/package.json +++ b/packages/@aws-cdk/aws-directoryservice/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::DirectoryService", diff --git a/packages/@aws-cdk/aws-dlm/package.json b/packages/@aws-cdk/aws-dlm/package.json index 6f4a8134dd5e6..e5ef692a59834 100644 --- a/packages/@aws-cdk/aws-dlm/package.json +++ b/packages/@aws-cdk/aws-dlm/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::DLM", diff --git a/packages/@aws-cdk/aws-dms/package.json b/packages/@aws-cdk/aws-dms/package.json index af3bd1ce5e56c..5214671a6b4ad 100644 --- a/packages/@aws-cdk/aws-dms/package.json +++ b/packages/@aws-cdk/aws-dms/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::DMS", diff --git a/packages/@aws-cdk/aws-docdb/package.json b/packages/@aws-cdk/aws-docdb/package.json index 4e1f18ea39357..3d3f83fbed1f7 100644 --- a/packages/@aws-cdk/aws-docdb/package.json +++ b/packages/@aws-cdk/aws-docdb/package.json @@ -50,7 +50,8 @@ "awslint": "cdk-awslint", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::DocDB", diff --git a/packages/@aws-cdk/aws-dynamodb/package.json b/packages/@aws-cdk/aws-dynamodb/package.json index c0d29b0258414..db8e59fd3be05 100644 --- a/packages/@aws-cdk/aws-dynamodb/package.json +++ b/packages/@aws-cdk/aws-dynamodb/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::DynamoDB", diff --git a/packages/@aws-cdk/aws-ec2/package.json b/packages/@aws-cdk/aws-ec2/package.json index e61318e44f6cf..a5d37a1f53a96 100644 --- a/packages/@aws-cdk/aws-ec2/package.json +++ b/packages/@aws-cdk/aws-ec2/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::EC2", diff --git a/packages/@aws-cdk/aws-ecr/package.json b/packages/@aws-cdk/aws-ecr/package.json index 23022426c5a0b..d84f095e0ea01 100644 --- a/packages/@aws-cdk/aws-ecr/package.json +++ b/packages/@aws-cdk/aws-ecr/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::ECR", diff --git a/packages/@aws-cdk/aws-ecs/package.json b/packages/@aws-cdk/aws-ecs/package.json index c3d6d784e8364..17d2965b792eb 100644 --- a/packages/@aws-cdk/aws-ecs/package.json +++ b/packages/@aws-cdk/aws-ecs/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::ECS", diff --git a/packages/@aws-cdk/aws-efs/package.json b/packages/@aws-cdk/aws-efs/package.json index 2e297e49cf73c..d936597b3db85 100644 --- a/packages/@aws-cdk/aws-efs/package.json +++ b/packages/@aws-cdk/aws-efs/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::EFS", diff --git a/packages/@aws-cdk/aws-eks-legacy/package.json b/packages/@aws-cdk/aws-eks-legacy/package.json index 0cbb2b783a0b4..ddbc04d379dc2 100644 --- a/packages/@aws-cdk/aws-eks-legacy/package.json +++ b/packages/@aws-cdk/aws-eks-legacy/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::EKS" diff --git a/packages/@aws-cdk/aws-eks/lib/cluster.ts b/packages/@aws-cdk/aws-eks/lib/cluster.ts index e583a270c3da4..7388c497a9906 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster.ts @@ -7,7 +7,6 @@ import * as kms from '@aws-cdk/aws-kms'; import * as lambda from '@aws-cdk/aws-lambda'; import * as ssm from '@aws-cdk/aws-ssm'; import { Annotations, CfnOutput, CfnResource, IResource, Resource, Stack, Tags, Token, Duration } from '@aws-cdk/core'; -import * as cdk8s from 'cdk8s'; import { Construct, Node } from 'constructs'; import * as YAML from 'yaml'; import { AwsAuth } from './aws-auth'; @@ -141,7 +140,7 @@ export interface ICluster extends IResource, ec2.IConnectable { * @param chart the cdk8s chart. * @returns a `KubernetesManifest` construct representing the chart. */ - addCdk8sChart(id: string, chart: cdk8s.Chart): KubernetesManifest; + addCdk8sChart(id: string, chart: Construct): KubernetesManifest; } @@ -641,8 +640,16 @@ abstract class ClusterBase extends Resource implements ICluster { * @param chart the cdk8s chart. * @returns a `KubernetesManifest` construct representing the chart. */ - public addCdk8sChart(id: string, chart: cdk8s.Chart): KubernetesManifest { - return this.addManifest(id, ...chart.toJson()); + public addCdk8sChart(id: string, chart: Construct): KubernetesManifest { + + const cdk8sChart = chart as any; + + // see https://github.com/awslabs/cdk8s/blob/master/packages/cdk8s/src/chart.ts#L84 + if (typeof cdk8sChart.toJson !== 'function') { + throw new Error(`Invalid cdk8s chart. Must contain a 'toJson' method, but found ${typeof cdk8sChart.toJson}`); + } + + return this.addManifest(id, ...cdk8sChart.toJson()); } } diff --git a/packages/@aws-cdk/aws-eks/lib/legacy-cluster.ts b/packages/@aws-cdk/aws-eks/lib/legacy-cluster.ts index c862f7fd3d0f6..5fead1f4818e4 100644 --- a/packages/@aws-cdk/aws-eks/lib/legacy-cluster.ts +++ b/packages/@aws-cdk/aws-eks/lib/legacy-cluster.ts @@ -3,7 +3,6 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as ssm from '@aws-cdk/aws-ssm'; -import * as cdk8s from 'cdk8s'; import { Annotations, CfnOutput, Resource, Stack, Token, Tags } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { ICluster, ClusterAttributes, KubernetesVersion, NodeType, DefaultCapacityType, EksOptimizedImage, AutoScalingGroupCapacityOptions, MachineImageType, AutoScalingGroupOptions, CommonClusterOptions } from './cluster'; @@ -372,7 +371,7 @@ export class LegacyCluster extends Resource implements ICluster { throw new Error('legacy cluster does not support adding helm charts'); } - public addCdk8sChart(_id: string, _chart: cdk8s.Chart): KubernetesManifest { + public addCdk8sChart(_id: string, _chart: Construct): KubernetesManifest { throw new Error('legacy cluster does not support adding cdk8s charts'); } @@ -434,7 +433,7 @@ class ImportedCluster extends Resource implements ICluster { throw new Error('legacy cluster does not support adding helm charts'); } - public addCdk8sChart(_id: string, _chart: cdk8s.Chart): KubernetesManifest { + public addCdk8sChart(_id: string, _chart: Construct): KubernetesManifest { throw new Error('legacy cluster does not support adding cdk8s charts'); } diff --git a/packages/@aws-cdk/aws-eks/package.json b/packages/@aws-cdk/aws-eks/package.json index dcf8ee02c9955..9fcf327b2c357 100644 --- a/packages/@aws-cdk/aws-eks/package.json +++ b/packages/@aws-cdk/aws-eks/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::EKS", @@ -80,7 +81,8 @@ "nodeunit": "^0.11.3", "pkglint": "0.0.0", "sinon": "^9.1.0", - "cdk8s-plus": "^0.29.0" + "cdk8s-plus": "^0.29.0", + "cdk8s": "^0.30.0" }, "dependencies": { "@aws-cdk/aws-autoscaling": "0.0.0", @@ -91,7 +93,6 @@ "@aws-cdk/aws-ssm": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", - "cdk8s": "^0.30.0", "constructs": "^3.0.4", "yaml": "1.10.0" }, @@ -108,7 +109,6 @@ "@aws-cdk/aws-ssm": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", - "cdk8s": "^0.30.0", "constructs": "^3.0.4" }, "engines": { diff --git a/packages/@aws-cdk/aws-eks/test/test.cluster.ts b/packages/@aws-cdk/aws-eks/test/test.cluster.ts index 89d5a26485542..10909690f99af 100644 --- a/packages/@aws-cdk/aws-eks/test/test.cluster.ts +++ b/packages/@aws-cdk/aws-eks/test/test.cluster.ts @@ -22,6 +22,38 @@ const CLUSTER_VERSION = eks.KubernetesVersion.V1_18; export = { + 'throws when a non cdk8s chart construct is added as cdk8s chart'(test: Test) { + + const { stack } = testFixture(); + + const cluster = new eks.Cluster(stack, 'Cluster', { + version: CLUSTER_VERSION, + }); + + // create a plain construct, not a cdk8s chart + const someConstruct = new constructs.Construct(stack, 'SomeConstruct'); + + test.throws(() => cluster.addCdk8sChart('chart', someConstruct), /Invalid cdk8s chart. Must contain a \'toJson\' method, but found undefined/); + test.done(); + + }, + + 'throws when a core construct is added as cdk8s chart'(test: Test) { + + const { stack } = testFixture(); + + const cluster = new eks.Cluster(stack, 'Cluster', { + version: CLUSTER_VERSION, + }); + + // create a plain construct, not a cdk8s chart + const someConstruct = new cdk.Construct(stack, 'SomeConstruct'); + + test.throws(() => cluster.addCdk8sChart('chart', someConstruct), /Invalid cdk8s chart. Must contain a \'toJson\' method, but found undefined/); + test.done(); + + }, + 'cdk8s chart can be added to cluster'(test: Test) { const { stack } = testFixture(); diff --git a/packages/@aws-cdk/aws-elasticache/package.json b/packages/@aws-cdk/aws-elasticache/package.json index ab6e459939236..64b7de26d8033 100644 --- a/packages/@aws-cdk/aws-elasticache/package.json +++ b/packages/@aws-cdk/aws-elasticache/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::ElastiCache", diff --git a/packages/@aws-cdk/aws-elasticbeanstalk/package.json b/packages/@aws-cdk/aws-elasticbeanstalk/package.json index 1f907f7aea14a..4072f080afd6b 100644 --- a/packages/@aws-cdk/aws-elasticbeanstalk/package.json +++ b/packages/@aws-cdk/aws-elasticbeanstalk/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::ElasticBeanstalk", diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/package.json b/packages/@aws-cdk/aws-elasticloadbalancing/package.json index a2f49664d154d..21c9fb0106eed 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancing/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::ElasticLoadBalancing", diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json index f674af8d93d7b..8e8bd7d3a8319 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::ElasticLoadBalancingV2", diff --git a/packages/@aws-cdk/aws-elasticsearch/package.json b/packages/@aws-cdk/aws-elasticsearch/package.json index 69947f1186589..5f42892c18a27 100644 --- a/packages/@aws-cdk/aws-elasticsearch/package.json +++ b/packages/@aws-cdk/aws-elasticsearch/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::Elasticsearch", diff --git a/packages/@aws-cdk/aws-emr/package.json b/packages/@aws-cdk/aws-emr/package.json index da8094218409d..49f0f0e96cfd8 100644 --- a/packages/@aws-cdk/aws-emr/package.json +++ b/packages/@aws-cdk/aws-emr/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::EMR", diff --git a/packages/@aws-cdk/aws-events-targets/package.json b/packages/@aws-cdk/aws-events-targets/package.json index 14764b6fcb0af..42e0d6d91db67 100644 --- a/packages/@aws-cdk/aws-events-targets/package.json +++ b/packages/@aws-cdk/aws-events-targets/package.json @@ -48,12 +48,10 @@ "awslint": "cdk-awslint", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "node ./build-tools/gen.js" }, "cdk-build": { - "pre": [ - "node ./build-tools/gen.js" - ], "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true diff --git a/packages/@aws-cdk/aws-events/package.json b/packages/@aws-cdk/aws-events/package.json index fe8af611759f3..10eae38d9c95a 100644 --- a/packages/@aws-cdk/aws-events/package.json +++ b/packages/@aws-cdk/aws-events/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::Events", diff --git a/packages/@aws-cdk/aws-eventschemas/package.json b/packages/@aws-cdk/aws-eventschemas/package.json index 2ad4983c3be32..8180b30813736 100644 --- a/packages/@aws-cdk/aws-eventschemas/package.json +++ b/packages/@aws-cdk/aws-eventschemas/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "compat": "cdk-compat", "build+test": "npm run build && npm test", - "build+test+package": "npm run build+test && npm run package" + "build+test+package": "npm run build+test && npm run package", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::EventSchemas", diff --git a/packages/@aws-cdk/aws-fms/package.json b/packages/@aws-cdk/aws-fms/package.json index 47ffdc69a57ef..f02b4c96d4a7b 100644 --- a/packages/@aws-cdk/aws-fms/package.json +++ b/packages/@aws-cdk/aws-fms/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::FMS", diff --git a/packages/@aws-cdk/aws-fsx/package.json b/packages/@aws-cdk/aws-fsx/package.json index 21da2047de0df..fc9eb2bb12c83 100644 --- a/packages/@aws-cdk/aws-fsx/package.json +++ b/packages/@aws-cdk/aws-fsx/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::FSx", diff --git a/packages/@aws-cdk/aws-gamelift/package.json b/packages/@aws-cdk/aws-gamelift/package.json index 306ffd6f328d3..7e2ab82775f9a 100644 --- a/packages/@aws-cdk/aws-gamelift/package.json +++ b/packages/@aws-cdk/aws-gamelift/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::GameLift", diff --git a/packages/@aws-cdk/aws-globalaccelerator/package.json b/packages/@aws-cdk/aws-globalaccelerator/package.json index ea5decf73ff1b..265cc4c542be5 100644 --- a/packages/@aws-cdk/aws-globalaccelerator/package.json +++ b/packages/@aws-cdk/aws-globalaccelerator/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::GlobalAccelerator", diff --git a/packages/@aws-cdk/aws-glue/package.json b/packages/@aws-cdk/aws-glue/package.json index c8ce2ebc7da42..853f13eba7f69 100644 --- a/packages/@aws-cdk/aws-glue/package.json +++ b/packages/@aws-cdk/aws-glue/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::Glue", diff --git a/packages/@aws-cdk/aws-greengrass/package.json b/packages/@aws-cdk/aws-greengrass/package.json index fa80e4b30ba52..eb00971db47ca 100644 --- a/packages/@aws-cdk/aws-greengrass/package.json +++ b/packages/@aws-cdk/aws-greengrass/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::Greengrass", diff --git a/packages/@aws-cdk/aws-guardduty/package.json b/packages/@aws-cdk/aws-guardduty/package.json index 617b4eeec97fe..2ad0431bf4f96 100644 --- a/packages/@aws-cdk/aws-guardduty/package.json +++ b/packages/@aws-cdk/aws-guardduty/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::GuardDuty", diff --git a/packages/@aws-cdk/aws-iam/package.json b/packages/@aws-cdk/aws-iam/package.json index 14c4c31c92d59..baadb15f398eb 100644 --- a/packages/@aws-cdk/aws-iam/package.json +++ b/packages/@aws-cdk/aws-iam/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::IAM", diff --git a/packages/@aws-cdk/aws-imagebuilder/package.json b/packages/@aws-cdk/aws-imagebuilder/package.json index 256a3b079a760..656f94b3a8c38 100644 --- a/packages/@aws-cdk/aws-imagebuilder/package.json +++ b/packages/@aws-cdk/aws-imagebuilder/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::ImageBuilder", diff --git a/packages/@aws-cdk/aws-inspector/package.json b/packages/@aws-cdk/aws-inspector/package.json index bc46eef38a438..8c6d5fd522c3f 100644 --- a/packages/@aws-cdk/aws-inspector/package.json +++ b/packages/@aws-cdk/aws-inspector/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::Inspector", diff --git a/packages/@aws-cdk/aws-iot/package.json b/packages/@aws-cdk/aws-iot/package.json index b9d7a26a10987..e0e7c04079287 100644 --- a/packages/@aws-cdk/aws-iot/package.json +++ b/packages/@aws-cdk/aws-iot/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::IoT", diff --git a/packages/@aws-cdk/aws-iot1click/package.json b/packages/@aws-cdk/aws-iot1click/package.json index 34f6ad2fc8b5c..9760e0c886270 100644 --- a/packages/@aws-cdk/aws-iot1click/package.json +++ b/packages/@aws-cdk/aws-iot1click/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::IoT1Click", diff --git a/packages/@aws-cdk/aws-iotanalytics/package.json b/packages/@aws-cdk/aws-iotanalytics/package.json index 02bffc449abc1..6e683f7bb8a5c 100644 --- a/packages/@aws-cdk/aws-iotanalytics/package.json +++ b/packages/@aws-cdk/aws-iotanalytics/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::IoTAnalytics", diff --git a/packages/@aws-cdk/aws-iotevents/package.json b/packages/@aws-cdk/aws-iotevents/package.json index 299bbb8da8861..37d73d2fd1cb4 100644 --- a/packages/@aws-cdk/aws-iotevents/package.json +++ b/packages/@aws-cdk/aws-iotevents/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test": "npm run build && npm test", "build+test+package": "npm run build+test && npm run package", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::IoTEvents", diff --git a/packages/@aws-cdk/aws-iotthingsgraph/package.json b/packages/@aws-cdk/aws-iotthingsgraph/package.json index 26e80a170a192..62ce3a0fbc627 100644 --- a/packages/@aws-cdk/aws-iotthingsgraph/package.json +++ b/packages/@aws-cdk/aws-iotthingsgraph/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test": "npm run build && npm test", "build+test+package": "npm run build+test && npm run package", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::IoTThingsGraph", diff --git a/packages/@aws-cdk/aws-kendra/package.json b/packages/@aws-cdk/aws-kendra/package.json index 1e94ce21c0553..17008caafbb38 100644 --- a/packages/@aws-cdk/aws-kendra/package.json +++ b/packages/@aws-cdk/aws-kendra/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::Kendra", diff --git a/packages/@aws-cdk/aws-kinesis/package.json b/packages/@aws-cdk/aws-kinesis/package.json index b4e7c21809883..a18995115299e 100644 --- a/packages/@aws-cdk/aws-kinesis/package.json +++ b/packages/@aws-cdk/aws-kinesis/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::Kinesis", diff --git a/packages/@aws-cdk/aws-kinesisanalytics/package.json b/packages/@aws-cdk/aws-kinesisanalytics/package.json index 020baefcf1f97..ecca781e5d946 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics/package.json +++ b/packages/@aws-cdk/aws-kinesisanalytics/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": [ diff --git a/packages/@aws-cdk/aws-kinesisfirehose/package.json b/packages/@aws-cdk/aws-kinesisfirehose/package.json index dac3480ca17bb..1c474c76b1ff8 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose/package.json +++ b/packages/@aws-cdk/aws-kinesisfirehose/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::KinesisFirehose", diff --git a/packages/@aws-cdk/aws-kms/package.json b/packages/@aws-cdk/aws-kms/package.json index 6d59d572727a9..b17ecde0082d9 100644 --- a/packages/@aws-cdk/aws-kms/package.json +++ b/packages/@aws-cdk/aws-kms/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::KMS", diff --git a/packages/@aws-cdk/aws-lakeformation/package.json b/packages/@aws-cdk/aws-lakeformation/package.json index 461b0aff0c1b0..756fd59ff172d 100644 --- a/packages/@aws-cdk/aws-lakeformation/package.json +++ b/packages/@aws-cdk/aws-lakeformation/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test": "npm run build && npm test", "build+test+package": "npm run build+test && npm run package", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::LakeFormation", diff --git a/packages/@aws-cdk/aws-lambda-event-sources/README.md b/packages/@aws-cdk/aws-lambda-event-sources/README.md index 452fba4bed43a..b88ce808a9d9f 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/README.md +++ b/packages/@aws-cdk/aws-lambda-event-sources/README.md @@ -144,7 +144,7 @@ and add it to your Lambda function. The following parameters will impact Amazon * __onFailure__: In the event a record fails after all retries or if the record age has exceeded the configured value, the record will be sent to SQS queue or SNS topic that is specified here * __parallelizationFactor__: The number of batches to concurrently process on each shard. * __retryAttempts__: The maximum number of times a record should be retried in the event of failure. -* __startingPosition__: Will determine where to being consumption, either at the most recent ('LATEST') record or the oldest record ('TRIM_HORIZON'). 'TRIM_HORIZON' will ensure you process all available data, while 'LATEST' will ignore all reocrds that arrived prior to attaching the event source. +* __startingPosition__: Will determine where to being consumption, either at the most recent ('LATEST') record or the oldest record ('TRIM_HORIZON'). 'TRIM_HORIZON' will ensure you process all available data, while 'LATEST' will ignore all records that arrived prior to attaching the event source. ```ts import * as dynamodb from '@aws-cdk/aws-dynamodb'; @@ -187,7 +187,7 @@ behavior: * __onFailure__: In the event a record fails and consumes all retries, the record will be sent to SQS queue or SNS topic that is specified here * __parallelizationFactor__: The number of batches to concurrently process on each shard. * __retryAttempts__: The maximum number of times a record should be retried in the event of failure. -* __startingPosition__: Will determine where to being consumption, either at the most recent ('LATEST') record or the oldest record ('TRIM_HORIZON'). 'TRIM_HORIZON' will ensure you process all available data, while 'LATEST' will ignore all reocrds that arrived prior to attaching the event source. +* __startingPosition__: Will determine where to being consumption, either at the most recent ('LATEST') record or the oldest record ('TRIM_HORIZON'). 'TRIM_HORIZON' will ensure you process all available data, while 'LATEST' will ignore all records that arrived prior to attaching the event source. ```ts import * as lambda from '@aws-cdk/aws-lambda'; @@ -196,7 +196,7 @@ import { KinesisEventSource } from '@aws-cdk/aws-lambda-event-sources'; const stream = new kinesis.Stream(this, 'MyStream'); -myFunction.addEventSource(new KinesisEventSource(queue, { +myFunction.addEventSource(new KinesisEventSource(stream, { batchSize: 100, // default startingPosition: lambda.StartingPosition.TRIM_HORIZON }); diff --git a/packages/@aws-cdk/aws-lambda/.gitignore b/packages/@aws-cdk/aws-lambda/.gitignore index d0a956699806b..4af109b196444 100644 --- a/packages/@aws-cdk/aws-lambda/.gitignore +++ b/packages/@aws-cdk/aws-lambda/.gitignore @@ -15,5 +15,6 @@ nyc.config.js .LAST_PACKAGE *.snk !.eslintrc.js +!jest.config.js junit.xml \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda/.npmignore b/packages/@aws-cdk/aws-lambda/.npmignore index a94c531529866..63ab95621c764 100644 --- a/packages/@aws-cdk/aws-lambda/.npmignore +++ b/packages/@aws-cdk/aws-lambda/.npmignore @@ -19,6 +19,7 @@ dist tsconfig.json .eslintrc.js +jest.config.js # exclude cdk artifacts **/cdk.out diff --git a/packages/@aws-cdk/aws-lambda/jest.config.js b/packages/@aws-cdk/aws-lambda/jest.config.js new file mode 100644 index 0000000000000..54e28beb9798b --- /dev/null +++ b/packages/@aws-cdk/aws-lambda/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda/package.json b/packages/@aws-cdk/aws-lambda/package.json index cd592e5bc3ce6..198d840dbf4ab 100644 --- a/packages/@aws-cdk/aws-lambda/package.json +++ b/packages/@aws-cdk/aws-lambda/package.json @@ -49,10 +49,12 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::Lambda", + "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,12 +79,11 @@ "@aws-cdk/assert": "0.0.0", "@types/aws-lambda": "^8.10.63", "@types/lodash": "^4.14.161", - "@types/nodeunit": "^0.0.31", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", + "jest": "^26.4.2", "lodash": "^4.17.20", - "nodeunit": "^0.11.3", "pkglint": "0.0.0" }, "dependencies": { diff --git a/packages/@aws-cdk/aws-lambda/test/test.alias.ts b/packages/@aws-cdk/aws-lambda/test/alias.test.ts similarity index 73% rename from packages/@aws-cdk/aws-lambda/test/test.alias.ts rename to packages/@aws-cdk/aws-lambda/test/alias.test.ts index 60be6208c48cb..334e40607ed5c 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.alias.ts +++ b/packages/@aws-cdk/aws-lambda/test/alias.test.ts @@ -1,12 +1,12 @@ -import { arrayWith, beASupersetOfTemplate, expect, haveResource, haveResourceLike, objectLike } from '@aws-cdk/assert'; +import '@aws-cdk/assert/jest'; +import { arrayWith, objectLike } from '@aws-cdk/assert'; import * as appscaling from '@aws-cdk/aws-applicationautoscaling'; import * as cloudwatch from '@aws-cdk/aws-cloudwatch'; import { Lazy, Stack } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; import * as lambda from '../lib'; -export = { - 'version and aliases'(test: Test): void { +describe('alias', () => { + test('version and aliases', () => { const stack = new Stack(); const fn = new lambda.Function(stack, 'MyLambda', { code: new lambda.InlineCode('hello()'), @@ -21,27 +21,18 @@ export = { version, }); - expect(stack).to(beASupersetOfTemplate({ - MyLambdaVersion16CDE3C40: { - Type: 'AWS::Lambda::Version', - Properties: { - FunctionName: { Ref: 'MyLambdaCCE802FB' }, - }, - }, - Alias325C5727: { - Type: 'AWS::Lambda::Alias', - Properties: { - FunctionName: { Ref: 'MyLambdaCCE802FB' }, - FunctionVersion: stack.resolve(version.version), - Name: 'prod', - }, - }, - })); + expect(stack).toHaveResource('AWS::Lambda::Version', { + FunctionName: { Ref: 'MyLambdaCCE802FB' }, + }); - test.done(); - }, + expect(stack).toHaveResource('AWS::Lambda::Alias', { + FunctionName: { Ref: 'MyLambdaCCE802FB' }, + FunctionVersion: stack.resolve(version.version), + Name: 'prod', + }); + }); - 'can create an alias to $LATEST'(test: Test): void { + test('can create an alias to $LATEST', () => { const stack = new Stack(); const fn = new lambda.Function(stack, 'MyLambda', { code: new lambda.InlineCode('hello()'), @@ -54,17 +45,15 @@ export = { version: fn.latestVersion, }); - expect(stack).to(haveResource('AWS::Lambda::Alias', { + expect(stack).toHaveResource('AWS::Lambda::Alias', { FunctionName: { Ref: 'MyLambdaCCE802FB' }, FunctionVersion: '$LATEST', Name: 'latest', - })); - expect(stack).notTo(haveResource('AWS::Lambda::Version')); - - test.done(); - }, + }); + expect(stack).not.toHaveResource('AWS::Lambda::Version'); + }); - 'can use newVersion to create a new Version'(test: Test) { + test('can use newVersion to create a new Version', () => { const stack = new Stack(); const fn = new lambda.Function(stack, 'MyLambda', { code: new lambda.InlineCode('hello()'), @@ -79,19 +68,17 @@ export = { version, }); - expect(stack).to(haveResourceLike('AWS::Lambda::Version', { + expect(stack).toHaveResourceLike('AWS::Lambda::Version', { FunctionName: { Ref: 'MyLambdaCCE802FB' }, - })); + }); - expect(stack).to(haveResourceLike('AWS::Lambda::Alias', { + expect(stack).toHaveResourceLike('AWS::Lambda::Alias', { FunctionName: { Ref: 'MyLambdaCCE802FB' }, Name: 'prod', - })); - - test.done(); - }, + }); + }); - 'can add additional versions to alias'(test: Test) { + test('can add additional versions to alias', () => { const stack = new Stack(); const fn = new lambda.Function(stack, 'MyLambda', { @@ -109,7 +96,7 @@ export = { additionalVersions: [{ version: version2, weight: 0.1 }], }); - expect(stack).to(haveResource('AWS::Lambda::Alias', { + expect(stack).toHaveResource('AWS::Lambda::Alias', { FunctionVersion: stack.resolve(version1.version), RoutingConfig: { AdditionalVersionWeights: [ @@ -119,11 +106,10 @@ export = { }, ], }, - })); + }); + }); - test.done(); - }, - 'version and aliases with provisioned execution'(test: Test): void { + test('version and aliases with provisioned execution', () => { const stack = new Stack(); const fn = new lambda.Function(stack, 'MyLambda', { code: new lambda.InlineCode('hello()'), @@ -140,34 +126,22 @@ export = { provisionedConcurrentExecutions: pce, }); - expect(stack).to(beASupersetOfTemplate({ - MyLambdaVersion16CDE3C40: { - Type: 'AWS::Lambda::Version', - Properties: { - FunctionName: { - Ref: 'MyLambdaCCE802FB', - }, - ProvisionedConcurrencyConfig: { - ProvisionedConcurrentExecutions: 5, - }, - }, + expect(stack).toHaveResource('AWS::Lambda::Version', { + ProvisionedConcurrencyConfig: { + ProvisionedConcurrentExecutions: 5, }, - Alias325C5727: { - Type: 'AWS::Lambda::Alias', - Properties: { - FunctionName: { Ref: 'MyLambdaCCE802FB' }, - FunctionVersion: stack.resolve(version.version), - Name: 'prod', - ProvisionedConcurrencyConfig: { - ProvisionedConcurrentExecutions: 5, - }, - }, + }); + + expect(stack).toHaveResource('AWS::Lambda::Alias', { + FunctionVersion: stack.resolve(version.version), + Name: 'prod', + ProvisionedConcurrencyConfig: { + ProvisionedConcurrentExecutions: 5, }, - })); + }); + }); - test.done(); - }, - 'sanity checks on version weights'(test: Test) { + test('sanity checks on version weights', () => { const stack = new Stack(); const fn = new lambda.Function(stack, 'MyLambda', { @@ -179,27 +153,25 @@ export = { const version = fn.addVersion('1'); // WHEN: Individual weight too high - test.throws(() => { + expect(() => { new lambda.Alias(stack, 'Alias1', { aliasName: 'prod', version, additionalVersions: [{ version, weight: 5 }], }); - }); + }).toThrow(); // WHEN: Sum too high - test.throws(() => { + expect(() => { new lambda.Alias(stack, 'Alias2', { aliasName: 'prod', version, additionalVersions: [{ version, weight: 0.5 }, { version, weight: 0.6 }], }); - }); + }).toThrow(); + }); - test.done(); - }, - - 'metric adds Resource: aliasArn to dimensions'(test: Test) { + test('metric adds Resource: aliasArn to dimensions', () => { const stack = new Stack(); // GIVEN @@ -221,7 +193,7 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::CloudWatch::Alarm', { + expect(stack).toHaveResource('AWS::CloudWatch::Alarm', { Dimensions: [{ Name: 'FunctionName', Value: { @@ -239,12 +211,10 @@ export = { ], }, }], - })); - - test.done(); - }, + }); + }); - 'sanity checks provisionedConcurrentExecutions'(test: Test) { + test('sanity checks provisionedConcurrentExecutions', () => { const stack = new Stack(); const pce = -1; @@ -255,33 +225,31 @@ export = { }); // WHEN: Alias provisionedConcurrencyConfig less than 0 - test.throws(() => { + expect(() => { new lambda.Alias(stack, 'Alias1', { aliasName: 'prod', version: fn.addVersion('1'), provisionedConcurrentExecutions: pce, }); - }); + }).toThrow(); // WHEN: Version provisionedConcurrencyConfig less than 0 - test.throws(() => { + expect(() => { new lambda.Version(stack, 'Version 1', { lambda: fn, codeSha256: undefined, description: undefined, provisionedConcurrentExecutions: pce, }); - }); + }).toThrow(); // WHEN: Adding a version provisionedConcurrencyConfig less than 0 - test.throws(() => { + expect(() => { fn.addVersion('1', undefined, undefined, pce); - }); - - test.done(); - }, + }).toThrow(); + }); - 'alias exposes real Lambdas role'(test: Test) { + test('alias exposes real Lambdas role', () => { const stack = new Stack(); // GIVEN @@ -295,12 +263,10 @@ export = { const alias = new lambda.Alias(stack, 'Alias', { aliasName: 'prod', version }); // THEN - test.equals(alias.role, fn.role); - - test.done(); - }, + expect(alias.role).toEqual(fn.role); + }); - 'functionName is derived from the aliasArn so that dependencies are sound'(test: Test) { + test('functionName is derived from the aliasArn so that dependencies are sound', () => { const stack = new Stack(); // GIVEN @@ -314,7 +280,7 @@ export = { const alias = new lambda.Alias(stack, 'Alias', { aliasName: 'prod', version }); // WHEN - test.deepEqual(stack.resolve(alias.functionName), { + expect(stack.resolve(alias.functionName)).toEqual({ 'Fn::Join': [ '', [ @@ -335,11 +301,9 @@ export = { ], ], }); + }); - test.done(); - }, - - 'with event invoke config'(test: Test) { + test('with event invoke config', () => { // GIVEN const stack = new Stack(); const fn = new lambda.Function(stack, 'fn', { @@ -361,7 +325,7 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::Lambda::EventInvokeConfig', { + expect(stack).toHaveResource('AWS::Lambda::EventInvokeConfig', { FunctionName: { Ref: 'fn5FF616E3', }, @@ -383,12 +347,10 @@ export = { Destination: 'on-success-arn', }, }, - })); - - test.done(); - }, + }); + }); - 'throws when calling configureAsyncInvoke on already configured alias'(test: Test) { + test('throws when calling configureAsyncInvoke on already configured alias', () => { // GIVEN const stack = new Stack(); const fn = new lambda.Function(stack, 'fn', { @@ -408,12 +370,10 @@ export = { }); // THEN - test.throws(() => alias.configureAsyncInvoke({ retryAttempts: 0 }), /An EventInvokeConfig has already been configured/); + expect(() => alias.configureAsyncInvoke({ retryAttempts: 0 })).toThrow(/An EventInvokeConfig has already been configured/); + }); - test.done(); - }, - - 'event invoke config on imported alias'(test: Test) { + test('event invoke config on imported alias', () => { // GIVEN const stack = new Stack(); const fn = lambda.Version.fromVersionArn(stack, 'Fn', 'arn:aws:lambda:region:account-id:function:function-name:version'); @@ -425,16 +385,14 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::Lambda::EventInvokeConfig', { + expect(stack).toHaveResource('AWS::Lambda::EventInvokeConfig', { FunctionName: 'function-name', Qualifier: 'alias-name', MaximumRetryAttempts: 1, - })); - - test.done(); - }, + }); + }); - 'can enable AutoScaling on aliases'(test: Test): void { + test('can enable AutoScaling on aliases', () => { // GIVEN const stack = new Stack(); const fn = new lambda.Function(stack, 'MyLambda', { @@ -454,7 +412,7 @@ export = { alias.addAutoScaling({ maxCapacity: 5 }); // THEN - expect(stack).to(haveResource('AWS::ApplicationAutoScaling::ScalableTarget', { + expect(stack).toHaveResource('AWS::ApplicationAutoScaling::ScalableTarget', { MinCapacity: 1, MaxCapacity: 5, ResourceId: objectLike({ @@ -471,12 +429,10 @@ export = { ':prod', )), }), - })); - - test.done(); - }, + }); + }); - 'can enable AutoScaling on aliases with Provisioned Concurrency set'(test: Test): void { + test('can enable AutoScaling on aliases with Provisioned Concurrency set', () => { // GIVEN const stack = new Stack(); const fn = new lambda.Function(stack, 'MyLambda', { @@ -497,7 +453,7 @@ export = { alias.addAutoScaling({ maxCapacity: 5 }); // THEN - expect(stack).to(haveResource('AWS::ApplicationAutoScaling::ScalableTarget', { + expect(stack).toHaveResource('AWS::ApplicationAutoScaling::ScalableTarget', { MinCapacity: 1, MaxCapacity: 5, ResourceId: objectLike({ @@ -514,17 +470,16 @@ export = { ':prod', )), }), - })); + }); - expect(stack).to(haveResourceLike('AWS::Lambda::Alias', { + expect(stack).toHaveResourceLike('AWS::Lambda::Alias', { ProvisionedConcurrencyConfig: { ProvisionedConcurrentExecutions: 10, }, - })); - test.done(); - }, + }); + }); - 'validation for utilizationTarget does not fail when using Tokens'(test: Test) { + test('validation for utilizationTarget does not fail when using Tokens', () => { // GIVEN const stack = new Stack(); const fn = new lambda.Function(stack, 'MyLambda', { @@ -547,19 +502,16 @@ export = { target.scaleOnUtilization({ utilizationTarget: Lazy.numberValue({ produce: () => 0.95 }) }); // THEN: no exception - expect(stack).to(haveResource('AWS::ApplicationAutoScaling::ScalingPolicy', { + expect(stack).toHaveResource('AWS::ApplicationAutoScaling::ScalingPolicy', { PolicyType: 'TargetTrackingScaling', TargetTrackingScalingPolicyConfiguration: { PredefinedMetricSpecification: { PredefinedMetricType: 'LambdaProvisionedConcurrencyUtilization' }, TargetValue: 0.95, }, + }); + }); - })); - - test.done(); - }, - - 'cannot enable AutoScaling twice on same property'(test: Test): void { + test('cannot enable AutoScaling twice on same property', () => { // GIVEN const stack = new Stack(); const fn = new lambda.Function(stack, 'MyLambda', { @@ -579,12 +531,10 @@ export = { alias.addAutoScaling({ maxCapacity: 5 }); // THEN - test.throws(() => alias.addAutoScaling({ maxCapacity: 8 }), /AutoScaling already enabled for this alias/); + expect(() => alias.addAutoScaling({ maxCapacity: 8 })).toThrow(/AutoScaling already enabled for this alias/); + }); - test.done(); - }, - - 'error when specifying invalid utilization value when AutoScaling on utilization'(test: Test): void { + test('error when specifying invalid utilization value when AutoScaling on utilization', () => { // GIVEN const stack = new Stack(); const fn = new lambda.Function(stack, 'MyLambda', { @@ -604,11 +554,10 @@ export = { const target = alias.addAutoScaling({ maxCapacity: 5 }); // THEN - test.throws(() => target.scaleOnUtilization({ utilizationTarget: 0.95 }), /Utilization Target should be between 0.1 and 0.9. Found 0.95/); - test.done(); - }, + expect(() => target.scaleOnUtilization({ utilizationTarget: 0.95 })).toThrow(/Utilization Target should be between 0.1 and 0.9. Found 0.95/); + }); - 'can autoscale on a schedule'(test: Test): void { + test('can autoscale on a schedule', () => { // GIVEN const stack = new Stack(); const fn = new lambda.Function(stack, 'MyLambda', { @@ -632,7 +581,7 @@ export = { }); // THEN - expect(stack).to(haveResourceLike('AWS::ApplicationAutoScaling::ScalableTarget', { + expect(stack).toHaveResourceLike('AWS::ApplicationAutoScaling::ScalableTarget', { ScheduledActions: [ { ScalableTargetAction: { MaxCapacity: 10 }, @@ -640,8 +589,6 @@ export = { ScheduledActionName: 'Scheduling', }, ], - })); - - test.done(); - }, -}; + }); + }); +}); diff --git a/packages/@aws-cdk/aws-lambda/test/test.code.ts b/packages/@aws-cdk/aws-lambda/test/code.test.ts similarity index 58% rename from packages/@aws-cdk/aws-lambda/test/test.code.ts rename to packages/@aws-cdk/aws-lambda/test/code.test.ts index b98653828d3c9..b00cf74562c3e 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.code.ts +++ b/packages/@aws-cdk/aws-lambda/test/code.test.ts @@ -1,37 +1,33 @@ +import '@aws-cdk/assert/jest'; import * as path from 'path'; -import { expect, haveResource, haveResourceLike, ResourcePart } from '@aws-cdk/assert'; +import { ResourcePart } from '@aws-cdk/assert'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { Test } from 'nodeunit'; import * as lambda from '../lib'; /* eslint-disable dot-notation */ -export = { - 'lambda.Code.fromInline': { - 'fails if used with unsupported runtimes'(test: Test) { - test.throws(() => defineFunction(lambda.Code.fromInline('boom'), lambda.Runtime.GO_1_X), /Inline source not allowed for go1\.x/); - test.throws(() => defineFunction(lambda.Code.fromInline('boom'), lambda.Runtime.JAVA_8), /Inline source not allowed for java8/); - test.done(); - }, - 'fails if larger than 4096 bytes'(test: Test) { - test.throws( - () => defineFunction(lambda.Code.fromInline(generateRandomString(4097)), lambda.Runtime.NODEJS_10_X), - /Lambda source is too large, must be <= 4096 but is 4097/); - test.done(); - }, - }, - 'lambda.Code.fromAsset': { - 'fails if a non-zip asset is used'(test: Test) { +describe('code', () => { + describe('lambda.Code.fromInline', () => { + test('fails if used with unsupported runtimes', () => { + expect(() => defineFunction(lambda.Code.fromInline('boom'), lambda.Runtime.GO_1_X)).toThrow(/Inline source not allowed for go1\.x/); + expect(() => defineFunction(lambda.Code.fromInline('boom'), lambda.Runtime.JAVA_8)).toThrow(/Inline source not allowed for java8/); + }); + test('fails if larger than 4096 bytes', () => { + expect(() => defineFunction(lambda.Code.fromInline(generateRandomString(4097)), lambda.Runtime.NODEJS_10_X)) + .toThrow(/Lambda source is too large, must be <= 4096 but is 4097/); + }); + }); + describe('lambda.Code.fromAsset', () => { + test('fails if a non-zip asset is used', () => { // GIVEN const fileAsset = lambda.Code.fromAsset(path.join(__dirname, 'my-lambda-handler', 'index.py')); // THEN - test.throws(() => defineFunction(fileAsset), /Asset must be a \.zip file or a directory/); - test.done(); - }, + expect(() => defineFunction(fileAsset)).toThrow(/Asset must be a \.zip file or a directory/); + }); - 'only one Asset object gets created even if multiple functions use the same AssetCode'(test: Test) { + test('only one Asset object gets created even if multiple functions use the same AssetCode', () => { // GIVEN const app = new cdk.App(); const stack = new cdk.Stack(app, 'MyStack'); @@ -55,11 +51,10 @@ export = { const synthesized = assembly.stacks[0]; // Func1 has an asset, Func2 does not - test.deepEqual(synthesized.assets.length, 1); - test.done(); - }, + expect(synthesized.assets.length).toEqual(1); + }); - 'adds code asset metadata'(test: Test) { + test('adds code asset metadata', () => { // GIVEN const stack = new cdk.Stack(); stack.node.setContext(cxapi.ASSET_RESOURCE_METADATA_ENABLED_CONTEXT, true); @@ -74,18 +69,17 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::Lambda::Function', { + expect(stack).toHaveResource('AWS::Lambda::Function', { Metadata: { [cxapi.ASSET_RESOURCE_METADATA_PATH_KEY]: 'asset.9678c34eca93259d11f2d714177347afd66c50116e1e08996eff893d3ca81232', [cxapi.ASSET_RESOURCE_METADATA_PROPERTY_KEY]: 'Code', }, - }, ResourcePart.CompleteDefinition)); - test.done(); - }, - }, + }, ResourcePart.CompleteDefinition); + }); + }); - 'lambda.Code.fromCfnParameters': { - "automatically creates the Bucket and Key parameters when it's used in a Function"(test: Test) { + describe('lambda.Code.fromCfnParameters', () => { + test("automatically creates the Bucket and Key parameters when it's used in a Function", () => { const stack = new cdk.Stack(); const code = new lambda.CfnParametersCode(); new lambda.Function(stack, 'Function', { @@ -94,7 +88,7 @@ export = { handler: 'index.handler', }); - expect(stack).to(haveResourceLike('AWS::Lambda::Function', { + expect(stack).toHaveResourceLike('AWS::Lambda::Function', { Code: { S3Bucket: { Ref: 'FunctionLambdaSourceBucketNameParameter9E9E108F', @@ -103,29 +97,21 @@ export = { Ref: 'FunctionLambdaSourceObjectKeyParameter1C7AED11', }, }, - })); - - test.equal(stack.resolve(code.bucketNameParam), 'FunctionLambdaSourceBucketNameParameter9E9E108F'); - test.equal(stack.resolve(code.objectKeyParam), 'FunctionLambdaSourceObjectKeyParameter1C7AED11'); + }); - test.done(); - }, + expect(stack.resolve(code.bucketNameParam)).toEqual('FunctionLambdaSourceBucketNameParameter9E9E108F'); + expect(stack.resolve(code.objectKeyParam)).toEqual('FunctionLambdaSourceObjectKeyParameter1C7AED11'); + }); - 'does not allow accessing the Parameter properties before being used in a Function'(test: Test) { + test('does not allow accessing the Parameter properties before being used in a Function', () => { const code = new lambda.CfnParametersCode(); - test.throws(() => { - test.notEqual(code.bucketNameParam, undefined); - }, /bucketNameParam/); - - test.throws(() => { - test.notEqual(code.objectKeyParam, undefined); - }, /objectKeyParam/); + expect(() => code.bucketNameParam).toThrow(/bucketNameParam/); - test.done(); - }, + expect(() => code.objectKeyParam).toThrow(/objectKeyParam/); + }); - 'allows passing custom Parameters when creating it'(test: Test) { + test('allows passing custom Parameters when creating it', () => { const stack = new cdk.Stack(); const bucketNameParam = new cdk.CfnParameter(stack, 'BucketNameParam', { type: 'String', @@ -139,8 +125,8 @@ export = { objectKeyParam: bucketKeyParam, }); - test.equal(stack.resolve(code.bucketNameParam), 'BucketNameParam'); - test.equal(stack.resolve(code.objectKeyParam), 'ObjectKeyParam'); + expect(stack.resolve(code.bucketNameParam)).toEqual('BucketNameParam'); + expect(stack.resolve(code.objectKeyParam)).toEqual('ObjectKeyParam'); new lambda.Function(stack, 'Function', { code, @@ -148,7 +134,7 @@ export = { handler: 'index.handler', }); - expect(stack).to(haveResourceLike('AWS::Lambda::Function', { + expect(stack).toHaveResourceLike('AWS::Lambda::Function', { Code: { S3Bucket: { Ref: 'BucketNameParam', @@ -157,12 +143,10 @@ export = { Ref: 'ObjectKeyParam', }, }, - })); - - test.done(); - }, + }); + }); - 'can assign parameters'(test: Test) { + test('can assign parameters', () => { // given const stack = new cdk.Stack(); const code = new lambda.CfnParametersCode({ @@ -181,13 +165,11 @@ export = { })); // then - test.equal(overrides['BucketNameParam'], 'SomeBucketName'); - test.equal(overrides['ObjectKeyParam'], 'SomeObjectKey'); - - test.done(); - }, - }, -}; + expect(overrides['BucketNameParam']).toEqual('SomeBucketName'); + expect(overrides['ObjectKeyParam']).toEqual('SomeObjectKey'); + }); + }); +}); function defineFunction(code: lambda.Code, runtime: lambda.Runtime = lambda.Runtime.NODEJS_10_X) { const stack = new cdk.Stack(); diff --git a/packages/@aws-cdk/aws-lambda/test/test.event-source-mapping.ts b/packages/@aws-cdk/aws-lambda/test/event-source-mapping.test.ts similarity index 51% rename from packages/@aws-cdk/aws-lambda/test/test.event-source-mapping.ts rename to packages/@aws-cdk/aws-lambda/test/event-source-mapping.test.ts index bc9492f1d2f7e..78c11922bf183 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.event-source-mapping.ts +++ b/packages/@aws-cdk/aws-lambda/test/event-source-mapping.test.ts @@ -1,10 +1,9 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert'; +import '@aws-cdk/assert/jest'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; import { Code, EventSourceMapping, Function, Runtime } from '../lib'; -export = { - 'throws if maxBatchingWindow > 300 seconds'(test: Test) { +describe('event source mapping', () => { + test('throws if maxBatchingWindow > 300 seconds', () => { const stack = new cdk.Stack(); const fn = new Function(stack, 'fn', { handler: 'index.handler', @@ -12,19 +11,14 @@ export = { runtime: Runtime.NODEJS_10_X, }); - test.throws(() => - new EventSourceMapping( - stack, - 'test', - { - target: fn, - eventSourceArn: '', - maxBatchingWindow: cdk.Duration.seconds(301), - }), /maxBatchingWindow cannot be over 300 seconds/); - - test.done(); - }, - 'throws if maxRecordAge is below 60 seconds'(test: Test) { + expect(() => new EventSourceMapping(stack, 'test', { + target: fn, + eventSourceArn: '', + maxBatchingWindow: cdk.Duration.seconds(301), + })).toThrow(/maxBatchingWindow cannot be over 300 seconds/); + }); + + test('throws if maxRecordAge is below 60 seconds', () => { const stack = new cdk.Stack(); const fn = new Function(stack, 'fn', { handler: 'index.handler', @@ -32,19 +26,14 @@ export = { runtime: Runtime.NODEJS_10_X, }); - test.throws(() => - new EventSourceMapping( - stack, - 'test', - { - target: fn, - eventSourceArn: '', - maxRecordAge: cdk.Duration.seconds(59), - }), /maxRecordAge must be between 60 seconds and 7 days inclusive/); - - test.done(); - }, - 'throws if maxRecordAge is over 7 days'(test: Test) { + expect(() => new EventSourceMapping(stack, 'test', { + target: fn, + eventSourceArn: '', + maxRecordAge: cdk.Duration.seconds(59), + })).toThrow(/maxRecordAge must be between 60 seconds and 7 days inclusive/); + }); + + test('throws if maxRecordAge is over 7 days', () => { const stack = new cdk.Stack(); const fn = new Function(stack, 'fn', { handler: 'index.handler', @@ -52,19 +41,14 @@ export = { runtime: Runtime.NODEJS_10_X, }); - test.throws(() => - new EventSourceMapping( - stack, - 'test', - { - target: fn, - eventSourceArn: '', - maxRecordAge: cdk.Duration.seconds(604801), - }), /maxRecordAge must be between 60 seconds and 7 days inclusive/); - - test.done(); - }, - 'throws if retryAttempts is negative'(test: Test) { + expect(() => new EventSourceMapping(stack, 'test', { + target: fn, + eventSourceArn: '', + maxRecordAge: cdk.Duration.seconds(604801), + })).toThrow(/maxRecordAge must be between 60 seconds and 7 days inclusive/); + }); + + test('throws if retryAttempts is negative', () => { const stack = new cdk.Stack(); const fn = new Function(stack, 'fn', { handler: 'index.handler', @@ -72,19 +56,14 @@ export = { runtime: Runtime.NODEJS_10_X, }); - test.throws(() => - new EventSourceMapping( - stack, - 'test', - { - target: fn, - eventSourceArn: '', - retryAttempts: -1, - }), /retryAttempts must be between 0 and 10000 inclusive, got -1/); - - test.done(); - }, - 'throws if retryAttempts is over 10000'(test: Test) { + expect(() => new EventSourceMapping(stack, 'test', { + target: fn, + eventSourceArn: '', + retryAttempts: -1, + })).toThrow(/retryAttempts must be between 0 and 10000 inclusive, got -1/); + }); + + test('throws if retryAttempts is over 10000', () => { const stack = new cdk.Stack(); const fn = new Function(stack, 'fn', { handler: 'index.handler', @@ -92,19 +71,14 @@ export = { runtime: Runtime.NODEJS_10_X, }); - test.throws(() => - new EventSourceMapping( - stack, - 'test', - { - target: fn, - eventSourceArn: '', - retryAttempts: 10001, - }), /retryAttempts must be between 0 and 10000 inclusive, got 10001/); - - test.done(); - }, - 'accepts if retryAttempts is a token'(test: Test) { + expect(() => new EventSourceMapping(stack, 'test', { + target: fn, + eventSourceArn: '', + retryAttempts: 10001, + })).toThrow(/retryAttempts must be between 0 and 10000 inclusive, got 10001/); + }); + + test('accepts if retryAttempts is a token', () => { const stack = new cdk.Stack(); const fn = new Function(stack, 'fn', { handler: 'index.handler', @@ -117,10 +91,9 @@ export = { eventSourceArn: '', retryAttempts: cdk.Lazy.numberValue({ produce: () => 100 }), }); + }); - test.done(); - }, - 'throws if parallelizationFactor is below 1'(test: Test) { + test('throws if parallelizationFactor is below 1', () => { const stack = new cdk.Stack(); const fn = new Function(stack, 'fn', { handler: 'index.handler', @@ -128,19 +101,14 @@ export = { runtime: Runtime.NODEJS_10_X, }); - test.throws(() => - new EventSourceMapping( - stack, - 'test', - { - target: fn, - eventSourceArn: '', - parallelizationFactor: 0, - }), /parallelizationFactor must be between 1 and 10 inclusive, got 0/); - - test.done(); - }, - 'throws if parallelizationFactor is over 10'(test: Test) { + expect(() => new EventSourceMapping(stack, 'test', { + target: fn, + eventSourceArn: '', + parallelizationFactor: 0, + })).toThrow(/parallelizationFactor must be between 1 and 10 inclusive, got 0/); + }); + + test('throws if parallelizationFactor is over 10', () => { const stack = new cdk.Stack(); const fn = new Function(stack, 'fn', { handler: 'index.handler', @@ -148,20 +116,14 @@ export = { runtime: Runtime.NODEJS_10_X, }); - test.throws(() => - new EventSourceMapping( - stack, - 'test', - { - target: fn, - eventSourceArn: '', - parallelizationFactor: 11, - }), /parallelizationFactor must be between 1 and 10 inclusive, got 11/); - - test.done(); - }, + expect(() => new EventSourceMapping(stack, 'test', { + target: fn, + eventSourceArn: '', + parallelizationFactor: 11, + })).toThrow(/parallelizationFactor must be between 1 and 10 inclusive, got 11/); + }); - 'accepts if parallelizationFactor is a token'(test: Test) { + test('accepts if parallelizationFactor is a token', () => { const stack = new cdk.Stack(); const fn = new Function(stack, 'fn', { handler: 'index.handler', @@ -174,20 +136,17 @@ export = { eventSourceArn: '', parallelizationFactor: cdk.Lazy.numberValue({ produce: () => 20 }), }); + }); - test.done(); - }, - - 'import event source mapping'(test: Test) { + test('import event source mapping', () => { const stack = new cdk.Stack(undefined, undefined, { stackName: 'test-stack' }); const imported = EventSourceMapping.fromEventSourceMappingId(stack, 'imported', '14e0db71-5d35-4eb5-b481-8945cf9d10c2'); - test.equals(imported.eventSourceMappingId, '14e0db71-5d35-4eb5-b481-8945cf9d10c2'); - test.equals(imported.stack.stackName, 'test-stack'); - test.done(); - }, + expect(imported.eventSourceMappingId).toEqual('14e0db71-5d35-4eb5-b481-8945cf9d10c2'); + expect(imported.stack.stackName).toEqual('test-stack'); + }); - 'accepts if kafkaTopic is a parameter'(test: Test) { + test('accepts if kafkaTopic is a parameter', () => { const stack = new cdk.Stack(); const topicNameParam = new cdk.CfnParameter(stack, 'TopicNameParam', { type: 'String', @@ -205,12 +164,10 @@ export = { kafkaTopic: topicNameParam.valueAsString, }); - expect(stack).to(haveResourceLike('AWS::Lambda::EventSourceMapping', { + expect(stack).toHaveResourceLike('AWS::Lambda::EventSourceMapping', { Topics: [{ Ref: 'TopicNameParam', }], - })); - - test.done(); - }, -}; + }); + }); +}); diff --git a/packages/@aws-cdk/aws-lambda/test/test.function-hash.ts b/packages/@aws-cdk/aws-lambda/test/function-hash.test.ts similarity index 68% rename from packages/@aws-cdk/aws-lambda/test/test.function-hash.ts rename to packages/@aws-cdk/aws-lambda/test/function-hash.test.ts index b17050d43c8d0..4f80c886e88d2 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.function-hash.ts +++ b/packages/@aws-cdk/aws-lambda/test/function-hash.test.ts @@ -1,30 +1,27 @@ +import '@aws-cdk/assert/jest'; import * as path from 'path'; import { CfnOutput, Stack } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; import * as lambda from '../lib'; import { calculateFunctionHash, trimFromStart } from '../lib/function-hash'; -export = { - 'trimFromStart': { +describe('function hash', () => { + describe('trimFromStart', () => { - 'trim not needed'(test: Test) { - test.deepEqual(trimFromStart('foo', 100), 'foo'); - test.deepEqual(trimFromStart('foo', 3), 'foo'); - test.deepEqual(trimFromStart('', 3), ''); - test.done(); - }, - - 'trim required'(test: Test) { - test.deepEqual(trimFromStart('hello', 3), 'llo'); - test.deepEqual(trimFromStart('hello', 4), 'ello'); - test.deepEqual(trimFromStart('hello', 1), 'o'); - test.done(); - }, + test('trim not needed', () => { + expect(trimFromStart('foo', 100)).toEqual('foo'); + expect(trimFromStart('foo', 3)).toEqual('foo'); + expect(trimFromStart('', 3)).toEqual(''); + }); - }, + test('trim required', () => { + expect(trimFromStart('hello', 3)).toEqual('llo'); + expect(trimFromStart('hello', 4)).toEqual('ello'); + expect(trimFromStart('hello', 1)).toEqual('o'); + }); + }); - 'calcHash': { - 'same configuration and code yields the same hash'(test: Test) { + describe('calcHash', () => { + test('same configuration and code yields the same hash', () => { const stack1 = new Stack(); const fn1 = new lambda.Function(stack1, 'MyFunction1', { runtime: lambda.Runtime.NODEJS_12_X, @@ -39,13 +36,12 @@ export = { handler: 'index.handler', }); - test.deepEqual(calculateFunctionHash(fn1), calculateFunctionHash(fn2)); - test.deepEqual(calculateFunctionHash(fn1), 'aea5463dba236007afe91d2832b3c836'); - test.done(); - }, - }, + expect(calculateFunctionHash(fn1)).toEqual(calculateFunctionHash(fn2)); + expect(calculateFunctionHash(fn1)).toEqual('aea5463dba236007afe91d2832b3c836'); + }); + }); - 'code impacts hash'(test: Test) { + test('code impacts hash', () => { const stack1 = new Stack(); const fn1 = new lambda.Function(stack1, 'MyFunction1', { runtime: lambda.Runtime.NODEJS_12_X, @@ -53,12 +49,11 @@ export = { handler: 'index.handler', }); - test.notDeepEqual(calculateFunctionHash(fn1), 'aea5463dba236007afe91d2832b3c836'); - test.deepEqual(calculateFunctionHash(fn1), '979b4a14c6f174c745cdbcd1036cf844'); - test.done(); - }, + expect(calculateFunctionHash(fn1)).not.toEqual('aea5463dba236007afe91d2832b3c836'); + expect(calculateFunctionHash(fn1)).toEqual('979b4a14c6f174c745cdbcd1036cf844'); + }); - 'environment variables impact hash'(test: Test) { + test('environment variables impact hash', () => { const stack1 = new Stack(); const fn1 = new lambda.Function(stack1, 'MyFunction', { runtime: lambda.Runtime.NODEJS_12_X, @@ -79,12 +74,11 @@ export = { }, }); - test.deepEqual(calculateFunctionHash(fn1), 'd1bc824ac5022b7d62d8b12dbae6580c'); - test.deepEqual(calculateFunctionHash(fn2), '3b683d05465012b0aa9c4ff53b32f014'); - test.done(); - }, + expect(calculateFunctionHash(fn1)).toEqual('d1bc824ac5022b7d62d8b12dbae6580c'); + expect(calculateFunctionHash(fn2)).toEqual('3b683d05465012b0aa9c4ff53b32f014'); + }); - 'runtime impacts hash'(test: Test) { + test('runtime impacts hash', () => { const stack1 = new Stack(); const fn1 = new lambda.Function(stack1, 'MyFunction', { runtime: lambda.Runtime.NODEJS_12_X, @@ -105,12 +99,11 @@ export = { }, }); - test.deepEqual(calculateFunctionHash(fn1), 'd1bc824ac5022b7d62d8b12dbae6580c'); - test.deepEqual(calculateFunctionHash(fn2), '0f168f0772463e8e547bb3800937e54d'); - test.done(); - }, + expect(calculateFunctionHash(fn1)).toEqual('d1bc824ac5022b7d62d8b12dbae6580c'); + expect(calculateFunctionHash(fn2)).toEqual('0f168f0772463e8e547bb3800937e54d'); + }); - 'inline code change impacts the hash'(test: Test) { + test('inline code change impacts the hash', () => { const stack1 = new Stack(); const fn1 = new lambda.Function(stack1, 'MyFunction', { runtime: lambda.Runtime.NODEJS_12_X, @@ -125,14 +118,13 @@ export = { handler: 'index.handler', }); - test.deepEqual(calculateFunctionHash(fn1), 'ebf2e871fc6a3062e8bdcc5ebe16db3f'); - test.deepEqual(calculateFunctionHash(fn2), 'ffedf6424a18a594a513129dc97bf53c'); - test.done(); - }, + expect(calculateFunctionHash(fn1)).toEqual('ebf2e871fc6a3062e8bdcc5ebe16db3f'); + expect(calculateFunctionHash(fn2)).toEqual('ffedf6424a18a594a513129dc97bf53c'); + }); - 'impact of env variables order on hash': { + describe('impact of env variables order on hash', () => { - 'without "currentVersion", we preserve old behavior to avoid unnesesary invalidation of templates'(test: Test) { + test('without "currentVersion", we preserve old behavior to avoid unnesesary invalidation of templates', () => { const stack1 = new Stack(); const fn1 = new lambda.Function(stack1, 'MyFunction', { runtime: lambda.Runtime.NODEJS_12_X, @@ -155,11 +147,10 @@ export = { }, }); - test.notDeepEqual(calculateFunctionHash(fn1), calculateFunctionHash(fn2)); - test.done(); - }, + expect(calculateFunctionHash(fn1)).not.toEqual(calculateFunctionHash(fn2)); + }); - 'with "currentVersion", we sort env keys so order is consistent'(test: Test) { + test('with "currentVersion", we sort env keys so order is consistent', () => { const stack1 = new Stack(); const fn1 = new lambda.Function(stack1, 'MyFunction', { runtime: lambda.Runtime.NODEJS_12_X, @@ -186,9 +177,7 @@ export = { new CfnOutput(stack2, 'VersionArn', { value: fn2.currentVersion.functionArn }); - test.deepEqual(calculateFunctionHash(fn1), calculateFunctionHash(fn2)); - test.done(); - }, - - }, -}; + expect(calculateFunctionHash(fn1)).toEqual(calculateFunctionHash(fn2)); + }); + }); +}); diff --git a/packages/@aws-cdk/aws-lambda/test/function.test.ts b/packages/@aws-cdk/aws-lambda/test/function.test.ts new file mode 100644 index 0000000000000..761a688762c48 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda/test/function.test.ts @@ -0,0 +1,1795 @@ +import '@aws-cdk/assert/jest'; +import * as path from 'path'; +import { ABSENT, ResourcePart, SynthUtils } from '@aws-cdk/assert'; +import { ProfilingGroup } from '@aws-cdk/aws-codeguruprofiler'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as efs from '@aws-cdk/aws-efs'; +import * as iam from '@aws-cdk/aws-iam'; +import * as logs from '@aws-cdk/aws-logs'; +import * as s3 from '@aws-cdk/aws-s3'; +import * as sqs from '@aws-cdk/aws-sqs'; +import * as cdk from '@aws-cdk/core'; +import * as constructs from 'constructs'; +import * as _ from 'lodash'; +import * as lambda from '../lib'; + +describe('function', () => { + test('default function', () => { + const stack = new cdk.Stack(); + + new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + }); + + expect(stack).toHaveResource('AWS::IAM::Role', { + AssumeRolePolicyDocument: + { + Statement: + [{ + Action: 'sts:AssumeRole', + Effect: 'Allow', + Principal: { Service: 'lambda.amazonaws.com' }, + }], + Version: '2012-10-17', + }, + ManagedPolicyArns: + [{ 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole']] }], + }); + + expect(stack).toHaveResource('AWS::Lambda::Function', { + Properties: + { + Code: { ZipFile: 'foo' }, + Handler: 'index.handler', + Role: { 'Fn::GetAtt': ['MyLambdaServiceRole4539ECB6', 'Arn'] }, + Runtime: 'nodejs10.x', + }, + DependsOn: ['MyLambdaServiceRole4539ECB6'], + }, ResourcePart.CompleteDefinition); + }); + + test('adds policy permissions', () => { + const stack = new cdk.Stack(); + new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + initialPolicy: [new iam.PolicyStatement({ actions: ['*'], resources: ['*'] })], + }); + expect(stack).toHaveResource('AWS::IAM::Role', { + AssumeRolePolicyDocument: + { + Statement: + [{ + Action: 'sts:AssumeRole', + Effect: 'Allow', + Principal: { Service: 'lambda.amazonaws.com' }, + }], + Version: '2012-10-17', + }, + ManagedPolicyArns: + // eslint-disable-next-line max-len + [{ 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole']] }], + }); + expect(stack).toHaveResource('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: '*', + Effect: 'Allow', + Resource: '*', + }, + ], + Version: '2012-10-17', + }, + PolicyName: 'MyLambdaServiceRoleDefaultPolicy5BBC6F68', + Roles: [ + { + Ref: 'MyLambdaServiceRole4539ECB6', + }, + ], + }); + + expect(stack).toHaveResource('AWS::Lambda::Function', { + Properties: { + Code: { ZipFile: 'foo' }, + Handler: 'index.handler', + Role: { 'Fn::GetAtt': ['MyLambdaServiceRole4539ECB6', 'Arn'] }, + Runtime: 'nodejs10.x', + }, + DependsOn: ['MyLambdaServiceRoleDefaultPolicy5BBC6F68', 'MyLambdaServiceRole4539ECB6'], + }, ResourcePart.CompleteDefinition); + }); + + test('fails if inline code is used for an invalid runtime', () => { + const stack = new cdk.Stack(); + expect(() => new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'bar', + runtime: lambda.Runtime.DOTNET_CORE_2, + })).toThrow(); + }); + + describe('addToResourcePolicy', () => { + test('can be used to add permissions to the Lambda function', () => { + const stack = new cdk.Stack(); + const fn = newTestLambda(stack); + + fn.addPermission('S3Permission', { + action: 'lambda:*', + principal: new iam.ServicePrincipal('s3.amazonaws.com'), + sourceAccount: stack.account, + sourceArn: 'arn:aws:s3:::my_bucket', + }); + + expect(stack).toHaveResource('AWS::IAM::Role', { + AssumeRolePolicyDocument: { + Statement: [ + { + Action: 'sts:AssumeRole', + Effect: 'Allow', + Principal: { + Service: 'lambda.amazonaws.com', + }, + }, + ], + Version: '2012-10-17', + }, + ManagedPolicyArns: + // eslint-disable-next-line max-len + [{ 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole']] }], + }); + + expect(stack).toHaveResource('AWS::Lambda::Function', { + Properties: { + Code: { + ZipFile: 'foo', + }, + Handler: 'bar', + Role: { + 'Fn::GetAtt': [ + 'MyLambdaServiceRole4539ECB6', + 'Arn', + ], + }, + Runtime: 'python2.7', + }, + DependsOn: [ + 'MyLambdaServiceRole4539ECB6', + ], + }, ResourcePart.CompleteDefinition); + + expect(stack).toHaveResource('AWS::Lambda::Permission', { + Action: 'lambda:*', + FunctionName: { + 'Fn::GetAtt': [ + 'MyLambdaCCE802FB', + 'Arn', + ], + }, + Principal: 's3.amazonaws.com', + SourceAccount: { + Ref: 'AWS::AccountId', + }, + SourceArn: 'arn:aws:s3:::my_bucket', + }); + }); + + test('fails if the principal is not a service, account or arn principal', () => { + const stack = new cdk.Stack(); + const fn = newTestLambda(stack); + + expect(() => fn.addPermission('F1', { principal: new iam.OrganizationPrincipal('org') })) + .toThrow(/Invalid principal type for Lambda permission statement/); + + fn.addPermission('S1', { principal: new iam.ServicePrincipal('my-service') }); + fn.addPermission('S2', { principal: new iam.AccountPrincipal('account') }); + fn.addPermission('S3', { principal: new iam.ArnPrincipal('my:arn') }); + }); + + test('BYORole', () => { + // GIVEN + const stack = new cdk.Stack(); + const role = new iam.Role(stack, 'SomeRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + }); + role.addToPolicy(new iam.PolicyStatement({ actions: ['confirm:itsthesame'], resources: ['*'] })); + + // WHEN + const fn = new lambda.Function(stack, 'Function', { + code: new lambda.InlineCode('test'), + runtime: lambda.Runtime.PYTHON_3_6, + handler: 'index.test', + role, + initialPolicy: [ + new iam.PolicyStatement({ actions: ['inline:inline'], resources: ['*'] }), + ], + }); + + fn.addToRolePolicy(new iam.PolicyStatement({ actions: ['explicit:explicit'], resources: ['*'] })); + + // THEN + expect(stack).toHaveResource('AWS::IAM::Policy', { + PolicyDocument: { + Version: '2012-10-17', + Statement: [ + { Action: 'confirm:itsthesame', Effect: 'Allow', Resource: '*' }, + { Action: 'inline:inline', Effect: 'Allow', Resource: '*' }, + { Action: 'explicit:explicit', Effect: 'Allow', Resource: '*' }, + ], + }, + }); + }); + }); + + test('fromFunctionArn', () => { + // GIVEN + const stack2 = new cdk.Stack(); + + // WHEN + const imported = lambda.Function.fromFunctionArn(stack2, 'Imported', 'arn:aws:lambda:us-east-1:123456789012:function:ProcessKinesisRecords'); + + // THEN + expect(imported.functionArn).toEqual('arn:aws:lambda:us-east-1:123456789012:function:ProcessKinesisRecords'); + expect(imported.functionName).toEqual('ProcessKinesisRecords'); + }); + + describe('addPermissions', () => { + test('imported Function w/ resolved account and function arn', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Imports', { + env: { account: '123456789012', region: 'us-east-1' }, + }); + + // WHEN + const iFunc = lambda.Function.fromFunctionAttributes(stack, 'iFunc', { + functionArn: 'arn:aws:lambda:us-east-1:123456789012:function:BaseFunction', + }); + iFunc.addPermission('iFunc', { + principal: new iam.ServicePrincipal('cloudformation.amazonaws.com'), + }); + + // THEN + expect(stack).toHaveResource('AWS::Lambda::Permission'); + }); + + test('imported Function w/ unresolved account', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Imports'); + + // WHEN + const iFunc = lambda.Function.fromFunctionAttributes(stack, 'iFunc', { + functionArn: 'arn:aws:lambda:us-east-1:123456789012:function:BaseFunction', + }); + iFunc.addPermission('iFunc', { + principal: new iam.ServicePrincipal('cloudformation.amazonaws.com'), + }); + + // THEN + expect(stack).toHaveResource('AWS::Lambda::Permission'); + }); + + test('imported Function w/different account', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Base', { + env: { account: '111111111111' }, + }); + + // WHEN + const iFunc = lambda.Function.fromFunctionAttributes(stack, 'iFunc', { + functionArn: 'arn:aws:lambda:us-east-1:123456789012:function:BaseFunction', + }); + iFunc.addPermission('iFunc', { + principal: new iam.ServicePrincipal('cloudformation.amazonaws.com'), + }); + + // THEN + expect(stack).not.toHaveResource('AWS::Lambda::Permission'); + }); + }); + + test('Lambda code can be read from a local directory via an asset', () => { + // GIVEN + const stack = new cdk.Stack(); + new lambda.Function(stack, 'MyLambda', { + code: lambda.Code.fromAsset(path.join(__dirname, 'my-lambda-handler')), + handler: 'index.handler', + runtime: lambda.Runtime.PYTHON_3_6, + }); + + // THEN + expect(stack).toHaveResource('AWS::Lambda::Function', { + Code: { + S3Bucket: { + Ref: 'AssetParameters9678c34eca93259d11f2d714177347afd66c50116e1e08996eff893d3ca81232S3Bucket1354C645', + }, + S3Key: { + 'Fn::Join': ['', [ + { 'Fn::Select': [0, { 'Fn::Split': ['||', { Ref: 'AssetParameters9678c34eca93259d11f2d714177347afd66c50116e1e08996eff893d3ca81232S3VersionKey5D873FAC' }] }] }, + { 'Fn::Select': [1, { 'Fn::Split': ['||', { Ref: 'AssetParameters9678c34eca93259d11f2d714177347afd66c50116e1e08996eff893d3ca81232S3VersionKey5D873FAC' }] }] }, + ]], + }, + }, + Handler: 'index.handler', + Role: { + 'Fn::GetAtt': [ + 'MyLambdaServiceRole4539ECB6', + 'Arn', + ], + }, + Runtime: 'python3.6', + }); + }); + + test('default function with SQS DLQ when client sets deadLetterQueueEnabled to true and functionName defined by client', () => { + const stack = new cdk.Stack(); + + new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + functionName: 'OneFunctionToRuleThemAll', + deadLetterQueueEnabled: true, + }); + + expect(stack).toHaveResource('AWS::IAM::Role', { + AssumeRolePolicyDocument: { + Statement: [ + { + Action: 'sts:AssumeRole', + Effect: 'Allow', + Principal: { + Service: 'lambda.amazonaws.com', + }, + }, + ], + Version: '2012-10-17', + }, + ManagedPolicyArns: [ + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole', + ], + ], + }, + ], + }); + expect(stack).toHaveResource('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: 'sqs:SendMessage', + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': [ + 'MyLambdaDeadLetterQueue399EEA2D', + 'Arn', + ], + }, + }, + ], + Version: '2012-10-17', + }, + PolicyName: 'MyLambdaServiceRoleDefaultPolicy5BBC6F68', + Roles: [ + { + Ref: 'MyLambdaServiceRole4539ECB6', + }, + ], + }); + expect(stack).toHaveResource('AWS::Lambda::Function', { + Properties: { + Code: { + ZipFile: 'foo', + }, + Handler: 'index.handler', + Role: { + 'Fn::GetAtt': [ + 'MyLambdaServiceRole4539ECB6', + 'Arn', + ], + }, + Runtime: 'nodejs10.x', + DeadLetterConfig: { + TargetArn: { + 'Fn::GetAtt': [ + 'MyLambdaDeadLetterQueue399EEA2D', + 'Arn', + ], + }, + }, + FunctionName: 'OneFunctionToRuleThemAll', + }, + DependsOn: [ + 'MyLambdaServiceRoleDefaultPolicy5BBC6F68', + 'MyLambdaServiceRole4539ECB6', + ], + }, ResourcePart.CompleteDefinition); + }); + + test('default function with SQS DLQ when client sets deadLetterQueueEnabled to true and functionName not defined by client', () => { + const stack = new cdk.Stack(); + + new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + deadLetterQueueEnabled: true, + }); + + expect(stack).toHaveResource('AWS::SQS::Queue', { + MessageRetentionPeriod: 1209600, + }); + + expect(stack).toHaveResource('AWS::Lambda::Function', { + DeadLetterConfig: { + TargetArn: { + 'Fn::GetAtt': [ + 'MyLambdaDeadLetterQueue399EEA2D', + 'Arn', + ], + }, + }, + }); + }); + + test('default function with SQS DLQ when client sets deadLetterQueueEnabled to false', () => { + const stack = new cdk.Stack(); + + new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + deadLetterQueueEnabled: false, + }); + + expect(stack).toHaveResource('AWS::Lambda::Function', { + Code: { + ZipFile: 'foo', + }, + Handler: 'index.handler', + Role: { + 'Fn::GetAtt': [ + 'MyLambdaServiceRole4539ECB6', + 'Arn', + ], + }, + Runtime: 'nodejs10.x', + }); + }); + + test('default function with SQS DLQ when client provides Queue to be used as DLQ', () => { + const stack = new cdk.Stack(); + + const dlQueue = new sqs.Queue(stack, 'DeadLetterQueue', { + queueName: 'MyLambda_DLQ', + retentionPeriod: cdk.Duration.days(14), + }); + + new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + deadLetterQueue: dlQueue, + }); + + expect(stack).toHaveResource('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: 'sqs:SendMessage', + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': [ + 'DeadLetterQueue9F481546', + 'Arn', + ], + }, + }, + ], + Version: '2012-10-17', + }, + }); + + expect(stack).toHaveResource('AWS::Lambda::Function', { + DeadLetterConfig: { + TargetArn: { + 'Fn::GetAtt': [ + 'DeadLetterQueue9F481546', + 'Arn', + ], + }, + }, + }); + }); + + test('default function with SQS DLQ when client provides Queue to be used as DLQ and deadLetterQueueEnabled set to true', () => { + const stack = new cdk.Stack(); + + const dlQueue = new sqs.Queue(stack, 'DeadLetterQueue', { + queueName: 'MyLambda_DLQ', + retentionPeriod: cdk.Duration.days(14), + }); + + new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + deadLetterQueueEnabled: true, + deadLetterQueue: dlQueue, + }); + + expect(stack).toHaveResource('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: 'sqs:SendMessage', + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': [ + 'DeadLetterQueue9F481546', + 'Arn', + ], + }, + }, + ], + Version: '2012-10-17', + }, + }); + + expect(stack).toHaveResource('AWS::Lambda::Function', { + DeadLetterConfig: { + TargetArn: { + 'Fn::GetAtt': [ + 'DeadLetterQueue9F481546', + 'Arn', + ], + }, + }, + }); + }); + + test('error when default function with SQS DLQ when client provides Queue to be used as DLQ and deadLetterQueueEnabled set to false', () => { + const stack = new cdk.Stack(); + + const dlQueue = new sqs.Queue(stack, 'DeadLetterQueue', { + queueName: 'MyLambda_DLQ', + retentionPeriod: cdk.Duration.days(14), + }); + + expect(() => new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + deadLetterQueueEnabled: false, + deadLetterQueue: dlQueue, + })).toThrow(/deadLetterQueue defined but deadLetterQueueEnabled explicitly set to false/); + }); + + test('default function with Active tracing', () => { + const stack = new cdk.Stack(); + + new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + tracing: lambda.Tracing.ACTIVE, + }); + + expect(stack).toHaveResource('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: [ + 'xray:PutTraceSegments', + 'xray:PutTelemetryRecords', + ], + Effect: 'Allow', + Resource: '*', + }, + ], + Version: '2012-10-17', + }, + PolicyName: 'MyLambdaServiceRoleDefaultPolicy5BBC6F68', + Roles: [ + { + Ref: 'MyLambdaServiceRole4539ECB6', + }, + ], + }); + + expect(stack).toHaveResource('AWS::Lambda::Function', { + Properties: { + Code: { + ZipFile: 'foo', + }, + Handler: 'index.handler', + Role: { + 'Fn::GetAtt': [ + 'MyLambdaServiceRole4539ECB6', + 'Arn', + ], + }, + Runtime: 'nodejs10.x', + TracingConfig: { + Mode: 'Active', + }, + }, + DependsOn: [ + 'MyLambdaServiceRoleDefaultPolicy5BBC6F68', + 'MyLambdaServiceRole4539ECB6', + ], + }, ResourcePart.CompleteDefinition); + }); + + test('default function with PassThrough tracing', () => { + const stack = new cdk.Stack(); + + new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + tracing: lambda.Tracing.PASS_THROUGH, + }); + + expect(stack).toHaveResource('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: [ + 'xray:PutTraceSegments', + 'xray:PutTelemetryRecords', + ], + Effect: 'Allow', + Resource: '*', + }, + ], + Version: '2012-10-17', + }, + PolicyName: 'MyLambdaServiceRoleDefaultPolicy5BBC6F68', + Roles: [ + { + Ref: 'MyLambdaServiceRole4539ECB6', + }, + ], + }); + + expect(stack).toHaveResource('AWS::Lambda::Function', { + Properties: { + Code: { + ZipFile: 'foo', + }, + Handler: 'index.handler', + Role: { + 'Fn::GetAtt': [ + 'MyLambdaServiceRole4539ECB6', + 'Arn', + ], + }, + Runtime: 'nodejs10.x', + TracingConfig: { + Mode: 'PassThrough', + }, + }, + DependsOn: [ + 'MyLambdaServiceRoleDefaultPolicy5BBC6F68', + 'MyLambdaServiceRole4539ECB6', + ], + }, ResourcePart.CompleteDefinition); + }); + + test('default function with Disabled tracing', () => { + const stack = new cdk.Stack(); + + new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + tracing: lambda.Tracing.DISABLED, + }); + + expect(stack).not.toHaveResource('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: [ + 'xray:PutTraceSegments', + 'xray:PutTelemetryRecords', + ], + Effect: 'Allow', + Resource: '*', + }, + ], + Version: '2012-10-17', + }, + PolicyName: 'MyLambdaServiceRoleDefaultPolicy5BBC6F68', + Roles: [ + { + Ref: 'MyLambdaServiceRole4539ECB6', + }, + ], + }); + + expect(stack).toHaveResource('AWS::Lambda::Function', { + Properties: { + Code: { + ZipFile: 'foo', + }, + Handler: 'index.handler', + Role: { + 'Fn::GetAtt': [ + 'MyLambdaServiceRole4539ECB6', + 'Arn', + ], + }, + Runtime: 'nodejs10.x', + }, + DependsOn: [ + 'MyLambdaServiceRole4539ECB6', + ], + }, ResourcePart.CompleteDefinition); + }); + + describe('grantInvoke', () => { + + test('adds iam:InvokeFunction', () => { + // GIVEN + const stack = new cdk.Stack(); + const role = new iam.Role(stack, 'Role', { + assumedBy: new iam.AccountPrincipal('1234'), + }); + const fn = new lambda.Function(stack, 'Function', { + code: lambda.Code.fromInline('xxx'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + }); + + // WHEN + fn.grantInvoke(role); + + // THEN + expect(stack).toHaveResource('AWS::IAM::Policy', { + PolicyDocument: { + Version: '2012-10-17', + Statement: [ + { + Action: 'lambda:InvokeFunction', + Effect: 'Allow', + Resource: { 'Fn::GetAtt': ['Function76856677', 'Arn'] }, + }, + ], + }, + }); + }); + + test('with a service principal', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new lambda.Function(stack, 'Function', { + code: lambda.Code.fromInline('xxx'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + }); + const service = new iam.ServicePrincipal('apigateway.amazonaws.com'); + + // WHEN + fn.grantInvoke(service); + + // THEN + expect(stack).toHaveResource('AWS::Lambda::Permission', { + Action: 'lambda:InvokeFunction', + FunctionName: { + 'Fn::GetAtt': [ + 'Function76856677', + 'Arn', + ], + }, + Principal: 'apigateway.amazonaws.com', + }); + }); + + test('with an account principal', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new lambda.Function(stack, 'Function', { + code: lambda.Code.fromInline('xxx'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + }); + const account = new iam.AccountPrincipal('123456789012'); + + // WHEN + fn.grantInvoke(account); + + // THEN + expect(stack).toHaveResource('AWS::Lambda::Permission', { + Action: 'lambda:InvokeFunction', + FunctionName: { + 'Fn::GetAtt': [ + 'Function76856677', + 'Arn', + ], + }, + Principal: '123456789012', + }); + }); + + test('with an arn principal', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new lambda.Function(stack, 'Function', { + code: lambda.Code.fromInline('xxx'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + }); + const account = new iam.ArnPrincipal('arn:aws:iam::123456789012:role/someRole'); + + // WHEN + fn.grantInvoke(account); + + // THEN + expect(stack).toHaveResource('AWS::Lambda::Permission', { + Action: 'lambda:InvokeFunction', + FunctionName: { + 'Fn::GetAtt': [ + 'Function76856677', + 'Arn', + ], + }, + Principal: 'arn:aws:iam::123456789012:role/someRole', + }); + }); + + test('can be called twice for the same service principal', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new lambda.Function(stack, 'Function', { + code: lambda.Code.fromInline('xxx'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + }); + const service = new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com'); + + // WHEN + fn.grantInvoke(service); + fn.grantInvoke(service); + + // THEN + expect(stack).toHaveResource('AWS::Lambda::Permission', { + Action: 'lambda:InvokeFunction', + FunctionName: { + 'Fn::GetAtt': [ + 'Function76856677', + 'Arn', + ], + }, + Principal: 'elasticloadbalancing.amazonaws.com', + }); + }); + + test('with an imported role (in the same account)', () => { + // GIVEN + const stack = new cdk.Stack(undefined, undefined, { + env: { account: '123456789012' }, + }); + const fn = new lambda.Function(stack, 'Function', { + code: lambda.Code.fromInline('xxx'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + }); + + // WHEN + fn.grantInvoke(iam.Role.fromRoleArn(stack, 'ForeignRole', 'arn:aws:iam::123456789012:role/someRole')); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: 'lambda:InvokeFunction', + Effect: 'Allow', + Resource: { 'Fn::GetAtt': ['Function76856677', 'Arn'] }, + }, + ], + }, + Roles: ['someRole'], + }); + }); + + test('with an imported role (from a different account)', () => { + // GIVEN + const stack = new cdk.Stack(undefined, undefined, { + env: { account: '3333' }, + }); + const fn = new lambda.Function(stack, 'Function', { + code: lambda.Code.fromInline('xxx'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + }); + + // WHEN + fn.grantInvoke(iam.Role.fromRoleArn(stack, 'ForeignRole', 'arn:aws:iam::123456789012:role/someRole')); + + // THEN + expect(stack).toHaveResource('AWS::Lambda::Permission', { + Action: 'lambda:InvokeFunction', + FunctionName: { + 'Fn::GetAtt': [ + 'Function76856677', + 'Arn', + ], + }, + Principal: 'arn:aws:iam::123456789012:role/someRole', + }); + }); + + test('on an imported function (same account)', () => { + // GIVEN + const stack = new cdk.Stack(undefined, undefined, { + env: { account: '123456789012' }, + }); + const fn = lambda.Function.fromFunctionArn(stack, 'Function', 'arn:aws:lambda:us-east-1:123456789012:function:MyFn'); + + // WHEN + fn.grantInvoke(new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com')); + + // THEN + expect(stack).toHaveResource('AWS::Lambda::Permission', { + Action: 'lambda:InvokeFunction', + FunctionName: 'arn:aws:lambda:us-east-1:123456789012:function:MyFn', + Principal: 'elasticloadbalancing.amazonaws.com', + }); + }); + + test('on an imported function (unresolved account)', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = lambda.Function.fromFunctionArn(stack, 'Function', 'arn:aws:lambda:us-east-1:123456789012:function:MyFn'); + + // WHEN + fn.grantInvoke(new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com')); + + // THEN + expect(stack).toHaveResource('AWS::Lambda::Permission', { + Action: 'lambda:InvokeFunction', + FunctionName: 'arn:aws:lambda:us-east-1:123456789012:function:MyFn', + Principal: 'elasticloadbalancing.amazonaws.com', + }); + }); + + test('on an imported function (different account)', () => { + // GIVEN + const stack = new cdk.Stack(undefined, undefined, { + env: { account: '111111111111' }, // Different account + }); + const fn = lambda.Function.fromFunctionArn(stack, 'Function', 'arn:aws:lambda:us-east-1:123456789012:function:MyFn'); + + // THEN + expect(() => { fn.grantInvoke(new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com')); }) + .toThrow(/Cannot modify permission to lambda function/); + }); + }); + + test('Can use metricErrors on a lambda Function', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new lambda.Function(stack, 'Function', { + code: lambda.Code.fromInline('xxx'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + }); + + // THEN + expect(stack.resolve(fn.metricErrors())).toEqual({ + dimensions: { FunctionName: { Ref: 'Function76856677' } }, + namespace: 'AWS/Lambda', + metricName: 'Errors', + period: cdk.Duration.minutes(5), + statistic: 'Sum', + }); + }); + + test('addEventSource calls bind', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new lambda.Function(stack, 'Function', { + code: lambda.Code.fromInline('xxx'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + }); + + let bindTarget; + + class EventSourceMock implements lambda.IEventSource { + public bind(target: lambda.IFunction) { + bindTarget = target; + } + } + + // WHEN + fn.addEventSource(new EventSourceMock()); + + // THEN + expect(bindTarget).toEqual(fn); + }); + + test('using an incompatible layer', () => { + // GIVEN + const stack = new cdk.Stack(undefined, 'TestStack'); + const layer = lambda.LayerVersion.fromLayerVersionAttributes(stack, 'TestLayer', { + layerVersionArn: 'arn:aws:...', + compatibleRuntimes: [lambda.Runtime.NODEJS_12_X], + }); + + // THEN + expect(() => new lambda.Function(stack, 'Function', { + layers: [layer], + runtime: lambda.Runtime.NODEJS_10_X, + code: lambda.Code.fromInline('exports.main = function() { console.log("DONE"); }'), + handler: 'index.main', + })).toThrow(/nodejs10.x is not in \[nodejs12.x\]/); + }); + + test('using more than 5 layers', () => { + // GIVEN + const stack = new cdk.Stack(undefined, 'TestStack'); + const layers = new Array(6).fill(lambda.LayerVersion.fromLayerVersionAttributes(stack, 'TestLayer', { + layerVersionArn: 'arn:aws:...', + compatibleRuntimes: [lambda.Runtime.NODEJS_10_X], + })); + + // THEN + expect(() => new lambda.Function(stack, 'Function', { + layers, + runtime: lambda.Runtime.NODEJS_10_X, + code: lambda.Code.fromInline('exports.main = function() { console.log("DONE"); }'), + handler: 'index.main', + })).toThrow(/Unable to add layer:/); + }); + + test('environment variables work in China', () => { + // GIVEN + const stack = new cdk.Stack(undefined, undefined, { env: { region: 'cn-north-1' } }); + + // WHEN + new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS, + environment: { + SOME: 'Variable', + }, + }); + + // THEN + expect(stack).toHaveResource('AWS::Lambda::Function', { + Environment: { + Variables: { + SOME: 'Variable', + }, + }, + }); + }); + + test('environment variables work in an unspecified region', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS, + environment: { + SOME: 'Variable', + }, + }); + + // THEN + expect(stack).toHaveResource('AWS::Lambda::Function', { + Environment: { + Variables: { + SOME: 'Variable', + }, + }, + }); + }); + + test('support reserved concurrent executions', () => { + const stack = new cdk.Stack(); + + new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS, + reservedConcurrentExecutions: 10, + }); + + expect(stack).toHaveResource('AWS::Lambda::Function', { + ReservedConcurrentExecutions: 10, + }); + }); + + test('its possible to specify event sources upon creation', () => { + // GIVEN + const stack = new cdk.Stack(); + + let bindCount = 0; + + class EventSource implements lambda.IEventSource { + public bind(_fn: lambda.IFunction): void { + bindCount++; + } + } + + // WHEN + new lambda.Function(stack, 'fn', { + code: lambda.Code.fromInline('boom'), + runtime: lambda.Runtime.NODEJS_10_X, + handler: 'index.bam', + events: [ + new EventSource(), + new EventSource(), + ], + }); + + // THEN + expect(bindCount).toEqual(2); + }); + + test('Provided Runtime returns the right values', () => { + const rt = lambda.Runtime.PROVIDED; + + expect(rt.name).toEqual('provided'); + expect(rt.supportsInlineCode).toEqual(false); + }); + + test('specify log retention', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS, + logRetention: logs.RetentionDays.ONE_MONTH, + }); + + // THEN + expect(stack).toHaveResource('Custom::LogRetention', { + LogGroupName: { + 'Fn::Join': [ + '', + [ + '/aws/lambda/', + { + Ref: 'MyLambdaCCE802FB', + }, + ], + ], + }, + RetentionInDays: 30, + }); + }); + + test('imported lambda with imported security group and allowAllOutbound set to false', () => { + // GIVEN + const stack = new cdk.Stack(); + + const fn = lambda.Function.fromFunctionAttributes(stack, 'fn', { + functionArn: 'arn:aws:lambda:us-east-1:123456789012:function:my-function', + securityGroup: ec2.SecurityGroup.fromSecurityGroupId(stack, 'SG', 'sg-123456789', { + allowAllOutbound: false, + }), + }); + + // WHEN + fn.connections.allowToAnyIpv4(ec2.Port.tcp(443)); + + // THEN + expect(stack).toHaveResource('AWS::EC2::SecurityGroupEgress', { + GroupId: 'sg-123456789', + }); + }); + + test('with event invoke config', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new lambda.Function(stack, 'fn', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + onFailure: { + bind: () => ({ destination: 'on-failure-arn' }), + }, + onSuccess: { + bind: () => ({ destination: 'on-success-arn' }), + }, + maxEventAge: cdk.Duration.hours(1), + retryAttempts: 0, + }); + + // THEN + expect(stack).toHaveResource('AWS::Lambda::EventInvokeConfig', { + FunctionName: { + Ref: 'fn5FF616E3', + }, + Qualifier: '$LATEST', + DestinationConfig: { + OnFailure: { + Destination: 'on-failure-arn', + }, + OnSuccess: { + Destination: 'on-success-arn', + }, + }, + MaximumEventAgeInSeconds: 3600, + MaximumRetryAttempts: 0, + }); + }); + + test('throws when calling configureAsyncInvoke on already configured function', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new lambda.Function(stack, 'fn', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + maxEventAge: cdk.Duration.hours(1), + }); + + // THEN + expect(() => fn.configureAsyncInvoke({ retryAttempts: 0 })).toThrow(/An EventInvokeConfig has already been configured/); + }); + + test('event invoke config on imported lambda', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = lambda.Function.fromFunctionAttributes(stack, 'fn', { + functionArn: 'arn:aws:lambda:us-east-1:123456789012:function:my-function', + }); + + // WHEN + fn.configureAsyncInvoke({ + retryAttempts: 1, + }); + + // THEN + expect(stack).toHaveResource('AWS::Lambda::EventInvokeConfig', { + FunctionName: 'my-function', + Qualifier: '$LATEST', + MaximumRetryAttempts: 1, + }); + }); + + test('add a version with event invoke config', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new lambda.Function(stack, 'fn', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + }); + + // WHEN + fn.addVersion('1', 'sha256', 'desc', undefined, { + retryAttempts: 0, + }); + + // THEN + expect(stack).toHaveResource('AWS::Lambda::EventInvokeConfig', { + FunctionName: { + Ref: 'fn5FF616E3', + }, + Qualifier: { + 'Fn::GetAtt': [ + 'fnVersion197FA813F', + 'Version', + ], + }, + MaximumRetryAttempts: 0, + }); + }); + + test('check edge compatibility with env vars that can be removed', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new lambda.Function(stack, 'fn', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_12_X, + }); + fn.addEnvironment('KEY', 'value', { removeInEdge: true }); + + // WHEN + fn._checkEdgeCompatibility(); + + // THEN + expect(stack).toHaveResource('AWS::Lambda::Function', { + Environment: ABSENT, + }); + }); + + test('check edge compatibility with env vars that cannot be removed', () => { + // GIVEN + const stack = new cdk.Stack(); + const fn = new lambda.Function(stack, 'fn', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_12_X, + environment: { + KEY: 'value', + }, + }); + fn.addEnvironment('OTHER_KEY', 'other_value', { removeInEdge: true }); + + // THEN + expect(() => fn._checkEdgeCompatibility()).toThrow(/The function Default\/fn contains environment variables \[KEY\] and is not compatible with Lambda@Edge/); + }); + + test('add incompatible layer', () => { + // GIVEN + const stack = new cdk.Stack(undefined, 'TestStack'); + const bucket = new s3.Bucket(stack, 'Bucket'); + const code = new lambda.S3Code(bucket, 'ObjectKey'); + + const func = new lambda.Function(stack, 'myFunc', { + runtime: lambda.Runtime.PYTHON_3_7, + handler: 'index.handler', + code, + }); + const layer = new lambda.LayerVersion(stack, 'myLayer', { + code, + compatibleRuntimes: [lambda.Runtime.NODEJS], + }); + + // THEN + expect(() => func.addLayers(layer)).toThrow( + /This lambda function uses a runtime that is incompatible with this layer/); + }); + + test('add compatible layer', () => { + // GIVEN + const stack = new cdk.Stack(undefined, 'TestStack'); + const bucket = new s3.Bucket(stack, 'Bucket'); + const code = new lambda.S3Code(bucket, 'ObjectKey'); + + const func = new lambda.Function(stack, 'myFunc', { + runtime: lambda.Runtime.PYTHON_3_7, + handler: 'index.handler', + code, + }); + const layer = new lambda.LayerVersion(stack, 'myLayer', { + code, + compatibleRuntimes: [lambda.Runtime.PYTHON_3_7], + }); + + // THEN + // should not throw + expect(() => func.addLayers(layer)).not.toThrow(); + }); + + test('add compatible layer for deep clone', () => { + // GIVEN + const stack = new cdk.Stack(undefined, 'TestStack'); + const bucket = new s3.Bucket(stack, 'Bucket'); + const code = new lambda.S3Code(bucket, 'ObjectKey'); + + const runtime = lambda.Runtime.PYTHON_3_7; + const func = new lambda.Function(stack, 'myFunc', { + runtime, + handler: 'index.handler', + code, + }); + const clone = _.cloneDeep(runtime); + const layer = new lambda.LayerVersion(stack, 'myLayer', { + code, + compatibleRuntimes: [clone], + }); + + // THEN + // should not throw + expect(() => func.addLayers(layer)).not.toThrow(); + }); + + test('empty inline code is not allowed', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN/THEN + expect(() => new lambda.Function(stack, 'fn', { + handler: 'foo', + runtime: lambda.Runtime.NODEJS_10_X, + code: lambda.Code.fromInline(''), + })).toThrow(/Lambda inline code cannot be empty/); + }); + + test('logGroup is correctly returned', () => { + const stack = new cdk.Stack(); + const fn = new lambda.Function(stack, 'fn', { + handler: 'foo', + runtime: lambda.Runtime.NODEJS_10_X, + code: lambda.Code.fromInline('foo'), + }); + const logGroup = fn.logGroup; + expect(logGroup.logGroupName).toBeDefined(); + expect(logGroup.logGroupArn).toBeDefined(); + }); + + test('dlq is returned when provided by user', () => { + const stack = new cdk.Stack(); + + const dlQueue = new sqs.Queue(stack, 'DeadLetterQueue', { + queueName: 'MyLambda_DLQ', + retentionPeriod: cdk.Duration.days(14), + }); + + const fn = new lambda.Function(stack, 'fn', { + handler: 'foo', + runtime: lambda.Runtime.NODEJS_10_X, + code: lambda.Code.fromInline('foo'), + deadLetterQueue: dlQueue, + }); + const deadLetterQueue = fn.deadLetterQueue; + expect(deadLetterQueue?.queueArn).toBeDefined(); + expect(deadLetterQueue?.queueName).toBeDefined(); + expect(deadLetterQueue?.queueUrl).toBeDefined(); + }); + + test('dlq is returned when setup by cdk', () => { + const stack = new cdk.Stack(); + const fn = new lambda.Function(stack, 'fn', { + handler: 'foo', + runtime: lambda.Runtime.NODEJS_10_X, + code: lambda.Code.fromInline('foo'), + deadLetterQueueEnabled: true, + }); + const deadLetterQueue = fn.deadLetterQueue; + expect(deadLetterQueue?.queueArn).toBeDefined(); + expect(deadLetterQueue?.queueName).toBeDefined(); + expect(deadLetterQueue?.queueUrl).toBeDefined(); + }); + + test('dlq is undefined when not setup', () => { + const stack = new cdk.Stack(); + const fn = new lambda.Function(stack, 'fn', { + handler: 'foo', + runtime: lambda.Runtime.NODEJS_10_X, + code: lambda.Code.fromInline('foo'), + }); + const deadLetterQueue = fn.deadLetterQueue; + expect(deadLetterQueue).toBeUndefined(); + }); + + test('one and only one child LogRetention construct will be created', () => { + const stack = new cdk.Stack(); + const fn = new lambda.Function(stack, 'fn', { + handler: 'foo', + runtime: lambda.Runtime.NODEJS_10_X, + code: lambda.Code.fromInline('foo'), + logRetention: logs.RetentionDays.FIVE_DAYS, + }); + + // Call logGroup a few times. If more than one instance of LogRetention was created, + // the second call will fail on duplicate constructs. + fn.logGroup; + fn.logGroup; + fn.logGroup; + }); + + test('fails when inline code is specified on an incompatible runtime', () => { + const stack = new cdk.Stack(); + expect(() => new lambda.Function(stack, 'fn', { + handler: 'foo', + runtime: lambda.Runtime.PROVIDED, + code: lambda.Code.fromInline('foo'), + })).toThrow(/Inline source not allowed for/); + }); + + test('multiple calls to latestVersion returns the same version', () => { + const stack = new cdk.Stack(); + + const fn = new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('hello()'), + handler: 'index.hello', + runtime: lambda.Runtime.NODEJS_10_X, + }); + + const version1 = fn.latestVersion; + const version2 = fn.latestVersion; + + const expectedArn = { + 'Fn::Join': ['', [ + { 'Fn::GetAtt': ['MyLambdaCCE802FB', 'Arn'] }, + ':$LATEST', + ]], + }; + expect(version1).toEqual(version2); + expect(stack.resolve(version1.functionArn)).toEqual(expectedArn); + expect(stack.resolve(version2.functionArn)).toEqual(expectedArn); + }); + + describe('profiling group', () => { + test('default function with CDK created Profiling Group', () => { + const stack = new cdk.Stack(); + + new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + profiling: true, + }); + + expect(stack).toHaveResource('AWS::CodeGuruProfiler::ProfilingGroup', { + ProfilingGroupName: 'MyLambdaProfilingGroupC5B6CCD8', + ComputePlatform: 'AWSLambda', + }); + + expect(stack).toHaveResource('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: [ + 'codeguru-profiler:ConfigureAgent', + 'codeguru-profiler:PostAgentProfile', + ], + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': ['MyLambdaProfilingGroupEC6DE32F', 'Arn'], + }, + }, + ], + Version: '2012-10-17', + }, + PolicyName: 'MyLambdaServiceRoleDefaultPolicy5BBC6F68', + Roles: [ + { + Ref: 'MyLambdaServiceRole4539ECB6', + }, + ], + }); + + expect(stack).toHaveResource('AWS::Lambda::Function', { + Environment: { + Variables: { + AWS_CODEGURU_PROFILER_GROUP_ARN: { 'Fn::GetAtt': ['MyLambdaProfilingGroupEC6DE32F', 'Arn'] }, + AWS_CODEGURU_PROFILER_ENABLED: 'TRUE', + }, + }, + }); + }); + + test('default function with client provided Profiling Group', () => { + const stack = new cdk.Stack(); + + new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + profilingGroup: new ProfilingGroup(stack, 'ProfilingGroup'), + }); + + expect(stack).toHaveResource('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: [ + 'codeguru-profiler:ConfigureAgent', + 'codeguru-profiler:PostAgentProfile', + ], + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': ['ProfilingGroup26979FD7', 'Arn'], + }, + }, + ], + Version: '2012-10-17', + }, + PolicyName: 'MyLambdaServiceRoleDefaultPolicy5BBC6F68', + Roles: [ + { + Ref: 'MyLambdaServiceRole4539ECB6', + }, + ], + }); + + expect(stack).toHaveResource('AWS::Lambda::Function', { + Environment: { + Variables: { + AWS_CODEGURU_PROFILER_GROUP_ARN: { + 'Fn::Join': [ + '', + [ + 'arn:', { Ref: 'AWS::Partition' }, ':codeguru-profiler:', { Ref: 'AWS::Region' }, + ':', { Ref: 'AWS::AccountId' }, ':profilingGroup/', { Ref: 'ProfilingGroup26979FD7' }, + ], + ], + }, + AWS_CODEGURU_PROFILER_ENABLED: 'TRUE', + }, + }, + }); + }); + + test('default function with client provided Profiling Group but profiling set to false', () => { + const stack = new cdk.Stack(); + + new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + profiling: false, + profilingGroup: new ProfilingGroup(stack, 'ProfilingGroup'), + }); + + expect(stack).not.toHaveResource('AWS::IAM::Policy'); + + expect(stack).not.toHaveResource('AWS::Lambda::Function', { + Environment: { + Variables: { + AWS_CODEGURU_PROFILER_GROUP_ARN: { + 'Fn::Join': [ + '', + [ + 'arn:', { Ref: 'AWS::Partition' }, ':codeguru-profiler:', { Ref: 'AWS::Region' }, + ':', { Ref: 'AWS::AccountId' }, ':profilingGroup/', { Ref: 'ProfilingGroup26979FD7' }, + ], + ], + }, + AWS_CODEGURU_PROFILER_ENABLED: 'TRUE', + }, + }, + }); + }); + + test('default function with profiling enabled and client provided env vars', () => { + const stack = new cdk.Stack(); + + expect(() => new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + profiling: true, + environment: { + AWS_CODEGURU_PROFILER_GROUP_ARN: 'profiler_group_arn', + AWS_CODEGURU_PROFILER_ENABLED: 'yes', + }, + })).toThrow(/AWS_CODEGURU_PROFILER_GROUP_ARN and AWS_CODEGURU_PROFILER_ENABLED must not be set when profiling options enabled/); + }); + + test('default function with client provided Profiling Group and client provided env vars', () => { + const stack = new cdk.Stack(); + + expect(() => new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_10_X, + profilingGroup: new ProfilingGroup(stack, 'ProfilingGroup'), + environment: { + AWS_CODEGURU_PROFILER_GROUP_ARN: 'profiler_group_arn', + AWS_CODEGURU_PROFILER_ENABLED: 'yes', + }, + })).toThrow(/AWS_CODEGURU_PROFILER_GROUP_ARN and AWS_CODEGURU_PROFILER_ENABLED must not be set when profiling options enabled/); + }); + }); + + describe('currentVersion', () => { + // see test.function-hash.ts for more coverage for this + test('logical id of version is based on the function hash', () => { + // GIVEN + const stack1 = new cdk.Stack(); + const fn1 = new lambda.Function(stack1, 'MyFunction', { + handler: 'foo', + runtime: lambda.Runtime.NODEJS_12_X, + code: lambda.Code.fromAsset(path.join(__dirname, 'handler.zip')), + environment: { + FOO: 'bar', + }, + }); + const stack2 = new cdk.Stack(); + const fn2 = new lambda.Function(stack2, 'MyFunction', { + handler: 'foo', + runtime: lambda.Runtime.NODEJS_12_X, + code: lambda.Code.fromAsset(path.join(__dirname, 'handler.zip')), + environment: { + FOO: 'bear', + }, + }); + + // WHEN + new cdk.CfnOutput(stack1, 'CurrentVersionArn', { + value: fn1.currentVersion.functionArn, + }); + new cdk.CfnOutput(stack2, 'CurrentVersionArn', { + value: fn2.currentVersion.functionArn, + }); + + // THEN + const template1 = SynthUtils.synthesize(stack1).template; + const template2 = SynthUtils.synthesize(stack2).template; + + // these functions are different in their configuration but the original + // logical ID of the version would be the same unless the logical ID + // includes the hash of function's configuration. + expect(template1.Outputs.CurrentVersionArn.Value).not.toEqual(template2.Outputs.CurrentVersionArn.Value); + }); + }); + + describe('filesystem', () => { + + test('mount efs filesystem', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { + maxAzs: 3, + natGateways: 1, + }); + + const fs = new efs.FileSystem(stack, 'Efs', { + vpc, + }); + const accessPoint = fs.addAccessPoint('AccessPoint'); + // WHEN + new lambda.Function(stack, 'MyFunction', { + handler: 'foo', + runtime: lambda.Runtime.NODEJS_12_X, + code: lambda.Code.fromAsset(path.join(__dirname, 'handler.zip')), + filesystem: lambda.FileSystem.fromEfsAccessPoint(accessPoint, '/mnt/msg'), + }); + + // THEN + expect(stack).toHaveResource('AWS::Lambda::Function', { + FileSystemConfigs: [ + { + Arn: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':elasticfilesystem:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':access-point/', + { + Ref: 'EfsAccessPointE419FED9', + }, + ], + ], + }, + LocalMountPath: '/mnt/msg', + }, + ], + }); + }); + }); +}); + +function newTestLambda(scope: constructs.Construct) { + return new lambda.Function(scope, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'bar', + runtime: lambda.Runtime.PYTHON_2_7, + }); +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda/test/test.lambda-version.ts b/packages/@aws-cdk/aws-lambda/test/lambda-version.test.ts similarity index 71% rename from packages/@aws-cdk/aws-lambda/test/test.lambda-version.ts rename to packages/@aws-cdk/aws-lambda/test/lambda-version.test.ts index e06ce385522ea..20b040a135a7b 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.lambda-version.ts +++ b/packages/@aws-cdk/aws-lambda/test/lambda-version.test.ts @@ -1,12 +1,9 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import '@aws-cdk/assert/jest'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; import * as lambda from '../lib'; -/* eslint-disable quote-props */ - -export = { - 'can import a Lambda version by ARN'(test: Test) { +describe('lambda version', () => { + test('can import a Lambda version by ARN', () => { // GIVEN const stack = new cdk.Stack(); @@ -17,7 +14,7 @@ export = { new cdk.CfnOutput(stack, 'Name', { value: version.functionName }); // THEN - expect(stack).toMatch({ + expect(stack).toMatchTemplate({ Outputs: { ARN: { Value: 'arn:aws:lambda:region:account-id:function:function-name:version', @@ -27,11 +24,9 @@ export = { }, }, }); + }); - test.done(); - }, - - 'create a version with event invoke config'(test: Test) { + test('create a version with event invoke config', () => { // GIVEN const stack = new cdk.Stack(); const fn = new lambda.Function(stack, 'Fn', { @@ -48,7 +43,7 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::Lambda::EventInvokeConfig', { + expect(stack).toHaveResource('AWS::Lambda::EventInvokeConfig', { FunctionName: { Ref: 'Fn9270CBC0', }, @@ -60,12 +55,10 @@ export = { }, MaximumEventAgeInSeconds: 3600, MaximumRetryAttempts: 0, - })); - - test.done(); - }, + }); + }); - 'throws when calling configureAsyncInvoke on already configured version'(test: Test) { + test('throws when calling configureAsyncInvoke on already configured version', () => { // GIVEN const stack = new cdk.Stack(); const fn = new lambda.Function(stack, 'Fn', { @@ -80,12 +73,10 @@ export = { }); // THEN - test.throws(() => version.configureAsyncInvoke({ retryAttempts: 1 }), /An EventInvokeConfig has already been configured/); + expect(() => version.configureAsyncInvoke({ retryAttempts: 1 })).toThrow(/An EventInvokeConfig has already been configured/); + }); - test.done(); - }, - - 'event invoke config on imported versions'(test: Test) { + test('event invoke config on imported versions', () => { // GIVEN const stack = new cdk.Stack(); const version1 = lambda.Version.fromVersionArn(stack, 'Version1', 'arn:aws:lambda:region:account-id:function:function-name:version1'); @@ -100,21 +91,19 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::Lambda::EventInvokeConfig', { + expect(stack).toHaveResource('AWS::Lambda::EventInvokeConfig', { FunctionName: 'function-name', Qualifier: 'version1', MaximumRetryAttempts: 1, - })); - expect(stack).to(haveResource('AWS::Lambda::EventInvokeConfig', { + }); + expect(stack).toHaveResource('AWS::Lambda::EventInvokeConfig', { FunctionName: 'function-name', Qualifier: 'version2', MaximumRetryAttempts: 0, - })); - - test.done(); - }, + }); + }); - 'addAlias can be used to add an alias that points to a version'(test: Test) { + test('addAlias can be used to add an alias that points to a version', () => { // GIVEN const stack = new cdk.Stack(); const fn = new lambda.Function(stack, 'Fn', { @@ -128,22 +117,21 @@ export = { version.addAlias('foo'); // THEN - expect(stack).to(haveResource('AWS::Lambda::Alias', { - 'FunctionName': { - 'Ref': 'Fn9270CBC0', + expect(stack).toHaveResource('AWS::Lambda::Alias', { + FunctionName: { + Ref: 'Fn9270CBC0', }, - 'FunctionVersion': { + FunctionVersion: { 'Fn::GetAtt': [ 'FnCurrentVersion17A89ABBab5c765f3c55e4e61583b51b00a95742', 'Version', ], }, - 'Name': 'foo', - })); - test.done(); - }, + Name: 'foo', + }); + }); - 'edgeArn'(test: Test) { + test('edgeArn', () => { // GIVEN const stack = new cdk.Stack(); const fn = new lambda.Function(stack, 'Fn', { @@ -154,23 +142,19 @@ export = { const version = fn.currentVersion; // THEN - test.deepEqual(stack.resolve(version.edgeArn), { Ref: 'FnCurrentVersion17A89ABB19ed45993ff69fd011ae9fd4ab6e2005' }); + expect(stack.resolve(version.edgeArn)).toEqual({ Ref: 'FnCurrentVersion17A89ABB19ed45993ff69fd011ae9fd4ab6e2005' }); + }); - test.done(); - }, - - 'edgeArn throws with $LATEST'(test: Test) { + test('edgeArn throws with $LATEST', () => { // GIVEN const stack = new cdk.Stack(); const version = lambda.Version.fromVersionArn(stack, 'Version', 'arn:aws:lambda:region:account-id:function:function-name:$LATEST'); // THEN - test.throws(() => version.edgeArn, /\$LATEST function version cannot be used for Lambda@Edge/); - - test.done(); - }, + expect(() => version.edgeArn).toThrow(/\$LATEST function version cannot be used for Lambda@Edge/); + }); - 'edgeArn throws at synthesis if underlying function is not edge compatible'(test: Test) { + test('edgeArn throws at synthesis if underlying function is not edge compatible', () => { // GIVEN const app = new cdk.App(); const stack = new cdk.Stack(app, 'Stack'); @@ -195,8 +179,6 @@ export = { fn.addEnvironment('KEY2', 'value2'); // THEN - test.throws(() => app.synth(), /KEY1,KEY2/); - - test.done(); - }, -}; + expect(() => app.synth()).toThrow(/KEY1,KEY2/); + }); +}); diff --git a/packages/@aws-cdk/aws-lambda/test/test.layers.ts b/packages/@aws-cdk/aws-lambda/test/layers.test.ts similarity index 69% rename from packages/@aws-cdk/aws-lambda/test/test.layers.ts rename to packages/@aws-cdk/aws-lambda/test/layers.test.ts index 2afc60b26ae3d..0806f6d823dba 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.layers.ts +++ b/packages/@aws-cdk/aws-lambda/test/layers.test.ts @@ -1,13 +1,13 @@ +import '@aws-cdk/assert/jest'; import * as path from 'path'; -import { canonicalizeTemplate, expect, haveResource, ResourcePart, SynthUtils } from '@aws-cdk/assert'; +import { canonicalizeTemplate, ResourcePart, SynthUtils } from '@aws-cdk/assert'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { Test, testCase } from 'nodeunit'; import * as lambda from '../lib'; -export = testCase({ - 'creating a layer'(test: Test) { +describe('layers', () => { + test('creating a layer', () => { // GIVEN const stack = new cdk.Stack(undefined, 'TestStack'); const bucket = new s3.Bucket(stack, 'Bucket'); @@ -20,18 +20,16 @@ export = testCase({ }); // THEN - expect(stack).to(haveResource('AWS::Lambda::LayerVersion', { + expect(stack).toHaveResource('AWS::Lambda::LayerVersion', { Content: { S3Bucket: stack.resolve(bucket.bucketName), S3Key: 'ObjectKey', }, CompatibleRuntimes: ['nodejs10.x'], - })); - - test.done(); - }, + }); + }); - 'granting access to a layer'(test: Test) { + test('granting access to a layer', () => { // GIVEN const stack = new cdk.Stack(undefined, 'TestStack'); const bucket = new s3.Bucket(stack, 'Bucket'); @@ -46,35 +44,31 @@ export = testCase({ layer.addPermission('GrantUsage-o-123456', { accountId: '*', organizationId: 'o-123456' }); // THEN - expect(stack).to(haveResource('AWS::Lambda::LayerVersionPermission', { + expect(stack).toHaveResource('AWS::Lambda::LayerVersionPermission', { Action: 'lambda:GetLayerVersion', LayerVersionArn: stack.resolve(layer.layerVersionArn), Principal: '123456789012', - })); - expect(stack).to(haveResource('AWS::Lambda::LayerVersionPermission', { + }); + expect(stack).toHaveResource('AWS::Lambda::LayerVersionPermission', { Action: 'lambda:GetLayerVersion', LayerVersionArn: stack.resolve(layer.layerVersionArn), Principal: '*', OrganizationId: 'o-123456', - })); - - test.done(); - }, + }); + }); - 'creating a layer with no runtimes compatible'(test: Test) { + test('creating a layer with no runtimes compatible', () => { // GIVEN const stack = new cdk.Stack(undefined, 'TestStack'); const bucket = new s3.Bucket(stack, 'Bucket'); const code = new lambda.S3Code(bucket, 'ObjectKey'); // THEN - test.throws(() => new lambda.LayerVersion(stack, 'LayerVersion', { code, compatibleRuntimes: [] }), - /supports no runtime/); - - test.done(); - }, + expect(() => new lambda.LayerVersion(stack, 'LayerVersion', { code, compatibleRuntimes: [] })) + .toThrow(/supports no runtime/); + }); - 'asset metadata is added to the cloudformation resource'(test: Test) { + test('asset metadata is added to the cloudformation resource', () => { // GIVEN const stack = new cdk.Stack(); stack.node.setContext(cxapi.ASSET_RESOURCE_METADATA_ENABLED_CONTEXT, true); @@ -85,12 +79,11 @@ export = testCase({ }); // THEN - expect(canonicalizeTemplate(SynthUtils.toCloudFormation(stack))).to(haveResource('AWS::Lambda::LayerVersion', { + expect(canonicalizeTemplate(SynthUtils.toCloudFormation(stack))).toHaveResource('AWS::Lambda::LayerVersion', { Metadata: { 'aws:asset:path': 'asset.Asset1Hash', 'aws:asset:property': 'Content', }, - }, ResourcePart.CompleteDefinition)); - test.done(); - }, + }, ResourcePart.CompleteDefinition); + }); }); diff --git a/packages/@aws-cdk/aws-lambda/test/runtime.test.ts b/packages/@aws-cdk/aws-lambda/test/runtime.test.ts new file mode 100644 index 0000000000000..e90d7535d8045 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda/test/runtime.test.ts @@ -0,0 +1,64 @@ +import '@aws-cdk/assert/jest'; +import * as lambda from '../lib'; + +describe('runtime', () => { + test('runtimes are equal for different instances', () => { + // GIVEN + const runtime1 = new lambda.Runtime('python3.7', lambda.RuntimeFamily.PYTHON, { supportsInlineCode: true }); + const runtime2 = new lambda.Runtime('python3.7', lambda.RuntimeFamily.PYTHON, { supportsInlineCode: true }); + + // WHEN + expect(runtime1.runtimeEquals(runtime2)).toBe(true); + }); + + test('runtimes are equal for same instance', () => { + const runtime = new lambda.Runtime('python3.7', lambda.RuntimeFamily.PYTHON, { supportsInlineCode: true }); + + expect(runtime.runtimeEquals(runtime)).toBe(true); + }); + + test('unequal when name changes', () => { + const runtime1 = new lambda.Runtime('python3.7', lambda.RuntimeFamily.PYTHON, { supportsInlineCode: true }); + const runtime2 = new lambda.Runtime('python3.6', lambda.RuntimeFamily.PYTHON, { supportsInlineCode: true }); + + expect(runtime1.runtimeEquals(runtime2)).toBe(false); + }); + + test('unequal when family changes', () => { + const runtime1 = new lambda.Runtime('python3.7', lambda.RuntimeFamily.PYTHON, { supportsInlineCode: true }); + const runtime2 = new lambda.Runtime('python3.7', lambda.RuntimeFamily.JAVA, { supportsInlineCode: true }); + + expect(runtime1.runtimeEquals(runtime2)).toBe(false); + }); + + test('unequal when supportsInlineCode changes', () => { + const runtime1 = new lambda.Runtime('python3.7', lambda.RuntimeFamily.PYTHON, { supportsInlineCode: true }); + const runtime2 = new lambda.Runtime('python3.7', lambda.RuntimeFamily.PYTHON, { supportsInlineCode: false }); + + expect(runtime1.runtimeEquals(runtime2)).toBe(false); + }); + + test('bundlingDockerImage points to AWS SAM build image', () => { + // GIVEN + const runtime = new lambda.Runtime('my-runtime-name'); + + // THEN + expect(runtime.bundlingDockerImage.image).toEqual('amazon/aws-sam-cli-build-image-my-runtime-name'); + }); + + test('overridde to bundlingDockerImage points to the correct image', () => { + // GIVEN + const runtime = new lambda.Runtime('my-runtime-name', undefined, { + bundlingDockerImage: 'my-docker-image', + }); + + // THEN + expect(runtime.bundlingDockerImage.image).toEqual('my-docker-image'); + }); + + test('dotnetcore and go have overridden images', () => { + expect(lambda.Runtime.DOTNET_CORE_3_1.bundlingDockerImage.image).toEqual('lambci/lambda:build-dotnetcore3.1'); + expect(lambda.Runtime.DOTNET_CORE_2_1.bundlingDockerImage.image).toEqual('lambci/lambda:build-dotnetcore2.1'); + expect(lambda.Runtime.GO_1_X.bundlingDockerImage.image).toEqual('lambci/lambda:build-go1.x'); + }); +}); diff --git a/packages/@aws-cdk/aws-lambda/test/test.singleton-lambda.ts b/packages/@aws-cdk/aws-lambda/test/singleton-lambda.test.ts similarity index 76% rename from packages/@aws-cdk/aws-lambda/test/test.singleton-lambda.ts rename to packages/@aws-cdk/aws-lambda/test/singleton-lambda.test.ts index 0183e78badd27..28eebb1a0c284 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.singleton-lambda.ts +++ b/packages/@aws-cdk/aws-lambda/test/singleton-lambda.test.ts @@ -1,11 +1,11 @@ -import { expect, haveResource, matchTemplate, ResourcePart } from '@aws-cdk/assert'; +import '@aws-cdk/assert/jest'; +import { ResourcePart } from '@aws-cdk/assert'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; import * as lambda from '../lib'; -export = { - 'can add same singleton Lambda multiple times, only instantiated once in template'(test: Test) { +describe('singleton lambda', () => { + test('can add same singleton Lambda multiple times, only instantiated once in template', () => { // GIVEN const stack = new cdk.Stack(); @@ -21,7 +21,7 @@ export = { } // THEN - expect(stack).to(matchTemplate({ + expect(stack).toMatchTemplate({ Resources: { SingletonLambda84c0de93353f42179b0b45b6c993251aServiceRole26D59235: { Type: 'AWS::IAM::Role', @@ -57,12 +57,10 @@ export = { DependsOn: ['SingletonLambda84c0de93353f42179b0b45b6c993251aServiceRole26D59235'], }, }, - })); - - test.done(); - }, + }); + }); - 'dependencies are correctly added'(test: Test) { + test('dependencies are correctly added', () => { // GIVEN const stack = new cdk.Stack(); const singleton = new lambda.SingletonFunction(stack, 'Singleton', { @@ -78,17 +76,15 @@ export = { singleton.addDependency(dependency); // THEN - expect(stack).to(haveResource('AWS::Lambda::Function', { + expect(stack).toHaveResource('AWS::Lambda::Function', { DependsOn: [ 'dependencyUser1B9CB07E', 'SingletonLambda84c0de93353f42179b0b45b6c993251aServiceRole26D59235', ], - }, ResourcePart.CompleteDefinition)); + }, ResourcePart.CompleteDefinition); + }); - test.done(); - }, - - 'dependsOn are correctly added'(test: Test) { + test('dependsOn are correctly added', () => { // GIVEN const stack = new cdk.Stack(); const singleton = new lambda.SingletonFunction(stack, 'Singleton', { @@ -104,17 +100,15 @@ export = { singleton.dependOn(user); // THEN - expect(stack).to(haveResource('AWS::IAM::User', { + expect(stack).toHaveResource('AWS::IAM::User', { DependsOn: [ 'SingletonLambda84c0de93353f42179b0b45b6c993251a840BCC38', 'SingletonLambda84c0de93353f42179b0b45b6c993251aServiceRole26D59235', ], - }, ResourcePart.CompleteDefinition)); - - test.done(); - }, + }, ResourcePart.CompleteDefinition); + }); - 'grantInvoke works correctly'(test: Test) { + test('grantInvoke works correctly', () => { // GIVEN const stack = new cdk.Stack(); const singleton = new lambda.SingletonFunction(stack, 'Singleton', { @@ -129,20 +123,19 @@ export = { const statement = stack.resolve(invokeResult.resourceStatement); // THEN - expect(stack).to(haveResource('AWS::Lambda::Permission', { + expect(stack).toHaveResource('AWS::Lambda::Permission', { Action: 'lambda:InvokeFunction', Principal: 'events.amazonaws.com', - })); - test.deepEqual(statement.action, ['lambda:InvokeFunction']); - test.deepEqual(statement.principal, { Service: ['events.amazonaws.com'] }); - test.deepEqual(statement.effect, 'Allow'); - test.deepEqual(statement.resource, [{ + }); + expect(statement.action).toEqual(['lambda:InvokeFunction']); + expect(statement.principal).toEqual({ Service: ['events.amazonaws.com'] }); + expect(statement.effect).toEqual('Allow'); + expect(statement.resource).toEqual([{ 'Fn::GetAtt': ['SingletonLambda84c0de93353f42179b0b45b6c993251a840BCC38', 'Arn'], }]); - test.done(); - }, + }); - 'check edge compatibility'(test: Test) { + test('check edge compatibility', () => { // GIVEN const stack = new cdk.Stack(); const singleton = new lambda.SingletonFunction(stack, 'Singleton', { @@ -156,12 +149,11 @@ export = { }); // THEN - test.throws(() => singleton._checkEdgeCompatibility(), /The function Default\/SingletonLambda84c0de93353f42179b0b45b6c993251a contains environment variables \[KEY\] and is not compatible with Lambda@Edge/); - - test.done(); - }, + expect(() => singleton._checkEdgeCompatibility()) + .toThrow(/contains environment variables .* and is not compatible with Lambda@Edge/); + }); - 'current version of a singleton function'(test: Test) { + test('current version of a singleton function', () => { // GIVEN const stack = new cdk.Stack(); const singleton = new lambda.SingletonFunction(stack, 'Singleton', { @@ -176,12 +168,10 @@ export = { version.addAlias('foo'); // THEN - expect(stack).to(haveResource('AWS::Lambda::Version', { + expect(stack).toHaveResource('AWS::Lambda::Version', { FunctionName: { Ref: 'SingletonLambda84c0de93353f42179b0b45b6c993251a840BCC38', }, - })); - - test.done(); - }, -}; + }); + }); +}); diff --git a/packages/@aws-cdk/aws-lambda/test/test.function.ts b/packages/@aws-cdk/aws-lambda/test/test.function.ts deleted file mode 100644 index 94c878161221b..0000000000000 --- a/packages/@aws-cdk/aws-lambda/test/test.function.ts +++ /dev/null @@ -1,486 +0,0 @@ -import * as path from 'path'; -import { expect, haveResource, SynthUtils } from '@aws-cdk/assert'; -import { ProfilingGroup } from '@aws-cdk/aws-codeguruprofiler'; -import * as ec2 from '@aws-cdk/aws-ec2'; -import * as efs from '@aws-cdk/aws-efs'; -import * as logs from '@aws-cdk/aws-logs'; -import * as s3 from '@aws-cdk/aws-s3'; -import * as sqs from '@aws-cdk/aws-sqs'; -import * as cdk from '@aws-cdk/core'; -import * as _ from 'lodash'; -import { Test, testCase } from 'nodeunit'; -import * as lambda from '../lib'; - -/* eslint-disable quote-props */ - -export = testCase({ - 'add incompatible layer'(test: Test) { - // GIVEN - const stack = new cdk.Stack(undefined, 'TestStack'); - const bucket = new s3.Bucket(stack, 'Bucket'); - const code = new lambda.S3Code(bucket, 'ObjectKey'); - - const func = new lambda.Function(stack, 'myFunc', { - runtime: lambda.Runtime.PYTHON_3_7, - handler: 'index.handler', - code, - }); - const layer = new lambda.LayerVersion(stack, 'myLayer', { - code, - compatibleRuntimes: [lambda.Runtime.NODEJS], - }); - - // THEN - test.throws(() => func.addLayers(layer), - /This lambda function uses a runtime that is incompatible with this layer/); - - test.done(); - }, - 'add compatible layer'(test: Test) { - // GIVEN - const stack = new cdk.Stack(undefined, 'TestStack'); - const bucket = new s3.Bucket(stack, 'Bucket'); - const code = new lambda.S3Code(bucket, 'ObjectKey'); - - const func = new lambda.Function(stack, 'myFunc', { - runtime: lambda.Runtime.PYTHON_3_7, - handler: 'index.handler', - code, - }); - const layer = new lambda.LayerVersion(stack, 'myLayer', { - code, - compatibleRuntimes: [lambda.Runtime.PYTHON_3_7], - }); - - // THEN - // should not throw - func.addLayers(layer); - - test.done(); - }, - 'add compatible layer for deep clone'(test: Test) { - // GIVEN - const stack = new cdk.Stack(undefined, 'TestStack'); - const bucket = new s3.Bucket(stack, 'Bucket'); - const code = new lambda.S3Code(bucket, 'ObjectKey'); - - const runtime = lambda.Runtime.PYTHON_3_7; - const func = new lambda.Function(stack, 'myFunc', { - runtime, - handler: 'index.handler', - code, - }); - const clone = _.cloneDeep(runtime); - const layer = new lambda.LayerVersion(stack, 'myLayer', { - code, - compatibleRuntimes: [clone], - }); - - // THEN - // should not throw - func.addLayers(layer); - - test.done(); - }, - - 'empty inline code is not allowed'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN/THEN - test.throws(() => new lambda.Function(stack, 'fn', { - handler: 'foo', - runtime: lambda.Runtime.NODEJS_10_X, - code: lambda.Code.fromInline(''), - }), /Lambda inline code cannot be empty/); - test.done(); - }, - - 'logGroup is correctly returned'(test: Test) { - const stack = new cdk.Stack(); - const fn = new lambda.Function(stack, 'fn', { - handler: 'foo', - runtime: lambda.Runtime.NODEJS_10_X, - code: lambda.Code.fromInline('foo'), - }); - const logGroup = fn.logGroup; - test.ok(logGroup.logGroupName); - test.ok(logGroup.logGroupArn); - test.done(); - }, - - 'dlq is returned when provided by user'(test: Test) { - const stack = new cdk.Stack(); - - const dlQueue = new sqs.Queue(stack, 'DeadLetterQueue', { - queueName: 'MyLambda_DLQ', - retentionPeriod: cdk.Duration.days(14), - }); - - const fn = new lambda.Function(stack, 'fn', { - handler: 'foo', - runtime: lambda.Runtime.NODEJS_10_X, - code: lambda.Code.fromInline('foo'), - deadLetterQueue: dlQueue, - }); - const deadLetterQueue = fn.deadLetterQueue; - test.ok(deadLetterQueue?.queueArn); - test.ok(deadLetterQueue?.queueName); - test.ok(deadLetterQueue?.queueUrl); - test.done(); - }, - - 'dlq is returned when setup by cdk'(test: Test) { - const stack = new cdk.Stack(); - const fn = new lambda.Function(stack, 'fn', { - handler: 'foo', - runtime: lambda.Runtime.NODEJS_10_X, - code: lambda.Code.fromInline('foo'), - deadLetterQueueEnabled: true, - }); - const deadLetterQueue = fn.deadLetterQueue; - test.ok(deadLetterQueue?.queueArn); - test.ok(deadLetterQueue?.queueName); - test.ok(deadLetterQueue?.queueUrl); - test.done(); - }, - - 'dlq is undefined when not setup'(test: Test) { - const stack = new cdk.Stack(); - const fn = new lambda.Function(stack, 'fn', { - handler: 'foo', - runtime: lambda.Runtime.NODEJS_10_X, - code: lambda.Code.fromInline('foo'), - }); - const deadLetterQueue = fn.deadLetterQueue; - test.ok(deadLetterQueue === undefined); - test.done(); - }, - - 'one and only one child LogRetention construct will be created'(test: Test) { - const stack = new cdk.Stack(); - const fn = new lambda.Function(stack, 'fn', { - handler: 'foo', - runtime: lambda.Runtime.NODEJS_10_X, - code: lambda.Code.fromInline('foo'), - logRetention: logs.RetentionDays.FIVE_DAYS, - }); - - // Call logGroup a few times. If more than one instance of LogRetention was created, - // the second call will fail on duplicate constructs. - fn.logGroup; - fn.logGroup; - fn.logGroup; - - test.done(); - }, - - 'fails when inline code is specified on an incompatible runtime'(test: Test) { - const stack = new cdk.Stack(); - test.throws(() => new lambda.Function(stack, 'fn', { - handler: 'foo', - runtime: lambda.Runtime.PROVIDED, - code: lambda.Code.fromInline('foo'), - }), /Inline source not allowed for/); - test.done(); - }, - - 'default function with CDK created Profiling Group'(test: Test) { - const stack = new cdk.Stack(); - - new lambda.Function(stack, 'MyLambda', { - code: new lambda.InlineCode('foo'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, - profiling: true, - }); - - expect(stack).to(haveResource('AWS::CodeGuruProfiler::ProfilingGroup', { - ProfilingGroupName: 'MyLambdaProfilingGroupC5B6CCD8', - ComputePlatform: 'AWSLambda', - })); - - expect(stack).to(haveResource('AWS::IAM::Policy', { - PolicyDocument: { - Statement: [ - { - Action: [ - 'codeguru-profiler:ConfigureAgent', - 'codeguru-profiler:PostAgentProfile', - ], - Effect: 'Allow', - Resource: { - 'Fn::GetAtt': ['MyLambdaProfilingGroupEC6DE32F', 'Arn'], - }, - }, - ], - Version: '2012-10-17', - }, - PolicyName: 'MyLambdaServiceRoleDefaultPolicy5BBC6F68', - Roles: [ - { - Ref: 'MyLambdaServiceRole4539ECB6', - }, - ], - })); - - expect(stack).to(haveResource('AWS::Lambda::Function', { - Environment: { - Variables: { - AWS_CODEGURU_PROFILER_GROUP_ARN: { 'Fn::GetAtt': ['MyLambdaProfilingGroupEC6DE32F', 'Arn'] }, - AWS_CODEGURU_PROFILER_ENABLED: 'TRUE', - }, - }, - })); - - test.done(); - }, - - 'default function with client provided Profiling Group'(test: Test) { - const stack = new cdk.Stack(); - - new lambda.Function(stack, 'MyLambda', { - code: new lambda.InlineCode('foo'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, - profilingGroup: new ProfilingGroup(stack, 'ProfilingGroup'), - }); - - expect(stack).to(haveResource('AWS::IAM::Policy', { - PolicyDocument: { - Statement: [ - { - Action: [ - 'codeguru-profiler:ConfigureAgent', - 'codeguru-profiler:PostAgentProfile', - ], - Effect: 'Allow', - Resource: { - 'Fn::GetAtt': ['ProfilingGroup26979FD7', 'Arn'], - }, - }, - ], - Version: '2012-10-17', - }, - PolicyName: 'MyLambdaServiceRoleDefaultPolicy5BBC6F68', - Roles: [ - { - Ref: 'MyLambdaServiceRole4539ECB6', - }, - ], - })); - - expect(stack).to(haveResource('AWS::Lambda::Function', { - Environment: { - Variables: { - AWS_CODEGURU_PROFILER_GROUP_ARN: { - 'Fn::Join': [ - '', - [ - 'arn:', { Ref: 'AWS::Partition' }, ':codeguru-profiler:', { Ref: 'AWS::Region' }, - ':', { Ref: 'AWS::AccountId' }, ':profilingGroup/', { Ref: 'ProfilingGroup26979FD7' }, - ], - ], - }, - AWS_CODEGURU_PROFILER_ENABLED: 'TRUE', - }, - }, - })); - - test.done(); - }, - - 'default function with client provided Profiling Group but profiling set to false'(test: Test) { - const stack = new cdk.Stack(); - - new lambda.Function(stack, 'MyLambda', { - code: new lambda.InlineCode('foo'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, - profiling: false, - profilingGroup: new ProfilingGroup(stack, 'ProfilingGroup'), - }); - - expect(stack).notTo(haveResource('AWS::IAM::Policy')); - - expect(stack).notTo(haveResource('AWS::Lambda::Function', { - Environment: { - Variables: { - AWS_CODEGURU_PROFILER_GROUP_ARN: { - 'Fn::Join': [ - '', - [ - 'arn:', { Ref: 'AWS::Partition' }, ':codeguru-profiler:', { Ref: 'AWS::Region' }, - ':', { Ref: 'AWS::AccountId' }, ':profilingGroup/', { Ref: 'ProfilingGroup26979FD7' }, - ], - ], - }, - AWS_CODEGURU_PROFILER_ENABLED: 'TRUE', - }, - }, - })); - - test.done(); - }, - - 'default function with profiling enabled and client provided env vars'(test: Test) { - const stack = new cdk.Stack(); - - test.throws(() => new lambda.Function(stack, 'MyLambda', { - code: new lambda.InlineCode('foo'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, - profiling: true, - environment: { - AWS_CODEGURU_PROFILER_GROUP_ARN: 'profiler_group_arn', - AWS_CODEGURU_PROFILER_ENABLED: 'yes', - }, - }), - /AWS_CODEGURU_PROFILER_GROUP_ARN and AWS_CODEGURU_PROFILER_ENABLED must not be set when profiling options enabled/); - - test.done(); - }, - - 'default function with client provided Profiling Group and client provided env vars'(test: Test) { - const stack = new cdk.Stack(); - - test.throws(() => new lambda.Function(stack, 'MyLambda', { - code: new lambda.InlineCode('foo'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, - profilingGroup: new ProfilingGroup(stack, 'ProfilingGroup'), - environment: { - AWS_CODEGURU_PROFILER_GROUP_ARN: 'profiler_group_arn', - AWS_CODEGURU_PROFILER_ENABLED: 'yes', - }, - }), - /AWS_CODEGURU_PROFILER_GROUP_ARN and AWS_CODEGURU_PROFILER_ENABLED must not be set when profiling options enabled/); - - test.done(); - }, - - 'multiple calls to latestVersion returns the same version'(test: Test) { - const stack = new cdk.Stack(); - - const fn = new lambda.Function(stack, 'MyLambda', { - code: new lambda.InlineCode('hello()'), - handler: 'index.hello', - runtime: lambda.Runtime.NODEJS_10_X, - }); - - const version1 = fn.latestVersion; - const version2 = fn.latestVersion; - - const expectedArn = { - 'Fn::Join': ['', [ - { 'Fn::GetAtt': ['MyLambdaCCE802FB', 'Arn'] }, - ':$LATEST', - ]], - }; - test.equal(version1, version2); - test.deepEqual(stack.resolve(version1.functionArn), expectedArn); - test.deepEqual(stack.resolve(version2.functionArn), expectedArn); - - test.done(); - }, - - 'currentVersion': { - // see test.function-hash.ts for more coverage for this - 'logical id of version is based on the function hash'(test: Test) { - // GIVEN - const stack1 = new cdk.Stack(); - const fn1 = new lambda.Function(stack1, 'MyFunction', { - handler: 'foo', - runtime: lambda.Runtime.NODEJS_12_X, - code: lambda.Code.fromAsset(path.join(__dirname, 'handler.zip')), - environment: { - FOO: 'bar', - }, - }); - const stack2 = new cdk.Stack(); - const fn2 = new lambda.Function(stack2, 'MyFunction', { - handler: 'foo', - runtime: lambda.Runtime.NODEJS_12_X, - code: lambda.Code.fromAsset(path.join(__dirname, 'handler.zip')), - environment: { - FOO: 'bear', - }, - }); - - // WHEN - new cdk.CfnOutput(stack1, 'CurrentVersionArn', { - value: fn1.currentVersion.functionArn, - }); - new cdk.CfnOutput(stack2, 'CurrentVersionArn', { - value: fn2.currentVersion.functionArn, - }); - - // THEN - const template1 = SynthUtils.synthesize(stack1).template; - const template2 = SynthUtils.synthesize(stack2).template; - - // these functions are different in their configuration but the original - // logical ID of the version would be the same unless the logical ID - // includes the hash of function's configuration. - test.notDeepEqual(template1.Outputs.CurrentVersionArn.Value, template2.Outputs.CurrentVersionArn.Value); - test.done(); - }, - }, - - 'filesystem': { - - 'mount efs filesystem'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { - maxAzs: 3, - natGateways: 1, - }); - - const fs = new efs.FileSystem(stack, 'Efs', { - vpc, - }); - const accessPoint = fs.addAccessPoint('AccessPoint'); - // WHEN - new lambda.Function(stack, 'MyFunction', { - handler: 'foo', - runtime: lambda.Runtime.NODEJS_12_X, - code: lambda.Code.fromAsset(path.join(__dirname, 'handler.zip')), - filesystem: lambda.FileSystem.fromEfsAccessPoint(accessPoint, '/mnt/msg'), - }); - - // THEN - expect(stack).to(haveResource('AWS::Lambda::Function', { - FileSystemConfigs: [ - { - Arn: { - 'Fn::Join': [ - '', - [ - 'arn:', - { - Ref: 'AWS::Partition', - }, - ':elasticfilesystem:', - { - Ref: 'AWS::Region', - }, - ':', - { - Ref: 'AWS::AccountId', - }, - ':access-point/', - { - Ref: 'EfsAccessPointE419FED9', - }, - ], - ], - }, - LocalMountPath: '/mnt/msg', - }, - ], - })); - test.done(); - }, - }, -}); diff --git a/packages/@aws-cdk/aws-lambda/test/test.lambda.ts b/packages/@aws-cdk/aws-lambda/test/test.lambda.ts deleted file mode 100644 index cad80e9d38931..0000000000000 --- a/packages/@aws-cdk/aws-lambda/test/test.lambda.ts +++ /dev/null @@ -1,1775 +0,0 @@ -import * as path from 'path'; -import { ABSENT, expect, haveResource, MatchStyle, ResourcePart, arrayWith, objectLike } from '@aws-cdk/assert'; -import * as ec2 from '@aws-cdk/aws-ec2'; -import * as iam from '@aws-cdk/aws-iam'; -import * as logs from '@aws-cdk/aws-logs'; -import * as sqs from '@aws-cdk/aws-sqs'; -import * as cdk from '@aws-cdk/core'; -import * as constructs from 'constructs'; -import { Test } from 'nodeunit'; -import * as lambda from '../lib'; - -/* eslint-disable quote-props */ - -export = { - 'default function'(test: Test) { - const stack = new cdk.Stack(); - - new lambda.Function(stack, 'MyLambda', { - code: new lambda.InlineCode('foo'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, - }); - - expect(stack).toMatch({ - Resources: - { - MyLambdaServiceRole4539ECB6: - { - Type: 'AWS::IAM::Role', - Properties: - { - AssumeRolePolicyDocument: - { - Statement: - [{ - Action: 'sts:AssumeRole', - Effect: 'Allow', - Principal: { Service: 'lambda.amazonaws.com' }, - }], - Version: '2012-10-17', - }, - ManagedPolicyArns: - // arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole - // eslint-disable-next-line max-len - [{ 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole']] }], - }, - }, - MyLambdaCCE802FB: - { - Type: 'AWS::Lambda::Function', - Properties: - { - Code: { ZipFile: 'foo' }, - Handler: 'index.handler', - Role: { 'Fn::GetAtt': ['MyLambdaServiceRole4539ECB6', 'Arn'] }, - Runtime: 'nodejs10.x', - }, - DependsOn: ['MyLambdaServiceRole4539ECB6'], - }, - }, - }); - test.done(); - }, - - 'adds policy permissions'(test: Test) { - const stack = new cdk.Stack(); - new lambda.Function(stack, 'MyLambda', { - code: new lambda.InlineCode('foo'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, - initialPolicy: [new iam.PolicyStatement({ actions: ['*'], resources: ['*'] })], - }); - expect(stack).toMatch({ - Resources: - { - MyLambdaServiceRole4539ECB6: - { - Type: 'AWS::IAM::Role', - Properties: - { - AssumeRolePolicyDocument: - { - Statement: - [{ - Action: 'sts:AssumeRole', - Effect: 'Allow', - Principal: { Service: 'lambda.amazonaws.com' }, - }], - Version: '2012-10-17', - }, - ManagedPolicyArns: - // eslint-disable-next-line max-len - [{ 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole']] }], - }, - }, - MyLambdaServiceRoleDefaultPolicy5BBC6F68: { - Type: 'AWS::IAM::Policy', - Properties: { - PolicyDocument: { - Statement: [ - { - Action: '*', - Effect: 'Allow', - Resource: '*', - }, - ], - Version: '2012-10-17', - }, - PolicyName: 'MyLambdaServiceRoleDefaultPolicy5BBC6F68', - Roles: [ - { - Ref: 'MyLambdaServiceRole4539ECB6', - }, - ], - }, - }, - MyLambdaCCE802FB: - { - Type: 'AWS::Lambda::Function', - Properties: - { - Code: { ZipFile: 'foo' }, - Handler: 'index.handler', - Role: { 'Fn::GetAtt': ['MyLambdaServiceRole4539ECB6', 'Arn'] }, - Runtime: 'nodejs10.x', - }, - DependsOn: ['MyLambdaServiceRoleDefaultPolicy5BBC6F68', 'MyLambdaServiceRole4539ECB6'], - }, - }, - }); - test.done(); - - }, - - 'fails if inline code is used for an invalid runtime'(test: Test) { - const stack = new cdk.Stack(); - test.throws(() => new lambda.Function(stack, 'MyLambda', { - code: new lambda.InlineCode('foo'), - handler: 'bar', - runtime: lambda.Runtime.DOTNET_CORE_2, - })); - test.done(); - }, - - 'addToResourcePolicy': { - 'can be used to add permissions to the Lambda function'(test: Test) { - const stack = new cdk.Stack(); - const fn = newTestLambda(stack); - - fn.addPermission('S3Permission', { - action: 'lambda:*', - principal: new iam.ServicePrincipal('s3.amazonaws.com'), - sourceAccount: stack.account, - sourceArn: 'arn:aws:s3:::my_bucket', - }); - - expect(stack).toMatch({ - 'Resources': { - 'MyLambdaServiceRole4539ECB6': { - 'Type': 'AWS::IAM::Role', - 'Properties': { - 'AssumeRolePolicyDocument': { - 'Statement': [ - { - 'Action': 'sts:AssumeRole', - 'Effect': 'Allow', - 'Principal': { - 'Service': 'lambda.amazonaws.com', - }, - }, - ], - 'Version': '2012-10-17', - }, - 'ManagedPolicyArns': - // eslint-disable-next-line max-len - [{ 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole']] }], - }, - }, - 'MyLambdaCCE802FB': { - 'Type': 'AWS::Lambda::Function', - 'Properties': { - 'Code': { - 'ZipFile': 'foo', - }, - 'Handler': 'bar', - 'Role': { - 'Fn::GetAtt': [ - 'MyLambdaServiceRole4539ECB6', - 'Arn', - ], - }, - 'Runtime': 'python2.7', - }, - 'DependsOn': [ - 'MyLambdaServiceRole4539ECB6', - ], - }, - 'MyLambdaS3Permission99D0EA08': { - 'Type': 'AWS::Lambda::Permission', - 'Properties': { - 'Action': 'lambda:*', - 'FunctionName': { - 'Fn::GetAtt': [ - 'MyLambdaCCE802FB', - 'Arn', - ], - }, - 'Principal': 's3.amazonaws.com', - 'SourceAccount': { - 'Ref': 'AWS::AccountId', - }, - 'SourceArn': 'arn:aws:s3:::my_bucket', - }, - }, - }, - }); - - test.done(); - }, - - 'fails if the principal is not a service, account or arn principal'(test: Test) { - const stack = new cdk.Stack(); - const fn = newTestLambda(stack); - - test.throws(() => fn.addPermission('F1', { principal: new iam.OrganizationPrincipal('org') }), - /Invalid principal type for Lambda permission statement/); - - fn.addPermission('S1', { principal: new iam.ServicePrincipal('my-service') }); - fn.addPermission('S2', { principal: new iam.AccountPrincipal('account') }); - fn.addPermission('S3', { principal: new iam.ArnPrincipal('my:arn') }); - - test.done(); - }, - - 'BYORole'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const role = new iam.Role(stack, 'SomeRole', { - assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), - }); - role.addToPolicy(new iam.PolicyStatement({ actions: ['confirm:itsthesame'], resources: ['*'] })); - - // WHEN - const fn = new lambda.Function(stack, 'Function', { - code: new lambda.InlineCode('test'), - runtime: lambda.Runtime.PYTHON_3_6, - handler: 'index.test', - role, - initialPolicy: [ - new iam.PolicyStatement({ actions: ['inline:inline'], resources: ['*'] }), - ], - }); - - fn.addToRolePolicy(new iam.PolicyStatement({ actions: ['explicit:explicit'], resources: ['*'] })); - - // THEN - expect(stack).to(haveResource('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Version': '2012-10-17', - 'Statement': [ - { 'Action': 'confirm:itsthesame', 'Effect': 'Allow', 'Resource': '*' }, - { 'Action': 'inline:inline', 'Effect': 'Allow', 'Resource': '*' }, - { 'Action': 'explicit:explicit', 'Effect': 'Allow', 'Resource': '*' }, - ], - }, - })); - - test.done(); - }, - }, - - 'fromFunctionArn'(test: Test) { - // GIVEN - const stack2 = new cdk.Stack(); - - // WHEN - const imported = lambda.Function.fromFunctionArn(stack2, 'Imported', 'arn:aws:lambda:us-east-1:123456789012:function:ProcessKinesisRecords'); - - // THEN - test.deepEqual(imported.functionArn, 'arn:aws:lambda:us-east-1:123456789012:function:ProcessKinesisRecords'); - test.deepEqual(imported.functionName, 'ProcessKinesisRecords'); - - test.done(); - }, - - 'addPermissions()': { - 'imported Function w/ resolved account and function arn'(test: Test) { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Imports', { - env: { account: '123456789012', region: 'us-east-1' }, - }); - - // WHEN - const iFunc = lambda.Function.fromFunctionAttributes(stack, 'iFunc', { - functionArn: 'arn:aws:lambda:us-east-1:123456789012:function:BaseFunction', - }); - iFunc.addPermission('iFunc', { - principal: new iam.ServicePrincipal('cloudformation.amazonaws.com'), - }); - - // THEN - expect(stack).to(haveResource('AWS::Lambda::Permission')); - test.done(); - }, - - 'imported Function w/ unresolved account'(test: Test) { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Imports'); - - // WHEN - const iFunc = lambda.Function.fromFunctionAttributes(stack, 'iFunc', { - functionArn: 'arn:aws:lambda:us-east-1:123456789012:function:BaseFunction', - }); - iFunc.addPermission('iFunc', { - principal: new iam.ServicePrincipal('cloudformation.amazonaws.com'), - }); - - // THEN - expect(stack).to(haveResource('AWS::Lambda::Permission')); - test.done(); - }, - - 'imported Function w/different account'(test: Test) { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Base', { - env: { account: '111111111111' }, - }); - - // WHEN - const iFunc = lambda.Function.fromFunctionAttributes(stack, 'iFunc', { - functionArn: 'arn:aws:lambda:us-east-1:123456789012:function:BaseFunction', - }); - iFunc.addPermission('iFunc', { - principal: new iam.ServicePrincipal('cloudformation.amazonaws.com'), - }); - - // THEN - expect(stack).notTo(haveResource('AWS::Lambda::Permission')); - test.done(); - }, - }, - - 'Lambda code can be read from a local directory via an asset'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - new lambda.Function(stack, 'MyLambda', { - code: lambda.Code.fromAsset(path.join(__dirname, 'my-lambda-handler')), - handler: 'index.handler', - runtime: lambda.Runtime.PYTHON_3_6, - }); - - // THEN - expect(stack).to(haveResource('AWS::Lambda::Function', { - 'Code': { - 'S3Bucket': { - 'Ref': 'AssetParameters9678c34eca93259d11f2d714177347afd66c50116e1e08996eff893d3ca81232S3Bucket1354C645', - }, - 'S3Key': { - 'Fn::Join': ['', [ - { 'Fn::Select': [0, { 'Fn::Split': ['||', { 'Ref': 'AssetParameters9678c34eca93259d11f2d714177347afd66c50116e1e08996eff893d3ca81232S3VersionKey5D873FAC' }] }] }, - { 'Fn::Select': [1, { 'Fn::Split': ['||', { 'Ref': 'AssetParameters9678c34eca93259d11f2d714177347afd66c50116e1e08996eff893d3ca81232S3VersionKey5D873FAC' }] }] }, - ]], - }, - }, - 'Handler': 'index.handler', - 'Role': { - 'Fn::GetAtt': [ - 'MyLambdaServiceRole4539ECB6', - 'Arn', - ], - }, - 'Runtime': 'python3.6', - })); - - test.done(); - }, - - 'default function with SQS DLQ when client sets deadLetterQueueEnabled to true and functionName defined by client'(test: Test) { - const stack = new cdk.Stack(); - - new lambda.Function(stack, 'MyLambda', { - code: new lambda.InlineCode('foo'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, - functionName: 'OneFunctionToRuleThemAll', - deadLetterQueueEnabled: true, - }); - - expect(stack).toMatch( - { - 'Resources': { - 'MyLambdaServiceRole4539ECB6': { - 'Type': 'AWS::IAM::Role', - 'Properties': { - 'AssumeRolePolicyDocument': { - 'Statement': [ - { - 'Action': 'sts:AssumeRole', - 'Effect': 'Allow', - 'Principal': { - 'Service': 'lambda.amazonaws.com', - }, - }, - ], - 'Version': '2012-10-17', - }, - 'ManagedPolicyArns': [ - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - 'Ref': 'AWS::Partition', - }, - ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole', - ], - ], - }, - ], - }, - }, - 'MyLambdaServiceRoleDefaultPolicy5BBC6F68': { - 'Type': 'AWS::IAM::Policy', - 'Properties': { - 'PolicyDocument': { - 'Statement': [ - { - 'Action': 'sqs:SendMessage', - 'Effect': 'Allow', - 'Resource': { - 'Fn::GetAtt': [ - 'MyLambdaDeadLetterQueue399EEA2D', - 'Arn', - ], - }, - }, - ], - 'Version': '2012-10-17', - }, - 'PolicyName': 'MyLambdaServiceRoleDefaultPolicy5BBC6F68', - 'Roles': [ - { - 'Ref': 'MyLambdaServiceRole4539ECB6', - }, - ], - }, - }, - 'MyLambdaDeadLetterQueue399EEA2D': { - 'Type': 'AWS::SQS::Queue', - 'Properties': { - 'MessageRetentionPeriod': 1209600, - }, - }, - 'MyLambdaCCE802FB': { - 'Type': 'AWS::Lambda::Function', - 'Properties': { - 'Code': { - 'ZipFile': 'foo', - }, - 'Handler': 'index.handler', - 'Role': { - 'Fn::GetAtt': [ - 'MyLambdaServiceRole4539ECB6', - 'Arn', - ], - }, - 'Runtime': 'nodejs10.x', - 'DeadLetterConfig': { - 'TargetArn': { - 'Fn::GetAtt': [ - 'MyLambdaDeadLetterQueue399EEA2D', - 'Arn', - ], - }, - }, - 'FunctionName': 'OneFunctionToRuleThemAll', - }, - 'DependsOn': [ - 'MyLambdaServiceRoleDefaultPolicy5BBC6F68', - 'MyLambdaServiceRole4539ECB6', - ], - }, - }, - }, - ); - test.done(); - }, - - 'default function with SQS DLQ when client sets deadLetterQueueEnabled to true and functionName not defined by client'(test: Test) { - const stack = new cdk.Stack(); - - new lambda.Function(stack, 'MyLambda', { - code: new lambda.InlineCode('foo'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, - deadLetterQueueEnabled: true, - }); - - expect(stack).toMatch( - { - 'Resources': { - 'MyLambdaServiceRole4539ECB6': { - 'Type': 'AWS::IAM::Role', - 'Properties': { - 'AssumeRolePolicyDocument': { - 'Statement': [ - { - 'Action': 'sts:AssumeRole', - 'Effect': 'Allow', - 'Principal': { - 'Service': 'lambda.amazonaws.com', - }, - }, - ], - 'Version': '2012-10-17', - }, - 'ManagedPolicyArns': [ - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - 'Ref': 'AWS::Partition', - }, - ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole', - ], - ], - }, - ], - }, - }, - 'MyLambdaServiceRoleDefaultPolicy5BBC6F68': { - 'Type': 'AWS::IAM::Policy', - 'Properties': { - 'PolicyDocument': { - 'Statement': [ - { - 'Action': 'sqs:SendMessage', - 'Effect': 'Allow', - 'Resource': { - 'Fn::GetAtt': [ - 'MyLambdaDeadLetterQueue399EEA2D', - 'Arn', - ], - }, - }, - ], - 'Version': '2012-10-17', - }, - 'PolicyName': 'MyLambdaServiceRoleDefaultPolicy5BBC6F68', - 'Roles': [ - { - 'Ref': 'MyLambdaServiceRole4539ECB6', - }, - ], - }, - }, - 'MyLambdaDeadLetterQueue399EEA2D': { - 'Type': 'AWS::SQS::Queue', - 'Properties': { - 'MessageRetentionPeriod': 1209600, - }, - }, - 'MyLambdaCCE802FB': { - 'Type': 'AWS::Lambda::Function', - 'Properties': { - 'Code': { - 'ZipFile': 'foo', - }, - 'Handler': 'index.handler', - 'Role': { - 'Fn::GetAtt': [ - 'MyLambdaServiceRole4539ECB6', - 'Arn', - ], - }, - 'Runtime': 'nodejs10.x', - 'DeadLetterConfig': { - 'TargetArn': { - 'Fn::GetAtt': [ - 'MyLambdaDeadLetterQueue399EEA2D', - 'Arn', - ], - }, - }, - }, - 'DependsOn': [ - 'MyLambdaServiceRoleDefaultPolicy5BBC6F68', - 'MyLambdaServiceRole4539ECB6', - ], - }, - }, - }, - ); - test.done(); - }, - - 'default function with SQS DLQ when client sets deadLetterQueueEnabled to false'(test: Test) { - const stack = new cdk.Stack(); - - new lambda.Function(stack, 'MyLambda', { - code: new lambda.InlineCode('foo'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, - deadLetterQueueEnabled: false, - }); - - expect(stack).toMatch( - { - 'Resources': { - 'MyLambdaServiceRole4539ECB6': { - 'Type': 'AWS::IAM::Role', - 'Properties': { - 'AssumeRolePolicyDocument': { - 'Statement': [ - { - 'Action': 'sts:AssumeRole', - 'Effect': 'Allow', - 'Principal': { - 'Service': 'lambda.amazonaws.com', - }, - }, - ], - 'Version': '2012-10-17', - }, - 'ManagedPolicyArns': [ - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - 'Ref': 'AWS::Partition', - }, - ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole', - ], - ], - }, - ], - }, - }, - 'MyLambdaCCE802FB': { - 'Type': 'AWS::Lambda::Function', - 'Properties': { - 'Code': { - 'ZipFile': 'foo', - }, - 'Handler': 'index.handler', - 'Role': { - 'Fn::GetAtt': [ - 'MyLambdaServiceRole4539ECB6', - 'Arn', - ], - }, - 'Runtime': 'nodejs10.x', - }, - 'DependsOn': [ - 'MyLambdaServiceRole4539ECB6', - ], - }, - }, - }, - ); - test.done(); - }, - - 'default function with SQS DLQ when client provides Queue to be used as DLQ'(test: Test) { - const stack = new cdk.Stack(); - - const dlQueue = new sqs.Queue(stack, 'DeadLetterQueue', { - queueName: 'MyLambda_DLQ', - retentionPeriod: cdk.Duration.days(14), - }); - - new lambda.Function(stack, 'MyLambda', { - code: new lambda.InlineCode('foo'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, - deadLetterQueue: dlQueue, - }); - - expect(stack).toMatch( - { - 'Resources': { - 'MyLambdaServiceRole4539ECB6': { - 'Type': 'AWS::IAM::Role', - 'Properties': { - 'AssumeRolePolicyDocument': { - 'Statement': [ - { - 'Action': 'sts:AssumeRole', - 'Effect': 'Allow', - 'Principal': { - 'Service': 'lambda.amazonaws.com', - }, - }, - ], - 'Version': '2012-10-17', - }, - 'ManagedPolicyArns': [ - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - 'Ref': 'AWS::Partition', - }, - ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole', - ], - ], - }, - ], - }, - }, - 'MyLambdaServiceRoleDefaultPolicy5BBC6F68': { - 'Type': 'AWS::IAM::Policy', - 'Properties': { - 'PolicyDocument': { - 'Statement': [ - { - 'Action': 'sqs:SendMessage', - 'Effect': 'Allow', - 'Resource': { - 'Fn::GetAtt': [ - 'DeadLetterQueue9F481546', - 'Arn', - ], - }, - }, - ], - 'Version': '2012-10-17', - }, - 'PolicyName': 'MyLambdaServiceRoleDefaultPolicy5BBC6F68', - 'Roles': [ - { - 'Ref': 'MyLambdaServiceRole4539ECB6', - }, - ], - }, - }, - 'MyLambdaCCE802FB': { - 'Type': 'AWS::Lambda::Function', - 'Properties': { - 'Code': { - 'ZipFile': 'foo', - }, - 'Handler': 'index.handler', - 'Role': { - 'Fn::GetAtt': [ - 'MyLambdaServiceRole4539ECB6', - 'Arn', - ], - }, - 'Runtime': 'nodejs10.x', - 'DeadLetterConfig': { - 'TargetArn': { - 'Fn::GetAtt': [ - 'DeadLetterQueue9F481546', - 'Arn', - ], - }, - }, - }, - 'DependsOn': [ - 'MyLambdaServiceRoleDefaultPolicy5BBC6F68', - 'MyLambdaServiceRole4539ECB6', - ], - }, - }, - } - , MatchStyle.SUPERSET); - test.done(); - }, - - 'default function with SQS DLQ when client provides Queue to be used as DLQ and deadLetterQueueEnabled set to true'(test: Test) { - const stack = new cdk.Stack(); - - const dlQueue = new sqs.Queue(stack, 'DeadLetterQueue', { - queueName: 'MyLambda_DLQ', - retentionPeriod: cdk.Duration.days(14), - }); - - new lambda.Function(stack, 'MyLambda', { - code: new lambda.InlineCode('foo'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, - deadLetterQueueEnabled: true, - deadLetterQueue: dlQueue, - }); - - expect(stack).toMatch( - { - 'Resources': { - 'MyLambdaServiceRole4539ECB6': { - 'Type': 'AWS::IAM::Role', - 'Properties': { - 'AssumeRolePolicyDocument': { - 'Statement': [ - { - 'Action': 'sts:AssumeRole', - 'Effect': 'Allow', - 'Principal': { - 'Service': 'lambda.amazonaws.com', - }, - }, - ], - 'Version': '2012-10-17', - }, - 'ManagedPolicyArns': [ - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - 'Ref': 'AWS::Partition', - }, - ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole', - ], - ], - }, - ], - }, - }, - 'MyLambdaServiceRoleDefaultPolicy5BBC6F68': { - 'Type': 'AWS::IAM::Policy', - 'Properties': { - 'PolicyDocument': { - 'Statement': [ - { - 'Action': 'sqs:SendMessage', - 'Effect': 'Allow', - 'Resource': { - 'Fn::GetAtt': [ - 'DeadLetterQueue9F481546', - 'Arn', - ], - }, - }, - ], - 'Version': '2012-10-17', - }, - 'PolicyName': 'MyLambdaServiceRoleDefaultPolicy5BBC6F68', - 'Roles': [ - { - 'Ref': 'MyLambdaServiceRole4539ECB6', - }, - ], - }, - }, - 'MyLambdaCCE802FB': { - 'Type': 'AWS::Lambda::Function', - 'Properties': { - 'Code': { - 'ZipFile': 'foo', - }, - 'Handler': 'index.handler', - 'Role': { - 'Fn::GetAtt': [ - 'MyLambdaServiceRole4539ECB6', - 'Arn', - ], - }, - 'Runtime': 'nodejs10.x', - 'DeadLetterConfig': { - 'TargetArn': { - 'Fn::GetAtt': [ - 'DeadLetterQueue9F481546', - 'Arn', - ], - }, - }, - }, - 'DependsOn': [ - 'MyLambdaServiceRoleDefaultPolicy5BBC6F68', - 'MyLambdaServiceRole4539ECB6', - ], - }, - }, - } - , MatchStyle.SUPERSET); - test.done(); - }, - - 'error when default function with SQS DLQ when client provides Queue to be used as DLQ and deadLetterQueueEnabled set to false'(test: Test) { - const stack = new cdk.Stack(); - - const dlQueue = new sqs.Queue(stack, 'DeadLetterQueue', { - queueName: 'MyLambda_DLQ', - retentionPeriod: cdk.Duration.days(14), - }); - - test.throws(() => new lambda.Function(stack, 'MyLambda', { - code: new lambda.InlineCode('foo'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, - deadLetterQueueEnabled: false, - deadLetterQueue: dlQueue, - }), /deadLetterQueue defined but deadLetterQueueEnabled explicitly set to false/); - - test.done(); - }, - - 'default function with Active tracing'(test: Test) { - const stack = new cdk.Stack(); - - new lambda.Function(stack, 'MyLambda', { - code: new lambda.InlineCode('foo'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, - tracing: lambda.Tracing.ACTIVE, - }); - - expect(stack).to(haveResource('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': [ - { - 'Action': [ - 'xray:PutTraceSegments', - 'xray:PutTelemetryRecords', - ], - 'Effect': 'Allow', - 'Resource': '*', - }, - ], - 'Version': '2012-10-17', - }, - 'PolicyName': 'MyLambdaServiceRoleDefaultPolicy5BBC6F68', - 'Roles': [ - { - 'Ref': 'MyLambdaServiceRole4539ECB6', - }, - ], - })); - - expect(stack).to(haveResource('AWS::Lambda::Function', { - 'Properties': { - 'Code': { - 'ZipFile': 'foo', - }, - 'Handler': 'index.handler', - 'Role': { - 'Fn::GetAtt': [ - 'MyLambdaServiceRole4539ECB6', - 'Arn', - ], - }, - 'Runtime': 'nodejs10.x', - 'TracingConfig': { - 'Mode': 'Active', - }, - }, - 'DependsOn': [ - 'MyLambdaServiceRoleDefaultPolicy5BBC6F68', - 'MyLambdaServiceRole4539ECB6', - ], - }, ResourcePart.CompleteDefinition)); - - test.done(); - }, - - 'default function with PassThrough tracing'(test: Test) { - const stack = new cdk.Stack(); - - new lambda.Function(stack, 'MyLambda', { - code: new lambda.InlineCode('foo'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, - tracing: lambda.Tracing.PASS_THROUGH, - }); - - expect(stack).to(haveResource('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': [ - { - 'Action': [ - 'xray:PutTraceSegments', - 'xray:PutTelemetryRecords', - ], - 'Effect': 'Allow', - 'Resource': '*', - }, - ], - 'Version': '2012-10-17', - }, - 'PolicyName': 'MyLambdaServiceRoleDefaultPolicy5BBC6F68', - 'Roles': [ - { - 'Ref': 'MyLambdaServiceRole4539ECB6', - }, - ], - })); - - expect(stack).to(haveResource('AWS::Lambda::Function', { - 'Properties': { - 'Code': { - 'ZipFile': 'foo', - }, - 'Handler': 'index.handler', - 'Role': { - 'Fn::GetAtt': [ - 'MyLambdaServiceRole4539ECB6', - 'Arn', - ], - }, - 'Runtime': 'nodejs10.x', - 'TracingConfig': { - 'Mode': 'PassThrough', - }, - }, - 'DependsOn': [ - 'MyLambdaServiceRoleDefaultPolicy5BBC6F68', - 'MyLambdaServiceRole4539ECB6', - ], - }, ResourcePart.CompleteDefinition)); - - test.done(); - }, - - 'default function with Disabled tracing'(test: Test) { - const stack = new cdk.Stack(); - - new lambda.Function(stack, 'MyLambda', { - code: new lambda.InlineCode('foo'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, - tracing: lambda.Tracing.DISABLED, - }); - - expect(stack).notTo(haveResource('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': [ - { - 'Action': [ - 'xray:PutTraceSegments', - 'xray:PutTelemetryRecords', - ], - 'Effect': 'Allow', - 'Resource': '*', - }, - ], - 'Version': '2012-10-17', - }, - 'PolicyName': 'MyLambdaServiceRoleDefaultPolicy5BBC6F68', - 'Roles': [ - { - 'Ref': 'MyLambdaServiceRole4539ECB6', - }, - ], - })); - - expect(stack).to(haveResource('AWS::Lambda::Function', { - 'Properties': { - 'Code': { - 'ZipFile': 'foo', - }, - 'Handler': 'index.handler', - 'Role': { - 'Fn::GetAtt': [ - 'MyLambdaServiceRole4539ECB6', - 'Arn', - ], - }, - 'Runtime': 'nodejs10.x', - }, - 'DependsOn': [ - 'MyLambdaServiceRole4539ECB6', - ], - }, ResourcePart.CompleteDefinition)); - - test.done(); - }, - - 'grantInvoke': { - - 'adds iam:InvokeFunction'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const role = new iam.Role(stack, 'Role', { - assumedBy: new iam.AccountPrincipal('1234'), - }); - const fn = new lambda.Function(stack, 'Function', { - code: lambda.Code.fromInline('xxx'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, - }); - - // WHEN - fn.grantInvoke(role); - - // THEN - expect(stack).to(haveResource('AWS::IAM::Policy', { - PolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Action: 'lambda:InvokeFunction', - Effect: 'Allow', - Resource: { 'Fn::GetAtt': ['Function76856677', 'Arn'] }, - }, - ], - }, - })); - - test.done(); - }, - - 'with a service principal'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const fn = new lambda.Function(stack, 'Function', { - code: lambda.Code.fromInline('xxx'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, - }); - const service = new iam.ServicePrincipal('apigateway.amazonaws.com'); - - // WHEN - fn.grantInvoke(service); - - // THEN - expect(stack).to(haveResource('AWS::Lambda::Permission', { - Action: 'lambda:InvokeFunction', - FunctionName: { - 'Fn::GetAtt': [ - 'Function76856677', - 'Arn', - ], - }, - Principal: 'apigateway.amazonaws.com', - })); - - test.done(); - }, - - 'with an account principal'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const fn = new lambda.Function(stack, 'Function', { - code: lambda.Code.fromInline('xxx'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, - }); - const account = new iam.AccountPrincipal('123456789012'); - - // WHEN - fn.grantInvoke(account); - - // THEN - expect(stack).to(haveResource('AWS::Lambda::Permission', { - Action: 'lambda:InvokeFunction', - FunctionName: { - 'Fn::GetAtt': [ - 'Function76856677', - 'Arn', - ], - }, - Principal: '123456789012', - })); - - test.done(); - }, - - 'with an arn principal'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const fn = new lambda.Function(stack, 'Function', { - code: lambda.Code.fromInline('xxx'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, - }); - const account = new iam.ArnPrincipal('arn:aws:iam::123456789012:role/someRole'); - - // WHEN - fn.grantInvoke(account); - - // THEN - expect(stack).to(haveResource('AWS::Lambda::Permission', { - Action: 'lambda:InvokeFunction', - FunctionName: { - 'Fn::GetAtt': [ - 'Function76856677', - 'Arn', - ], - }, - Principal: 'arn:aws:iam::123456789012:role/someRole', - })); - - test.done(); - }, - - 'can be called twice for the same service principal'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const fn = new lambda.Function(stack, 'Function', { - code: lambda.Code.fromInline('xxx'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, - }); - const service = new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com'); - - // WHEN - fn.grantInvoke(service); - fn.grantInvoke(service); - - // THEN - expect(stack).to(haveResource('AWS::Lambda::Permission', { - Action: 'lambda:InvokeFunction', - FunctionName: { - 'Fn::GetAtt': [ - 'Function76856677', - 'Arn', - ], - }, - Principal: 'elasticloadbalancing.amazonaws.com', - })); - - test.done(); - }, - - 'with an imported role (in the same account)'(test: Test) { - // GIVEN - const stack = new cdk.Stack(undefined, undefined, { - env: { account: '123456789012' }, - }); - const fn = new lambda.Function(stack, 'Function', { - code: lambda.Code.fromInline('xxx'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, - }); - - // WHEN - fn.grantInvoke(iam.Role.fromRoleArn(stack, 'ForeignRole', 'arn:aws:iam::123456789012:role/someRole')); - - // THEN - expect(stack).to(haveResource('AWS::IAM::Policy', { - PolicyDocument: objectLike({ - Statement: arrayWith( - { - Action: 'lambda:InvokeFunction', - Effect: 'Allow', - Resource: { 'Fn::GetAtt': ['Function76856677', 'Arn'] }, - }, - ), - }), - Roles: ['someRole'], - })); - - test.done(); - }, - - 'with an imported role (from a different account)'(test: Test) { - // GIVEN - const stack = new cdk.Stack(undefined, undefined, { - env: { account: '3333' }, - }); - const fn = new lambda.Function(stack, 'Function', { - code: lambda.Code.fromInline('xxx'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, - }); - - // WHEN - fn.grantInvoke(iam.Role.fromRoleArn(stack, 'ForeignRole', 'arn:aws:iam::123456789012:role/someRole')); - - // THEN - expect(stack).to(haveResource('AWS::Lambda::Permission', { - Action: 'lambda:InvokeFunction', - FunctionName: { - 'Fn::GetAtt': [ - 'Function76856677', - 'Arn', - ], - }, - Principal: 'arn:aws:iam::123456789012:role/someRole', - })); - - test.done(); - }, - - 'on an imported function (same account)'(test: Test) { - // GIVEN - const stack = new cdk.Stack(undefined, undefined, { - env: { account: '123456789012' }, - }); - const fn = lambda.Function.fromFunctionArn(stack, 'Function', 'arn:aws:lambda:us-east-1:123456789012:function:MyFn'); - - // WHEN - fn.grantInvoke(new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com')); - - // THEN - expect(stack).to(haveResource('AWS::Lambda::Permission', { - Action: 'lambda:InvokeFunction', - FunctionName: 'arn:aws:lambda:us-east-1:123456789012:function:MyFn', - Principal: 'elasticloadbalancing.amazonaws.com', - })); - - test.done(); - }, - - 'on an imported function (unresolved account)'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const fn = lambda.Function.fromFunctionArn(stack, 'Function', 'arn:aws:lambda:us-east-1:123456789012:function:MyFn'); - - // WHEN - fn.grantInvoke(new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com')); - - // THEN - expect(stack).to(haveResource('AWS::Lambda::Permission', { - Action: 'lambda:InvokeFunction', - FunctionName: 'arn:aws:lambda:us-east-1:123456789012:function:MyFn', - Principal: 'elasticloadbalancing.amazonaws.com', - })); - - test.done(); - }, - - 'on an imported function (different account)'(test: Test) { - // GIVEN - const stack = new cdk.Stack(undefined, undefined, { - env: { account: '111111111111' }, // Different account - }); - const fn = lambda.Function.fromFunctionArn(stack, 'Function', 'arn:aws:lambda:us-east-1:123456789012:function:MyFn'); - - // THEN - test.throws(() => { fn.grantInvoke(new iam.ServicePrincipal('elasticloadbalancing.amazonaws.com')); }, - /Cannot modify permission to lambda function/); - - test.done(); - }, - }, - - 'Can use metricErrors on a lambda Function'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const fn = new lambda.Function(stack, 'Function', { - code: lambda.Code.fromInline('xxx'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, - }); - - // THEN - test.deepEqual(stack.resolve(fn.metricErrors()), { - dimensions: { FunctionName: { Ref: 'Function76856677' } }, - namespace: 'AWS/Lambda', - metricName: 'Errors', - period: cdk.Duration.minutes(5), - statistic: 'Sum', - }); - - test.done(); - }, - - 'addEventSource calls bind'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const fn = new lambda.Function(stack, 'Function', { - code: lambda.Code.fromInline('xxx'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, - }); - - let bindTarget; - - class EventSourceMock implements lambda.IEventSource { - public bind(target: lambda.IFunction) { - bindTarget = target; - } - } - - // WHEN - fn.addEventSource(new EventSourceMock()); - - // THEN - test.same(bindTarget, fn); - test.done(); - }, - - 'using an incompatible layer'(test: Test) { - // GIVEN - const stack = new cdk.Stack(undefined, 'TestStack'); - const layer = lambda.LayerVersion.fromLayerVersionAttributes(stack, 'TestLayer', { - layerVersionArn: 'arn:aws:...', - compatibleRuntimes: [lambda.Runtime.NODEJS_12_X], - }); - - // THEN - test.throws(() => new lambda.Function(stack, 'Function', { - layers: [layer], - runtime: lambda.Runtime.NODEJS_10_X, - code: lambda.Code.fromInline('exports.main = function() { console.log("DONE"); }'), - handler: 'index.main', - }), /nodejs10.x is not in \[nodejs12.x\]/); - - test.done(); - }, - - 'using more than 5 layers'(test: Test) { - // GIVEN - const stack = new cdk.Stack(undefined, 'TestStack'); - const layers = new Array(6).fill(lambda.LayerVersion.fromLayerVersionAttributes(stack, 'TestLayer', { - layerVersionArn: 'arn:aws:...', - compatibleRuntimes: [lambda.Runtime.NODEJS_10_X], - })); - - // THEN - test.throws(() => new lambda.Function(stack, 'Function', { - layers, - runtime: lambda.Runtime.NODEJS_10_X, - code: lambda.Code.fromInline('exports.main = function() { console.log("DONE"); }'), - handler: 'index.main', - }), /Unable to add layer:/); - - test.done(); - }, - - 'environment variables work in China'(test: Test) { - // GIVEN - const stack = new cdk.Stack(undefined, undefined, { env: { region: 'cn-north-1' } }); - - // WHEN - new lambda.Function(stack, 'MyLambda', { - code: new lambda.InlineCode('foo'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS, - environment: { - SOME: 'Variable', - }, - }); - - // THEN - expect(stack).to(haveResource('AWS::Lambda::Function', { - Environment: { - Variables: { - SOME: 'Variable', - }, - }, - })); - - test.done(); - }, - - 'environment variables work in an unspecified region'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new lambda.Function(stack, 'MyLambda', { - code: new lambda.InlineCode('foo'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS, - environment: { - SOME: 'Variable', - }, - }); - - // THEN - expect(stack).to(haveResource('AWS::Lambda::Function', { - Environment: { - Variables: { - SOME: 'Variable', - }, - }, - })); - - test.done(); - - }, - - 'support reserved concurrent executions'(test: Test) { - const stack = new cdk.Stack(); - - new lambda.Function(stack, 'MyLambda', { - code: new lambda.InlineCode('foo'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS, - reservedConcurrentExecutions: 10, - }); - - expect(stack).toMatch({ - Resources: - { - MyLambdaServiceRole4539ECB6: - { - Type: 'AWS::IAM::Role', - Properties: - { - AssumeRolePolicyDocument: - { - Statement: - [{ - Action: 'sts:AssumeRole', - Effect: 'Allow', - Principal: { Service: 'lambda.amazonaws.com' }, - }], - Version: '2012-10-17', - }, - ManagedPolicyArns: - // arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole - // eslint-disable-next-line max-len - [{ 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole']] }], - }, - }, - MyLambdaCCE802FB: - { - Type: 'AWS::Lambda::Function', - Properties: - { - Code: { ZipFile: 'foo' }, - Handler: 'index.handler', - ReservedConcurrentExecutions: 10, - Role: { 'Fn::GetAtt': ['MyLambdaServiceRole4539ECB6', 'Arn'] }, - Runtime: 'nodejs', - }, - DependsOn: ['MyLambdaServiceRole4539ECB6'], - }, - }, - }); - test.done(); - }, - - 'its possible to specify event sources upon creation'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - let bindCount = 0; - - class EventSource implements lambda.IEventSource { - public bind(_: lambda.IFunction): void { - bindCount++; - } - } - - // WHEN - new lambda.Function(stack, 'fn', { - code: lambda.Code.fromInline('boom'), - runtime: lambda.Runtime.NODEJS_10_X, - handler: 'index.bam', - events: [ - new EventSource(), - new EventSource(), - ], - }); - - // THEN - test.deepEqual(bindCount, 2); - test.done(); - }, - - 'Provided Runtime returns the right values'(test: Test) { - const rt = lambda.Runtime.PROVIDED; - - test.equal(rt.name, 'provided'); - test.equal(rt.supportsInlineCode, false); - - test.done(); - }, - - 'specify log retention'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new lambda.Function(stack, 'MyLambda', { - code: new lambda.InlineCode('foo'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS, - logRetention: logs.RetentionDays.ONE_MONTH, - }); - - // THEN - expect(stack).to(haveResource('Custom::LogRetention', { - 'LogGroupName': { - 'Fn::Join': [ - '', - [ - '/aws/lambda/', - { - Ref: 'MyLambdaCCE802FB', - }, - ], - ], - }, - 'RetentionInDays': 30, - })); - - test.done(); - }, - - 'imported lambda with imported security group and allowAllOutbound set to false'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - const fn = lambda.Function.fromFunctionAttributes(stack, 'fn', { - functionArn: 'arn:aws:lambda:us-east-1:123456789012:function:my-function', - securityGroup: ec2.SecurityGroup.fromSecurityGroupId(stack, 'SG', 'sg-123456789', { - allowAllOutbound: false, - }), - }); - - // WHEN - fn.connections.allowToAnyIpv4(ec2.Port.tcp(443)); - - // THEN - expect(stack).to(haveResource('AWS::EC2::SecurityGroupEgress', { - GroupId: 'sg-123456789', - })); - - test.done(); - }, - - 'with event invoke config'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new lambda.Function(stack, 'fn', { - code: new lambda.InlineCode('foo'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, - onFailure: { - bind: () => ({ destination: 'on-failure-arn' }), - }, - onSuccess: { - bind: () => ({ destination: 'on-success-arn' }), - }, - maxEventAge: cdk.Duration.hours(1), - retryAttempts: 0, - }); - - // THEN - expect(stack).to(haveResource('AWS::Lambda::EventInvokeConfig', { - FunctionName: { - Ref: 'fn5FF616E3', - }, - Qualifier: '$LATEST', - DestinationConfig: { - OnFailure: { - Destination: 'on-failure-arn', - }, - OnSuccess: { - Destination: 'on-success-arn', - }, - }, - MaximumEventAgeInSeconds: 3600, - MaximumRetryAttempts: 0, - })); - - test.done(); - }, - - 'throws when calling configureAsyncInvoke on already configured function'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const fn = new lambda.Function(stack, 'fn', { - code: new lambda.InlineCode('foo'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, - maxEventAge: cdk.Duration.hours(1), - }); - - // THEN - test.throws(() => fn.configureAsyncInvoke({ retryAttempts: 0 }), /An EventInvokeConfig has already been configured/); - - test.done(); - }, - - 'event invoke config on imported lambda'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const fn = lambda.Function.fromFunctionAttributes(stack, 'fn', { - functionArn: 'arn:aws:lambda:us-east-1:123456789012:function:my-function', - }); - - // WHEN - fn.configureAsyncInvoke({ - retryAttempts: 1, - }); - - // THEN - expect(stack).to(haveResource('AWS::Lambda::EventInvokeConfig', { - FunctionName: 'my-function', - Qualifier: '$LATEST', - MaximumRetryAttempts: 1, - })); - - test.done(); - }, - - 'add a version with event invoke config'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const fn = new lambda.Function(stack, 'fn', { - code: new lambda.InlineCode('foo'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_10_X, - }); - - // WHEN - fn.addVersion('1', 'sha256', 'desc', undefined, { - retryAttempts: 0, - }); - - // THEN - expect(stack).to(haveResource('AWS::Lambda::EventInvokeConfig', { - FunctionName: { - Ref: 'fn5FF616E3', - }, - Qualifier: { - 'Fn::GetAtt': [ - 'fnVersion197FA813F', - 'Version', - ], - }, - MaximumRetryAttempts: 0, - })); - - test.done(); - }, - - 'check edge compatibility with env vars that can be removed'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const fn = new lambda.Function(stack, 'fn', { - code: new lambda.InlineCode('foo'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_12_X, - }); - fn.addEnvironment('KEY', 'value', { removeInEdge: true }); - - // WHEN - fn._checkEdgeCompatibility(); - - // THEN - expect(stack).to(haveResource('AWS::Lambda::Function', { - Environment: ABSENT, - })); - - test.done(); - }, - - 'check edge compatibility with env vars that cannot be removed'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const fn = new lambda.Function(stack, 'fn', { - code: new lambda.InlineCode('foo'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_12_X, - environment: { - KEY: 'value', - }, - }); - fn.addEnvironment('OTHER_KEY', 'other_value', { removeInEdge: true }); - - // THEN - test.throws(() => fn._checkEdgeCompatibility(), /The function Default\/fn contains environment variables \[KEY\] and is not compatible with Lambda@Edge/); - - test.done(); - }, -}; - -function newTestLambda(scope: constructs.Construct) { - return new lambda.Function(scope, 'MyLambda', { - code: new lambda.InlineCode('foo'), - handler: 'bar', - runtime: lambda.Runtime.PYTHON_2_7, - }); -} diff --git a/packages/@aws-cdk/aws-lambda/test/test.runtime.ts b/packages/@aws-cdk/aws-lambda/test/test.runtime.ts deleted file mode 100644 index e46686669da1d..0000000000000 --- a/packages/@aws-cdk/aws-lambda/test/test.runtime.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { Test, testCase } from 'nodeunit'; -import * as lambda from '../lib'; - -export = testCase({ - 'runtimes are equal for different instances'(test: Test) { - // GIVEN - const runtime1 = new lambda.Runtime('python3.7', lambda.RuntimeFamily.PYTHON, { supportsInlineCode: true }); - const runtime2 = new lambda.Runtime('python3.7', lambda.RuntimeFamily.PYTHON, { supportsInlineCode: true }); - - // WHEN - const result = runtime1.runtimeEquals(runtime2); - - // THEN - test.strictEqual(result, true, 'Runtimes should be equal'); - - test.done(); - }, - 'runtimes are equal for same instance'(test: Test) { - // GIVEN - const runtime = new lambda.Runtime('python3.7', lambda.RuntimeFamily.PYTHON, { supportsInlineCode: true }); - - // WHEN - const result = runtime.runtimeEquals(runtime); - - // THEN - test.strictEqual(result, true, 'Runtimes should be equal'); - - test.done(); - }, - 'unequal when name changes'(test: Test) { - // GIVEN - const runtime1 = new lambda.Runtime('python3.7', lambda.RuntimeFamily.PYTHON, { supportsInlineCode: true }); - const runtime2 = new lambda.Runtime('python3.6', lambda.RuntimeFamily.PYTHON, { supportsInlineCode: true }); - - // WHEN - const result = runtime1.runtimeEquals(runtime2); - - // THEN - test.strictEqual(result, false, 'Runtimes should be unequal when name changes'); - - test.done(); - }, - 'unequal when family changes'(test: Test) { - // GIVEN - const runtime1 = new lambda.Runtime('python3.7', lambda.RuntimeFamily.PYTHON, { supportsInlineCode: true }); - const runtime2 = new lambda.Runtime('python3.7', lambda.RuntimeFamily.JAVA, { supportsInlineCode: true }); - - // WHEN - const result = runtime1.runtimeEquals(runtime2); - - // THEN - test.strictEqual(result, false, 'Runtimes should be unequal when family changes'); - - test.done(); - }, - 'unequal when supportsInlineCode changes'(test: Test) { - // GIVEN - const runtime1 = new lambda.Runtime('python3.7', lambda.RuntimeFamily.PYTHON, { supportsInlineCode: true }); - const runtime2 = new lambda.Runtime('python3.7', lambda.RuntimeFamily.PYTHON, { supportsInlineCode: false }); - - // WHEN - const result = runtime1.runtimeEquals(runtime2); - - // THEN - test.strictEqual(result, false, 'Runtimes should be unequal when supportsInlineCode changes'); - - test.done(); - }, - 'bundlingDockerImage points to AWS SAM build image'(test: Test) { - // GIVEN - const runtime = new lambda.Runtime('my-runtime-name'); - - // THEN - test.equal(runtime.bundlingDockerImage.image, 'amazon/aws-sam-cli-build-image-my-runtime-name'); - - test.done(); - }, - 'overridde to bundlingDockerImage points to the correct image'(test: Test) { - // GIVEN - const runtime = new lambda.Runtime('my-runtime-name', undefined, { - bundlingDockerImage: 'my-docker-image', - }); - - // THEN - test.equal(runtime.bundlingDockerImage.image, 'my-docker-image'); - - test.done(); - }, - 'dotnetcore and go have overridden images'(test: Test) { - test.equal(lambda.Runtime.DOTNET_CORE_3_1.bundlingDockerImage.image, 'lambci/lambda:build-dotnetcore3.1'); - test.equal(lambda.Runtime.DOTNET_CORE_2_1.bundlingDockerImage.image, 'lambci/lambda:build-dotnetcore2.1'); - test.equal(lambda.Runtime.GO_1_X.bundlingDockerImage.image, 'lambci/lambda:build-go1.x'); - test.done(); - }, -}); diff --git a/packages/@aws-cdk/aws-lambda/test/test.vpc-lambda.ts b/packages/@aws-cdk/aws-lambda/test/vpc-lambda.test.ts similarity index 61% rename from packages/@aws-cdk/aws-lambda/test/test.vpc-lambda.ts rename to packages/@aws-cdk/aws-lambda/test/vpc-lambda.test.ts index 1f560f151b01d..8c3dde47306b3 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.vpc-lambda.ts +++ b/packages/@aws-cdk/aws-lambda/test/vpc-lambda.test.ts @@ -1,35 +1,34 @@ -import { expect, haveResource } from '@aws-cdk/assert'; +import '@aws-cdk/assert/jest'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as cdk from '@aws-cdk/core'; -import { ICallbackFunction, Test } from 'nodeunit'; import * as lambda from '../lib'; -export = { - 'lambda in a VPC': classFixture(class Henk { - private readonly app: cdk.App; - private readonly stack: cdk.Stack; - private readonly vpc: ec2.Vpc; - private readonly lambda: lambda.Function; +describe('lambda + vpc', () => { + describe('lambda in vpc', () => { + let app: cdk.App; + let stack: cdk.Stack; + let vpc: ec2.Vpc; + let fn: lambda.Function; - constructor() { + beforeEach(() => { // GIVEN - this.app = new cdk.App(); - this.stack = new cdk.Stack(this.app, 'stack'); - this.vpc = new ec2.Vpc(this.stack, 'VPC'); + app = new cdk.App(); + stack = new cdk.Stack(app, 'stack'); + vpc = new ec2.Vpc(stack, 'VPC'); // WHEN - this.lambda = new lambda.Function(this.stack, 'Lambda', { + fn = new lambda.Function(stack, 'Lambda', { code: new lambda.InlineCode('foo'), handler: 'index.handler', runtime: lambda.Runtime.NODEJS_10_X, - vpc: this.vpc, + vpc: vpc, allowAllOutbound: false, }); - } + }); - public 'has subnet and securitygroup'(test: Test) { + test('has subnet and securitygroup', () => { // THEN - expect(this.stack).to(haveResource('AWS::Lambda::Function', { + expect(stack).toHaveResource('AWS::Lambda::Function', { VpcConfig: { SecurityGroupIds: [ { 'Fn::GetAtt': ['LambdaSecurityGroupE74659A1', 'GroupId'] }, @@ -39,22 +38,20 @@ export = { { Ref: 'VPCPrivateSubnet2SubnetCFCDAA7A' }, ], }, - })); - - test.done(); - } + }); + }); - public 'has securitygroup that is passed in props'(test: Test) { + test('has securitygroup that is passed in props', () => { // WHEN - new lambda.Function(this.stack, 'LambdaWithCustomSG', { + new lambda.Function(stack, 'LambdaWithCustomSG', { code: new lambda.InlineCode('foo'), handler: 'index.handler', runtime: lambda.Runtime.NODEJS_10_X, - vpc: this.vpc, - securityGroup: new ec2.SecurityGroup(this.stack, 'CustomSecurityGroupX', { vpc: this.vpc }), + vpc, + securityGroup: new ec2.SecurityGroup(stack, 'CustomSecurityGroupX', { vpc }), }); // THEN - expect(this.stack).to(haveResource('AWS::Lambda::Function', { + expect(stack).toHaveResource('AWS::Lambda::Function', { VpcConfig: { SecurityGroupIds: [ { 'Fn::GetAtt': ['CustomSecurityGroupX6C7F3A78', 'GroupId'] }, @@ -64,25 +61,23 @@ export = { { Ref: 'VPCPrivateSubnet2SubnetCFCDAA7A' }, ], }, - })); - - test.done(); - } + }); + }); - public 'has all the securitygroups that are passed as a list of SG in props'(test: Test) { + test('has all the securitygroups that are passed as a list of SG in props', () => { // WHEN - new lambda.Function(this.stack, 'LambdaWithCustomSGList', { + new lambda.Function(stack, 'LambdaWithCustomSGList', { code: new lambda.InlineCode('foo'), handler: 'index.handler', runtime: lambda.Runtime.NODEJS_10_X, - vpc: this.vpc, + vpc, securityGroups: [ - new ec2.SecurityGroup(this.stack, 'CustomSecurityGroupA', { vpc: this.vpc }), - new ec2.SecurityGroup(this.stack, 'CustomSecurityGroupB', { vpc: this.vpc }), + new ec2.SecurityGroup(stack, 'CustomSecurityGroupA', { vpc }), + new ec2.SecurityGroup(stack, 'CustomSecurityGroupB', { vpc }), ], }); // THEN - expect(this.stack).to(haveResource('AWS::Lambda::Function', { + expect(stack).toHaveResource('AWS::Lambda::Function', { VpcConfig: { SecurityGroupIds: [ { 'Fn::GetAtt': ['CustomSecurityGroupA267F62DE', 'GroupId'] }, @@ -93,72 +88,66 @@ export = { { Ref: 'VPCPrivateSubnet2SubnetCFCDAA7A' }, ], }, - })); - - test.done(); - } + }); + }); - public 'fails if both of securityGroup and securityGroups are passed in props at once'(test: Test) { + test('fails if both of securityGroup and securityGroups are passed in props at once', () => { // THEN - test.throws(() => { - new lambda.Function(this.stack, 'LambdaWithWrongProps', { + expect(() => { + new lambda.Function(stack, 'LambdaWithWrongProps', { code: new lambda.InlineCode('foo'), handler: 'index.handler', runtime: lambda.Runtime.NODEJS_10_X, - vpc: this.vpc, - securityGroup: new ec2.SecurityGroup(this.stack, 'CustomSecurityGroupB', { vpc: this.vpc }), + vpc, + securityGroup: new ec2.SecurityGroup(stack, 'CustomSecurityGroupB', { vpc }), securityGroups: [ - new ec2.SecurityGroup(this.stack, 'CustomSecurityGroupC', { vpc: this.vpc }), - new ec2.SecurityGroup(this.stack, 'CustomSecurityGroupD', { vpc: this.vpc }), + new ec2.SecurityGroup(stack, 'CustomSecurityGroupC', { vpc }), + new ec2.SecurityGroup(stack, 'CustomSecurityGroupD', { vpc }), ], }); - }, /Only one of the function props, securityGroup or securityGroups, is allowed/); - - test.done(); - } + }).toThrow(/Only one of the function props, securityGroup or securityGroups, is allowed/); + }); - public 'participates in Connections objects'(test: Test) { + test('participates in Connections objects', () => { // GIVEN - const securityGroup = new ec2.SecurityGroup(this.stack, 'SomeSecurityGroup', { vpc: this.vpc }); + const securityGroup = new ec2.SecurityGroup(stack, 'SomeSecurityGroup', { vpc }); const somethingConnectable = new SomethingConnectable(new ec2.Connections({ securityGroups: [securityGroup] })); // WHEN - this.lambda.connections.allowTo(somethingConnectable, ec2.Port.allTcp(), 'Lambda can call connectable'); + fn.connections.allowTo(somethingConnectable, ec2.Port.allTcp(), 'Lambda can call connectable'); // THEN: Lambda can connect to SomeSecurityGroup - expect(this.stack).to(haveResource('AWS::EC2::SecurityGroupEgress', { + expect(stack).toHaveResource('AWS::EC2::SecurityGroupEgress', { GroupId: { 'Fn::GetAtt': ['LambdaSecurityGroupE74659A1', 'GroupId'] }, IpProtocol: 'tcp', Description: 'Lambda can call connectable', DestinationSecurityGroupId: { 'Fn::GetAtt': ['SomeSecurityGroupEF219AD6', 'GroupId'] }, FromPort: 0, ToPort: 65535, - })); + }); // THEN: SomeSecurityGroup accepts connections from Lambda - expect(this.stack).to(haveResource('AWS::EC2::SecurityGroupIngress', { + expect(stack).toHaveResource('AWS::EC2::SecurityGroupIngress', { IpProtocol: 'tcp', Description: 'Lambda can call connectable', FromPort: 0, GroupId: { 'Fn::GetAtt': ['SomeSecurityGroupEF219AD6', 'GroupId'] }, SourceSecurityGroupId: { 'Fn::GetAtt': ['LambdaSecurityGroupE74659A1', 'GroupId'] }, ToPort: 65535, - })); - - test.done(); - } + }); + }); - public 'can still make Connections after export/import'(test: Test) { + test('can still make Connections after export/import', () => { // GIVEN - const stack2 = new cdk.Stack(this.app, 'stack2'); - const securityGroup = new ec2.SecurityGroup(stack2, 'SomeSecurityGroup', { vpc: this.vpc }); + const stack2 = new cdk.Stack(app, 'stack2'); + const securityGroup = new ec2.SecurityGroup(stack2, 'SomeSecurityGroup', { vpc }); const somethingConnectable = new SomethingConnectable(new ec2.Connections({ securityGroups: [securityGroup] })); // WHEN - somethingConnectable.connections.allowFrom(this.lambda.connections, ec2.Port.allTcp(), 'Lambda can call connectable'); + somethingConnectable.connections.allowFrom(fn.connections, ec2.Port.allTcp(), 'Lambda can call connectable'); // THEN: SomeSecurityGroup accepts connections from Lambda - expect(stack2).to(haveResource('AWS::EC2::SecurityGroupEgress', { + expect(stack2).toHaveResource('AWS::EC2::SecurityGroupEgress', { GroupId: { 'Fn::ImportValue': 'stack:ExportsOutputFnGetAttLambdaSecurityGroupE74659A1GroupId8F3EC6F1', }, @@ -172,10 +161,10 @@ export = { }, FromPort: 0, ToPort: 65535, - })); + }); // THEN: Lambda can connect to SomeSecurityGroup - expect(stack2).to(haveResource('AWS::EC2::SecurityGroupIngress', { + expect(stack2).toHaveResource('AWS::EC2::SecurityGroupIngress', { IpProtocol: 'tcp', Description: 'Lambda can call connectable', FromPort: 0, @@ -189,13 +178,11 @@ export = { 'Fn::ImportValue': 'stack:ExportsOutputFnGetAttLambdaSecurityGroupE74659A1GroupId8F3EC6F1', }, ToPort: 65535, - })); - - test.done(); - } - }), + }); + }); + }); - 'lambda without VPC throws Error upon accessing connections'(test: Test) { + test('lambda without VPC throws Error upon accessing connections', () => { // GIVEN const stack = new cdk.Stack(); const lambdaFn = new lambda.Function(stack, 'Lambda', { @@ -205,14 +192,12 @@ export = { }); // WHEN - test.throws(() => { + expect(() => { lambdaFn.connections.allowToAnyIpv4(ec2.Port.allTcp(), 'Reach for the world Lambda!'); - }); - - test.done(); - }, + }).toThrow(); + }); - 'can pick public subnet for Lambda'(test: Test) { + test('can pick public subnet for Lambda', () => { // GIVEN const stack = new cdk.Stack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -228,7 +213,7 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::Lambda::Function', { + expect(stack).toHaveResource('AWS::Lambda::Function', { VpcConfig: { SecurityGroupIds: [ { 'Fn::GetAtt': ['PublicLambdaSecurityGroup61D896FD', 'GroupId'] }, @@ -238,11 +223,10 @@ export = { { Ref: 'VPCPublicSubnet2Subnet74179F39' }, ], }, - })); - test.done(); - }, + }); + }); - 'can pick private subnet for Lambda'(test: Test) { + test('can pick private subnet for Lambda', () => { // GIVEN const stack = new cdk.Stack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -258,7 +242,7 @@ export = { // THEN - expect(stack).to(haveResource('AWS::Lambda::Function', { + expect(stack).toHaveResource('AWS::Lambda::Function', { VpcConfig: { SecurityGroupIds: [ { 'Fn::GetAtt': ['PrivateLambdaSecurityGroupF53C8342', 'GroupId'] }, @@ -268,11 +252,10 @@ export = { { Ref: 'VPCPrivateSubnet2SubnetCFCDAA7A' }, ], }, - })); - test.done(); - }, + }); + }); - 'can pick isolated subnet for Lambda'(test: Test) { + test('can pick isolated subnet for Lambda', () => { // GIVEN const stack = new cdk.Stack(); const vpc = new ec2.Vpc(stack, 'VPC', { @@ -295,7 +278,7 @@ export = { // THEN - expect(stack).to(haveResource('AWS::Lambda::Function', { + expect(stack).toHaveResource('AWS::Lambda::Function', { VpcConfig: { SecurityGroupIds: [ { 'Fn::GetAtt': ['IsolatedLambdaSecurityGroupCE25B6A9', 'GroupId'] }, @@ -305,11 +288,10 @@ export = { { Ref: 'VPCIsolatedSubnet2Subnet4B1C8CAA' }, ], }, - })); - test.done(); - }, + }); + }); - 'picking public subnet type is not allowed if not overriding allowPublicSubnet'(test: Test) { + test('picking public subnet type is not allowed if not overriding allowPublicSubnet', () => { // GIVEN const stack = new cdk.Stack(); const vpc = new ec2.Vpc(stack, 'VPC', { @@ -330,7 +312,7 @@ export = { }); // WHEN - test.throws(() => { + expect(() => { new lambda.Function(stack, 'PublicLambda', { code: new lambda.InlineCode('foo'), handler: 'index.handler', @@ -338,41 +320,9 @@ export = { vpc, vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC }, }); - }, /Lambda Functions in a public subnet/); - test.done(); - }, -}; - -/** - * Use a class as test fixture - * - * setUp() will be mapped to the (synchronous) constructor. tearDown(cb) will be called if available. - */ -function classFixture(klass: any) { - let fixture: any; - - const ret: any = { - setUp(cb: ICallbackFunction) { - fixture = new klass(); - cb(); - }, - - tearDown(cb: ICallbackFunction) { - if (fixture.tearDown) { - fixture.tearDown(cb); - } else { - cb(); - } - }, - }; - - const testNames = Reflect.ownKeys(klass.prototype).filter(m => m !== 'tearDown' && m !== 'constructor'); - for (const testName of testNames) { - ret[testName] = (test: Test) => fixture[testName](test); - } - - return ret; -} + }).toThrow(/Lambda Functions in a public subnet/); + }); +}); class SomethingConnectable implements ec2.IConnectable { constructor(public readonly connections: ec2.Connections) { diff --git a/packages/@aws-cdk/aws-logs/package.json b/packages/@aws-cdk/aws-logs/package.json index 43f2520c4280b..d92212dd10a68 100644 --- a/packages/@aws-cdk/aws-logs/package.json +++ b/packages/@aws-cdk/aws-logs/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::Logs", diff --git a/packages/@aws-cdk/aws-macie/package.json b/packages/@aws-cdk/aws-macie/package.json index 88f4023ea790e..31cadb759a266 100644 --- a/packages/@aws-cdk/aws-macie/package.json +++ b/packages/@aws-cdk/aws-macie/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::Macie", diff --git a/packages/@aws-cdk/aws-managedblockchain/package.json b/packages/@aws-cdk/aws-managedblockchain/package.json index 11963c04905d8..5172350e42045 100644 --- a/packages/@aws-cdk/aws-managedblockchain/package.json +++ b/packages/@aws-cdk/aws-managedblockchain/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test": "npm run build && npm test", "build+test+package": "npm run build+test && npm run package", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::ManagedBlockchain", diff --git a/packages/@aws-cdk/aws-mediaconvert/package.json b/packages/@aws-cdk/aws-mediaconvert/package.json index 90371cff4644f..9b3653dce2e4c 100644 --- a/packages/@aws-cdk/aws-mediaconvert/package.json +++ b/packages/@aws-cdk/aws-mediaconvert/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "compat": "cdk-compat", "build+test": "npm run build && npm test", - "build+test+package": "npm run build+test && npm run package" + "build+test+package": "npm run build+test && npm run package", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::MediaConvert", diff --git a/packages/@aws-cdk/aws-medialive/package.json b/packages/@aws-cdk/aws-medialive/package.json index ce03aa8f8559d..d6039025f23d4 100644 --- a/packages/@aws-cdk/aws-medialive/package.json +++ b/packages/@aws-cdk/aws-medialive/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test": "npm run build && npm test", "build+test+package": "npm run build+test && npm run package", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::MediaLive", diff --git a/packages/@aws-cdk/aws-mediastore/package.json b/packages/@aws-cdk/aws-mediastore/package.json index 1d0e9516ac62f..5beb69fd781e2 100644 --- a/packages/@aws-cdk/aws-mediastore/package.json +++ b/packages/@aws-cdk/aws-mediastore/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test": "npm run build && npm test", "build+test+package": "npm run build+test && npm run package", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::MediaStore", diff --git a/packages/@aws-cdk/aws-msk/package.json b/packages/@aws-cdk/aws-msk/package.json index c2b82ed9b62d0..d3304bd2d3d99 100644 --- a/packages/@aws-cdk/aws-msk/package.json +++ b/packages/@aws-cdk/aws-msk/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test": "npm run build && npm test", "build+test+package": "npm run build+test && npm run package", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::MSK", diff --git a/packages/@aws-cdk/aws-neptune/package.json b/packages/@aws-cdk/aws-neptune/package.json index 4d99679cc9705..e5acaee45a5a0 100644 --- a/packages/@aws-cdk/aws-neptune/package.json +++ b/packages/@aws-cdk/aws-neptune/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::Neptune", diff --git a/packages/@aws-cdk/aws-networkmanager/package.json b/packages/@aws-cdk/aws-networkmanager/package.json index 472734536bacb..c37cae4a92c20 100644 --- a/packages/@aws-cdk/aws-networkmanager/package.json +++ b/packages/@aws-cdk/aws-networkmanager/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::NetworkManager", diff --git a/packages/@aws-cdk/aws-opsworks/package.json b/packages/@aws-cdk/aws-opsworks/package.json index b33783b40cb45..34dece81bd77f 100644 --- a/packages/@aws-cdk/aws-opsworks/package.json +++ b/packages/@aws-cdk/aws-opsworks/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::OpsWorks", diff --git a/packages/@aws-cdk/aws-opsworkscm/package.json b/packages/@aws-cdk/aws-opsworkscm/package.json index 107aa2d9a4f47..a43d46ae04d3f 100644 --- a/packages/@aws-cdk/aws-opsworkscm/package.json +++ b/packages/@aws-cdk/aws-opsworkscm/package.json @@ -50,7 +50,8 @@ "awslint": "cdk-awslint", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::OpsWorksCM", diff --git a/packages/@aws-cdk/aws-pinpoint/package.json b/packages/@aws-cdk/aws-pinpoint/package.json index fd660c7d8e04c..f4c5c8a97c063 100644 --- a/packages/@aws-cdk/aws-pinpoint/package.json +++ b/packages/@aws-cdk/aws-pinpoint/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test": "npm run build && npm test", "build+test+package": "npm run build+test && npm run package", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::Pinpoint", diff --git a/packages/@aws-cdk/aws-pinpointemail/package.json b/packages/@aws-cdk/aws-pinpointemail/package.json index ec43537f13f82..70add6d8405eb 100644 --- a/packages/@aws-cdk/aws-pinpointemail/package.json +++ b/packages/@aws-cdk/aws-pinpointemail/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test": "npm run build && npm test", "build+test+package": "npm run build+test && npm run package", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::PinpointEmail", diff --git a/packages/@aws-cdk/aws-qldb/package.json b/packages/@aws-cdk/aws-qldb/package.json index 158598e00ac11..2c12734c3bf7a 100644 --- a/packages/@aws-cdk/aws-qldb/package.json +++ b/packages/@aws-cdk/aws-qldb/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test": "npm run build && npm test", "build+test+package": "npm run build+test && npm run package", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::QLDB", diff --git a/packages/@aws-cdk/aws-ram/package.json b/packages/@aws-cdk/aws-ram/package.json index aee469902f46c..a38b60a12404b 100644 --- a/packages/@aws-cdk/aws-ram/package.json +++ b/packages/@aws-cdk/aws-ram/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::RAM", diff --git a/packages/@aws-cdk/aws-rds/package.json b/packages/@aws-cdk/aws-rds/package.json index 3169954e99ffa..5cac89b6e38f4 100644 --- a/packages/@aws-cdk/aws-rds/package.json +++ b/packages/@aws-cdk/aws-rds/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::RDS", diff --git a/packages/@aws-cdk/aws-redshift/package.json b/packages/@aws-cdk/aws-redshift/package.json index 77deed8ac0c8e..73619e02a08b6 100644 --- a/packages/@aws-cdk/aws-redshift/package.json +++ b/packages/@aws-cdk/aws-redshift/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::Redshift", diff --git a/packages/@aws-cdk/aws-resourcegroups/package.json b/packages/@aws-cdk/aws-resourcegroups/package.json index bc9d79393aeaf..1e0965bc9bbd3 100644 --- a/packages/@aws-cdk/aws-resourcegroups/package.json +++ b/packages/@aws-cdk/aws-resourcegroups/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::ResourceGroups", diff --git a/packages/@aws-cdk/aws-robomaker/package.json b/packages/@aws-cdk/aws-robomaker/package.json index 5baeb85f6582e..f0479c1ad5f73 100644 --- a/packages/@aws-cdk/aws-robomaker/package.json +++ b/packages/@aws-cdk/aws-robomaker/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::RoboMaker", diff --git a/packages/@aws-cdk/aws-route53/package.json b/packages/@aws-cdk/aws-route53/package.json index 4aa7c9084b782..43d57731f2c9e 100644 --- a/packages/@aws-cdk/aws-route53/package.json +++ b/packages/@aws-cdk/aws-route53/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::Route53", diff --git a/packages/@aws-cdk/aws-route53resolver/package.json b/packages/@aws-cdk/aws-route53resolver/package.json index e0003ac9de3fc..f191269f0f42b 100644 --- a/packages/@aws-cdk/aws-route53resolver/package.json +++ b/packages/@aws-cdk/aws-route53resolver/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::Route53Resolver", diff --git a/packages/@aws-cdk/aws-s3-deployment/package.json b/packages/@aws-cdk/aws-s3-deployment/package.json index 429991c20e751..7394ffb84b4d8 100644 --- a/packages/@aws-cdk/aws-s3-deployment/package.json +++ b/packages/@aws-cdk/aws-s3-deployment/package.json @@ -48,12 +48,10 @@ "awslint": "cdk-awslint", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "/bin/bash lambda/build.sh" }, "cdk-build": { - "pre": [ - "/bin/bash lambda/build.sh" - ], "test": [ "/bin/bash lambda/test.sh" ], diff --git a/packages/@aws-cdk/aws-s3/package.json b/packages/@aws-cdk/aws-s3/package.json index fec39ed3100c9..f0b983a92e255 100644 --- a/packages/@aws-cdk/aws-s3/package.json +++ b/packages/@aws-cdk/aws-s3/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::S3", diff --git a/packages/@aws-cdk/aws-sagemaker/package.json b/packages/@aws-cdk/aws-sagemaker/package.json index efca2898af564..5919c20b0be5e 100644 --- a/packages/@aws-cdk/aws-sagemaker/package.json +++ b/packages/@aws-cdk/aws-sagemaker/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::SageMaker", diff --git a/packages/@aws-cdk/aws-sam/package.json b/packages/@aws-cdk/aws-sam/package.json index e5a2c9f67d57a..d9178069d5f23 100644 --- a/packages/@aws-cdk/aws-sam/package.json +++ b/packages/@aws-cdk/aws-sam/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::Serverless", diff --git a/packages/@aws-cdk/aws-sdb/package.json b/packages/@aws-cdk/aws-sdb/package.json index da9bc2cd9ab13..b6b5c9328fb1e 100644 --- a/packages/@aws-cdk/aws-sdb/package.json +++ b/packages/@aws-cdk/aws-sdb/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::SDB", diff --git a/packages/@aws-cdk/aws-secretsmanager/package.json b/packages/@aws-cdk/aws-secretsmanager/package.json index 85ecb114c647d..430f2b4a62980 100644 --- a/packages/@aws-cdk/aws-secretsmanager/package.json +++ b/packages/@aws-cdk/aws-secretsmanager/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::SecretsManager", diff --git a/packages/@aws-cdk/aws-securityhub/package.json b/packages/@aws-cdk/aws-securityhub/package.json index cd4ff6bbc426d..a8cb19e6bf497 100644 --- a/packages/@aws-cdk/aws-securityhub/package.json +++ b/packages/@aws-cdk/aws-securityhub/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test": "npm run build && npm test", "build+test+package": "npm run build+test && npm run package", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::SecurityHub", diff --git a/packages/@aws-cdk/aws-servicecatalog/package.json b/packages/@aws-cdk/aws-servicecatalog/package.json index 1e93e64585ef2..e9689df96ec12 100644 --- a/packages/@aws-cdk/aws-servicecatalog/package.json +++ b/packages/@aws-cdk/aws-servicecatalog/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::ServiceCatalog", diff --git a/packages/@aws-cdk/aws-servicediscovery/package.json b/packages/@aws-cdk/aws-servicediscovery/package.json index 11be7c8fc3b3a..ba3c5463d4dba 100644 --- a/packages/@aws-cdk/aws-servicediscovery/package.json +++ b/packages/@aws-cdk/aws-servicediscovery/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::ServiceDiscovery", diff --git a/packages/@aws-cdk/aws-ses/package.json b/packages/@aws-cdk/aws-ses/package.json index 626397c3936eb..d20ba13ca5910 100644 --- a/packages/@aws-cdk/aws-ses/package.json +++ b/packages/@aws-cdk/aws-ses/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::SES", diff --git a/packages/@aws-cdk/aws-sns/package.json b/packages/@aws-cdk/aws-sns/package.json index b5baef7a3135a..c570761f59017 100644 --- a/packages/@aws-cdk/aws-sns/package.json +++ b/packages/@aws-cdk/aws-sns/package.json @@ -52,7 +52,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::SNS", diff --git a/packages/@aws-cdk/aws-sqs/package.json b/packages/@aws-cdk/aws-sqs/package.json index 68b8431b6a80a..4cc3cf6224ee5 100644 --- a/packages/@aws-cdk/aws-sqs/package.json +++ b/packages/@aws-cdk/aws-sqs/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::SQS", diff --git a/packages/@aws-cdk/aws-ssm/package.json b/packages/@aws-cdk/aws-ssm/package.json index 3d06a2eedbf03..986c258b57d5d 100644 --- a/packages/@aws-cdk/aws-ssm/package.json +++ b/packages/@aws-cdk/aws-ssm/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::SSM", diff --git a/packages/@aws-cdk/aws-sso/package.json b/packages/@aws-cdk/aws-sso/package.json index c8960a4309e39..cc6fa80e8a042 100644 --- a/packages/@aws-cdk/aws-sso/package.json +++ b/packages/@aws-cdk/aws-sso/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::SSO", diff --git a/packages/@aws-cdk/aws-stepfunctions/package.json b/packages/@aws-cdk/aws-stepfunctions/package.json index c37edc6fca586..832fe6c9df5e0 100644 --- a/packages/@aws-cdk/aws-stepfunctions/package.json +++ b/packages/@aws-cdk/aws-stepfunctions/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::StepFunctions", diff --git a/packages/@aws-cdk/aws-synthetics/package.json b/packages/@aws-cdk/aws-synthetics/package.json index 3c53ad9c2bfa8..bcd59674419eb 100644 --- a/packages/@aws-cdk/aws-synthetics/package.json +++ b/packages/@aws-cdk/aws-synthetics/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::Synthetics", diff --git a/packages/@aws-cdk/aws-timestream/package.json b/packages/@aws-cdk/aws-timestream/package.json index fbe0847ca8b9c..57285b6625155 100644 --- a/packages/@aws-cdk/aws-timestream/package.json +++ b/packages/@aws-cdk/aws-timestream/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::Timestream", diff --git a/packages/@aws-cdk/aws-transfer/package.json b/packages/@aws-cdk/aws-transfer/package.json index 2b11c123c59cc..49c4a61f942d4 100644 --- a/packages/@aws-cdk/aws-transfer/package.json +++ b/packages/@aws-cdk/aws-transfer/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "build+test": "npm run build && npm test", "build+test+package": "npm run build+test && npm run package", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::Transfer", diff --git a/packages/@aws-cdk/aws-waf/package.json b/packages/@aws-cdk/aws-waf/package.json index 03101648417b6..8bda60d5f2ef2 100644 --- a/packages/@aws-cdk/aws-waf/package.json +++ b/packages/@aws-cdk/aws-waf/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::WAF", diff --git a/packages/@aws-cdk/aws-wafregional/package.json b/packages/@aws-cdk/aws-wafregional/package.json index 3f1b6333fcfc2..fbd5fad56a5bd 100644 --- a/packages/@aws-cdk/aws-wafregional/package.json +++ b/packages/@aws-cdk/aws-wafregional/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::WAFRegional", diff --git a/packages/@aws-cdk/aws-wafv2/package.json b/packages/@aws-cdk/aws-wafv2/package.json index 3469018e07c3b..fa2e95eeeb743 100644 --- a/packages/@aws-cdk/aws-wafv2/package.json +++ b/packages/@aws-cdk/aws-wafv2/package.json @@ -50,7 +50,8 @@ "cfn2ts": "cfn2ts", "compat": "cdk-compat", "build+test": "npm run build && npm test", - "build+test+package": "npm run build+test && npm run package" + "build+test+package": "npm run build+test && npm run package", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::WAFv2", diff --git a/packages/@aws-cdk/aws-workspaces/package.json b/packages/@aws-cdk/aws-workspaces/package.json index 54198f3012d6f..500617ab61464 100644 --- a/packages/@aws-cdk/aws-workspaces/package.json +++ b/packages/@aws-cdk/aws-workspaces/package.json @@ -49,7 +49,8 @@ "cfn2ts": "cfn2ts", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::WorkSpaces", diff --git a/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts b/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts index 8b0e00fa15582..2bf2b707b6a09 100644 --- a/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts +++ b/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts @@ -152,6 +152,7 @@ async function main() { 'build+test+package': 'npm run build+test && npm run package', 'build+test': 'npm run build && npm test', compat: 'cdk-compat', + gen: 'cfn2ts', }, 'cdk-build': { cloudformation: namespace, diff --git a/packages/@aws-cdk/core/package.json b/packages/@aws-cdk/core/package.json index 9731f371c38d6..b5384adedcc12 100644 --- a/packages/@aws-cdk/core/package.json +++ b/packages/@aws-cdk/core/package.json @@ -134,14 +134,17 @@ "awslint": "cdk-awslint", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cfn2ts" }, "cdk-build": { "cloudformation": "AWS::CloudFormation", "cfn2ts-core-import": ".", "jest": true, "pre": [ - "rm -rf test/fs/fixtures && cd test/fs && tar -xzf fixtures.tar.gz" + "rm -rf test/fs/fixtures", + "cd test/fs", + "tar -xzf fixtures.tar.gz" ], "env": { "AWSLINT_BASE_CONSTRUCT": "true" diff --git a/packages/@aws-cdk/custom-resources/package.json b/packages/@aws-cdk/custom-resources/package.json index 1f704be83dd4f..280f69bc77ade 100644 --- a/packages/@aws-cdk/custom-resources/package.json +++ b/packages/@aws-cdk/custom-resources/package.json @@ -48,12 +48,10 @@ "awslint": "cdk-awslint", "build+test+package": "npm run build+test && npm run package", "build+test": "npm run build && npm test", - "compat": "cdk-compat" + "compat": "cdk-compat", + "gen": "cp -f $(node -p 'require.resolve(\"aws-sdk/apis/metadata.json\")') lib/aws-custom-resource/sdk-api-metadata.json && rm -rf test/aws-custom-resource/cdk.out" }, "cdk-build": { - "pre": [ - "cp -f $(node -p 'require.resolve(\"aws-sdk/apis/metadata.json\")') lib/aws-custom-resource/sdk-api-metadata.json && rm -rf test/aws-custom-resource/cdk.out" - ], "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true diff --git a/packages/@aws-cdk/pipelines/README.md b/packages/@aws-cdk/pipelines/README.md index d567675f1ca2f..b575fcd00732d 100644 --- a/packages/@aws-cdk/pipelines/README.md +++ b/packages/@aws-cdk/pipelines/README.md @@ -149,6 +149,7 @@ class MyPipelineStack extends Stack { // Replace these with your actual GitHub project name owner: 'OWNER', repo: 'REPO', + branch: 'main', // default: 'master' }), synthAction: SimpleSynthAction.standardNpmSynth({ @@ -543,6 +544,24 @@ class MyPipelineStack extends Stack { } ``` +### Developing the pipeline + +The self-mutation feature of the `CdkPipeline` might at times get in the way +of the pipeline development workflow. Each change to the pipeline must be pushed +to git, otherwise, after the pipeline was updated using `cdk deploy`, it will +automatically revert to the state found in git. + +To make the development more convenient, the self-mutation feature can be turned +off temporarily, by passing `selfMutating: false` property, example: + +```ts +const pipeline = new CdkPipeline(this, 'Pipeline', { + selfMutating: false, + ... +}); +``` + + ## CDK Environment Bootstrapping An *environment* is an *(account, region)* pair where you want to deploy a diff --git a/packages/@aws-cdk/pipelines/lib/pipeline.ts b/packages/@aws-cdk/pipelines/lib/pipeline.ts index bc9342af543c4..cf9445681d200 100644 --- a/packages/@aws-cdk/pipelines/lib/pipeline.ts +++ b/packages/@aws-cdk/pipelines/lib/pipeline.ts @@ -105,6 +105,20 @@ export interface CdkPipelineProps { * @default - All private subnets. */ readonly subnetSelection?: ec2.SubnetSelection; + + /** + * Whether the pipeline will update itself + * + * This needs to be set to `true` to allow the pipeline to reconfigure + * itself when assets or stages are being added to it, and `true` is the + * recommended setting. + * + * You can temporarily set this to `false` while you are iterating + * on the pipeline itself and prefer to deploy changes using `cdk deploy`. + * + * @default true + */ + readonly selfMutating?: boolean; } /** @@ -178,15 +192,17 @@ export class CdkPipeline extends CoreConstruct { }); } - this._pipeline.addStage({ - stageName: 'UpdatePipeline', - actions: [new UpdatePipelineAction(this, 'UpdatePipeline', { - cloudAssemblyInput: this._cloudAssemblyArtifact, - pipelineStackName: pipelineStack.stackName, - cdkCliVersion: props.cdkCliVersion, - projectName: maybeSuffix(props.pipelineName, '-selfupdate'), - })], - }); + if (props.selfMutating ?? true) { + this._pipeline.addStage({ + stageName: 'UpdatePipeline', + actions: [new UpdatePipelineAction(this, 'UpdatePipeline', { + cloudAssemblyInput: this._cloudAssemblyArtifact, + pipelineStackName: pipelineStack.stackName, + cdkCliVersion: props.cdkCliVersion, + projectName: maybeSuffix(props.pipelineName, '-selfupdate'), + })], + }); + } this._assets = new AssetPublishing(this, 'Assets', { cloudAssemblyInput: this._cloudAssemblyArtifact, diff --git a/packages/@aws-cdk/pipelines/test/pipeline.test.ts b/packages/@aws-cdk/pipelines/test/pipeline.test.ts index 023f4bdcf575d..003aacf021d47 100644 --- a/packages/@aws-cdk/pipelines/test/pipeline.test.ts +++ b/packages/@aws-cdk/pipelines/test/pipeline.test.ts @@ -1,6 +1,15 @@ import * as fs from 'fs'; import * as path from 'path'; -import { anything, arrayWith, Capture, deepObjectLike, encodedJson, objectLike, stringLike } from '@aws-cdk/assert'; +import { + anything, + arrayWith, + Capture, + deepObjectLike, + encodedJson, + notMatching, + objectLike, + stringLike, +} from '@aws-cdk/assert'; import '@aws-cdk/assert/jest'; import * as cp from '@aws-cdk/aws-codepipeline'; import * as cpa from '@aws-cdk/aws-codepipeline-actions'; @@ -332,6 +341,23 @@ test('selfmutation stage correctly identifies nested assembly of pipeline stack' }); }); +test('selfmutation feature can be turned off', () => { + const stack = new Stack(); + const cloudAssemblyArtifact = new cp.Artifact(); + // WHEN + new TestGitHubNpmPipeline(stack, 'Cdk', { + cloudAssemblyArtifact, + selfMutating: false, + }); + // THEN + expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Stages: notMatching(arrayWith({ + Name: 'UpdatePipeline', + Actions: anything(), + })), + }); +}); + test('overridden stack names are respected', () => { // WHEN pipeline.addApplicationStage(new OneStackAppWithCustomName(app, 'App1')); diff --git a/packages/@aws-cdk/region-info/package.json b/packages/@aws-cdk/region-info/package.json index 5ea296f02297d..433bd60aa6a17 100644 --- a/packages/@aws-cdk/region-info/package.json +++ b/packages/@aws-cdk/region-info/package.json @@ -33,9 +33,6 @@ "projectReferences": true }, "cdk-build": { - "pre": [ - "npm run gen" - ], "jest": true }, "scripts": { diff --git a/packages/@monocdk-experiment/assert/package.json b/packages/@monocdk-experiment/assert/package.json index f5dc4ddfe584f..063ac8be41c60 100644 --- a/packages/@monocdk-experiment/assert/package.json +++ b/packages/@monocdk-experiment/assert/package.json @@ -17,7 +17,7 @@ "cdk-build": { "jest": true, "pre": [ - "./clone.sh" + "./clone.sh" ], "eslint": { "disable": true diff --git a/packages/aws-cdk-lib/package.json b/packages/aws-cdk-lib/package.json index ed74431300d64..833751e24d76e 100644 --- a/packages/aws-cdk-lib/package.json +++ b/packages/aws-cdk-lib/package.json @@ -32,10 +32,7 @@ "cdk-build": { "eslint": { "disable": true - }, - "pre": [ - "npm run gen" - ] + } }, "pkglint": { "exclude": [ @@ -261,7 +258,6 @@ "@types/node": "^10.17.35", "cdk-build-tools": "0.0.0", "constructs": "^3.0.4", - "cdk8s": "^0.30.0", "fs-extra": "^9.0.1", "pkglint": "0.0.0", "ts-node": "^9.0.0", @@ -269,8 +265,7 @@ "ubergen": "0.0.0" }, "peerDependencies": { - "constructs": "^3.0.4", - "cdk8s": "^0.30.0" + "constructs": "^3.0.4" }, "homepage": "https://github.com/aws/aws-cdk", "engines": { diff --git a/packages/aws-cdk/lib/api/aws-auth/account-cache.ts b/packages/aws-cdk/lib/api/aws-auth/account-cache.ts index 75082b9953966..30ac1704ccc36 100644 --- a/packages/aws-cdk/lib/api/aws-auth/account-cache.ts +++ b/packages/aws-cdk/lib/api/aws-auth/account-cache.ts @@ -83,6 +83,9 @@ export class AccountAccessKeyCache { // File doesn't exist or is not readable. This is a cache, // pretend we successfully loaded an empty map. if (e.code === 'ENOENT' || e.code === 'EACCES') { return {}; } + // File is not JSON, could be corrupted because of concurrent writes. + // Again, an empty cache is fine. + if (e instanceof SyntaxError) { return {}; } throw e; } } diff --git a/packages/aws-cdk/lib/commands/context.ts b/packages/aws-cdk/lib/commands/context.ts index cd5309bae7360..e4ed02a8b4212 100644 --- a/packages/aws-cdk/lib/commands/context.ts +++ b/packages/aws-cdk/lib/commands/context.ts @@ -28,8 +28,6 @@ export function handler(args: yargs.Arguments) { export async function realHandler(options: CommandOptions): Promise { const { configuration, args } = options; - const contextValues = configuration.context.all; - if (args.clear) { configuration.context.clear(); await configuration.saveContext(); @@ -40,9 +38,10 @@ export async function realHandler(options: CommandOptions): Promise { } else { // List -- support '--json' flag if (args.json) { + const contextValues = configuration.context.all; process.stdout.write(JSON.stringify(contextValues, undefined, 2)); } else { - listContext(contextValues); + listContext(configuration.context); } } await version.displayVersionMessage(); @@ -50,7 +49,7 @@ export async function realHandler(options: CommandOptions): Promise { return 0; } -function listContext(context: any) { +function listContext(context: Context) { const keys = contextKeys(context); if (keys.length === 0) { @@ -66,7 +65,7 @@ function listContext(context: any) { // Print config by default const data: any[] = [[colors.green('#'), colors.green('Key'), colors.green('Value')]]; for (const [i, key] of keys) { - const jsonWithoutNewlines = JSON.stringify(context[key], undefined, 2).replace(/\s+/g, ' '); + const jsonWithoutNewlines = JSON.stringify(context.all[key], undefined, 2).replace(/\s+/g, ' '); data.push([i, key, jsonWithoutNewlines]); } @@ -94,7 +93,7 @@ function invalidateContext(context: Context, key: string) { } } -function keyByNumber(context: any, n: number) { +function keyByNumber(context: Context, n: number) { for (const [i, key] of contextKeys(context)) { if (n === i) { return key; @@ -107,7 +106,7 @@ function keyByNumber(context: any, n: number) { * Return enumerated keys in a definitive order */ function contextKeys(context: Context): [number, string][] { - const keys = Object.keys(context); + const keys = context.keys; keys.sort(); return enumerate1(keys); } diff --git a/packages/aws-cdk/lib/init-templates/app/java/pom.template.xml b/packages/aws-cdk/lib/init-templates/app/java/pom.template.xml index dcce5ea68a5ef..58067e2745e2d 100644 --- a/packages/aws-cdk/lib/init-templates/app/java/pom.template.xml +++ b/packages/aws-cdk/lib/init-templates/app/java/pom.template.xml @@ -47,7 +47,7 @@ junit junit - 4.13 + 4.13.1 test diff --git a/packages/aws-cdk/lib/init-templates/sample-app/java/pom.template.xml b/packages/aws-cdk/lib/init-templates/sample-app/java/pom.template.xml index 98af8eb52d2ff..a0f32927a3d5f 100644 --- a/packages/aws-cdk/lib/init-templates/sample-app/java/pom.template.xml +++ b/packages/aws-cdk/lib/init-templates/sample-app/java/pom.template.xml @@ -59,7 +59,7 @@ junit junit - 4.13 + 4.13.1 test diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index 030b3d2325504..e02905f1c86ae 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -22,13 +22,11 @@ "integ-cli-regression-latest-release": "test/integ/run-against-dist test/integ/test-cli-regression-against-latest-release.sh", "integ-cli-regression-latest-code": "test/integ/run-against-dist test/integ/test-cli-regression-against-current-code.sh", "integ-cli-no-regression": "test/integ/run-against-repo test/integ/cli/test.sh", - "integ-init": "test/integ/run-against-dist test/integ/init/test-all.sh" + "integ-init": "test/integ/run-against-dist test/integ/init/test-all.sh", + "gen": "./generate.sh" }, "cdk-build": { - "jest": true, - "pre": [ - "./generate.sh" - ] + "jest": true }, "cdk-package": { "shrinkWrap": true @@ -89,7 +87,7 @@ "table": "^6.0.3", "uuid": "^8.3.0", "wrap-ansi": "^7.0.0", - "yargs": "^16.0.3" + "yargs": "^16.1.0" }, "repository": { "url": "https://github.com/aws/aws-cdk.git", diff --git a/packages/aws-cdk/test/account-cache.test.ts b/packages/aws-cdk/test/account-cache.test.ts index f8860046df584..89887cc627d71 100644 --- a/packages/aws-cdk/test/account-cache.test.ts +++ b/packages/aws-cdk/test/account-cache.test.ts @@ -111,3 +111,14 @@ test(`cache is nuked if it exceeds ${AccountAccessKeyCache.MAX_ENTRIES} entries` await nukeCache(cacheDir); } }); + +test('cache pretends to be empty if cache file does not contain JSON', async() => { + const { cacheDir, cacheFile, cache } = await makeCache(); + try { + await fs.writeFile(cacheFile, ''); + + await expect(cache.get('abc')).resolves.toEqual(undefined); + } finally { + await nukeCache(cacheDir); + } +}); diff --git a/packages/aws-cdk/test/commands/context-command.test.ts b/packages/aws-cdk/test/commands/context-command.test.ts index 87389fd1896f6..6a73c8008b52e 100644 --- a/packages/aws-cdk/test/commands/context-command.test.ts +++ b/packages/aws-cdk/test/commands/context-command.test.ts @@ -39,3 +39,26 @@ test('context reset can remove a context key', async () => { baz: 'quux', }); }); + +test('context reset can remove a context key using number', async () => { + // GIVEN + const configuration = new Configuration(); + configuration.context.set('foo', 'bar'); + configuration.context.set('baz', 'quux'); + + expect(configuration.context.all).toEqual({ + foo: 'bar', + baz: 'quux', + }); + + // WHEN + await realHandler({ + configuration, + args: { reset: '1' }, + } as any); + + // THEN + expect(configuration.context.all).toEqual({ + foo: 'bar', + }); +}); diff --git a/packages/awslint/package.json b/packages/awslint/package.json index b7344c170348d..e419d165e53a5 100644 --- a/packages/awslint/package.json +++ b/packages/awslint/package.json @@ -21,7 +21,7 @@ "colors": "^1.4.0", "fs-extra": "^9.0.1", "jsii-reflect": "^1.13.0", - "yargs": "^16.0.3" + "yargs": "^16.1.0" }, "devDependencies": { "@types/fs-extra": "^8.1.1", diff --git a/packages/cdk-assets/package.json b/packages/cdk-assets/package.json index bd25264df1acd..d0a828f251ea5 100644 --- a/packages/cdk-assets/package.json +++ b/packages/cdk-assets/package.json @@ -49,7 +49,7 @@ "archiver": "^5.0.2", "aws-sdk": "^2.739.0", "glob": "^7.1.6", - "yargs": "^16.0.3" + "yargs": "^16.1.0" }, "repository": { "url": "https://github.com/aws/aws-cdk.git", diff --git a/packages/decdk/package.json b/packages/decdk/package.json index 6cda72fc471a9..f87aadce13e5d 100644 --- a/packages/decdk/package.json +++ b/packages/decdk/package.json @@ -192,7 +192,7 @@ "jsii-reflect": "^1.13.0", "jsonschema": "^1.2.10", "yaml": "1.10.0", - "yargs": "^16.0.3" + "yargs": "^16.1.0" }, "devDependencies": { "@types/fs-extra": "^8.1.1", diff --git a/packages/monocdk/CONTRIBUTING.md b/packages/monocdk/CONTRIBUTING.md new file mode 100644 index 0000000000000..5ba861d6f841c --- /dev/null +++ b/packages/monocdk/CONTRIBUTING.md @@ -0,0 +1,8 @@ +## monocdk + +To build `monocdk` outside of the AWS CDK build process, execute: + +``` +$ ./scripts/gen.sh +$ lerna run build --scope monocdk +``` \ No newline at end of file diff --git a/packages/monocdk/package.json b/packages/monocdk/package.json index 16b014db49902..87917ce856928 100644 --- a/packages/monocdk/package.json +++ b/packages/monocdk/package.json @@ -31,10 +31,7 @@ "cdk-build": { "eslint": { "disable": true - }, - "pre": [ - "npm run gen" - ] + } }, "pkglint": { "exclude": [ @@ -260,7 +257,6 @@ "@types/node": "^10.17.35", "cdk-build-tools": "0.0.0", "constructs": "^3.0.4", - "cdk8s": "^0.30.0", "fs-extra": "^9.0.1", "pkglint": "0.0.0", "ts-node": "^9.0.0", @@ -268,8 +264,7 @@ "ubergen": "0.0.0" }, "peerDependencies": { - "constructs": "^3.0.4", - "cdk8s": "^0.30.0" + "constructs": "^3.0.4" }, "homepage": "https://github.com/aws/aws-cdk", "engines": { diff --git a/scripts/gen.sh b/scripts/gen.sh new file mode 100755 index 0000000000000..d3acf1e403904 --- /dev/null +++ b/scripts/gen.sh @@ -0,0 +1,22 @@ +#!/bin/bash +set -euo pipefail + +export PATH=$(npm bin):$PATH +export NODE_OPTIONS="--max-old-space-size=4096 ${NODE_OPTIONS:-}" + +echo "=============================================================================================" +echo "installing..." +yarn install --frozen-lockfile --network-timeout 1000000 + +fail() { + echo "❌ Last command failed. Scroll up to see errors in log (search for '!!!!!!!!')." + exit 1 +} + +echo "=============================================================================================" +echo "building required build tools..." +time lerna run --stream build --scope cfn2ts --scope ubergen --include-dependencies || fail + +echo "=============================================================================================" +echo "executing gen..." +time lerna run --stream gen || fail \ No newline at end of file diff --git a/scripts/merge-forward.sh b/scripts/merge-forward.sh new file mode 100755 index 0000000000000..92d67a85da250 --- /dev/null +++ b/scripts/merge-forward.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# Forward merge 'master' branch into 'v2-main' branch + +set -exo pipefail + +git fetch --all +git checkout -B v2-main origin/v2-main +git merge origin/master --no-edit diff --git a/tools/cdk-build-tools/bin/cdk-build.ts b/tools/cdk-build-tools/bin/cdk-build.ts index 96039a2d5b6ea..d745de50aa2be 100644 --- a/tools/cdk-build-tools/bin/cdk-build.ts +++ b/tools/cdk-build-tools/bin/cdk-build.ts @@ -2,7 +2,7 @@ import * as yargs from 'yargs'; import { compileCurrentPackage } from '../lib/compile'; import { lintCurrentPackage } from '../lib/lint'; import { shell } from '../lib/os'; -import { cdkBuildOptions, currentPackageJson, CompilerOverrides } from '../lib/package-info'; +import { cdkBuildOptions, CompilerOverrides, currentPackageJson, genScript } from '../lib/package-info'; import { Timers } from '../lib/timer'; async function main() { @@ -24,22 +24,24 @@ async function main() { desc: 'Specify a different eslint executable', defaultDescription: 'eslint provided by node dependencies', }) + .option('gen', { + type: 'boolean', + desc: 'execute gen script', + default: true, + }) .argv; const options = cdkBuildOptions(); const env = options.env; if (options.pre) { - await shell(options.pre, { timers, env }); + const commands = options.pre.join(' && '); + await shell([commands], { timers, env }); } - // See if we need to call cfn2ts - if (options.cloudformation) { - if (typeof options.cloudformation === 'string') { - // There can be multiple scopes, ensuring it's always an array. - options.cloudformation = [options.cloudformation]; - } - await shell(['cfn2ts', ...options.cloudformation.map(scope => `--scope=${scope}`)], { timers, env }); + const gen = genScript(); + if (args.gen && gen) { + await shell([gen], { timers, env }); } const overrides: CompilerOverrides = { eslint: args.eslint, jsii: args.jsii, tsc: args.tsc }; diff --git a/tools/cdk-build-tools/lib/package-info.ts b/tools/cdk-build-tools/lib/package-info.ts index cf5b657d9a470..9e12b86b80580 100644 --- a/tools/cdk-build-tools/lib/package-info.ts +++ b/tools/cdk-build-tools/lib/package-info.ts @@ -89,6 +89,14 @@ export function packageCompiler(compilers: CompilerOverrides): string[] { } } +/** + * Return the command defined in scripts.gen if exists + */ +export function genScript(): string | undefined { + return currentPackageJson().scripts?.gen; +} + + export interface CDKBuildOptions { /** * What CloudFormation scope to generate resources for, if any diff --git a/tools/cdk-build-tools/package.json b/tools/cdk-build-tools/package.json index dee0bc8c47031..7e5ea946ea5b3 100644 --- a/tools/cdk-build-tools/package.json +++ b/tools/cdk-build-tools/package.json @@ -56,7 +56,7 @@ "nyc": "^15.1.0", "ts-jest": "^26.4.1", "typescript": "~3.9.7", - "yargs": "^16.0.3", + "yargs": "^16.1.0", "yarn-cling": "0.0.0" }, "keywords": [ diff --git a/tools/cdk-integ-tools/package.json b/tools/cdk-integ-tools/package.json index 7053652ad7dd4..33fbc7e557f79 100644 --- a/tools/cdk-integ-tools/package.json +++ b/tools/cdk-integ-tools/package.json @@ -40,7 +40,7 @@ "@aws-cdk/assert": "0.0.0", "aws-cdk": "0.0.0", "fs-extra": "^9.0.1", - "yargs": "^16.0.3" + "yargs": "^16.1.0" }, "keywords": [ "aws", diff --git a/tools/cfn2ts/package.json b/tools/cfn2ts/package.json index a29fd4f2de6d2..899adf76ae1e5 100644 --- a/tools/cfn2ts/package.json +++ b/tools/cfn2ts/package.json @@ -33,7 +33,7 @@ "codemaker": "^1.13.0", "fast-json-patch": "^3.0.0-1", "fs-extra": "^9.0.1", - "yargs": "^16.0.3" + "yargs": "^16.1.0" }, "devDependencies": { "@types/fs-extra": "^8.1.1", diff --git a/tools/pkglint/lib/rules.ts b/tools/pkglint/lib/rules.ts index f04446df7e4a9..25d59e434169e 100644 --- a/tools/pkglint/lib/rules.ts +++ b/tools/pkglint/lib/rules.ts @@ -1462,4 +1462,4 @@ function toRegExp(str: string): RegExp { function readBannerFile(file: string): string { return fs.readFileSync(path.join(__dirname, 'banners', file), { encoding: 'utf-8' }); -} +} \ No newline at end of file diff --git a/tools/pkglint/package.json b/tools/pkglint/package.json index d83de33dfdd46..b1ac5ff7aec8a 100644 --- a/tools/pkglint/package.json +++ b/tools/pkglint/package.json @@ -48,6 +48,6 @@ "fs-extra": "^9.0.1", "glob": "^7.1.6", "semver": "^7.3.2", - "yargs": "^16.0.3" + "yargs": "^16.1.0" } } diff --git a/tools/pkgtools/package.json b/tools/pkgtools/package.json index 2c910e2bee71e..545966b08e07e 100644 --- a/tools/pkgtools/package.json +++ b/tools/pkgtools/package.json @@ -36,7 +36,7 @@ }, "dependencies": { "fs-extra": "^9.0.1", - "yargs": "^16.0.3" + "yargs": "^16.1.0" }, "keywords": [ "aws", diff --git a/tools/ubergen/bin/ubergen.ts b/tools/ubergen/bin/ubergen.ts index 2500c05377c27..3026eb04c8430 100644 --- a/tools/ubergen/bin/ubergen.ts +++ b/tools/ubergen/bin/ubergen.ts @@ -1,17 +1,21 @@ import * as console from 'console'; +import * as os from 'os'; import * as path from 'path'; import * as process from 'process'; import * as fs from 'fs-extra'; import * as ts from 'typescript'; const LIB_ROOT = path.resolve(process.cwd(), 'lib'); +const ROOT_PATH = findWorkspacePath(); async function main() { + console.log(`🌴 workspace root path is: ${ROOT_PATH}`); const libraries = await findLibrariesToPackage(); const packageJson = await verifyDependencies(libraries); await prepareSourceFiles(libraries, packageJson); } + main().then( () => process.exit(0), (err) => { @@ -54,12 +58,32 @@ interface PackageJson { readonly [key: string]: unknown; } +/** + * Find the workspace root path. Walk up the directory tree until you find lerna.json + */ +function findWorkspacePath(): string { + + return _findRootPath(process.cwd()); + + function _findRootPath(part: string): string { + if (process.cwd() === os.homedir()) { + throw new Error('couldn\'t find a \'lerna.json\' file when walking up the directory tree, are you in a aws-cdk project?'); + } + + if (fs.existsSync(path.resolve(part, 'lerna.json'))) { + return part; + } + + return _findRootPath(path.resolve(part, '..')); + } +} + async function findLibrariesToPackage(): Promise { console.log('🔍 Discovering libraries that need packaging...'); const result = new Array(); + const librariesRoot = path.resolve(ROOT_PATH, 'packages', '@aws-cdk'); - const librariesRoot = path.resolve(process.cwd(), '..', '..', 'packages', '@aws-cdk'); for (const dir of await fs.readdir(librariesRoot)) { const packageJson = await fs.readJson(path.resolve(librariesRoot, dir, 'package.json')); @@ -73,7 +97,6 @@ async function findLibrariesToPackage(): Promise { console.log(`\t⚠️ Skipping (not jsii-enabled): ${packageJson.name}`); continue; } - result.push({ packageJson, root: path.join(librariesRoot, dir), @@ -121,8 +144,7 @@ async function verifyDependencies(libraries: readonly LibraryReference[]): Promi [library.packageJson.name]: library.packageJson.version, }); } - - const workspacePath = path.resolve(process.cwd(), '..', '..', 'package.json'); + const workspacePath = path.resolve(ROOT_PATH, 'package.json'); const workspace = await fs.readJson(workspacePath); let workspaceChanged = false; diff --git a/yarn.lock b/yarn.lock index d6e7b9cf672d1..f91354d5b77cd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3668,11 +3668,6 @@ anymatch@^3.0.3: normalize-path "^3.0.0" picomatch "^2.0.4" -app-root-path@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-2.2.1.tgz#d0df4a682ee408273583d43f6f79e9892624bc9a" - integrity sha512-91IFKeKk7FjfmezPKkwtaRvSpnUc4gDwPAjA1YZ9Gn0q0PPeW+vbeUsZuyDwjI7+QTHhcLen2v25fi/AmhvbJA== - append-transform@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-1.0.0.tgz#046a52ae582a228bd72f58acfbe2967c678759ab" @@ -3940,7 +3935,7 @@ aws-sdk-mock@^5.1.0: sinon "^9.0.1" traverse "^0.6.6" -aws-sdk@^2.596.0, aws-sdk@^2.637.0, aws-sdk@^2.739.0: +aws-sdk@^2.637.0, aws-sdk@^2.739.0: version "2.764.0" resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.764.0.tgz#587bf954645bbcb706c0ce985e7befeb94b15427" integrity sha512-0asgRwAI3WxUyOjlx2fL7pPHEZajFbAVRerE2h0xX649123PwdhIiJ2HM7lWwn/f+mX7IagYjOCn9dIyvCHBVQ== @@ -4671,10 +4666,10 @@ cliui@^6.0.0: strip-ansi "^6.0.0" wrap-ansi "^6.2.0" -cliui@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.1.tgz#a4cb67aad45cd83d8d05128fc9f4d8fbb887e6b3" - integrity sha512-rcvHOWyGyid6I1WjT/3NatKj2kDt9OdSHSXpyLXaMWFbKpGACNW8pRhhdPUq9MWUOdwn8Rz9AVETjF4105rZZQ== +cliui@^7.0.2: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.3.tgz#ef180f26c8d9bff3927ee52428bfec2090427981" + integrity sha512-Gj3QHTkVMPKqwP3f7B4KPkBZRMR9r4rfi5bXFpg1a+Svvj8l7q5CnkBkVQzfxT5DFSsGk2+PascOgL0JYkL2kw== dependencies: string-width "^4.2.0" strip-ansi "^6.0.0" @@ -5916,21 +5911,11 @@ dotenv-expand@^5.1.0: resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0" integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA== -dotenv-json@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/dotenv-json/-/dotenv-json-1.0.0.tgz#fc7f672aafea04bed33818733b9f94662332815c" - integrity sha512-jAssr+6r4nKhKRudQ0HOzMskOFFi9+ubXWwmrSGJFgTvpjyPXCXsCsYbjif6mXp7uxA7xY3/LGaiTQukZzSbOQ== - dotenv@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-7.0.0.tgz#a2be3cd52736673206e8a85fb5210eea29628e7c" integrity sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g== -dotenv@^8.0.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" - integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== - dotgitignore@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/dotgitignore/-/dotgitignore-2.1.0.tgz#a4b15a4e4ef3cf383598aaf1dfa4a04bcc089b7b" @@ -6163,10 +6148,10 @@ es6-promisify@^5.0.0: dependencies: es6-promise "^4.0.3" -escalade@^3.0.2, escalade@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.0.tgz#e8e2d7c7a8b76f6ee64c2181d6b8151441602d4e" - integrity sha512-mAk+hPSO8fLDkhV7V0dXazH5pDc6MrjBTPyD3VeKzxnVFjH1MIxbCdqGZB9O8+EwWakZs3ZCbDS4IpRt79V1ig== +escalade@^3.1.0, escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== escape-html@~1.0.3: version "1.0.3" @@ -6200,11 +6185,6 @@ escodegen@1.x.x, escodegen@^1.11.0, escodegen@^1.11.1, escodegen@^1.14.1: optionalDependencies: source-map "~0.6.1" -eslint-config-standard@^14.1.1: - version "14.1.1" - resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-14.1.1.tgz#830a8e44e7aef7de67464979ad06b406026c56ea" - integrity sha512-Z9B+VR+JIXRxz21udPTL9HpFMyoMUEeX1G251EQ6e05WD9aPVtVBn09XUmZ259wCMlCDmYDSZG62Hhm+ZTJcUg== - eslint-import-resolver-node@^0.3.4: version "0.3.4" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717" @@ -6232,14 +6212,6 @@ eslint-module-utils@^2.6.0: debug "^2.6.9" pkg-dir "^2.0.0" -eslint-plugin-es@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz#75a7cdfdccddc0589934aeeb384175f221c57893" - integrity sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ== - dependencies: - eslint-utils "^2.0.0" - regexpp "^3.0.0" - eslint-plugin-import@^2.22.1: version "2.22.1" resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz#0896c7e6a0cf44109a2d97b95903c2bb689d7702" @@ -6259,33 +6231,11 @@ eslint-plugin-import@^2.22.1: resolve "^1.17.0" tsconfig-paths "^3.9.0" -eslint-plugin-node@^11.1.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz#c95544416ee4ada26740a30474eefc5402dc671d" - integrity sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g== - dependencies: - eslint-plugin-es "^3.0.0" - eslint-utils "^2.0.0" - ignore "^5.1.1" - minimatch "^3.0.4" - resolve "^1.10.1" - semver "^6.1.0" - -eslint-plugin-promise@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz#845fd8b2260ad8f82564c1222fce44ad71d9418a" - integrity sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw== - eslint-plugin-rulesdir@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/eslint-plugin-rulesdir/-/eslint-plugin-rulesdir-0.1.0.tgz#ad144d7e98464fda82963eff3fab331aecb2bf08" integrity sha1-rRRNfphGT9qClj7/P6szGuyyvwg= -eslint-plugin-standard@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-4.0.1.tgz#ff0519f7ffaff114f76d1bd7c3996eef0f6e20b4" - integrity sha512-v/KBnfyaOMPmZc/dmc6ozOdWqekGp7bBGq4jLAecEfPGmfKiWS4sA8sC0LqiV9w5qmXAtXVn4M3p1jSyhY85SQ== - eslint-scope@^5.0.0, eslint-scope@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" @@ -7593,7 +7543,7 @@ ignore@^4.0.3, ignore@^4.0.6: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== -ignore@^5.1.1, ignore@^5.1.4: +ignore@^5.1.4: version "5.1.8" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== @@ -9382,24 +9332,6 @@ kleur@^3.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== -lambda-leak@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/lambda-leak/-/lambda-leak-2.0.0.tgz#771985d3628487f6e885afae2b54510dcfb2cd7e" - integrity sha1-dxmF02KEh/boha+uK1RRDc+yzX4= - -lambda-tester@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/lambda-tester/-/lambda-tester-3.6.0.tgz#ceb7d4f4f0da768487a05cff37dcd088508b5247" - integrity sha512-F2ZTGWCLyIR95o/jWK46V/WnOCFAEUG/m/V7/CLhPJ7PCM+pror1rZ6ujP3TkItSGxUfpJi0kqwidw+M/nEqWw== - dependencies: - app-root-path "^2.2.1" - dotenv "^8.0.0" - dotenv-json "^1.0.0" - lambda-leak "^2.0.0" - semver "^6.1.1" - uuid "^3.3.2" - vandium-utils "^1.1.1" - lazystream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4" @@ -12307,7 +12239,7 @@ resolve@1.1.7: resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= -resolve@^1.1.6, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.11.1, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.3.2: +resolve@^1.1.6, resolve@^1.10.0, resolve@^1.11.1, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.3.2: version "1.17.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== @@ -12506,7 +12438,7 @@ semver@7.x, semver@^7.1.1, semver@^7.2.1, semver@^7.3.2: resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== -semver@^6.0.0, semver@^6.1.0, semver@^6.1.1, semver@^6.2.0, semver@^6.3.0: +semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== @@ -14090,11 +14022,6 @@ validate-npm-package-name@^3.0.0: dependencies: builtins "^1.0.3" -vandium-utils@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/vandium-utils/-/vandium-utils-1.2.0.tgz#44735de4b7641a05de59ebe945f174e582db4f59" - integrity sha1-RHNd5LdkGgXeWevpRfF05YLbT1k= - vendors@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.4.tgz#e2b800a53e7a29b93506c3cf41100d16c4c4ad8e" @@ -14427,10 +14354,10 @@ y18n@^4.0.0: resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== -y18n@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.1.tgz#1ad2a7eddfa8bce7caa2e1f6b5da96c39d99d571" - integrity sha512-/jJ831jEs4vGDbYPQp4yGKDYPSCCEQ45uZWJHE1AoYBzqdZi8+LDWas0z4HrmJXmKdpFsTiowSHXdxyFhpmdMg== +y18n@^5.0.2: + version "5.0.4" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.4.tgz#0ab2db89dd5873b5ec4682d8e703e833373ea897" + integrity sha512-deLOfD+RvFgrpAmSZgfGdWYE+OKyHcVHaRQ7NphG/63scpRvTHHeQMAxGGvaLVGJ+HYVcCXlzcTK0ZehFf+eHQ== yallist@^2.1.2: version "2.1.2" @@ -14457,10 +14384,10 @@ yapool@^1.0.0: resolved "https://registry.yarnpkg.com/yapool/-/yapool-1.0.0.tgz#f693f29a315b50d9a9da2646a7a6645c96985b6a" integrity sha1-9pPymjFbUNmp2iZGp6ZkXJaYW2o= -yargs-parser@20.x, yargs-parser@^20.0.0: - version "20.2.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.0.tgz#944791ca2be2e08ddadd3d87e9de4c6484338605" - integrity sha512-2agPoRFPoIcFzOIp6656gcvsg2ohtscpw2OINr/q46+Sq41xz2OYLqx5HRHabmFU1OARIPAYH5uteICE7mn/5A== +yargs-parser@20.x, yargs-parser@^20.2.2: + version "20.2.3" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.3.tgz#92419ba867b858c868acf8bae9bf74af0dd0ce26" + integrity sha512-emOFRT9WVHw03QSvN5qor9QQT9+sw5vwxfYweivSMHTcAXPefwVae2FjO7JJjj8hCE4CzPOPeFM83VwT29HCww== yargs-parser@^13.0.0, yargs-parser@^13.1.2: version "13.1.2" @@ -14536,18 +14463,18 @@ yargs@^15.0.2, yargs@^15.3.1, yargs@^15.4.1: y18n "^4.0.0" yargs-parser "^18.1.2" -yargs@^16.0.3: - version "16.0.3" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.0.3.tgz#7a919b9e43c90f80d4a142a89795e85399a7e54c" - integrity sha512-6+nLw8xa9uK1BOEOykaiYAJVh6/CjxWXK/q9b5FpRgNslt8s22F2xMBqVIKgCRjNgGvGPBy8Vog7WN7yh4amtA== +yargs@^16.0.3, yargs@^16.1.0: + version "16.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.1.0.tgz#fc333fe4791660eace5a894b39d42f851cd48f2a" + integrity sha512-upWFJOmDdHN0syLuESuvXDmrRcWd1QafJolHskzaw79uZa7/x53gxQKiR07W59GWY1tFhhU/Th9DrtSfpS782g== dependencies: - cliui "^7.0.0" - escalade "^3.0.2" + cliui "^7.0.2" + escalade "^3.1.1" get-caller-file "^2.0.5" require-directory "^2.1.1" string-width "^4.2.0" - y18n "^5.0.1" - yargs-parser "^20.0.0" + y18n "^5.0.2" + yargs-parser "^20.2.2" yn@3.1.1: version "3.1.1"