diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index 5371d422793e3..0000000000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -name: "\U00002753 General Issue" -about: Create a new issue -labels: needs-triage ---- - - - -## :question: General Issue - - - -### The Question - - -### Environment - - - **CDK CLI Version:** - - **Module Version:** - - **Node.js Version:** - - **OS:** - - **Language:** - - -### Other information - diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md deleted file mode 100644 index 6835abe99e034..0000000000000 --- a/.github/ISSUE_TEMPLATE/bug.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -name: "\U0001F41B Bug Report" -about: Report a bug -title: "(module name): short issue description" -labels: bug, needs-triage ---- - - - - - - -### Reproduction Steps - - - -### What did you expect to happen? - - - -### What actually happened? - - - - -### Environment - - - **CDK CLI Version :** - - **Framework Version:** - - **Node.js Version:** - - **OS :** - - **Language (Version):** - -### Other - - - - - - ---- - -This is :bug: Bug Report diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml new file mode 100644 index 0000000000000..f77fa5beb193e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -0,0 +1,108 @@ +name: Bug Report +description: Report a bug +title: "(module name): short issue description" +labels: [bug, needs-triage] +body: + - type: textarea + id: problem + attributes: + label: What is the problem? + validations: + required: true + + - type: textarea + id: reproduction + attributes: + label: Reproduction Steps + description: | + Minimal amount of code that causes the bug (if possible) or a reference. + + The code sample should be an SSCCE. See http://sscce.org/ for details. + In short, provide a code sample that we can copy/paste, run and reproduce. + validations: + required: true + + - type: textarea + id: expected + attributes: + label: What did you expect to happen? + description: | + What were you trying to achieve by performing the steps above? + validations: + required: true + + - type: textarea + id: actual + attributes: + label: What actually happened? + description: | + What is the unexpected behavior you were seeing? If you got an error, paste it here. + validations: + required: true + + - type: input + id: cdk-version + attributes: + label: CDK CLI Version + description: Output of `cdk version` + validations: + required: true + + - type: input + id: framework-version + attributes: + label: Framework Version + validations: + required: false + + - type: input + id: node-version + attributes: + label: Node.js Version + validations: + required: true + + - type: input + id: operating-system + attributes: + label: OS + validations: + required: true + + - type: dropdown + id: language + attributes: + label: Language + multiple: true + options: + - Typescript + - Python + - .NET + - Java + - Go + validations: + required: true + + - type: input + id: language-version + attributes: + label: Language Version + description: E.g. TypeScript (3.8.3) | Java (8) | Python (3.7.3) + validations: + required: false + + - type: textarea + id: other + attributes: + label: Other information + description: | + e.g. detailed explanation, stacktraces, related issues, suggestions how to fix, links for us to have context, eg. associated pull-request, stackoverflow, slack, etc + validations: + required: false + + - type: markdown + attributes: + value: | + --- + + This is :bug: Bug Report diff --git a/.github/ISSUE_TEMPLATE/doc.md b/.github/ISSUE_TEMPLATE/doc.md deleted file mode 100644 index 3c8a1dc691d0e..0000000000000 --- a/.github/ISSUE_TEMPLATE/doc.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -name: "πŸ“• Documentation Issue" -about: Issue in the reference documentation or developer guide -title: "(module name): short issue description" -labels: feature-request, documentation, needs-triage ---- - - - - - - - - - - - - - ---- - -This is a πŸ“• documentation issue diff --git a/.github/ISSUE_TEMPLATE/doc.yml b/.github/ISSUE_TEMPLATE/doc.yml new file mode 100644 index 0000000000000..974a752cac810 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/doc.yml @@ -0,0 +1,32 @@ +name: Documentation Issue +description: Issue in the reference documentation or developer guide +title: "(module name): short issue description" +labels: [feature-request, documentation, needs-triage] +body: + - type: markdown + attributes: + value: | + Developer guide? Raise issue/pr here: https://github.com/awsdocs/aws-cdk-guide + + Want to help? Submit a pull request here: https://github.com/aws/aws-cdk + + - type: input + id: doc-link + attributes: + label: link to reference doc page + validations: + required: false + + - type: textarea + id: issue + attributes: + label: Describe your issue? + validations: + required: true + + - type: markdown + attributes: + value: | + --- + + This is a πŸ“• documentation issue diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md deleted file mode 100644 index 163f2f54d0b88..0000000000000 --- a/.github/ISSUE_TEMPLATE/feature-request.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -name: "\U0001F680 Feature Request" -about: Request a new feature -title: "(module name): short issue description" -labels: feature-request, needs-triage ---- - - - - - - - -### Use Case - - - - - - - -### Proposed Solution - - - - - - - -### Other - - - - - - - -* [ ] :wave: I may be able to implement this feature request -* [ ] :warning: This feature might incur a breaking change - ---- - -This is a :rocket: Feature Request diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml new file mode 100644 index 0000000000000..a16053f420a82 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -0,0 +1,56 @@ +name: Feature Request +description: Request a new feature +title: "(module name): short issue description" +labels: [feature-request, needs-triage] +body: + - type: textarea + id: description + attributes: + label: Description + description: Short description of the feature you are proposing. + validations: + required: true + + - type: textarea + id: use-case + attributes: + label: Use Case + description: | + Why do you need this feature? + validations: + required: true + + - type: textarea + id: solution + attributes: + label: Proposed Solution + description: | + Please include prototype/workaround/sketch/reference implementation. + validations: + required: true + + - type: textarea + id: other + attributes: + label: Other information + description: | + e.g. detailed explanation, stacktraces, related issues, suggestions how to fix, links for us to have context, eg. associated pull-request, stackoverflow, slack, etc + validations: + required: false + + - type: checkboxes + id: acknowledgments + attributes: + label: Acknowledge + options: + - label: I may be able to implement this feature request + required: false + - label: This feature might incur a breaking change + required: false + + - type: markdown + attributes: + value: | + --- + + This is a :rocket: Feature Request diff --git a/.github/ISSUE_TEMPLATE/general-issue.yml b/.github/ISSUE_TEMPLATE/general-issue.yml new file mode 100644 index 0000000000000..61119a33a761c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/general-issue.yml @@ -0,0 +1,87 @@ +name: General Issue +description: Create a new issue +title: "(module name): short issue description" +labels: [needs-triage, guidance] +body: + - type: markdown + attributes: + value: | + If there is an issue regarding developer guide, please create an issue [here](https://github.com/awsdocs/aws-cdk-guide/issues). + + - type: input + id: issue + attributes: + label: General Issue + description: | + For support questions, please first reference our [documentation](https://docs.aws.amazon.com/cdk/api/latest), then use [Stackoverflow](https://stackoverflow.com/questions/tagged/aws-cdk). This repository's issues are intended for feature requests and bug reports. + validations: + required: true + + - type: textarea + id: question + attributes: + label: The Question + description: | + Ask your question here. Include any details relevant. Make sure you are not falling prey to the [X/Y problem](http://xyproblem.info)! + validations: + required: true + + - type: input + id: cdk-version + attributes: + label: CDK CLI Version + description: Output of `cdk version` + validations: + required: true + + - type: input + id: framework-version + attributes: + label: Framework Version + validations: + required: false + + - type: input + id: node-version + attributes: + label: Node.js Version + validations: + required: false + + - type: input + id: operating-system + attributes: + label: OS + validations: + required: false + + - type: dropdown + id: language + attributes: + label: Language + multiple: true + options: + - Typescript + - Python + - .NET + - Java + - Go + validations: + required: true + + - type: input + id: language-version + attributes: + label: Language Version + description: E.g. TypeScript (3.8.3) | Java (8) | Python (3.7.3) + validations: + required: false + + - type: textarea + id: other + attributes: + label: Other information + description: | + e.g. detailed explanation, stacktraces, related issues, suggestions how to fix, links for us to have context, eg. associated pull-request, stackoverflow, slack, etc + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/general-issues.md b/.github/ISSUE_TEMPLATE/general-issues.md deleted file mode 100644 index 2b478904a6fca..0000000000000 --- a/.github/ISSUE_TEMPLATE/general-issues.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -name: "\U00002753 General Issue" -about: Create a new issue -title: "(module name): short issue description" -labels: needs-triage, guidance ---- - - - -## :question: General Issue - - - -### The Question - - -### Environment - - - **CDK CLI Version:** - - **Module Version:** - - **Node.js Version:** - - **OS:** - - **Language (Version):** - - -### Other information - diff --git a/.github/ISSUE_TEMPLATE/tracking.md b/.github/ISSUE_TEMPLATE/tracking.md deleted file mode 100644 index b3655dfaa6dca..0000000000000 --- a/.github/ISSUE_TEMPLATE/tracking.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -name: "πŸ“Š Tracking Issue" -title: "πŸ“ŠTracking: [service]" -about: Add a module tracking issue (internal use only) -labels: management/tracking ---- - -Add your +1 πŸ‘ to help us prioritize high-level constructs for this service ---- - -### Overview: - - - - - - - -[AWS Docs](url) - -### Maturity: CloudFormation Resources Only - - -See the [AWS Construct Library Module Lifecycle doc](https://github.com/aws/aws-cdk-rfcs/blob/master/text/0107-construct-library-module-lifecycle.md) for more information about maturity levels. - - -### Implementation: - -See the [CDK API Reference](url) for more implementation details. - - - - - - -### Issue list: - - - - - - - - ---- -This is a πŸ“ŠTracking Issue diff --git a/.github/ISSUE_TEMPLATE/tracking.yml b/.github/ISSUE_TEMPLATE/tracking.yml new file mode 100644 index 0000000000000..0ecfc903b002c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/tracking.yml @@ -0,0 +1,76 @@ +name: Tracking Issue +description: Add a module tracking issue (internal use only) +title: "Tracking: [service]" +labels: [management/tracking] +body: + - type: markdown + attributes: + value: | + Add your +1 πŸ‘ to help us prioritize high-level constructs for this service + + - type: textarea + id: overview + attributes: + label: Overview + description: | + Summary of the service (leverage the service’s product page for the text) and a link to the relevant AWS Docs. This should be the same text that we put at the top of the package’s README.md. + validations: + required: true + + - type: input + id: cdk-api-docs-link + attributes: + label: Link to the service’s CDK Construct Library API reference page. + validations: + required: true + + - type: dropdown + id: maturity + attributes: + label: "Maturity: CloudFormation Resources Only" + description: | + See the [AWS Construct Library Module Lifecycle doc](https://github.com/aws/aws-cdk-rfcs/blob/master/text/0107-construct-library-module-lifecycle.md) for more information about maturity levels. + options: + - CloudFormation Resources Only + - Experimental + - Developer Preview + - Stable + validations: + required: true + + - type: textarea + id: implementation + attributes: + label: Implementation + description: | + Checklist of use cases, constructs, features (such as grant methods) that will ship in this package. This is not required until the issue is added to the public roadmap. + validations: + required: true + + - type: textarea + id: issue-list + attributes: + label: Issue list + description: | + Checklist of links to feature requests, bugs, and PRs that are in scope for GA release of this module (not required until the issues is added to the public roadmap). + value: | + - [ ] + - [ ] + validations: + required: true + + - type: markdown + attributes: + value: | + Labels to add: + - package/[name] (create new labels if they don’t already exist) + - needs-design (if cfn-only) + - management/roadmap (when added to the roadmap) + - in-progress (when added to β€œworking on it” column of the roadmap) + + - type: markdown + attributes: + value: | + --- + + This is a πŸ“Š Tracking Issue diff --git a/.github/workflows/close-stale-issues.yml b/.github/workflows/close-stale-issues.yml index db75a56aa7f8b..487a095e0c372 100644 --- a/.github/workflows/close-stale-issues.yml +++ b/.github/workflows/close-stale-issues.yml @@ -2,6 +2,7 @@ name: "Close Stale Issues" # Controls when the action will run. on: + workflow_dispatch: schedule: - cron: "0 6 * * *" @@ -9,6 +10,8 @@ jobs: cleanup: permissions: issues: write + contents: read + pull-requests: write runs-on: ubuntu-latest name: Stale issue job steps: @@ -32,8 +35,8 @@ jobs: closed-for-staleness-label: closed-for-staleness # Issue timing - days-before-stale: 7 - days-before-close: 4 + days-before-stale: 2 + days-before-close: 5 days-before-ancient: 365 # If you don't want to mark a issue as being ancient based on a @@ -43,6 +46,6 @@ jobs: minimum-upvotes-to-exempt: 5 repo-token: ${{ secrets.GITHUB_TOKEN }} - # loglevel: DEBUG + loglevel: DEBUG # Set dry-run to true to not perform label or close actions. dry-run: false diff --git a/.github/workflows/issue-label-assign.yml b/.github/workflows/issue-label-assign.yml index 0d34e0fa4d4a0..1c9c5997781bd 100644 --- a/.github/workflows/issue-label-assign.yml +++ b/.github/workflows/issue-label-assign.yml @@ -40,20 +40,20 @@ jobs: {"area":"@aws-cdk/aws-appmesh","keywords":["aws-appmesh","app-mesh","GatewayRoute","VirtualGateway","VirtualNode","VirtualRouter","VirtualService"],"labels":["@aws-cdk/aws-appmesh"],"assignees":["Seiya6329"]}, {"area":"@aws-cdk/aws-appstream","keywords":["aws-appstream","app-stream"],"labels":["@aws-cdk/aws-appstream"],"assignees":["madeline-k"]}, {"area":"@aws-cdk/aws-appsync","keywords":["aws-appsync","app-sync","appsyncfunction","graphqlapi","dynamodbdatasource","lambdadatasource","nonedatasource","rdsdatasource","resolver"],"labels":["@aws-cdk/aws-appsync"],"assignees":["otaviomacedo"]}, - {"area":"@aws-cdk/aws-athena","keywords":["aws-athena","athena","cfndatacatalog","cfnnamedquery","cfnworkgroup"],"labels":["@aws-cdk/aws-athena"],"assignees":["BenChaimberg"]}, + {"area":"@aws-cdk/aws-athena","keywords":["aws-athena","athena","cfndatacatalog","cfnnamedquery","cfnworkgroup"],"labels":["@aws-cdk/aws-athena"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-auditmanager","keywords":["(aws-auditmanager)","(auditmanager)"],"labels":["@aws-cdk/aws-auditmanager"],"assignees":["njlynch"]}, {"area":"@aws-cdk/aws-autoscaling","keywords":["aws-autoscaling","auto-scaling","AutoScalingGroup","LifescycleHook","scheduledaction"],"labels":["@aws-cdk/aws-autoscaling"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-autoscaling-api","keywords":["aws-autoscaling-api","autoscaling-api"],"labels":["@aws-cdk/aws-autoscaling-api"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-autoscaling-common","keywords":["aws-autoscaling-common","autoscaling-common","arbitraryintervals","completescalinginterval","scalinginterval"],"labels":["@aws-cdk/aws-autoscaling-common"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-autoscaling-hooktargets","keywords":["aws-autoscaling-hooktargets","autoscaling hooktargets","functionhook","queuehook","topichook"],"labels":["@aws-cdk/aws-autoscaling-hooktargets"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-autoscalingplans","keywords":["aws-autoscalingplans","autoscaling-plans","cfnscalingplan"],"labels":["@aws-cdk/aws-autoscalingplans"],"assignees":["comcalvi"]}, - {"area":"@aws-cdk/aws-backup","keywords":["aws-backup","backupplan","backupselection","backupvault"],"labels":["@aws-cdk/aws-backup"],"assignees":["BenChaimberg"]}, + {"area":"@aws-cdk/aws-backup","keywords":["aws-backup","backupplan","backupselection","backupvault"],"labels":["@aws-cdk/aws-backup"],"assignees":["kaizen3031593"]}, {"area":"@aws-cdk/aws-batch","keywords":["aws-batch","batch","computeenvironment","jobdefinition","jobqueue"],"labels":["@aws-cdk/aws-batch"],"assignees":["madeline-k"]}, {"area":"@aws-cdk/aws-budgets","keywords":["aws-budgets","budgets","cfnbudget"],"labels":["@aws-cdk/aws-budgets"],"assignees":["njlynch"]}, {"area":"@aws-cdk/aws-cassandra","keywords":["aws-cassandra","cassandra","cfnkeyspace"],"labels":["@aws-cdk/aws-cassandra"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-ce","keywords":["aws-ce","cfnanomalymonitor","cfncostcategory"],"labels":["@aws-cdk/aws-ce"],"assignees":["njlynch"]}, {"area":"@aws-cdk/aws-certificatemanager","keywords":["aws-certificatemanager","certificate-manager","dnsvalidatedcertificate","acm"],"labels":["@aws-cdk/aws-certificatemanager"],"assignees":["njlynch"]}, - {"area":"@aws-cdk/aws-chatbot","keywords":["aws-chatbot","chatbot","slackchannelconfiguration"],"labels":["@aws-cdk/aws-chatbot"],"assignees":["BenChaimberg"]}, + {"area":"@aws-cdk/aws-chatbot","keywords":["aws-chatbot","chatbot","slackchannelconfiguration"],"labels":["@aws-cdk/aws-chatbot"],"assignees":["kaizen3031593"]}, {"area":"@aws-cdk/aws-cloud9","keywords":["aws-cloud9","cloud 9","ec2environment"],"labels":["@aws-cdk/aws-cloud9"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-cloudformation","keywords":["aws-cloudformation","nestedstack","customresource"],"labels":["@aws-cdk/aws-cloudformation"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/aws-cloudfront","keywords":["aws-cloudfront","cloud front","cachepolicy","cloudfrontwebdistribution"],"labels":["@aws-cdk/aws-cloudfront"],"assignees":["njlynch"]}, @@ -75,9 +75,9 @@ jobs: {"area":"@aws-cdk/aws-cognito","keywords":["aws-cognito","cognito","userpool","userpoolclient","userpooldomain"],"labels":["@aws-cdk/aws-cognito"],"assignees":["nija-at"]}, {"area":"@aws-cdk/aws-config","keywords":["aws-config","accesskeysrotated","CloudFormationStackDriftDetectionCheck","CloudFormationStackNotificationCheck","managedrule"],"labels":["@aws-cdk/aws-config"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/aws-customerprofiles","keywords":["(aws-customerprofiles)","(customerprofiles)"],"labels":["@aws-cdk/aws-customerprofiles"],"assignees":["otaviomacedo"]}, - {"area":"@aws-cdk/aws-databrew","keywords":["(aws-databrew)","(databrew)"],"labels":["@aws-cdk/aws-databrew"],"assignees":["BenChaimberg"]}, - {"area":"@aws-cdk/aws-datapipeline","keywords":["aws-datapipeline","data-pipeline"],"labels":["@aws-cdk/aws-datapipeline"],"assignees":["BenChaimberg"]}, - {"area":"@aws-cdk/aws-datasync","keywords":["(aws-datasync)","(datasync)"],"labels":["@aws-cdk/aws-datasync"],"assignees":["BenChaimberg"]}, + {"area":"@aws-cdk/aws-databrew","keywords":["(aws-databrew)","(databrew)"],"labels":["@aws-cdk/aws-databrew"],"assignees":["kaizen3031593"]}, + {"area":"@aws-cdk/aws-datapipeline","keywords":["aws-datapipeline","data-pipeline"],"labels":["@aws-cdk/aws-datapipeline"],"assignees":["kaizen3031593"]}, + {"area":"@aws-cdk/aws-datasync","keywords":["(aws-datasync)","(datasync)"],"labels":["@aws-cdk/aws-datasync"],"assignees":["kaizen3031593"]}, {"area":"@aws-cdk/aws-dax","keywords":["aws-dax","dax"],"labels":["@aws-cdk/aws-dax"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-detective","keywords":["aws-detective","detective"],"labels":["@aws-cdk/aws-detective"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-devopsguru","keywords":["(aws-devopsguru)","(devopsguru)"],"labels":["@aws-cdk/aws-devopsguru"],"assignees":["nija-at"]}, @@ -101,9 +101,9 @@ jobs: {"area":"@aws-cdk/aws-elasticloadbalancingv2","keywords":["aws-elasticloadbalancingv2","elastic-loadbalancing-v2","elbv2","applicationlistener","applicationloadbalancer","applicationtargetgroup","networklistener","networkloadbalancer","networktargetgroup"],"labels":["@aws-cdk/aws-elasticloadbalancingv2"],"assignees":["njlynch"]}, {"area":"@aws-cdk/aws-elasticloadbalancingv2-actions","keywords":["(aws-elasticloadbalancingv2-actions)","(elasticloadbalancingv2-actions)"],"labels":["@aws-cdk/aws-elasticloadbalancingv2-actions"],"assignees":["njlynch"]}, {"area":"@aws-cdk/aws-elasticloadbalancingv2-targets","keywords":["aws-elasticloadbalancingv2-targets","elbv2 targets"],"labels":["@aws-cdk/aws-elasticloadbalancingv2-targets"],"assignees":["njlynch"]}, - {"area":"@aws-cdk/aws-elasticsearch","keywords":["aws-elasticsearch","elastic-search"],"labels":["@aws-cdk/aws-elasticsearch"],"assignees":["BenChaimberg"]}, - {"area":"@aws-cdk/aws-emr","keywords":["aws-emr","emr"],"labels":["@aws-cdk/aws-emr"],"assignees":["BenChaimberg"]}, - {"area":"@aws-cdk/aws-emrcontainers","keywords":["(aws-emrcontainers)","(emrcontainers)"],"labels":["@aws-cdk/aws-emrcontainers"],"assignees":["BenChaimberg"]}, + {"area":"@aws-cdk/aws-elasticsearch","keywords":["aws-elasticsearch","elastic-search"],"labels":["@aws-cdk/aws-elasticsearch"],"assignees":["kaizen3031593"]}, + {"area":"@aws-cdk/aws-emr","keywords":["aws-emr","emr"],"labels":["@aws-cdk/aws-emr"],"assignees":["kaizen3031593"]}, + {"area":"@aws-cdk/aws-emrcontainers","keywords":["(aws-emrcontainers)","(emrcontainers)"],"labels":["@aws-cdk/aws-emrcontainers"],"assignees":["kaizen3031593"]}, {"area":"@aws-cdk/aws-events","keywords":["aws-events","events","event-bridge","eventbus"],"labels":["@aws-cdk/aws-events"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/aws-events-targets","keywords":["aws-events-targets","events-targets","events targets"],"labels":["@aws-cdk/aws-events-targets"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/aws-eventschemas","keywords":["aws-eventschemas","event schemas"],"labels":["@aws-cdk/aws-eventschemas"],"assignees":["skinny85"]}, @@ -115,7 +115,7 @@ jobs: {"area":"@aws-cdk/aws-gamelift","keywords":["aws-gamelift","game lift"],"labels":["@aws-cdk/aws-gamelift"],"assignees":["madeline-k"]}, {"area":"@aws-cdk/aws-globalaccelerator","keywords":["aws-globalaccelerator","global-accelerator"],"labels":["@aws-cdk/aws-globalaccelerator"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/aws-globalaccelerator-endpoints","keywords":["(aws-globalaccelerator-endpoints)","(globalaccelerator-endpoints)"],"labels":["@aws-cdk/aws-globalaccelerator-endpoints"],"assignees":["rix0rrr"]}, - {"area":"@aws-cdk/aws-glue","keywords":["aws-glue","glue"],"labels":["@aws-cdk/aws-glue"],"assignees":["BenChaimberg"]}, + {"area":"@aws-cdk/aws-glue","keywords":["aws-glue","glue"],"labels":["@aws-cdk/aws-glue"],"assignees":["kaizen3031593"]}, {"area":"@aws-cdk/aws-greengrass","keywords":["aws-greengrass","green-grass"],"labels":["@aws-cdk/aws-greengrass"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-greengrassv2","keywords":["(aws-greengrassv2)","(greengrassv2)"],"labels":["@aws-cdk/aws-greengrassv2"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-groundstation","keywords":["(aws-groundstation)","(groundstation)"],"labels":["@aws-cdk/aws-groundstation"],"assignees":["rix0rrr"]}, @@ -138,7 +138,7 @@ jobs: {"area":"@aws-cdk/aws-kinesisanalytics-flink","keywords":["(aws-kinesisanalytics-flink)","(kinesisanalytics-flink)"],"labels":["@aws-cdk/aws-kinesisanalytics-flink"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-kinesisfirehose","keywords":["aws-kinesisfirehose","kinesisfirehose"],"labels":["@aws-cdk/aws-kinesisfirehose"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-kms","keywords":["key-management-service","aws-kms","kms"],"labels":["@aws-cdk/aws-kms"],"assignees":["njlynch"]}, - {"area":"@aws-cdk/aws-lakeformation","keywords":["data-lake","aws-lakeformation","lakeformation"],"labels":["@aws-cdk/aws-lakeformation"],"assignees":["BenChaimberg"]}, + {"area":"@aws-cdk/aws-lakeformation","keywords":["data-lake","aws-lakeformation","lakeformation"],"labels":["@aws-cdk/aws-lakeformation"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-lambda","keywords":["function","layerversion","aws-lambda","lambda"],"labels":["@aws-cdk/aws-lambda"],"assignees":["nija-at"]}, {"area":"@aws-cdk/aws-lambda-destinations","keywords":["(aws-lambda-destinations)","(lambda-destinations)"],"labels":["@aws-cdk/aws-lambda-destinations"],"assignees":["nija-at"]}, {"area":"@aws-cdk/aws-lambda-event-sources","keywords":["dynamoeventsource","aws-lambda-event-sources","lambda-event-sources","apieventsource","kinesiseventsource"],"labels":["@aws-cdk/aws-lambda-event-sources"],"assignees":["nija-at"]}, @@ -148,8 +148,8 @@ jobs: {"area":"@aws-cdk/aws-licensemanager","keywords":["(aws-licensemanager)","(licensemanager)"],"labels":["@aws-cdk/aws-licensemanager"],"assignees":["njlynch"]}, {"area":"@aws-cdk/aws-logs","keywords":["loggroup","aws-logs","logs","logretention"],"labels":["@aws-cdk/aws-logs"],"assignees":["rix0rrr"]}, {"area":"@aws-cdk/aws-logs-destinations","keywords":["aws-logs-destinations","lambdadestination","kinesisdestination","logs-destinations"],"labels":["@aws-cdk/aws-logs-destinations"],"assignees":["rix0rrr"]}, - {"area":"@aws-cdk/aws-lookoutmetrics","keywords":["(aws-lookoutmetrics)","(lookoutmetrics)"],"labels":["@aws-cdk/aws-lookoutmetrics"],"assignees":["BenChaimberg"]}, - {"area":"@aws-cdk/aws-lookoutvision","keywords":["(aws-lookoutvision)","(lookoutvision)"],"labels":["@aws-cdk/aws-lookoutvision"],"assignees":["BenChaimberg"]}, + {"area":"@aws-cdk/aws-lookoutmetrics","keywords":["(aws-lookoutmetrics)","(lookoutmetrics)"],"labels":["@aws-cdk/aws-lookoutmetrics"],"assignees":["comcalvi"]}, + {"area":"@aws-cdk/aws-lookoutvision","keywords":["(aws-lookoutvision)","(lookoutvision)"],"labels":["@aws-cdk/aws-lookoutvision"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-macie","keywords":["aws-macie","macie"],"labels":["@aws-cdk/aws-macie"],"assignees":["njlynch"]}, {"area":"@aws-cdk/aws-managedblockchain","keywords":["aws-managedblockchain","managedblockchain"],"labels":["@aws-cdk/aws-managedblockchain"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-mediaconnect","keywords":["(aws-mediaconnect)","(mediaconnect)"],"labels":["@aws-cdk/aws-mediaconnect"],"assignees":["skinny85"]}, @@ -163,13 +163,14 @@ jobs: {"area":"@aws-cdk/aws-networkfirewall","keywords":["(aws-networkfirewall)","(networkfirewall)"],"labels":["@aws-cdk/aws-networkfirewall"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-networkmanager","keywords":["aws-networkmanager","networkmanager","globalnetwork"],"labels":["@aws-cdk/aws-networkmanager"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-nimblestudio","keywords":["(aws-nimblestudio)","(nimblestudio)"],"labels":["@aws-cdk/aws-nimblestudio"],"assignees":["madeline-k"]}, + {"area":"@aws-cdk/aws-opensearchservice","keywords":["aws-opensearchservice","opensearchservice","aws-opensearch","opensearch"],"labels":["@aws-cdk/aws-opensearch"],"assignees":["kaizen3031593"]}, {"area":"@aws-cdk/aws-opsworks","keywords":["aws-opsworks","opsworks"],"labels":["@aws-cdk/aws-opsworks"],"assignees":["madeline-k"]}, {"area":"@aws-cdk/aws-opsworkscm","keywords":["aws-opsworkscm","opsworkscm"],"labels":["@aws-cdk/aws-opsworkscm"],"assignees":["madeline-k"]}, {"area":"@aws-cdk/aws-personalize","keywords":["aws-personalize","personalize"],"labels":["@aws-cdk/aws-personalize"],"assignees":["njlynch"]}, {"area":"@aws-cdk/aws-pinpoint","keywords":["aws-pinpoint","pinpoint"],"labels":["@aws-cdk/aws-pinpoint"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-pinpointemail","keywords":["aws-pinpointemail","pinpointemail"],"labels":["@aws-cdk/aws-pinpointemail"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-qldb","keywords":["aws-qldb","qldb"],"labels":["@aws-cdk/aws-qldb"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-quicksight","keywords":["(aws-quicksight)","(quicksight)"],"labels":["@aws-cdk/aws-quicksight"],"assignees":["BenChaimberg"]}, + {"area":"@aws-cdk/aws-quicksight","keywords":["(aws-quicksight)","(quicksight)"],"labels":["@aws-cdk/aws-quicksight"],"assignees":["comcalvi"]}, {"area":"@aws-cdk/aws-ram","keywords":["aws-ram","ram", "resource-access-manager"],"labels":["@aws-cdk/aws-ram"],"assignees":["madeline-k"]}, {"area":"@aws-cdk/aws-rds","keywords":["aws-rds","rds", "database-cluster","database-instance"],"labels":["@aws-cdk/aws-rds"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-redshift","keywords":["aws-redshift","redshift"],"labels":["@aws-cdk/aws-redshift"],"assignees":["njlynch"]}, @@ -201,9 +202,9 @@ jobs: {"area":"@aws-cdk/aws-sqs","keywords":["queue","simple-queue-service","aws-sqs","sqs","fifo"],"labels":["@aws-cdk/aws-sqs"],"assignees":["njlynch"]}, {"area":"@aws-cdk/aws-ssm","keywords":["aws-ssm","ssm","systems-manager","stringparameter","stringlistparameter"],"labels":["@aws-cdk/aws-ssm"],"assignees":["njlynch"]}, {"area":"@aws-cdk/aws-sso","keywords":["aws-sso","sso","single-sign-on"],"labels":["@aws-cdk/aws-sso"],"assignees":["skinny85"]}, - {"area":"@aws-cdk/aws-stepfunctions","keywords":["aws-stepfunctions","stepfunctions","state machine", "chain"],"labels":["@aws-cdk/aws-stepfunctions"],"assignees":["BenChaimberg"]}, - {"area":"@aws-cdk/aws-stepfunctions-tasks","keywords":["aws-stepfunctions-tasks","stepfunctions-tasks"],"labels":["@aws-cdk/aws-stepfunctions-tasks"],"assignees":["BenChaimberg"]}, - {"area":"@aws-cdk/aws-synthetics","keywords":["aws-synthetics","synthetics", "canary"],"labels":["@aws-cdk/aws-synthetics"],"assignees":["BenChaimberg"]}, + {"area":"@aws-cdk/aws-stepfunctions","keywords":["aws-stepfunctions","stepfunctions","state machine", "chain"],"labels":["@aws-cdk/aws-stepfunctions"],"assignees":["kaizen3031593"]}, + {"area":"@aws-cdk/aws-stepfunctions-tasks","keywords":["aws-stepfunctions-tasks","stepfunctions-tasks"],"labels":["@aws-cdk/aws-stepfunctions-tasks"],"assignees":["kaizen3031593"]}, + {"area":"@aws-cdk/aws-synthetics","keywords":["aws-synthetics","synthetics", "canary"],"labels":["@aws-cdk/aws-synthetics"],"assignees":["kaizen3031593"]}, {"area":"@aws-cdk/aws-timestream","keywords":["aws-timestream","timestream"],"labels":["@aws-cdk/aws-timestream"],"assignees":["skinny85"]}, {"area":"@aws-cdk/aws-transfer","keywords":["aws-transfer","transfer"],"labels":["@aws-cdk/aws-transfer"],"assignees":["otaviomacedo"]}, {"area":"@aws-cdk/aws-waf","keywords":["waf","web-application-firewall"],"labels":["@aws-cdk/aws-waf"],"assignees":["njlynch"]}, diff --git a/.github/workflows/pr-linter.yml b/.github/workflows/pr-linter.yml index 36f20b6456d0b..d88d64d89537d 100644 --- a/.github/workflows/pr-linter.yml +++ b/.github/workflows/pr-linter.yml @@ -24,10 +24,10 @@ jobs: uses: actions/checkout@v2 - name: Install & Build prlint - run: cd tools/prlint && yarn install --frozen-lockfile && yarn build+test + run: cd tools/@aws-cdk/prlint && yarn install --frozen-lockfile && yarn build+test - name: Validate - uses: ./tools/prlint + uses: ./tools/@aws-cdk/prlint env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} REPO_ROOT: ${{ github.workspace }} diff --git a/.gitpod.yml b/.gitpod.yml index 2e63da1c1cb98..ac367f2ce4329 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -3,11 +3,11 @@ github: pullRequestsFromForks: true addComment: true -image: jsii/superchain +image: jsii/superchain:1-buster-slim tasks: - init: yarn build --skip-test --no-bail --skip-prereqs --skip-compat vscode: extensions: - - dbaeumer.vscode-eslint@2.1.5:9Wg0Glx/TwD8ElFBg+FKcQ== + - dbaeumer.vscode-eslint@2.1.20 diff --git a/CHANGELOG.md b/CHANGELOG.md index d6b5328d87b1c..e47c967a1926e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,56 @@ 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.125.0](https://github.com/aws/aws-cdk/compare/v1.124.0...v1.125.0) (2021-09-29) + + +### Features + +* **lambda:** support for ARM architecture ([b3ba35e](https://github.com/aws/aws-cdk/commit/b3ba35e9b8b157303a29350031885eff0c73b05b)) + +## [1.124.0](https://github.com/aws/aws-cdk/compare/v1.123.0...v1.124.0) (2021-09-21) + + +### ⚠ BREAKING CHANGES TO EXPERIMENTAL FEATURES + +* **assertions:** the `findResources()` API previously returned a list of resources, but now returns a map of logical id to resource. +* **assertions:** the `findOutputs()` API previously returned a list of outputs, but now returns a map of logical id to output. +* **assertions:** the `findMappings()` API previously returned a list of mappings, but now returns a map of logical id to mapping. + +### Features + +* **assertions:** capture matching value ([#16426](https://github.com/aws/aws-cdk/issues/16426)) ([cc74f92](https://github.com/aws/aws-cdk/commit/cc74f92f275a338cb53caa7d6f124ab0dd960f0b)) +* **assertions:** findXxx() APIs now includes the logical id as part of its result ([#16454](https://github.com/aws/aws-cdk/issues/16454)) ([532a72b](https://github.com/aws/aws-cdk/commit/532a72b133e6ebd0c7b8b7c65b273bb0e6f3293c)) +* **assertions:** match into serialized json ([#16456](https://github.com/aws/aws-cdk/issues/16456)) ([fed30fc](https://github.com/aws/aws-cdk/commit/fed30fc815bac1006003524ac6232778f3c3babe)) +* **batch:** fargate support for jobs ([#15848](https://github.com/aws/aws-cdk/issues/15848)) ([066bcb1](https://github.com/aws/aws-cdk/commit/066bcb1e5d53192bd465190c8a4f81c5838987f4)), closes [#13591](https://github.com/aws/aws-cdk/issues/13591) [#13590](https://github.com/aws/aws-cdk/issues/13590) [#13591](https://github.com/aws/aws-cdk/issues/13591) +* **cfnspec:** cloudformation spec v41.1.0 ([#16472](https://github.com/aws/aws-cdk/issues/16472)) ([28875f9](https://github.com/aws/aws-cdk/commit/28875f9dda4911d3a2fcfcdc6e6d8358bee7c689)) +* **cfnspec:** cloudformation spec v41.1.0 ([#16524](https://github.com/aws/aws-cdk/issues/16524)) ([124a7a1](https://github.com/aws/aws-cdk/commit/124a7a1c20981c72bfdce0c857c87c46c6cb5f51)) +* **cfnspec:** cloudformation spec v41.2.0 ([#16550](https://github.com/aws/aws-cdk/issues/16550)) ([e047bd8](https://github.com/aws/aws-cdk/commit/e047bd80ab08f49a22408eb8c5401f4306747eff)) +* **ec2/ecs:** `cacheInContext` properties for machine images ([#16021](https://github.com/aws/aws-cdk/issues/16021)) ([430f50a](https://github.com/aws/aws-cdk/commit/430f50a546e9c575f8cdbd259367e440d985e68f)), closes [#12484](https://github.com/aws/aws-cdk/issues/12484) +* **ecs-service-extensions:** Publish Extension ([#16326](https://github.com/aws/aws-cdk/issues/16326)) ([c6c5941](https://github.com/aws/aws-cdk/commit/c6c594159c7fbda66f40fe8666f70b6806bb2d5e)) +* **glue:** Job construct ([#12506](https://github.com/aws/aws-cdk/issues/12506)) ([fc74110](https://github.com/aws/aws-cdk/commit/fc74110ff7eae544d9cfc11b2f6779169f17d145)), closes [#12443](https://github.com/aws/aws-cdk/issues/12443) +* **lambda:** configure workdir for docker image based functions ([#16111](https://github.com/aws/aws-cdk/issues/16111)) ([b3eafc2](https://github.com/aws/aws-cdk/commit/b3eafc2dc61ed69de20196fa08a4df3c29ecc894)) +* **lambda:** use bundling docker image from ECR public for dotnet and go runtimes ([#16281](https://github.com/aws/aws-cdk/issues/16281)) ([9bbfd18](https://github.com/aws/aws-cdk/commit/9bbfd185c2383612e2be7317a091b72cc5e7a120)) +* **neptune:** add engine version 1.0.5.0 ([#16394](https://github.com/aws/aws-cdk/issues/16394)) ([deaac4a](https://github.com/aws/aws-cdk/commit/deaac4a16e957bd046f24a6c26d735fc4cf980bd)), closes [#16388](https://github.com/aws/aws-cdk/issues/16388) +* **pipeline:** allow enabling KMS key rotation for cross-region Stacks ([#16468](https://github.com/aws/aws-cdk/issues/16468)) ([2a629dd](https://github.com/aws/aws-cdk/commit/2a629dd7a86cc36c3a503bfc5957880c9edd4d49)), closes [#14381](https://github.com/aws/aws-cdk/issues/14381) +* **rds:** region replication for generated secrets ([#16497](https://github.com/aws/aws-cdk/issues/16497)) ([1e9d8be](https://github.com/aws/aws-cdk/commit/1e9d8be0a81e1f875bf8b31c701e1069bb98728e)), closes [#16480](https://github.com/aws/aws-cdk/issues/16480) +* **redshift:** manage database users and tables via cdk ([#15931](https://github.com/aws/aws-cdk/issues/15931)) ([a9d5118](https://github.com/aws/aws-cdk/commit/a9d51185a144cd4962c85227ae5b904510399fa4)), closes [#9815](https://github.com/aws/aws-cdk/issues/9815) +* **s3-deployment:** enable efs support for handling large files in lambda ([#15220](https://github.com/aws/aws-cdk/issues/15220)) ([2737119](https://github.com/aws/aws-cdk/commit/27371197a24ce6c9212fc99e120c5d77fa08065e)) +* **sns:** adding support for firehose subscription protocol ([#15764](https://github.com/aws/aws-cdk/issues/15764)) ([18aff6b](https://github.com/aws/aws-cdk/commit/18aff6b4c0a5e17c64685ac384b243c16cd910f1)) +* **stepfunctions-tasks:** support Associate Workflow Executions on StepFunctionsStartExecution via associateWithParent property ([#16475](https://github.com/aws/aws-cdk/issues/16475)) ([7d3b90b](https://github.com/aws/aws-cdk/commit/7d3b90b2097aa9b7170a77befcee5822d5d0c3e7)), closes [#14778](https://github.com/aws/aws-cdk/issues/14778) + + +### Bug Fixes + +* **apigatewayv2:** ApiMapping does not depend on DomainName ([#16201](https://github.com/aws/aws-cdk/issues/16201)) ([1e247d8](https://github.com/aws/aws-cdk/commit/1e247d89adbc09ff79b87753fcd78b238a6752e8)), closes [#15464](https://github.com/aws/aws-cdk/issues/15464) +* **cloudformation-diff:** cdk diff not picking up differences if old/new value is in format n.n.n ([#16050](https://github.com/aws/aws-cdk/issues/16050)) ([38426c9](https://github.com/aws/aws-cdk/commit/38426c985d5e0713bbbf14fa639520eca6294124)), closes [#15935](https://github.com/aws/aws-cdk/issues/15935) +* **config:** the IGW mapping to correct resource type ([#16464](https://github.com/aws/aws-cdk/issues/16464)) ([23d9b6a](https://github.com/aws/aws-cdk/commit/23d9b6a7d5b213e4a1ba4a71984e8e19e3657bd7)), closes [#16463](https://github.com/aws/aws-cdk/issues/16463) +* **core:** asset hash of symlinked dir is wrong ([#16429](https://github.com/aws/aws-cdk/issues/16429)) ([36ff738](https://github.com/aws/aws-cdk/commit/36ff73809a37998e15176cb8815c118e7ea0c295)) +* **ec2:** set proper role for --role argument of cfn-init ([#16503](https://github.com/aws/aws-cdk/issues/16503)) ([cdbd65d](https://github.com/aws/aws-cdk/commit/cdbd65dc525147810650b4c32d48664a38abede1)), closes [#16501](https://github.com/aws/aws-cdk/issues/16501) +* **logs:** log retention fails with OperationAbortedException ([#16083](https://github.com/aws/aws-cdk/issues/16083)) ([3e9f04d](https://github.com/aws/aws-cdk/commit/3e9f04dbbd7aadb8ab4394fefd6281f1d6d30fe0)), closes [aws#15709](https://github.com/aws/aws/issues/15709) +* **route53resolver:** FirewallDomainList throws with wildcard domains ([#16538](https://github.com/aws/aws-cdk/issues/16538)) ([643e5ee](https://github.com/aws/aws-cdk/commit/643e5ee519095968a758942220f1e3a6c20f54b3)), closes [#16527](https://github.com/aws/aws-cdk/issues/16527) +* **SSM API docs:** Typo `SecretString` -> `SecureString` and note how SecureStrings cannot be created via CDK ([#16228](https://github.com/aws/aws-cdk/issues/16228)) ([950e875](https://github.com/aws/aws-cdk/commit/950e875bfb431c051b5ee2fd405aaf7f2b47bfeb)) + ## [1.123.0](https://github.com/aws/aws-cdk/compare/v1.122.0...v1.123.0) (2021-09-16) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8c85b5a2ce259..cc425a73c7d0f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,9 +16,9 @@ let us know if it's not up-to-date (even better, submit a PR with your correcti - [Getting Started](#getting-started) - [Pull Requests](#pull-requests) - [Step 1: Find something to work on](#step-1-find-something-to-work-on) - - [Step 2: Design (optional)](#step-2-design-optional) + - [Step 2: Design (optional)](#step-2-design) - [Step 3: Work your Magic](#step-3-work-your-magic) - - [Step 4: Pull Request](#step-5-pull-request) + - [Step 4: Pull Request](#step-4-pull-request) - [Step 5: Merge](#step-5-merge) - [Breaking Changes](#breaking-changes) - [Documentation](#documentation) @@ -602,7 +602,7 @@ The following linters are used: #### eslint -All packages in the repo use a standard base configuration found at [eslintrc.js](tools/cdk-build-tools/config/eslintrc.js). +All packages in the repo use a standard base configuration found at [eslintrc.js](tools/@aws-cdk/cdk-build-tools/config/eslintrc.js). This can be customized for any package by modifying the `.eslintrc` file found at its root. If you're using the VS Code and would like to see eslint violations on it, install the [eslint @@ -780,7 +780,7 @@ the feature flag. A couple of [jest helper methods] are available for use with unit tests. These help run unit tests that test behaviour when flags are enabled or disabled in the two major versions. -[jest helper methods]: https://github.com/aws/aws-cdk/blob/master/tools/cdk-build-tools/lib/feature-flag.ts +[jest helper methods]: https://github.com/aws/aws-cdk/blob/master/tools/@aws-cdk/cdk-build-tools/lib/feature-flag.ts ## Versioning and Release diff --git a/buildspec-pr.yaml b/buildspec-pr.yaml index 3d6ee87c8d1ff..647b78849b3e8 100644 --- a/buildspec-pr.yaml +++ b/buildspec-pr.yaml @@ -12,6 +12,10 @@ phases: # Install yarn if it wasn't already present in the image - yarn --version || npm -g install yarn + + # Packing the mono-libraries (monocdk & aws-cdk-lib) can cause + # memory errors. Increasing this value allows our build to more consistently succeed + - (command -v sysctl || yum install -y procps-ng) && /sbin/sysctl -w vm.max_map_count=2251954 build: commands: - /bin/bash ./build.sh --extract diff --git a/buildspec.yaml b/buildspec.yaml index 3f2bb4e7e1102..0fc990a17c805 100644 --- a/buildspec.yaml +++ b/buildspec.yaml @@ -12,6 +12,10 @@ phases: # Install yarn if it wasn't already present in the image - yarn --version || npm -g install yarn + + # Packing the mono-libraries (monocdk & aws-cdk-lib) can cause + # memory errors. Increasing this value allows our build to more consistently succeed + - /sbin/sysctl -w vm.max_map_count=2251954 build: commands: - 'if ${BUMP_CANDIDATE:-false}; then /bin/bash ./scripts/bump-candidate.sh; fi' diff --git a/bump.sh b/bump.sh index b3c04198b50d3..597cfa8e15489 100755 --- a/bump.sh +++ b/bump.sh @@ -18,6 +18,6 @@ cd ${scriptdir} yarn install --frozen-lockfile if [[ "${LEGACY_BUMP:-}" == "" ]]; then # if we're using 'cdk-release' for the bump, build that package, including all of its dependencies - npx lerna run build --include-dependencies --scope cdk-release + npx lerna run build --include-dependencies --scope @aws-cdk/cdk-release fi ${scriptdir}/scripts/bump.js ${1:-minor} diff --git a/docs/CLOUDFORMATION.md b/docs/CLOUDFORMATION.md new file mode 100644 index 0000000000000..726ec4e423ab5 --- /dev/null +++ b/docs/CLOUDFORMATION.md @@ -0,0 +1,188 @@ +# CloudFormation internals + +This is documenting CloudFormation internals, that may come in useful when developing +custom resources, working on the CLI or debugging CloudFormation operations. + +If you are a user of the CDK, you do not need to read this (except maybe out of interest). + +## CloudFormation stack lifecycle + +This shows the states a CloudFormation stack goes through in its lifetime. + +For the `_IN_PROGRESS` states, the letter `[C,U,D]` indicates whether in that +state resource `Creates`, `Updates` or `Deletes` are performed. + +`GetTemplate` will return: + +- For `Creates`: the template that we are creating. During rollback of a `Create`, it + will show the template that failed to create. +- For `Updates`: during the roll-forward it will return the template we are updating + to. During rollback, it will show the template we are rolling back to. + +```text + ╔══════════════════╗ + β•‘ β•‘ + β•‘ ║──────────────────┐ + β•‘ β•‘ β–Ό + β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ β”‚ β”‚ + β”‚ β”‚ REVIEW_IN_PROGRESS β”‚ + β”‚ β”‚ β”‚ + β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ β”‚ + β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β–Ό + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” ╔════════════════════╗ + β”‚ β”‚ β”‚ β”‚ β•‘ β•‘ + β”‚ CREATE_IN_PROGRESS │─────▢│ROLLBACK_IN_PROGRESS │──┬───▢║ CREATE_FAILED β•‘ + β”‚ [C] β”‚ β”‚ [D] β”‚ β”‚ β•‘ β•‘ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• + β”‚ β–Ό + β”‚ ╔════════════════════╗ + β”‚ β•‘ β•‘ + β”‚ β•‘ ROLLBACK_FAILED β•‘ + β”‚ β•‘ β•‘ + β–Ό β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• + ╔═════════════════════════╗ + β•‘ CREATE_COMPLETE β•‘ +β”Œβ”€β”€β•‘ UPDATE_COMPLETE ║◀─────────────────────────────────┬─────────────────┐ +β”‚ β•‘UPDATE_ROLLBACK_COMPLETE β•‘ β”‚ β”‚ +β”‚ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β–Ό β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ β”‚ β”‚ UPDATE_COMPLETE_ β”‚ β”‚ +β”‚ β”‚ UPDATE_IN_PROGRESS │─────────────────────────▢│CLEANUP_IN_PROGRESS β”‚ β”‚ +β”‚ β”‚ [C,U] β”‚ β”‚ [D] β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β—€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ +β”‚ β”‚ β–Ό β”‚ β”‚ +β”‚ β”‚ ╔════════════════════╗ β”‚ β”‚ +β”‚ β”‚ β•‘ (no-rollback) β•‘ β”‚ β”‚ +β”‚ β”‚ β•‘ UPDATE_FAILED β•‘β”€β”€β”˜ β”‚ +β”‚ β”‚ β•‘ β•‘ β”‚ +β”‚ β”‚ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β–Ό β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ UPDATE_ROLLBACK_ β”‚ β”‚ UPDATE_ROLLBACK_COMPLETE_ β”‚ β”‚ +β”‚ β”‚ IN_PROGRESS │────────────────────▢│ CLEANUP_IN_PROGRESS β”‚β”€β”€β”˜ +β”‚ β”‚ [U] β”‚ β”‚ [D] β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +β”‚ β”‚ β–² +β”‚ β–Ό β”‚ +β”‚ ╔════════════════════╗ +β”‚ β•‘ UPDATE_ROLLBACK_ β•‘ +β”‚ β•‘ FAILED β•‘ +β”‚ β•‘ β•‘ +β”‚ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• +β”‚ β”‚ +β”‚ β”‚ +β”‚ β–Ό +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” ╔════════════════════╗ +β”‚ β”‚ DELETE_IN_PROGRESS β”‚ β•‘ β•‘ +└───▢│ [D] │───────▢║ DELETE_FAILED β•‘ + β”‚ β”‚ β•‘ β•‘ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• + β”‚ + β”‚ + β–Ό + ╔════════════════════╗ + β•‘ β•‘ + β•‘ DELETE_COMPLETE β•‘ + β•‘ β•‘ + β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• +``` + +### Rollbacks + +When rolling back: + +* `ROLLBACK_IN_PROGRESS` will exclusively do deletes. +* `UPDATE_ROLLBACK_IN_PROGRESS` will do updates, + `UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS` will do deletes, including for + resources that got created in this update. + +## Resource lifecycle + +Below shows the lifecycle of single resource. + +Of note is that `CREATE_FAILED` and `UPDATE_FAILED` are not stable states. They will +be immediately followed by delete and an update back to the original state, respectively. + +(We have yet to research what happens when a rollback update fails). + +```text + ╔════════════════════════╗ + β•‘ β•‘ + β•‘ β•‘ + β•‘ β•‘ + β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• + β”‚ + β”‚ + β–Ό + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ β”‚ β”‚ β”‚ + β”‚ CREATE_IN_PROGRESS │─────────────▢│ CREATE_FAILED │──┐ + β”‚ β”‚ β”‚ β”‚ β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ + β”‚ β”‚ + β”‚ β”‚ + β–Ό β”‚ + ╔═════════════════════════╗ β”‚ + β•‘ β•‘ β”‚ + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β•‘ CREATE_COMPLETE β•‘ β”‚ + β”‚ β•‘ β•‘ β”‚ + β”‚ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• β”‚ + β”‚ β”‚ β”‚ + β”‚ β”‚ custom resource β”‚ + β”‚ β–Ό rollback β”‚ + β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β—€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ + β”‚ β”‚ β”‚ β”‚ β”‚ + β”‚ β”‚ UPDATE_IN_PROGRESS │──────────────────────┐ β”‚ β”‚ + β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ + β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ + β”‚ β”‚ β”‚ β”‚ β”‚ + β”‚ β”‚ β”‚ β”‚ β”‚ + β”‚ β–Ό β–Ό β”‚ β”‚ + β”‚ ╔═════════════════════════╗ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ + β”‚ β•‘ β•‘ β”‚ β”‚ β”‚ + β”‚ β•‘ UPDATE_COMPLETE ║◀────────│ UPDATE_FAILED β”‚ β”‚ + β”‚ β•‘ β•‘ no-op β”‚ β”‚ β”‚ + β”‚ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• rollbackβ””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ + β”‚ β”‚ β”‚ + └─────────────────────────── β”‚ + β”‚ β”‚ + β–Ό β”‚ + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ + β”‚ β”‚ β”‚ +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Άβ”‚ DELETE_IN_PROGRESS │◀───────────────────────────────────── +β”‚ β”‚ β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ β”‚ β”‚ β”‚ +β”‚ β–Ό β–Ό β–Ό β”‚ +╔═════════════════════════╗ ╔═════════════════════════╗ ╔═════════════════════════╗ β”‚ +β•‘ β•‘ β•‘ β•‘ β•‘ β•‘ β”‚ +β•‘ DELETE_FAILED β•‘ β•‘ DELETE_SKIPPED β•‘ β•‘ DELETE_COMPLETE β•‘β—€β”€β”˜ +β•‘ β•‘ β•‘ β•‘ β•‘ β•‘ +β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• +``` + +### Custom Resources + +- A custom resource is updated whenever any of its properties change. It is not + re-executed when its source code changes. +- Boolean properties are stringified. `true` and `false` in `Properties` are turned + into `"true"` and `"false"`. +- When releasing a new version of a custom resource, be aware that you may still + get properties from any of its previous versions. +- If you return a different PhysicalId from a custom resource during an Update, + CloudFormation will send a `Delete` of the previous PhysicalId during + cleanup. +- If an `Update` fails, CloudFormation will trigger a second `Update` during rollback. + The rollback update will have `ResourceProperties=OLD` and `OldResourceProperties=NEW`. \ No newline at end of file diff --git a/lerna.json b/lerna.json index 0fcae573a32ae..81738d74fb433 100644 --- a/lerna.json +++ b/lerna.json @@ -9,7 +9,9 @@ "packages/@monocdk-experiment/*", "packages/@aws-cdk/*/lambda-packages/*", "tools/*", - "scripts/script-tests" + "tools/@aws-cdk/*", + "scripts/script-tests", + "packages/individual-packages/*" ], "rejectCycles": "true", "version": "0.0.0" diff --git a/package.json b/package.json index 029b1989ea072..038642572d7b1 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "include": "dependencies/node-version" }, "scripts": { - "pkglint": "lerna --scope pkglint run build && lerna run pkglint", + "pkglint": "lerna --scope @aws-cdk/pkglint run build && lerna run pkglint", "build": "./build.sh", "pack": "./pack.sh", "compat": "./scripts/check-api-compatibility.sh", @@ -18,20 +18,18 @@ "@yarnpkg/lockfile": "^1.1.0", "conventional-changelog-cli": "^2.1.1", "fs-extra": "^9.1.0", - "graceful-fs": "^4.2.6", - "jest-junit": "^12.2.0", - "jsii-diff": "^1.34.0", - "jsii-pacmak": "^1.34.0", - "jsii-reflect": "^1.34.0", - "jsii-rosetta": "^1.34.0", + "graceful-fs": "^4.2.8", + "jest-junit": "^12.3.0", + "jsii-diff": "^1.35.0", + "jsii-pacmak": "^1.35.0", + "jsii-reflect": "^1.35.0", + "jsii-rosetta": "^1.35.0", "lerna": "^4.0.0", "patch-package": "^6.4.7", "standard-version": "^9.3.1", "typescript": "~3.9.10" }, - "tap-mocha-reporter-resolutions-comment": "should be removed or reviewed when nodeunit dependency is dropped or adjusted", "resolutions": { - "tap-mocha-reporter": "^5.0.1", "string-width": "^4.2.2" }, "repository": { @@ -66,7 +64,9 @@ "packages/@monocdk-experiment/*", "packages/@aws-cdk/*/lambda-packages/*", "tools/*", - "scripts/script-tests" + "tools/@aws-cdk/*", + "scripts/@aws-cdk/script-tests", + "packages/individual-packages/*" ], "nohoist": [ "**/jszip", @@ -182,5 +182,8 @@ "monocdk/yaml", "monocdk/yaml/**" ] + }, + "dependencies": { + "string-width": "^4.2.2" } } diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/.eslintrc.js b/packages/@aws-cdk-containers/ecs-service-extensions/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/.eslintrc.js +++ b/packages/@aws-cdk-containers/ecs-service-extensions/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/jest.config.js b/packages/@aws-cdk-containers/ecs-service-extensions/jest.config.js index 983d4635f71f4..e88b48ab04549 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/jest.config.js +++ b/packages/@aws-cdk-containers/ecs-service-extensions/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/package.json b/packages/@aws-cdk-containers/ecs-service-extensions/package.json index 0c124971b150d..3c6620d80ecbc 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/package.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/package.json @@ -36,16 +36,13 @@ "organization": true }, "license": "Apache-2.0", - "cdk-build": { - "jest": true - }, "devDependencies": { "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@aws-cdk/assert-internal": "0.0.0" }, "dependencies": { diff --git a/packages/@aws-cdk-containers/ecs-service-extensions/tsconfig.json b/packages/@aws-cdk-containers/ecs-service-extensions/tsconfig.json index b886d9b504084..124a3ce0d3346 100644 --- a/packages/@aws-cdk-containers/ecs-service-extensions/tsconfig.json +++ b/packages/@aws-cdk-containers/ecs-service-extensions/tsconfig.json @@ -92,16 +92,16 @@ "path": "../../@aws-cdk/assert" }, { - "path": "../../../tools/cdk-build-tools" + "path": "../../../tools/@aws-cdk/cdk-build-tools" }, { - "path": "../../../tools/cdk-integ-tools" + "path": "../../../tools/@aws-cdk/cdk-integ-tools" }, { - "path": "../../../tools/cfn2ts" + "path": "../../../tools/@aws-cdk/cfn2ts" }, { - "path": "../../../tools/pkglint" + "path": "../../../tools/@aws-cdk/pkglint" } ], "_generated_by_jsii_": "Generated by jsii - safe to delete, and ideally should be in .gitignore" diff --git a/packages/@aws-cdk/alexa-ask/.eslintrc.js b/packages/@aws-cdk/alexa-ask/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/alexa-ask/.eslintrc.js +++ b/packages/@aws-cdk/alexa-ask/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/alexa-ask/jest.config.js b/packages/@aws-cdk/alexa-ask/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/alexa-ask/jest.config.js +++ b/packages/@aws-cdk/alexa-ask/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/alexa-ask/package.json b/packages/@aws-cdk/alexa-ask/package.json index cf42ce0ff70cd..e773c5c1e9364 100644 --- a/packages/@aws-cdk/alexa-ask/package.json +++ b/packages/@aws-cdk/alexa-ask/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "Alexa::ASK", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -74,11 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/app-delivery/.eslintrc.js b/packages/@aws-cdk/app-delivery/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/app-delivery/.eslintrc.js +++ b/packages/@aws-cdk/app-delivery/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/app-delivery/jest.config.js b/packages/@aws-cdk/app-delivery/jest.config.js index cd664e1d069e5..34818e1593f6b 100644 --- a/packages/@aws-cdk/app-delivery/jest.config.js +++ b/packages/@aws-cdk/app-delivery/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/app-delivery/package.json b/packages/@aws-cdk/app-delivery/package.json index 9b5bb232938dd..3448885fbbe39 100644 --- a/packages/@aws-cdk/app-delivery/package.json +++ b/packages/@aws-cdk/app-delivery/package.json @@ -54,21 +54,20 @@ "@aws-cdk/aws-codepipeline-actions": "0.0.0", "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "@aws-cdk/cloud-assembly-schema": "0.0.0", "constructs": "^3.3.69" }, "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "@types/nodeunit": "^0.0.32", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", "fast-check": "^2.17.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "repository": { "type": "git", @@ -82,9 +81,6 @@ "url": "https://aws.amazon.com", "organization": true }, - "cdk-build": { - "jest": true - }, "keywords": [ "aws", "cdk" @@ -96,9 +92,9 @@ "@aws-cdk/aws-codepipeline-actions": "0.0.0", "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "@aws-cdk/cloud-assembly-schema": "0.0.0", "constructs": "^3.3.69" }, "engines": { diff --git a/packages/@aws-cdk/assert-internal/.eslintrc.js b/packages/@aws-cdk/assert-internal/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/assert-internal/.eslintrc.js +++ b/packages/@aws-cdk/assert-internal/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/assert-internal/jest.config.js b/packages/@aws-cdk/assert-internal/jest.config.js index ac8c47076506a..6a8dc8ed67646 100644 --- a/packages/@aws-cdk/assert-internal/jest.config.js +++ b/packages/@aws-cdk/assert-internal/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/assert-internal/package.json b/packages/@aws-cdk/assert-internal/package.json index 4d9ae5a6a5ec8..c8fa0b2fca84d 100644 --- a/packages/@aws-cdk/assert-internal/package.json +++ b/packages/@aws-cdk/assert-internal/package.json @@ -24,10 +24,10 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0", "ts-jest": "^26.5.6" }, "dependencies": { @@ -57,9 +57,6 @@ }, "stability": "experimental", "maturity": "experimental", - "cdk-build": { - "jest": true - }, "publishConfig": { "tag": "latest" }, diff --git a/packages/@aws-cdk/assert/.eslintrc.js b/packages/@aws-cdk/assert/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/assert/.eslintrc.js +++ b/packages/@aws-cdk/assert/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/assert/jest.config.js b/packages/@aws-cdk/assert/jest.config.js index 582b2b3040eb0..06408ea0581b8 100644 --- a/packages/@aws-cdk/assert/jest.config.js +++ b/packages/@aws-cdk/assert/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/assert/package.json b/packages/@aws-cdk/assert/package.json index a4366c4372345..156a2b583f02c 100644 --- a/packages/@aws-cdk/assert/package.json +++ b/packages/@aws-cdk/assert/package.json @@ -17,7 +17,6 @@ "build+test+extract": "yarn build+test" }, "cdk-build": { - "jest": true, "pre": [ "./clone.sh" ], @@ -35,13 +34,13 @@ }, "license": "Apache-2.0", "devDependencies": { - "aws-cdk-migration": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", + "aws-cdk-migration": "0.0.0", "constructs": "^3.3.69", "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0", "ts-jest": "^26.5.6" }, "dependencies": { diff --git a/packages/@aws-cdk/assertions/.eslintrc.js b/packages/@aws-cdk/assertions/.eslintrc.js index 7d73af332f5d8..274069c3dd9e0 100644 --- a/packages/@aws-cdk/assertions/.eslintrc.js +++ b/packages/@aws-cdk/assertions/.eslintrc.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = { ...baseConfig, diff --git a/packages/@aws-cdk/assertions/jest.config.js b/packages/@aws-cdk/assertions/jest.config.js index e2cea817aefd7..50cd7fd05c74f 100644 --- a/packages/@aws-cdk/assertions/jest.config.js +++ b/packages/@aws-cdk/assertions/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/assertions/package.json b/packages/@aws-cdk/assertions/package.json index 952063b3423f6..e3c0612bf486d 100644 --- a/packages/@aws-cdk/assertions/package.json +++ b/packages/@aws-cdk/assertions/package.json @@ -49,7 +49,6 @@ "projectReferences": true }, "cdk-build": { - "jest": true, "pre": [ "./vendor-in.sh" ] @@ -61,12 +60,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/cfnspec": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", "constructs": "^3.3.69", "jest": "^26.6.3", - "pkglint": "0.0.0", "ts-jest": "^26.5.6" }, "dependencies": { @@ -77,7 +76,7 @@ "constructs": "^3.3.69", "diff": "^5.0.0", "fast-deep-equal": "^3.1.3", - "string-width": "^4.2.2", + "string-width": "^4.2.3", "table": "^6.7.1" }, "peerDependencies": { @@ -108,7 +107,18 @@ "node": ">= 10.13.0 <13 || >=13.7.0" }, "nozem": { - "ostools": ["dirname", "cd", "bash", "rm", "xargs", "sed", "mkdir", "rsync", "cat", "find"], + "ostools": [ + "dirname", + "cd", + "bash", + "rm", + "xargs", + "sed", + "mkdir", + "rsync", + "cat", + "find" + ], "additionalDirs": [ "../cfnspec/lib", "ARTIFACTS:../cfnspec/spec", diff --git a/packages/@aws-cdk/assets/.eslintrc.js b/packages/@aws-cdk/assets/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/assets/.eslintrc.js +++ b/packages/@aws-cdk/assets/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/assets/jest.config.js b/packages/@aws-cdk/assets/jest.config.js index f5d5c4c8ad18f..34818e1593f6b 100644 --- a/packages/@aws-cdk/assets/jest.config.js +++ b/packages/@aws-cdk/assets/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); -module.exports = baseConfig; \ No newline at end of file +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/assets/package.json b/packages/@aws-cdk/assets/package.json index df31bf21db5e9..7b77655ea3a16 100644 --- a/packages/@aws-cdk/assets/package.json +++ b/packages/@aws-cdk/assets/package.json @@ -54,8 +54,7 @@ "cdk-build": { "pre": [ "rm -rf test/fs/fixtures && cd test/fs && tar -xzvf fixtures.tar.gz" - ], - "jest": true + ] }, "keywords": [ "aws", @@ -70,16 +69,16 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", "@types/sinon": "^9.0.11", "aws-cdk": "0.0.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0", "sinon": "^9.2.4", - "ts-mock-imports": "^1.3.7", - "@aws-cdk/assert-internal": "0.0.0" + "ts-mock-imports": "^1.3.7" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-accessanalyzer/.eslintrc.js b/packages/@aws-cdk/aws-accessanalyzer/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-accessanalyzer/.eslintrc.js +++ b/packages/@aws-cdk/aws-accessanalyzer/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-accessanalyzer/jest.config.js b/packages/@aws-cdk/aws-accessanalyzer/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-accessanalyzer/jest.config.js +++ b/packages/@aws-cdk/aws-accessanalyzer/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-accessanalyzer/package.json b/packages/@aws-cdk/aws-accessanalyzer/package.json index ef5d378f88205..d1938b9d354e5 100644 --- a/packages/@aws-cdk/aws-accessanalyzer/package.json +++ b/packages/@aws-cdk/aws-accessanalyzer/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::AccessAnalyzer", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-acmpca/.eslintrc.js b/packages/@aws-cdk/aws-acmpca/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-acmpca/.eslintrc.js +++ b/packages/@aws-cdk/aws-acmpca/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-acmpca/jest.config.js b/packages/@aws-cdk/aws-acmpca/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-acmpca/jest.config.js +++ b/packages/@aws-cdk/aws-acmpca/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-acmpca/package.json b/packages/@aws-cdk/aws-acmpca/package.json index 771c64edeb0a8..a3478244753f9 100644 --- a/packages/@aws-cdk/aws-acmpca/package.json +++ b/packages/@aws-cdk/aws-acmpca/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::ACMPCA", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-amazonmq/.eslintrc.js b/packages/@aws-cdk/aws-amazonmq/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-amazonmq/.eslintrc.js +++ b/packages/@aws-cdk/aws-amazonmq/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-amazonmq/jest.config.js b/packages/@aws-cdk/aws-amazonmq/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-amazonmq/jest.config.js +++ b/packages/@aws-cdk/aws-amazonmq/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-amazonmq/package.json b/packages/@aws-cdk/aws-amazonmq/package.json index 393ef14b15326..fd3fd5946e6f3 100644 --- a/packages/@aws-cdk/aws-amazonmq/package.json +++ b/packages/@aws-cdk/aws-amazonmq/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::AmazonMQ", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -74,11 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-amplify/.eslintrc.js b/packages/@aws-cdk/aws-amplify/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-amplify/.eslintrc.js +++ b/packages/@aws-cdk/aws-amplify/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-amplify/jest.config.js b/packages/@aws-cdk/aws-amplify/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-amplify/jest.config.js +++ b/packages/@aws-cdk/aws-amplify/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-amplify/package.json b/packages/@aws-cdk/aws-amplify/package.json index dad425ea592f2..13bbcc0ec61d4 100644 --- a/packages/@aws-cdk/aws-amplify/package.json +++ b/packages/@aws-cdk/aws-amplify/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Amplify", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -76,26 +75,26 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { - "@aws-cdk/aws-iam": "0.0.0", - "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-codebuild": "0.0.0", "@aws-cdk/aws-codecommit": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "peerDependencies": { - "@aws-cdk/aws-iam": "0.0.0", - "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-codebuild": "0.0.0", "@aws-cdk/aws-codecommit": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" diff --git a/packages/@aws-cdk/aws-apigateway/.eslintrc.js b/packages/@aws-cdk/aws-apigateway/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-apigateway/.eslintrc.js +++ b/packages/@aws-cdk/aws-apigateway/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-apigateway/jest.config.js b/packages/@aws-cdk/aws-apigateway/jest.config.js index 82c5d0bb93666..3403249680be2 100644 --- a/packages/@aws-cdk/aws-apigateway/jest.config.js +++ b/packages/@aws-cdk/aws-apigateway/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/aws-apigateway/package.json b/packages/@aws-cdk/aws-apigateway/package.json index 1b5673c9cf66d..2c1a9ff0d7944 100644 --- a/packages/@aws-cdk/aws-apigateway/package.json +++ b/packages/@aws-cdk/aws-apigateway/package.json @@ -57,8 +57,7 @@ "cloudformation": "AWS::ApiGateway", "env": { "AWSLINT_BASE_CONSTRUCT": true - }, - "jest": true + } }, "keywords": [ "aws", @@ -73,12 +72,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", @@ -326,6 +325,7 @@ "attribute-tag:@aws-cdk/aws-apigateway.LambdaRestApi.restApiName", "from-method:@aws-cdk/aws-apigateway.Stage", "resource-attribute:@aws-cdk/aws-apigateway.ApiKey.apiKeyId", + "resource-attribute:@aws-cdk/aws-apigateway.GatewayResponse.gatewayResponseId", "resource-attribute:@aws-cdk/aws-apigateway.RateLimitedApiKey.apiKeyId" ] }, diff --git a/packages/@aws-cdk/aws-apigateway/test/usage-plan.test.ts b/packages/@aws-cdk/aws-apigateway/test/usage-plan.test.ts index 2cb6e4ed48ed2..195e17a0b7fbf 100644 --- a/packages/@aws-cdk/aws-apigateway/test/usage-plan.test.ts +++ b/packages/@aws-cdk/aws-apigateway/test/usage-plan.test.ts @@ -2,7 +2,7 @@ import '@aws-cdk/assert-internal/jest'; import { ResourcePart } from '@aws-cdk/assert-internal'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as apigateway from '../lib'; const RESOURCE_TYPE = 'AWS::ApiGateway::UsagePlan'; diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/.eslintrc.js b/packages/@aws-cdk/aws-apigatewayv2-authorizers/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/.eslintrc.js +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/jest.config.js b/packages/@aws-cdk/aws-apigatewayv2-authorizers/jest.config.js index b5ccdecc15ee0..9f9ccac177e1b 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/jest.config.js +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { @@ -7,4 +7,4 @@ module.exports = { branches: 70, }, }, -}; \ No newline at end of file +}; diff --git a/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json b/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json index 8466c95ddc9da..cc9588ca09adc 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2-authorizers/package.json @@ -55,7 +55,6 @@ "build+test+extract": "yarn build+test && yarn rosetta:extract" }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -74,13 +73,13 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", - "@types/jest": "^26.0.24", - "@types/aws-lambda": "^8.10.79", "@aws-cdk/aws-apigatewayv2-integrations": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/aws-lambda": "^8.10.83", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-apigatewayv2": "0.0.0", diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/.eslintrc.js b/packages/@aws-cdk/aws-apigatewayv2-integrations/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/.eslintrc.js +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/jest.config.js b/packages/@aws-cdk/aws-apigatewayv2-integrations/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/jest.config.js +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json b/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json index f857a94bc93f4..a950d542429e0 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json @@ -53,7 +53,6 @@ "build+test+extract": "yarn build+test && yarn rosetta:extract" }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -72,10 +71,10 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-apigatewayv2": "0.0.0", diff --git a/packages/@aws-cdk/aws-apigatewayv2/.eslintrc.js b/packages/@aws-cdk/aws-apigatewayv2/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/.eslintrc.js +++ b/packages/@aws-cdk/aws-apigatewayv2/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-apigatewayv2/jest.config.js b/packages/@aws-cdk/aws-apigatewayv2/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/jest.config.js +++ b/packages/@aws-cdk/aws-apigatewayv2/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-apigatewayv2/package.json b/packages/@aws-cdk/aws-apigatewayv2/package.json index d0f2d3b6288c2..349c1ab9517cf 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2/package.json @@ -60,7 +60,6 @@ }, "cdk-build": { "cloudformation": "AWS::ApiGatewayV2", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -79,25 +78,25 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", + "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", - "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "peerDependencies": { - "@aws-cdk/aws-ec2": "0.0.0", - "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-certificatemanager": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, diff --git a/packages/@aws-cdk/aws-appconfig/.eslintrc.js b/packages/@aws-cdk/aws-appconfig/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-appconfig/.eslintrc.js +++ b/packages/@aws-cdk/aws-appconfig/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-appconfig/jest.config.js b/packages/@aws-cdk/aws-appconfig/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-appconfig/jest.config.js +++ b/packages/@aws-cdk/aws-appconfig/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-appconfig/package.json b/packages/@aws-cdk/aws-appconfig/package.json index 87877e48cadd7..afa652c138049 100644 --- a/packages/@aws-cdk/aws-appconfig/package.json +++ b/packages/@aws-cdk/aws-appconfig/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::AppConfig", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-appflow/.eslintrc.js b/packages/@aws-cdk/aws-appflow/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-appflow/.eslintrc.js +++ b/packages/@aws-cdk/aws-appflow/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-appflow/jest.config.js b/packages/@aws-cdk/aws-appflow/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-appflow/jest.config.js +++ b/packages/@aws-cdk/aws-appflow/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-appflow/package.json b/packages/@aws-cdk/aws-appflow/package.json index 3c1164cb36e44..3e5d52954046c 100644 --- a/packages/@aws-cdk/aws-appflow/package.json +++ b/packages/@aws-cdk/aws-appflow/package.json @@ -55,8 +55,7 @@ "build+test+extract": "yarn build+test && yarn rosetta:extract" }, "cdk-build": { - "cloudformation": "AWS::AppFlow", - "jest": true + "cloudformation": "AWS::AppFlow" }, "keywords": [ "aws", @@ -72,11 +71,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-appintegrations/.eslintrc.js b/packages/@aws-cdk/aws-appintegrations/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-appintegrations/.eslintrc.js +++ b/packages/@aws-cdk/aws-appintegrations/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-appintegrations/jest.config.js b/packages/@aws-cdk/aws-appintegrations/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-appintegrations/jest.config.js +++ b/packages/@aws-cdk/aws-appintegrations/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-appintegrations/package.json b/packages/@aws-cdk/aws-appintegrations/package.json index df834c9675083..d0129f5818d65 100644 --- a/packages/@aws-cdk/aws-appintegrations/package.json +++ b/packages/@aws-cdk/aws-appintegrations/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::AppIntegrations", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-applicationautoscaling/.eslintrc.js b/packages/@aws-cdk/aws-applicationautoscaling/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/.eslintrc.js +++ b/packages/@aws-cdk/aws-applicationautoscaling/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-applicationautoscaling/jest.config.js b/packages/@aws-cdk/aws-applicationautoscaling/jest.config.js index 3eef7ba398c07..211d217076e38 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/jest.config.js +++ b/packages/@aws-cdk/aws-applicationautoscaling/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/aws-applicationautoscaling/package.json b/packages/@aws-cdk/aws-applicationautoscaling/package.json index 5026578a5d6d0..f1bf7ba4c5d95 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/package.json +++ b/packages/@aws-cdk/aws-applicationautoscaling/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::ApplicationAutoScaling", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,13 +72,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", "fast-check": "^2.17.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-autoscaling-common": "0.0.0", diff --git a/packages/@aws-cdk/aws-applicationinsights/.eslintrc.js b/packages/@aws-cdk/aws-applicationinsights/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-applicationinsights/.eslintrc.js +++ b/packages/@aws-cdk/aws-applicationinsights/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-applicationinsights/jest.config.js b/packages/@aws-cdk/aws-applicationinsights/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-applicationinsights/jest.config.js +++ b/packages/@aws-cdk/aws-applicationinsights/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-applicationinsights/package.json b/packages/@aws-cdk/aws-applicationinsights/package.json index 3b0b998051313..28045bdba0613 100644 --- a/packages/@aws-cdk/aws-applicationinsights/package.json +++ b/packages/@aws-cdk/aws-applicationinsights/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::ApplicationInsights", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-appmesh/.eslintrc.js b/packages/@aws-cdk/aws-appmesh/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-appmesh/.eslintrc.js +++ b/packages/@aws-cdk/aws-appmesh/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-appmesh/jest.config.js b/packages/@aws-cdk/aws-appmesh/jest.config.js index cd664e1d069e5..34818e1593f6b 100644 --- a/packages/@aws-cdk/aws-appmesh/jest.config.js +++ b/packages/@aws-cdk/aws-appmesh/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-appmesh/package.json b/packages/@aws-cdk/aws-appmesh/package.json index d67eeb9a0be40..989db40a2844f 100644 --- a/packages/@aws-cdk/aws-appmesh/package.json +++ b/packages/@aws-cdk/aws-appmesh/package.json @@ -58,8 +58,7 @@ "cloudformation": "AWS::AppMesh", "env": { "AWSLINT_BASE_CONSTRUCT": true - }, - "jest": true + } }, "nyc": { "statements": 75 @@ -78,13 +77,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-acmpca": "0.0.0", diff --git a/packages/@aws-cdk/aws-apprunner/.eslintrc.js b/packages/@aws-cdk/aws-apprunner/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-apprunner/.eslintrc.js +++ b/packages/@aws-cdk/aws-apprunner/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-apprunner/README.md b/packages/@aws-cdk/aws-apprunner/README.md index f6619f99bd149..e9c01f631d4b8 100644 --- a/packages/@aws-cdk/aws-apprunner/README.md +++ b/packages/@aws-cdk/aws-apprunner/README.md @@ -9,6 +9,14 @@ > > [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib +![cdk-constructs: Experimental](https://img.shields.io/badge/cdk--constructs-experimental-important.svg?style=for-the-badge) + +> The APIs of higher level constructs in this module are experimental and under active development. +> They are subject to non-backward compatible changes or removal in any future version. These are +> not subject to the [Semantic Versioning](https://semver.org/) model and breaking changes will be +> announced in the release notes. This means that while you may use them, you may need to update +> your source code when upgrading to a newer version of this package. + --- @@ -18,3 +26,108 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aw ```ts import apprunner = require('@aws-cdk/aws-apprunner'); ``` + +## Introduction + +AWS App Runner is a fully managed service that makes it easy for developers to quickly deploy containerized web applications and APIs, at scale and with no prior infrastructure experience required. Start with your source code or a container image. App Runner automatically builds and deploys the web application and load balances traffic with encryption. App Runner also scales up or down automatically to meet your traffic needs. With App Runner, rather than thinking about servers or scaling, you have more time to focus on your applications. + +## Service + +The `Service` construct allows you to create AWS App Runner services with `ECR Public`, `ECR` or `Github` with the `source` property in the following scenarios: + +- `Source.fromEcr()` - To define the source repository from `ECR`. +- `Source.fromEcrPublic()` - To define the source repository from `ECR Public`. +- `Source.fromGitHub()` - To define the source repository from the `Github repository`. +- `Source.fromAsset()` - To define the source from local asset directory. + + +## ECR Public + +To create a `Service` with ECR Public: + +```ts +new Service(stack, 'Service', { + source: Source.fromEcrPublic({ + imageConfiguration: { port: 8000 }, + imageIdentifier: 'public.ecr.aws/aws-containers/hello-app-runner:latest', + }), +}); +``` + +## ECR + +To create a `Service` from an existing ECR repository: + +```ts +new Service(stack, 'Service', { + source: Source.fromEcr({ + imageConfiguration: { port: 80 }, + repository: ecr.Repository.fromRepositoryName(stack, 'NginxRepository', 'nginx'), + tag: 'latest', + }), +}); +``` + +To create a `Service` from local docker image asset directory built and pushed to Amazon ECR: + +```ts +const imageAsset = new assets.DockerImageAsset(stack, 'ImageAssets', { + directory: path.join(__dirname, './docker.assets'), +}); +new Service(stack, 'Service', { + source: Source.fromAsset({ + imageConfiguration: { port: 8000 }, + asset: imageAsset, + }), +}); +``` + +## GitHub + +To create a `Service` from the GitHub repository, you need to specify an existing App Runner `Connection`. + +See [Managing App Runner connections](https://docs.aws.amazon.com/apprunner/latest/dg/manage-connections.html) for more details. + +```ts +new Service(stack, 'Service', { + source: Source.fromGitHub({ + repositoryUrl: 'https://github.com/aws-containers/hello-app-runner', + branch: 'main', + configurationSource: ConfigurationSourceType.REPOSITORY, + connection: GitHubConnection.fromConnectionArn('CONNECTION_ARN'), + }), +}); +``` + +Use `codeConfigurationValues` to override configuration values with the `API` configuration source type. + +```ts +new Service(stack, 'Service', { + source: Source.fromGitHub({ + repositoryUrl: 'https://github.com/aws-containers/hello-app-runner', + branch: 'main', + configurationSource: ConfigurationSourceType.API, + codeConfigurationValues: { + runtime: Runtime.PYTHON_3, + port: '8000', + startCommand: 'python app.py', + buildCommand: 'yum install -y pycairo && pip install -r requirements.txt', + }, + connection: GitHubConnection.fromConnectionArn('CONNECTION_ARN'), + }), +}); +``` + + +## IAM Roles + +You are allowed to define `instanceRole` and `accessRole` for the `Service`. + +`instanceRole` - The IAM role that provides permissions to your App Runner service. These are permissions that +your code needs when it calls any AWS APIs. + +`accessRole` - The IAM role that grants the App Runner service access to a source repository. It's required for +ECR image repositories (but not for ECR Public repositories). If not defined, a new access role will be generated +when required. + +See [App Runner IAM Roles](https://docs.aws.amazon.com/apprunner/latest/dg/security_iam_service-with-iam.html#security_iam_service-with-iam-roles) for more details. diff --git a/packages/@aws-cdk/aws-apprunner/jest.config.js b/packages/@aws-cdk/aws-apprunner/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-apprunner/jest.config.js +++ b/packages/@aws-cdk/aws-apprunner/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-apprunner/lib/index.ts b/packages/@aws-cdk/aws-apprunner/lib/index.ts index bebaa074b0dd0..1aedf192186b1 100644 --- a/packages/@aws-cdk/aws-apprunner/lib/index.ts +++ b/packages/@aws-cdk/aws-apprunner/lib/index.ts @@ -1,2 +1,3 @@ // AWS::AppRunner CloudFormation Resources: export * from './apprunner.generated'; +export * from './service'; diff --git a/packages/@aws-cdk/aws-apprunner/lib/service.ts b/packages/@aws-cdk/aws-apprunner/lib/service.ts new file mode 100644 index 0000000000000..32e5151da9cbd --- /dev/null +++ b/packages/@aws-cdk/aws-apprunner/lib/service.ts @@ -0,0 +1,831 @@ +import * as ecr from '@aws-cdk/aws-ecr'; +import * as assets from '@aws-cdk/aws-ecr-assets'; +import * as iam from '@aws-cdk/aws-iam'; +import * as cdk from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import { CfnService } from './apprunner.generated'; + +/** + * The image repository types + */ +export enum ImageRepositoryType { + /** + * Amazon ECR Public + */ + ECR_PUBLIC = 'ECR_PUBLIC', + + /** + * Amazon ECR + */ + ECR = 'ECR', +} + +/** + * The number of CPU units reserved for each instance of your App Runner service. + * + */ +export class Cpu { + /** + * 1 vCPU + */ + public static readonly ONE_VCPU = Cpu.of('1 vCPU') + + /** + * 2 vCPU + */ + public static readonly TWO_VCPU = Cpu.of('2 vCPU') + + /** + * Custom CPU unit + * + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-instanceconfiguration.html#cfn-apprunner-service-instanceconfiguration-cpu + * + * @param unit custom CPU unit + */ + public static of(unit: string) { return new Cpu(unit); } + + /** + * + * @param unit The unit of CPU. + */ + private constructor(public readonly unit: string) {} +} + + +/** + * The amount of memory reserved for each instance of your App Runner service. + */ +export class Memory { + /** + * 2 GB(for 1 vCPU) + */ + public static readonly TWO_GB = Memory.of('2 GB') + + /** + * 3 GB(for 1 vCPU) + */ + public static readonly THREE_GB = Memory.of('3 GB') + + /** + * 4 GB(for 1 or 2 vCPU) + */ + public static readonly FOUR_GB = Memory.of('4 GB') + + /** + * Custom Memory unit + * + * @param unit custom Memory unit + * + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-instanceconfiguration.html#cfn-apprunner-service-instanceconfiguration-memory + */ + public static of(unit: string) { return new Memory(unit); } + + /** + * + * @param unit The unit of memory. + */ + private constructor(public readonly unit: string) { } +} + +/** + * The code runtimes + */ +export class Runtime { + /** + * NodeJS 12 + */ + public static readonly NODEJS_12 = Runtime.of('NODEJS_12') + + /** + * Python 3 + */ + public static readonly PYTHON_3 = Runtime.of('PYTHON_3') + + /** + * Other runtimes + * + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-codeconfigurationvalues.html#cfn-apprunner-service-codeconfigurationvalues-runtime for all available runtimes. + * + * @param name runtime name + * + */ + public static of(name: string) { return new Runtime(name); } + + /** + * + * @param name The runtime name. + */ + private constructor(public readonly name: string) { } +} + + +/** + * Result of binding `Source` into a `Service`. + */ +export interface SourceConfig { + /** + * The image repository configuration (mutually exclusive with `codeRepository`). + * + * @default - no image repository. + */ + readonly imageRepository?: ImageRepository; + + /** + * The ECR repository (required to grant the pull privileges for the iam role). + * + * @default - no ECR repository. + */ + readonly ecrRepository?: ecr.IRepository; + + /** + * The code repository configuration (mutually exclusive with `imageRepository`). + * + * @default - no code repository. + */ + readonly codeRepository?: CodeRepositoryProps; +} + +/** + * Properties of the Github repository for `Source.fromGitHub()` + */ +export interface GithubRepositoryProps { + /** + * The code configuration values. Will be ignored if configurationSource is `REPOSITORY`. + * @default - no values will be passed. The `apprunner.yaml` from the github reopsitory will be used instead. + */ + readonly codeConfigurationValues?: CodeConfigurationValues; + + /** + * The source of the App Runner configuration. + */ + readonly configurationSource: ConfigurationSourceType; + + /** + * The location of the repository that contains the source code. + */ + readonly repositoryUrl: string; + + /** + * The branch name that represents a specific version for the repository. + * + * @default main + */ + readonly branch?: string; + + /** + * ARN of the connection to Github. Only required for Github source. + */ + readonly connection: GitHubConnection; +} + + +/** + * Properties of the image repository for `Source.fromEcrPublic()` + */ +export interface EcrPublicProps { + /** + * The image configuration for the image from ECR Public. + * @default - no image configuration will be passed. The default `port` will be 8080. + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-imageconfiguration.html#cfn-apprunner-service-imageconfiguration-port + */ + readonly imageConfiguration?: ImageConfiguration; + /** + * The ECR Public image URI. + */ + readonly imageIdentifier: string; +} + +/** + * Properties of the image repository for `Source.fromEcr()` + */ +export interface EcrProps { + /** + * The image configuration for the image from ECR. + * @default - no image configuration will be passed. The default `port` will be 8080. + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-imageconfiguration.html#cfn-apprunner-service-imageconfiguration-port + */ + readonly imageConfiguration?: ImageConfiguration; + /** + * Represents the ECR repository. + */ + readonly repository: ecr.IRepository; + /** + * Image tag. + * @default - 'latest' + */ + readonly tag?: string; +} + +/** + * Properties of the image repository for `Source.fromAsset()` + */ +export interface AssetProps { + /** + * The image configuration for the image built from the asset. + * @default - no image configuration will be passed. The default `port` will be 8080. + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-imageconfiguration.html#cfn-apprunner-service-imageconfiguration-port + */ + readonly imageConfiguration?: ImageConfiguration; + /** + * Represents the docker image asset. + */ + readonly asset: assets.DockerImageAsset; +} + + +/** + * Represents the App Runner service source. + */ +export abstract class Source { + /** + * Source from the GitHub repository. + */ + public static fromGitHub(props: GithubRepositoryProps): GithubSource { + return new GithubSource(props); + } + /** + * Source from the ECR repository. + */ + public static fromEcr(props: EcrProps): EcrSource { + return new EcrSource(props); + } + /** + * Source from the ECR Public repository. + */ + public static fromEcrPublic(props: EcrPublicProps): EcrPublicSource { + return new EcrPublicSource(props); + } + /** + * Source from local assets. + */ + public static fromAsset(props: AssetProps): AssetSource { + return new AssetSource(props); + } + /** + * Called when the Job is initialized to allow this object to bind. + */ + public abstract bind(scope: Construct): SourceConfig; +} + +/** + * Represents the service source from a Github repository. + */ +export class GithubSource extends Source { + private readonly props: GithubRepositoryProps + constructor(props: GithubRepositoryProps) { + super(); + this.props = props; + } + public bind(_scope: Construct): SourceConfig { + return { + codeRepository: { + codeConfiguration: { + configurationSource: this.props.configurationSource, + configurationValues: this.props.codeConfigurationValues, + }, + repositoryUrl: this.props.repositoryUrl, + sourceCodeVersion: { + type: 'BRANCH', + value: this.props.branch ?? 'main', + }, + connection: this.props.connection, + }, + }; + } +} +/** + * Represents the service source from ECR. + */ +export class EcrSource extends Source { + private readonly props: EcrProps + constructor(props: EcrProps) { + super(); + this.props = props; + } + public bind(_scope: Construct): SourceConfig { + return { + imageRepository: { + imageConfiguration: this.props.imageConfiguration, + imageIdentifier: this.props.repository.repositoryUriForTag(this.props.tag || 'latest'), + imageRepositoryType: ImageRepositoryType.ECR, + }, + ecrRepository: this.props.repository, + }; + } +} + +/** + * Represents the service source from ECR Public. + */ +export class EcrPublicSource extends Source { + private readonly props: EcrPublicProps; + constructor(props: EcrPublicProps) { + super(); + this.props = props; + } + public bind(_scope: Construct): SourceConfig { + return { + imageRepository: { + imageConfiguration: this.props.imageConfiguration, + imageIdentifier: this.props.imageIdentifier, + imageRepositoryType: ImageRepositoryType.ECR_PUBLIC, + }, + }; + } +} + +/** + * Represents the source from local assets. + */ +export class AssetSource extends Source { + private readonly props: AssetProps + constructor(props: AssetProps) { + super(); + this.props = props; + } + public bind(_scope: Construct): SourceConfig { + return { + imageRepository: { + imageConfiguration: this.props.imageConfiguration, + imageIdentifier: this.props.asset.imageUri, + imageRepositoryType: ImageRepositoryType.ECR, + }, + ecrRepository: this.props.asset.repository, + }; + } +} + +/** + * Describes the configuration that AWS App Runner uses to run an App Runner service + * using an image pulled from a source image repository. + * + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-imageconfiguration.html + */ +export interface ImageConfiguration { + /** + * The port that your application listens to in the container. + * + * @default 8080 + */ + readonly port?: number; + + /** + * Environment variables that are available to your running App Runner service. + * + * @default - no environment variables + */ + readonly environment?: { [key: string]: string }; + + /** + * An optional command that App Runner runs to start the application in the source image. + * If specified, this command overrides the Docker image’s default start command. + * + * @default - no start command + */ + readonly startCommand?: string; +} + +/** + * Describes a source image repository. + * + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-imagerepository.html + */ +export interface ImageRepository { + /** + * The identifier of the image. For `ECR_PUBLIC` imageRepositoryType, the identifier domain should + * always be `public.ecr.aws`. For `ECR`, the pattern should be + * `([0-9]{12}.dkr.ecr.[a-z\-]+-[0-9]{1}.amazonaws.com\/.*)`. + * + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-imagerepository.html for more details. + */ + readonly imageIdentifier: string; + + /** + * The type of the image repository. This reflects the repository provider and whether + * the repository is private or public. + */ + readonly imageRepositoryType: ImageRepositoryType; + + /** + * Configuration for running the identified image. + * @default - no image configuration will be passed. The default `port` will be 8080. + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-imageconfiguration.html#cfn-apprunner-service-imageconfiguration-port + */ + readonly imageConfiguration?: ImageConfiguration; +} + +/** + * Identifies a version of code that AWS App Runner refers to within a source code repository. + * + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-sourcecodeversion.html + */ +export interface SourceCodeVersion { + /** + * The type of version identifier. + */ + readonly type: string; + + /** + * A source code version. + */ + readonly value: string; +} + +/** + * Properties of the CodeRepository. + */ +export interface CodeRepositoryProps { + /** + * Configuration for building and running the service from a source code repository. + */ + readonly codeConfiguration: CodeConfiguration; + + /** + * The location of the repository that contains the source code. + */ + readonly repositoryUrl: string; + + /** + * The version that should be used within the source code repository. + */ + readonly sourceCodeVersion: SourceCodeVersion; + + /** + * The App Runner connection for GitHub. + */ + readonly connection: GitHubConnection; +} + +/** + * Properties of the AppRunner Service + */ +export interface ServiceProps { + /** + * The source of the repository for the service. + */ + readonly source: Source; + + /** + * The number of CPU units reserved for each instance of your App Runner service. + * + * @default Cpu.ONE_VCPU + */ + readonly cpu?: Cpu; + + /** + * The amount of memory reserved for each instance of your App Runner service. + * + * @default Memory.TWO_GB + */ + readonly memory?: Memory; + + /** + * The IAM role that grants the App Runner service access to a source repository. + * It's required for ECR image repositories (but not for ECR Public repositories). + * + * @default - generate a new access role. + */ + readonly accessRole?: iam.IRole; + + /** + * The IAM role that provides permissions to your App Runner service. + * These are permissions that your code needs when it calls any AWS APIs. + * + * @default - no instance role attached. + */ + readonly instanceRole?: iam.IRole; + + /** + * Name of the service. + * + * @default - auto-generated if undefined. + */ + readonly serviceName?: string; +} + +/** + * The source of the App Runner configuration. + */ +export enum ConfigurationSourceType { + /** + * App Runner reads configuration values from `the apprunner.yaml` file in the source code repository + * and ignores `configurationValues`. + */ + REPOSITORY = 'REPOSITORY', + + /** + * App Runner uses configuration values provided in `configurationValues` and ignores the `apprunner.yaml` + * file in the source code repository. + */ + API = 'API', +} + +/** + * Describes the configuration that AWS App Runner uses to build and run an App Runner service + * from a source code repository. + * + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apprunner-service-codeconfiguration.html + */ +export interface CodeConfiguration { + /** + * The basic configuration for building and running the App Runner service. + * Use it to quickly launch an App Runner service without providing a apprunner.yaml file in the + * source code repository (or ignoring the file if it exists). + * + * @default - not specified. Use `apprunner.yaml` instead. + */ + readonly configurationValues?: CodeConfigurationValues; + + /** + * The source of the App Runner configuration. + */ + readonly configurationSource: ConfigurationSourceType; +} + +/** + * Describes resources needed to authenticate access to some source repositories. + * The specific resource depends on the repository provider. + */ +interface AuthenticationConfiguration { + /** + * The Amazon Resource Name (ARN) of the IAM role that grants the App Runner service access to a + * source repository. It's required for ECR image repositories (but not for ECR Public repositories). + * + * @defult - no access role. + */ + readonly accessRoleArn?: string; + + /** + * The Amazon Resource Name (ARN) of the App Runner connection that enables the App Runner service + * to connect to a source repository. It's required for GitHub code repositories. + * + * @default - no connection. + */ + readonly connectionArn?: string; +} + +/** + * Describes the basic configuration needed for building and running an AWS App Runner service. + * This type doesn't support the full set of possible configuration options. Fur full configuration capabilities, + * use a `apprunner.yaml` file in the source code repository. + */ +export interface CodeConfigurationValues { + /** + * The command App Runner runs to build your application. + * + * @default - no build command. + */ + readonly buildCommand?: string; + + /** + * The port that your application listens to in the container. + * + * @default 8080 + */ + readonly port?: string; + + /** + * A runtime environment type for building and running an App Runner service. It represents + * a programming language runtime. + */ + readonly runtime: Runtime; + + /** + * The environment variables that are available to your running App Runner service. + * + * @default - no environment variables. + */ + readonly environment?: { [key: string]: string }; + + /** + * The command App Runner runs to start your application. + * + * @default - no start command. + */ + readonly startCommand?: string; +} + +/** + * Represents the App Runner connection that enables the App Runner service to connect + * to a source repository. It's required for GitHub code repositories. + */ +export class GitHubConnection { + /** + * Using existing App Runner connection by specifying the connection ARN. + * @param arn connection ARN + * @returns Connection + */ + public static fromConnectionArn(arn: string): GitHubConnection { + return new GitHubConnection(arn); + } + /** + * The ARN of the Connection for App Runner service to connect to the repository. + */ + public readonly connectionArn: string + constructor(arn: string) { + this.connectionArn = arn; + } +} + +/** + * Attributes for the App Runner Service + */ +export interface ServiceAttributes { + /** + * The name of the service. + */ + readonly serviceName: string; + + /** + * The ARN of the service. + */ + readonly serviceArn: string; + + /** + * The URL of the service. + */ + readonly serviceUrl: string; + + /** + * The status of the service. + */ + readonly serviceStatus: string; +} + +/** + * Represents the App Runner Service. + */ +export interface IService extends cdk.IResource { + /** + * The Name of the service. + */ + readonly serviceName: string; + + /** + * The ARN of the service. + */ + readonly serviceArn: string; +} + +/** + * The App Runner Service. + */ +export class Service extends cdk.Resource { + /** + * Import from service name. + */ + public static fromServiceName(scope: Construct, id: string, serviceName: string): IService { + class Import extends cdk.Resource { + public serviceName = serviceName; + public serviceArn = cdk.Stack.of(this).formatArn({ + resource: 'service', + service: 'apprunner', + resourceName: serviceName, + }) + } + return new Import(scope, id); + } + + /** + * Import from service attributes. + */ + public static fromServiceAttributes(scope: Construct, id: string, attrs: ServiceAttributes): IService { + const serviceArn = attrs.serviceArn; + const serviceName = attrs.serviceName; + const serviceUrl = attrs.serviceUrl; + const serviceStatus = attrs.serviceStatus; + + class Import extends cdk.Resource { + public readonly serviceArn = serviceArn + public readonly serviceName = serviceName + public readonly serviceUrl = serviceUrl + public readonly serviceStatus = serviceStatus + } + + return new Import(scope, id); + } + private readonly props: ServiceProps; + private accessRole?: iam.IRole; + private source: SourceConfig; + + /** + * The ARN of the Service. + * @attribute + */ + readonly serviceArn: string; + + /** + * The ID of the Service. + * @attribute + */ + readonly serviceId: string; + + /** + * The URL of the Service. + * @attribute + */ + readonly serviceUrl: string; + + /** + * The status of the Service. + * @attribute + */ + readonly serviceStatus: string; + + /** + * The name of the service. + * @attribute + */ + readonly serviceName: string; + + public constructor(scope: Construct, id: string, props: ServiceProps) { + super(scope, id); + + const source = props.source.bind(this); + this.source = source; + this.props = props; + + // generate an IAM role only when ImageRepositoryType is ECR and props.role is undefined + this.accessRole = (this.source.imageRepository?.imageRepositoryType == ImageRepositoryType.ECR) ? + this.props.accessRole ? this.props.accessRole : this.generateDefaultRole() : undefined; + + if (source.codeRepository?.codeConfiguration.configurationSource == ConfigurationSourceType.REPOSITORY && + source.codeRepository?.codeConfiguration.configurationValues) { + throw new Error('configurationValues cannot be provided if the ConfigurationSource is Repository'); + } + + const resource = new CfnService(this, 'Resource', { + instanceConfiguration: { + cpu: props.cpu?.unit, + memory: props.memory?.unit, + instanceRoleArn: props.instanceRole?.roleArn, + }, + sourceConfiguration: { + authenticationConfiguration: this.renderAuthenticationConfiguration(), + imageRepository: source.imageRepository ? this.renderImageRepository() : undefined, + codeRepository: source.codeRepository ? this.renderCodeConfiguration() : undefined, + }, + }); + + // grant required privileges for the role + if (source.ecrRepository && this.accessRole) { + source.ecrRepository.grantPull(this.accessRole); + } + + this.serviceArn = resource.attrServiceArn; + this.serviceId = resource.attrServiceId; + this.serviceUrl = resource.attrServiceUrl; + this.serviceStatus = resource.attrStatus; + this.serviceName = resource.ref; + } + private renderAuthenticationConfiguration(): AuthenticationConfiguration { + return { + accessRoleArn: this.accessRole?.roleArn, + connectionArn: this.source.codeRepository?.connection?.connectionArn, + }; + } + private renderCodeConfiguration() { + return { + codeConfiguration: { + configurationSource: this.source.codeRepository!.codeConfiguration.configurationSource, + // codeConfigurationValues will be ignored if configurationSource is REPOSITORY + codeConfigurationValues: this.source.codeRepository!.codeConfiguration.configurationValues ? + this.renderCodeConfigurationValues(this.source.codeRepository!.codeConfiguration.configurationValues) : undefined, + }, + repositoryUrl: this.source.codeRepository!.repositoryUrl, + sourceCodeVersion: this.source.codeRepository!.sourceCodeVersion, + }; + + } + private renderCodeConfigurationValues(props: CodeConfigurationValues): any { + return { + ...props, + runtime: props.runtime.name, + }; + } + private renderImageRepository(): any { + const repo = this.source.imageRepository!; + if (repo.imageConfiguration?.port) { + // convert port from type number to string + return Object.assign(repo, { + imageConfiguration: { + port: repo.imageConfiguration.port.toString(), + }, + }); + } else { + return repo; + } + } + + private generateDefaultRole(): iam.Role { + const accessRole = new iam.Role(this, 'AccessRole', { + assumedBy: new iam.ServicePrincipal('build.apprunner.amazonaws.com'), + }); + accessRole.addToPrincipalPolicy(new iam.PolicyStatement({ + actions: ['ecr:GetAuthorizationToken'], + resources: ['*'], + })); + this.accessRole = accessRole; + return accessRole; + } +} diff --git a/packages/@aws-cdk/aws-apprunner/package.json b/packages/@aws-cdk/aws-apprunner/package.json index ffbecdc004aa6..8b236cbfb01f5 100644 --- a/packages/@aws-cdk/aws-apprunner/package.json +++ b/packages/@aws-cdk/aws-apprunner/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::AppRunner", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,23 +76,33 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { - "@aws-cdk/core": "0.0.0" + "@aws-cdk/aws-ecr": "0.0.0", + "@aws-cdk/aws-ecr-assets": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/core": "0.0.0", + "constructs": "^3.3.69" }, "peerDependencies": { - "@aws-cdk/core": "0.0.0" + "@aws-cdk/aws-ecr": "0.0.0", + "@aws-cdk/aws-ecr-assets": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/core": "0.0.0", + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", - "maturity": "cfn-only", + "maturity": "experimental", "awscdkio": { "announce": false }, diff --git a/packages/@aws-cdk/aws-apprunner/test/docker.assets/Dockerfile b/packages/@aws-cdk/aws-apprunner/test/docker.assets/Dockerfile new file mode 100644 index 0000000000000..878fb18669506 --- /dev/null +++ b/packages/@aws-cdk/aws-apprunner/test/docker.assets/Dockerfile @@ -0,0 +1,2 @@ +# image from https://gallery.ecr.aws/aws-containers/hello-app-runner +FROM public.ecr.aws/aws-containers/hello-app-runner:latest diff --git a/packages/@aws-cdk/aws-apprunner/test/integ.service.expected.json b/packages/@aws-cdk/aws-apprunner/test/integ.service.expected.json new file mode 100644 index 0000000000000..ed37fa7666d4c --- /dev/null +++ b/packages/@aws-cdk/aws-apprunner/test/integ.service.expected.json @@ -0,0 +1,364 @@ +{ + "Resources": { + "Service1EDCC8134": { + "Type": "AWS::AppRunner::Service", + "Properties": { + "SourceConfiguration": { + "AuthenticationConfiguration": {}, + "ImageRepository": { + "ImageConfiguration": { + "Port": "8000" + }, + "ImageIdentifier": "public.ecr.aws/aws-containers/hello-app-runner:latest", + "ImageRepositoryType": "ECR_PUBLIC" + } + }, + "InstanceConfiguration": {} + } + }, + "Service2AccessRole759CA73D": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "build.apprunner.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "Service2AccessRoleDefaultPolicy08C28479": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "ecr:GetAuthorizationToken", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "ecr:BatchCheckLayerAvailability", + "ecr:GetDownloadUrlForLayer", + "ecr:BatchGetImage" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":ecr:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":repository/nginx" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "Service2AccessRoleDefaultPolicy08C28479", + "Roles": [ + { + "Ref": "Service2AccessRole759CA73D" + } + ] + } + }, + "Service2AB4D14D8": { + "Type": "AWS::AppRunner::Service", + "Properties": { + "SourceConfiguration": { + "AuthenticationConfiguration": { + "AccessRoleArn": { + "Fn::GetAtt": [ + "Service2AccessRole759CA73D", + "Arn" + ] + } + }, + "ImageRepository": { + "ImageConfiguration": { + "Port": "80" + }, + "ImageIdentifier": { + "Fn::Join": [ + "", + [ + { + "Ref": "AWS::AccountId" + }, + ".dkr.ecr.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/nginx:latest" + ] + ] + }, + "ImageRepositoryType": "ECR" + } + }, + "InstanceConfiguration": {} + } + }, + "Service3AccessRole3ACBAAA0": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "build.apprunner.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "Service3AccessRoleDefaultPolicy57B9744E": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "ecr:GetAuthorizationToken", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "ecr:BatchCheckLayerAvailability", + "ecr:GetDownloadUrlForLayer", + "ecr:BatchGetImage" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":ecr:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":repository/aws-cdk/assets" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "Service3AccessRoleDefaultPolicy57B9744E", + "Roles": [ + { + "Ref": "Service3AccessRole3ACBAAA0" + } + ] + } + }, + "Service342D067F2": { + "Type": "AWS::AppRunner::Service", + "Properties": { + "SourceConfiguration": { + "AuthenticationConfiguration": { + "AccessRoleArn": { + "Fn::GetAtt": [ + "Service3AccessRole3ACBAAA0", + "Arn" + ] + } + }, + "ImageRepository": { + "ImageConfiguration": { + "Port": "8000" + }, + "ImageIdentifier": { + "Fn::Join": [ + "", + [ + { + "Ref": "AWS::AccountId" + }, + ".dkr.ecr.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/aws-cdk/assets:77284835684772d19c95f4f5a37e7618d5f9efc40db9321d44ac039db457b967" + ] + ] + }, + "ImageRepositoryType": "ECR" + } + }, + "InstanceConfiguration": {} + } + }, + "Service429949929": { + "Type": "AWS::AppRunner::Service", + "Properties": { + "SourceConfiguration": { + "AuthenticationConfiguration": { + "ConnectionArn": "MOCK" + }, + "CodeRepository": { + "CodeConfiguration": { + "ConfigurationSource": "REPOSITORY" + }, + "RepositoryUrl": "https://github.com/aws-containers/hello-app-runner", + "SourceCodeVersion": { + "Type": "BRANCH", + "Value": "main" + } + } + }, + "InstanceConfiguration": {} + } + }, + "Service5AD92B5A5": { + "Type": "AWS::AppRunner::Service", + "Properties": { + "SourceConfiguration": { + "AuthenticationConfiguration": { + "ConnectionArn": "MOCK" + }, + "CodeRepository": { + "CodeConfiguration": { + "CodeConfigurationValues": { + "BuildCommand": "yum install -y pycairo && pip install -r requirements.txt", + "Port": "8000", + "Runtime": "PYTHON_3", + "StartCommand": "python app.py" + }, + "ConfigurationSource": "API" + }, + "RepositoryUrl": "https://github.com/aws-containers/hello-app-runner", + "SourceCodeVersion": { + "Type": "BRANCH", + "Value": "main" + } + } + }, + "InstanceConfiguration": {} + } + } + }, + "Outputs": { + "URL1": { + "Value": { + "Fn::Join": [ + "", + [ + "https://", + { + "Fn::GetAtt": [ + "Service1EDCC8134", + "ServiceUrl" + ] + } + ] + ] + } + }, + "URL2": { + "Value": { + "Fn::Join": [ + "", + [ + "https://", + { + "Fn::GetAtt": [ + "Service2AB4D14D8", + "ServiceUrl" + ] + } + ] + ] + } + }, + "URL3": { + "Value": { + "Fn::Join": [ + "", + [ + "https://", + { + "Fn::GetAtt": [ + "Service342D067F2", + "ServiceUrl" + ] + } + ] + ] + } + }, + "URL4": { + "Value": { + "Fn::Join": [ + "", + [ + "https://", + { + "Fn::GetAtt": [ + "Service429949929", + "ServiceUrl" + ] + } + ] + ] + } + }, + "URL5": { + "Value": { + "Fn::Join": [ + "", + [ + "https://", + { + "Fn::GetAtt": [ + "Service5AD92B5A5", + "ServiceUrl" + ] + } + ] + ] + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-apprunner/test/integ.service.ts b/packages/@aws-cdk/aws-apprunner/test/integ.service.ts new file mode 100644 index 0000000000000..2df2dab9301aa --- /dev/null +++ b/packages/@aws-cdk/aws-apprunner/test/integ.service.ts @@ -0,0 +1,71 @@ +import * as path from 'path'; +import * as ecr from '@aws-cdk/aws-ecr'; +import * as assets from '@aws-cdk/aws-ecr-assets'; +import * as cdk from '@aws-cdk/core'; +import { Service, Source, GitHubConnection, ConfigurationSourceType, Runtime } from '../lib'; + + +const app = new cdk.App(); + +const stack = new cdk.Stack(app, 'integ-apprunner'); + +// Scenario 1: Create the service from ECR public +const service1 = new Service(stack, 'Service1', { + source: Source.fromEcrPublic({ + imageConfiguration: { + port: 8000, + }, + imageIdentifier: 'public.ecr.aws/aws-containers/hello-app-runner:latest', + }), +}); +new cdk.CfnOutput(stack, 'URL1', { value: `https://${service1.serviceUrl}` }); + +// Scenario 2: Create the service from existing ECR repository, make sure you have `nginx` ECR repo in your account. +const service2 = new Service(stack, 'Service2', { + source: Source.fromEcr({ + imageConfiguration: { port: 80 }, + repository: ecr.Repository.fromRepositoryName(stack, 'NginxRepository', 'nginx'), + }), +}); +new cdk.CfnOutput(stack, 'URL2', { value: `https://${service2.serviceUrl}` }); + +// Scenario 3: Create the service from local code assets +const imageAsset = new assets.DockerImageAsset(stack, 'ImageAssets', { + directory: path.join(__dirname, './docker.assets'), +}); +const service3 = new Service(stack, 'Service3', { + source: Source.fromAsset({ + imageConfiguration: { port: 8000 }, + asset: imageAsset, + }), +}); +new cdk.CfnOutput(stack, 'URL3', { value: `https://${service3.serviceUrl}` }); + +// Scenario 4: Create the service from Github. Make sure you specify a valid connection ARN. +const connectionArn = stack.node.tryGetContext('CONNECTION_ARN') || 'MOCK'; +const service4 = new Service(stack, 'Service4', { + source: Source.fromGitHub({ + repositoryUrl: 'https://github.com/aws-containers/hello-app-runner', + branch: 'main', + configurationSource: ConfigurationSourceType.REPOSITORY, + connection: GitHubConnection.fromConnectionArn(connectionArn), + }), +}); +new cdk.CfnOutput(stack, 'URL4', { value: `https://${service4.serviceUrl}` }); + +// Scenario 5: Create the service from Github with configuration values override. +const service5 = new Service(stack, 'Service5', { + source: Source.fromGitHub({ + repositoryUrl: 'https://github.com/aws-containers/hello-app-runner', + branch: 'main', + configurationSource: ConfigurationSourceType.API, + codeConfigurationValues: { + runtime: Runtime.PYTHON_3, + port: '8000', + startCommand: 'python app.py', + buildCommand: 'yum install -y pycairo && pip install -r requirements.txt', + }, + connection: GitHubConnection.fromConnectionArn(connectionArn), + }), +}); +new cdk.CfnOutput(stack, 'URL5', { value: `https://${service5.serviceUrl}` }); diff --git a/packages/@aws-cdk/aws-apprunner/test/service.test.ts b/packages/@aws-cdk/aws-apprunner/test/service.test.ts new file mode 100644 index 0000000000000..a36cc97950119 --- /dev/null +++ b/packages/@aws-cdk/aws-apprunner/test/service.test.ts @@ -0,0 +1,419 @@ +import * as path from 'path'; +import { Template } from '@aws-cdk/assertions'; +import * as ecr from '@aws-cdk/aws-ecr'; +import * as ecr_assets from '@aws-cdk/aws-ecr-assets'; +import * as iam from '@aws-cdk/aws-iam'; +import * as cdk from '@aws-cdk/core'; +import { Service, GitHubConnection, Runtime, Source, Cpu, Memory, ConfigurationSourceType } from '../lib'; + +test('create a service with ECR Public(image repository type: ECR_PUBLIC)', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'demo-stack'); + // WHEN + new Service(stack, 'DemoService', { + source: Source.fromEcrPublic({ + imageConfiguration: { port: 8000 }, + imageIdentifier: 'public.ecr.aws/aws-containers/hello-app-runner:latest', + }), + }); + // we should have the service + Template.fromStack(stack).hasResourceProperties('AWS::AppRunner::Service', { + SourceConfiguration: { + AuthenticationConfiguration: {}, + ImageRepository: { + ImageConfiguration: { + Port: '8000', + }, + ImageIdentifier: 'public.ecr.aws/aws-containers/hello-app-runner:latest', + ImageRepositoryType: 'ECR_PUBLIC', + }, + }, + }); +}); + +test('create a service from existing ECR repository(image repository type: ECR)', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'demo-stack'); + // WHEN + new Service(stack, 'Service', { + source: Source.fromEcr({ + imageConfiguration: { port: 80 }, + repository: ecr.Repository.fromRepositoryName(stack, 'NginxRepository', 'nginx'), + }), + }); + + // THEN + // we should have an IAM role + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { + AssumeRolePolicyDocument: { + Statement: [ + { + Action: 'sts:AssumeRole', + Effect: 'Allow', + Principal: { + Service: 'build.apprunner.amazonaws.com', + }, + }, + ], + Version: '2012-10-17', + }, + }); + // we should have the service + Template.fromStack(stack).hasResourceProperties('AWS::AppRunner::Service', { + SourceConfiguration: { + AuthenticationConfiguration: { + AccessRoleArn: { + 'Fn::GetAtt': [ + 'ServiceAccessRole4763579D', + 'Arn', + ], + }, + }, + ImageRepository: { + ImageConfiguration: { + Port: '80', + }, + ImageIdentifier: { + 'Fn::Join': [ + '', + [ + { + Ref: 'AWS::AccountId', + }, + '.dkr.ecr.', + { + Ref: 'AWS::Region', + }, + '.', + { + Ref: 'AWS::URLSuffix', + }, + '/nginx:latest', + ], + ], + }, + ImageRepositoryType: 'ECR', + }, + }, + }); +}); + +test('create a service with local assets(image repository type: ECR)', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'demo-stack'); + // WHEN + const dockerAsset = new ecr_assets.DockerImageAsset(stack, 'Assets', { + directory: path.join(__dirname, './docker.assets'), + }); + new Service(stack, 'DemoService', { + source: Source.fromAsset({ + imageConfiguration: { port: 8000 }, + asset: dockerAsset, + }), + }); + + // THEN + // we should have an IAM role + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { + AssumeRolePolicyDocument: { + Statement: [ + { + Action: 'sts:AssumeRole', + Effect: 'Allow', + Principal: { + Service: 'build.apprunner.amazonaws.com', + }, + }, + ], + Version: '2012-10-17', + }, + }); + // we should have the service + Template.fromStack(stack).hasResourceProperties('AWS::AppRunner::Service', { + SourceConfiguration: { + AuthenticationConfiguration: { + AccessRoleArn: { + 'Fn::GetAtt': [ + 'DemoServiceAccessRoleE7F08742', + 'Arn', + ], + }, + }, + ImageRepository: { + ImageConfiguration: { + Port: '8000', + }, + ImageIdentifier: { + 'Fn::Join': [ + '', + [ + { + Ref: 'AWS::AccountId', + }, + '.dkr.ecr.', + { + Ref: 'AWS::Region', + }, + '.', + { + Ref: 'AWS::URLSuffix', + }, + '/aws-cdk/assets:e9db95c5eb5c683b56dbb8a1930ab8b028babb58b58058d72fa77071e38e66a4', + ], + ], + }, + ImageRepositoryType: 'ECR', + }, + }, + }); +}); + + +test('create a service with github repository', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'demo-stack'); + // WHEN + new Service(stack, 'DemoService', { + source: Source.fromGitHub({ + repositoryUrl: 'https://github.com/aws-containers/hello-app-runner', + branch: 'main', + configurationSource: ConfigurationSourceType.REPOSITORY, + connection: GitHubConnection.fromConnectionArn('MOCK'), + }), + }); + + // THEN + // we should have the service + Template.fromStack(stack).hasResourceProperties('AWS::AppRunner::Service', { + SourceConfiguration: { + AuthenticationConfiguration: { + ConnectionArn: 'MOCK', + }, + CodeRepository: { + CodeConfiguration: { + ConfigurationSource: 'REPOSITORY', + }, + RepositoryUrl: 'https://github.com/aws-containers/hello-app-runner', + SourceCodeVersion: { + Type: 'BRANCH', + Value: 'main', + }, + }, + }, + }); +}); + +test('create a service with github repository - undefined branch name is allowed', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'demo-stack'); + // WHEN + new Service(stack, 'DemoService', { + source: Source.fromGitHub({ + repositoryUrl: 'https://github.com/aws-containers/hello-app-runner', + configurationSource: ConfigurationSourceType.API, + codeConfigurationValues: { + runtime: Runtime.PYTHON_3, + port: '8000', + }, + connection: GitHubConnection.fromConnectionArn('MOCK'), + }), + }); + + // THEN + // we should have the service with the branch value as 'main' + Template.fromStack(stack).hasResourceProperties('AWS::AppRunner::Service', { + SourceConfiguration: { + AuthenticationConfiguration: { + ConnectionArn: 'MOCK', + }, + CodeRepository: { + CodeConfiguration: { + CodeConfigurationValues: { + Port: '8000', + Runtime: 'PYTHON_3', + }, + ConfigurationSource: 'API', + }, + RepositoryUrl: 'https://github.com/aws-containers/hello-app-runner', + SourceCodeVersion: { + Type: 'BRANCH', + Value: 'main', + }, + }, + }, + }); +}); + + +test('import from service name', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'demo-stack'); + // WHEN + const svc = Service.fromServiceName(stack, 'ImportService', 'ExistingService'); + // THEN + expect(svc).toHaveProperty('serviceName'); + expect(svc).toHaveProperty('serviceArn'); +}); + +test('import from service attributes', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'demo-stack'); + // WHEN + const svc = Service.fromServiceAttributes(stack, 'ImportService', { + serviceName: 'mock', + serviceArn: 'mock', + serviceStatus: 'mock', + serviceUrl: 'mock', + }); + // THEN + expect(svc).toHaveProperty('serviceName'); + expect(svc).toHaveProperty('serviceArn'); + expect(svc).toHaveProperty('serviceStatus'); + expect(svc).toHaveProperty('serviceUrl'); +}); + + +test('undefined imageConfiguration port is allowed', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'demo-stack'); + // WHEN + new Service(stack, 'Service', { + source: Source.fromEcrPublic({ + imageIdentifier: 'public.ecr.aws/aws-containers/hello-app-runner:latest', + }), + }); + + // THEN + // we should have the service + Template.fromStack(stack).hasResourceProperties('AWS::AppRunner::Service', { + SourceConfiguration: { + AuthenticationConfiguration: {}, + ImageRepository: { + ImageIdentifier: 'public.ecr.aws/aws-containers/hello-app-runner:latest', + ImageRepositoryType: 'ECR_PUBLIC', + }, + }, + }); +}); + +test('custom IAM access role and instance role are allowed', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'demo-stack'); + // WHEN + const dockerAsset = new ecr_assets.DockerImageAsset(stack, 'Assets', { + directory: path.join(__dirname, './docker.assets'), + }); + new Service(stack, 'DemoService', { + source: Source.fromAsset({ + asset: dockerAsset, + imageConfiguration: { port: 8000 }, + }), + accessRole: new iam.Role(stack, 'AccessRole', { + assumedBy: new iam.ServicePrincipal('build.apprunner.amazonaws.com'), + managedPolicies: [ + iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSAppRunnerServicePolicyForECRAccess'), + ], + }), + instanceRole: new iam.Role(stack, 'InstanceRole', { + assumedBy: new iam.ServicePrincipal('tasks.apprunner.amazonaws.com'), + }), + }); + // THEN + // we should have the service with the branch value as 'main' + Template.fromStack(stack).hasResourceProperties('AWS::AppRunner::Service', { + SourceConfiguration: { + AuthenticationConfiguration: { + AccessRoleArn: { + 'Fn::GetAtt': [ + 'AccessRoleEC309AE6', + 'Arn', + ], + }, + }, + ImageRepository: { + ImageConfiguration: { + Port: '8000', + }, + ImageIdentifier: { + 'Fn::Join': [ + '', + [ + { + Ref: 'AWS::AccountId', + }, + '.dkr.ecr.', + { + Ref: 'AWS::Region', + }, + '.', + { + Ref: 'AWS::URLSuffix', + }, + '/aws-cdk/assets:e9db95c5eb5c683b56dbb8a1930ab8b028babb58b58058d72fa77071e38e66a4', + ], + ], + }, + ImageRepositoryType: 'ECR', + }, + }, + InstanceConfiguration: { + InstanceRoleArn: { + 'Fn::GetAtt': [ + 'InstanceRole3CCE2F1D', + 'Arn', + ], + }, + }, + }); +}); + +test('cpu and memory properties are allowed', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'demo-stack'); + // WHEN + new Service(stack, 'DemoService', { + source: Source.fromEcrPublic({ + imageIdentifier: 'public.ecr.aws/aws-containers/hello-app-runner:latest', + }), + cpu: Cpu.ONE_VCPU, + memory: Memory.THREE_GB, + }); + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppRunner::Service', { + InstanceConfiguration: { + Cpu: '1 vCPU', + Memory: '3 GB', + }, + }); +}); + +test('custom cpu and memory units are allowed', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'demo-stack'); + // WHEN + new Service(stack, 'DemoService', { + source: Source.fromEcrPublic({ + imageIdentifier: 'public.ecr.aws/aws-containers/hello-app-runner:latest', + }), + cpu: Cpu.of('Some vCPU'), + memory: Memory.of('Some GB'), + }); + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::AppRunner::Service', { + InstanceConfiguration: { + Cpu: 'Some vCPU', + Memory: 'Some GB', + }, + }); +}); diff --git a/packages/@aws-cdk/aws-appstream/.eslintrc.js b/packages/@aws-cdk/aws-appstream/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-appstream/.eslintrc.js +++ b/packages/@aws-cdk/aws-appstream/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-appstream/jest.config.js b/packages/@aws-cdk/aws-appstream/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-appstream/jest.config.js +++ b/packages/@aws-cdk/aws-appstream/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-appstream/package.json b/packages/@aws-cdk/aws-appstream/package.json index 3605b0f0e9ccf..90e8f1938488c 100644 --- a/packages/@aws-cdk/aws-appstream/package.json +++ b/packages/@aws-cdk/aws-appstream/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::AppStream", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -74,11 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-appsync/.eslintrc.js b/packages/@aws-cdk/aws-appsync/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-appsync/.eslintrc.js +++ b/packages/@aws-cdk/aws-appsync/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-appsync/jest.config.js b/packages/@aws-cdk/aws-appsync/jest.config.js index ff8ca0285ed49..219d718579a52 100644 --- a/packages/@aws-cdk/aws-appsync/jest.config.js +++ b/packages/@aws-cdk/aws-appsync/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/aws-appsync/package.json b/packages/@aws-cdk/aws-appsync/package.json index bc2dc7796af93..a471666ffe98d 100644 --- a/packages/@aws-cdk/aws-appsync/package.json +++ b/packages/@aws-cdk/aws-appsync/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::AppSync", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,23 +74,23 @@ "devDependencies": { "@aws-cdk/assertions": "0.0.0", "@aws-cdk/aws-stepfunctions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-cognito": "0.0.0", "@aws-cdk/aws-dynamodb": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-elasticsearch": "0.0.0", - "@aws-cdk/aws-rds": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", - "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/aws-rds": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", + "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, @@ -103,10 +102,10 @@ "@aws-cdk/aws-elasticsearch": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", - "@aws-cdk/aws-s3-assets": "0.0.0", - "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-rds": "0.0.0", + "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", + "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "engines": { diff --git a/packages/@aws-cdk/aws-aps/.eslintrc.js b/packages/@aws-cdk/aws-aps/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-aps/.eslintrc.js +++ b/packages/@aws-cdk/aws-aps/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-aps/jest.config.js b/packages/@aws-cdk/aws-aps/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-aps/jest.config.js +++ b/packages/@aws-cdk/aws-aps/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-aps/package.json b/packages/@aws-cdk/aws-aps/package.json index 7300436384ab6..2e69665a8fb54 100644 --- a/packages/@aws-cdk/aws-aps/package.json +++ b/packages/@aws-cdk/aws-aps/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::APS", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-athena/.eslintrc.js b/packages/@aws-cdk/aws-athena/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-athena/.eslintrc.js +++ b/packages/@aws-cdk/aws-athena/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-athena/jest.config.js b/packages/@aws-cdk/aws-athena/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-athena/jest.config.js +++ b/packages/@aws-cdk/aws-athena/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-athena/package.json b/packages/@aws-cdk/aws-athena/package.json index 57bc9bfd3a677..468ce471247d7 100644 --- a/packages/@aws-cdk/aws-athena/package.json +++ b/packages/@aws-cdk/aws-athena/package.json @@ -32,7 +32,6 @@ }, "cdk-build": { "cloudformation": "AWS::Athena", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,13 +72,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "jest": "^26.6.3", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-auditmanager/.eslintrc.js b/packages/@aws-cdk/aws-auditmanager/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-auditmanager/.eslintrc.js +++ b/packages/@aws-cdk/aws-auditmanager/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-auditmanager/jest.config.js b/packages/@aws-cdk/aws-auditmanager/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-auditmanager/jest.config.js +++ b/packages/@aws-cdk/aws-auditmanager/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-auditmanager/package.json b/packages/@aws-cdk/aws-auditmanager/package.json index f667b4c12c375..a787fca8f6ec3 100644 --- a/packages/@aws-cdk/aws-auditmanager/package.json +++ b/packages/@aws-cdk/aws-auditmanager/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::AuditManager", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-autoscaling-common/.eslintrc.js b/packages/@aws-cdk/aws-autoscaling-common/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-autoscaling-common/.eslintrc.js +++ b/packages/@aws-cdk/aws-autoscaling-common/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-autoscaling-common/jest.config.js b/packages/@aws-cdk/aws-autoscaling-common/jest.config.js index cd664e1d069e5..34818e1593f6b 100644 --- a/packages/@aws-cdk/aws-autoscaling-common/jest.config.js +++ b/packages/@aws-cdk/aws-autoscaling-common/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-autoscaling-common/package.json b/packages/@aws-cdk/aws-autoscaling-common/package.json index bd150e90f21ee..64bc1d528f2fa 100644 --- a/packages/@aws-cdk/aws-autoscaling-common/package.json +++ b/packages/@aws-cdk/aws-autoscaling-common/package.json @@ -64,13 +64,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", "fast-check": "^2.17.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", @@ -115,8 +115,7 @@ "cdk-build": { "env": { "AWSLINT_BASE_CONSTRUCT": true - }, - "jest": true + } }, "publishConfig": { "tag": "latest" diff --git a/packages/@aws-cdk/aws-autoscaling-hooktargets/.eslintrc.js b/packages/@aws-cdk/aws-autoscaling-hooktargets/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-autoscaling-hooktargets/.eslintrc.js +++ b/packages/@aws-cdk/aws-autoscaling-hooktargets/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-autoscaling-hooktargets/jest.config.js b/packages/@aws-cdk/aws-autoscaling-hooktargets/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-autoscaling-hooktargets/jest.config.js +++ b/packages/@aws-cdk/aws-autoscaling-hooktargets/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json b/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json index 08a1b4120aee1..ac5aeabab06ca 100644 --- a/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json +++ b/packages/@aws-cdk/aws-autoscaling-hooktargets/package.json @@ -64,14 +64,14 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-autoscaling": "0.0.0", @@ -105,7 +105,6 @@ }, "maturity": "stable", "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-autoscaling/.eslintrc.js b/packages/@aws-cdk/aws-autoscaling/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-autoscaling/.eslintrc.js +++ b/packages/@aws-cdk/aws-autoscaling/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-autoscaling/jest.config.js b/packages/@aws-cdk/aws-autoscaling/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-autoscaling/jest.config.js +++ b/packages/@aws-cdk/aws-autoscaling/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-autoscaling/package.json b/packages/@aws-cdk/aws-autoscaling/package.json index 67fb9d4e1dd7e..0a04e34718096 100644 --- a/packages/@aws-cdk/aws-autoscaling/package.json +++ b/packages/@aws-cdk/aws-autoscaling/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::AutoScaling", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,15 +72,15 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "@aws-cdk/cx-api": "0.0.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/cx-api": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-autoscaling-common": "0.0.0", diff --git a/packages/@aws-cdk/aws-autoscalingplans/.eslintrc.js b/packages/@aws-cdk/aws-autoscalingplans/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-autoscalingplans/.eslintrc.js +++ b/packages/@aws-cdk/aws-autoscalingplans/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-autoscalingplans/jest.config.js b/packages/@aws-cdk/aws-autoscalingplans/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-autoscalingplans/jest.config.js +++ b/packages/@aws-cdk/aws-autoscalingplans/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-autoscalingplans/package.json b/packages/@aws-cdk/aws-autoscalingplans/package.json index 653b5457f3c97..cd0c974c03acf 100644 --- a/packages/@aws-cdk/aws-autoscalingplans/package.json +++ b/packages/@aws-cdk/aws-autoscalingplans/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::AutoScalingPlans", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-backup/.eslintrc.js b/packages/@aws-cdk/aws-backup/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-backup/.eslintrc.js +++ b/packages/@aws-cdk/aws-backup/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-backup/README.md b/packages/@aws-cdk/aws-backup/README.md index 22b2398ba08ea..b59d5307f9d67 100644 --- a/packages/@aws-cdk/aws-backup/README.md +++ b/packages/@aws-cdk/aws-backup/README.md @@ -132,13 +132,18 @@ const vault = new backup.BackupVault(this, 'Vault', { }) ``` -Use the `blockRecoveryPointDeletion` property to add statements to the vault access policy that -prevents recovery point deletions in your vault: +Alternativately statements can be added to the vault policy using `addToAccessPolicy()`. + +Use the `blockRecoveryPointDeletion` property or the `blockRecoveryPointDeletion()` method to add +a statement to the vault access policy that prevents recovery point deletions in your vault: ```ts new backup.BackupVault(this, 'Vault', { blockRecoveryPointDeletion: true, }); + +const plan = backup.BackupPlan.dailyMonthly1YearRetention(this, 'Plan'); +plan.backupVault.blockRecoveryPointDeletion(); ``` By default access is not restricted. diff --git a/packages/@aws-cdk/aws-backup/jest.config.js b/packages/@aws-cdk/aws-backup/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-backup/jest.config.js +++ b/packages/@aws-cdk/aws-backup/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-backup/lib/vault.ts b/packages/@aws-cdk/aws-backup/lib/vault.ts index ac2c67a19dff3..5f4f0d05c6001 100644 --- a/packages/@aws-cdk/aws-backup/lib/vault.ts +++ b/packages/@aws-cdk/aws-backup/lib/vault.ts @@ -1,7 +1,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as sns from '@aws-cdk/aws-sns'; -import { IResource, Names, RemovalPolicy, Resource, Stack } from '@aws-cdk/core'; +import { IResource, Lazy, Names, RemovalPolicy, Resource, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { CfnBackupVault } from './backup.generated'; @@ -198,6 +198,8 @@ export class BackupVault extends BackupVaultBase { public readonly backupVaultName: string; public readonly backupVaultArn: string; + private readonly accessPolicy: iam.PolicyDocument; + constructor(scope: Construct, id: string, props: BackupVaultProps = {}) { super(scope, id); @@ -214,23 +216,14 @@ export class BackupVault extends BackupVaultBase { props.notificationTopic.grantPublish(new iam.ServicePrincipal('backup.amazonaws.com')); } - const accessPolicy = props.accessPolicy ?? new iam.PolicyDocument(); + this.accessPolicy = props.accessPolicy ?? new iam.PolicyDocument(); if (props.blockRecoveryPointDeletion) { - accessPolicy.addStatements(new iam.PolicyStatement({ - effect: iam.Effect.DENY, - actions: [ - 'backup:DeleteRecoveryPoint', - 'backup:UpdateRecoveryPointLifecycle', - ], - principals: [new iam.AnyPrincipal()], - resources: ['*'], - }), - ); + this.blockRecoveryPointDeletion(); } const vault = new CfnBackupVault(this, 'Resource', { backupVaultName: props.backupVaultName || this.uniqueVaultName(), - accessPolicy: accessPolicy.toJSON(), + accessPolicy: Lazy.any({ produce: () => this.accessPolicy.toJSON() }), encryptionKeyArn: props.encryptionKey && props.encryptionKey.keyArn, notifications, }); @@ -240,6 +233,29 @@ export class BackupVault extends BackupVaultBase { this.backupVaultArn = vault.attrBackupVaultArn; } + /** + * Adds a statement to the vault access policy + */ + public addToAccessPolicy(statement: iam.PolicyStatement) { + this.accessPolicy.addStatements(statement); + } + + /** + * Adds a statement to the vault access policy that prevents anyone + * from deleting a recovery point. + */ + public blockRecoveryPointDeletion() { + this.addToAccessPolicy(new iam.PolicyStatement({ + effect: iam.Effect.DENY, + actions: [ + 'backup:DeleteRecoveryPoint', + 'backup:UpdateRecoveryPointLifecycle', + ], + principals: [new iam.AnyPrincipal()], + resources: ['*'], + })); + } + private uniqueVaultName() { // Max length of 50 chars, get the last 50 chars const id = Names.uniqueId(this); diff --git a/packages/@aws-cdk/aws-backup/package.json b/packages/@aws-cdk/aws-backup/package.json index 78f771c99a2b7..fa3dd9c9f3693 100644 --- a/packages/@aws-cdk/aws-backup/package.json +++ b/packages/@aws-cdk/aws-backup/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Backup", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -76,11 +75,11 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-dynamodb": "0.0.0", diff --git a/packages/@aws-cdk/aws-backup/test/vault.test.ts b/packages/@aws-cdk/aws-backup/test/vault.test.ts index 30b145f55d3ac..e72b039e75c63 100644 --- a/packages/@aws-cdk/aws-backup/test/vault.test.ts +++ b/packages/@aws-cdk/aws-backup/test/vault.test.ts @@ -138,6 +138,62 @@ test('merges statements from accessPolicy and blockRecoveryPointDeletion', () => }); }); +test('addToAccessPolicy()', () => { + // GIVEN + const vault = new BackupVault(stack, 'Vault'); + + // WHEN + vault.addToAccessPolicy(new iam.PolicyStatement({ + effect: iam.Effect.DENY, + principals: [new iam.ArnPrincipal('arn:aws:iam::123456789012:role/MyRole')], + actions: ['backup:StartRestoreJob'], + })); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Backup::BackupVault', { + AccessPolicy: { + Version: '2012-10-17', + Statement: [ + { + Action: 'backup:StartRestoreJob', + Effect: 'Deny', + Principal: { + AWS: 'arn:aws:iam::123456789012:role/MyRole', + }, + }, + ], + }, + }); +}); + +test('blockRecoveryPointDeletion()', () => { + // GIVEN + const vault = new BackupVault(stack, 'Vault'); + + // WHEN + vault.blockRecoveryPointDeletion(); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Backup::BackupVault', { + AccessPolicy: { + Version: '2012-10-17', + Statement: [ + { + Effect: 'Deny', + Principal: { + AWS: '*', + }, + Action: [ + 'backup:DeleteRecoveryPoint', + 'backup:UpdateRecoveryPointLifecycle', + ], + Resource: '*', + }, + ], + }, + }); +}); + test('with encryption key', () => { // GIVEN const encryptionKey = new kms.Key(stack, 'Key'); diff --git a/packages/@aws-cdk/aws-batch/.eslintrc.js b/packages/@aws-cdk/aws-batch/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-batch/.eslintrc.js +++ b/packages/@aws-cdk/aws-batch/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-batch/jest.config.js b/packages/@aws-cdk/aws-batch/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-batch/jest.config.js +++ b/packages/@aws-cdk/aws-batch/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-batch/package.json b/packages/@aws-cdk/aws-batch/package.json index bc9cbf389cd8c..1c385bf9b0d91 100644 --- a/packages/@aws-cdk/aws-batch/package.json +++ b/packages/@aws-cdk/aws-batch/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::Batch", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -74,32 +73,32 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { - "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-ecr": "0.0.0", "@aws-cdk/aws-ecs": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", + "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { - "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-ecr": "0.0.0", "@aws-cdk/aws-ecs": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", + "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "engines": { diff --git a/packages/@aws-cdk/aws-budgets/.eslintrc.js b/packages/@aws-cdk/aws-budgets/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-budgets/.eslintrc.js +++ b/packages/@aws-cdk/aws-budgets/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-budgets/jest.config.js b/packages/@aws-cdk/aws-budgets/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-budgets/jest.config.js +++ b/packages/@aws-cdk/aws-budgets/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-budgets/package.json b/packages/@aws-cdk/aws-budgets/package.json index 37c92a04ef9cc..cabef6dd2e5f1 100644 --- a/packages/@aws-cdk/aws-budgets/package.json +++ b/packages/@aws-cdk/aws-budgets/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::Budgets", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-cassandra/.eslintrc.js b/packages/@aws-cdk/aws-cassandra/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-cassandra/.eslintrc.js +++ b/packages/@aws-cdk/aws-cassandra/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cassandra/jest.config.js b/packages/@aws-cdk/aws-cassandra/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-cassandra/jest.config.js +++ b/packages/@aws-cdk/aws-cassandra/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cassandra/package.json b/packages/@aws-cdk/aws-cassandra/package.json index 1515c0f8cbebe..bf0aa5a1e3a1e 100644 --- a/packages/@aws-cdk/aws-cassandra/package.json +++ b/packages/@aws-cdk/aws-cassandra/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Cassandra", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-ce/.eslintrc.js b/packages/@aws-cdk/aws-ce/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-ce/.eslintrc.js +++ b/packages/@aws-cdk/aws-ce/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ce/jest.config.js b/packages/@aws-cdk/aws-ce/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-ce/jest.config.js +++ b/packages/@aws-cdk/aws-ce/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ce/package.json b/packages/@aws-cdk/aws-ce/package.json index 8148d2c5f2dd2..088987329b0f8 100644 --- a/packages/@aws-cdk/aws-ce/package.json +++ b/packages/@aws-cdk/aws-ce/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::CE", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-certificatemanager/.eslintrc.js b/packages/@aws-cdk/aws-certificatemanager/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-certificatemanager/.eslintrc.js +++ b/packages/@aws-cdk/aws-certificatemanager/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-certificatemanager/jest.config.js b/packages/@aws-cdk/aws-certificatemanager/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-certificatemanager/jest.config.js +++ b/packages/@aws-cdk/aws-certificatemanager/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/.eslintrc.js b/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/.eslintrc.js index 2ab6719877209..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/.eslintrc.js +++ b/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; -module.exports = baseConfig; \ No newline at end of file +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/package.json b/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/package.json index 63784c4cf30ce..5c0502d0f9c54 100644 --- a/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/package.json +++ b/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/package.json @@ -1,5 +1,5 @@ { - "name": "dns_validated_certificate_handler", + "name": "@aws-cdk/dns_validated_certificate_handler", "private": true, "version": "0.0.0", "description": "This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project.", @@ -29,21 +29,21 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/aws-lambda": "^8.10.79", + "@types/aws-lambda": "^8.10.83", "@types/sinon": "^9.0.11", - "cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", "aws-sdk": "^2.596.0", - "aws-sdk-mock": "^5.2.1", - "eslint": "^7.31.0", + "aws-sdk-mock": "^5.4.0", + "eslint": "^7.32.0", "eslint-config-standard": "^14.1.1", - "eslint-plugin-import": "^2.23.4", + "eslint-plugin-import": "^2.24.2", "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^4.3.1", "eslint-plugin-standard": "^4.1.0", "jest": "^26.6.3", "lambda-tester": "^3.6.0", "sinon": "^9.2.4", - "nock": "^13.1.1", + "nock": "^13.1.3", "ts-jest": "^26.5.6" } } diff --git a/packages/@aws-cdk/aws-certificatemanager/package.json b/packages/@aws-cdk/aws-certificatemanager/package.json index f84f775f108de..990c09fc3aa55 100644 --- a/packages/@aws-cdk/aws-certificatemanager/package.json +++ b/packages/@aws-cdk/aws-certificatemanager/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::CertificateManager", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", @@ -89,12 +88,12 @@ }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { + "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-route53": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.3.69", - "@aws-cdk/aws-cloudwatch": "0.0.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-chatbot/.eslintrc.js b/packages/@aws-cdk/aws-chatbot/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-chatbot/.eslintrc.js +++ b/packages/@aws-cdk/aws-chatbot/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-chatbot/jest.config.js b/packages/@aws-cdk/aws-chatbot/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-chatbot/jest.config.js +++ b/packages/@aws-cdk/aws-chatbot/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-chatbot/package.json b/packages/@aws-cdk/aws-chatbot/package.json index 9fcdfedfcda21..353033b0e9224 100644 --- a/packages/@aws-cdk/aws-chatbot/package.json +++ b/packages/@aws-cdk/aws-chatbot/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Chatbot", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,16 +74,16 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { - "@aws-cdk/aws-codestarnotifications": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", + "@aws-cdk/aws-codestarnotifications": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", @@ -92,8 +91,8 @@ "constructs": "^3.3.69" }, "peerDependencies": { - "@aws-cdk/aws-codestarnotifications": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", + "@aws-cdk/aws-codestarnotifications": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloud9/.eslintrc.js b/packages/@aws-cdk/aws-cloud9/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-cloud9/.eslintrc.js +++ b/packages/@aws-cdk/aws-cloud9/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloud9/jest.config.js b/packages/@aws-cdk/aws-cloud9/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-cloud9/jest.config.js +++ b/packages/@aws-cdk/aws-cloud9/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloud9/package.json b/packages/@aws-cdk/aws-cloud9/package.json index 452002a0e5dde..82d3f7d1b25dd 100644 --- a/packages/@aws-cdk/aws-cloud9/package.json +++ b/packages/@aws-cdk/aws-cloud9/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::Cloud9", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,23 +74,23 @@ "devDependencies": { "@aws-cdk/assertions": "0.0.0", "@aws-cdk/aws-codecommit": "0.0.0", - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { - "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-codecommit": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { - "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-codecommit": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "engines": { diff --git a/packages/@aws-cdk/aws-cloudformation/.eslintrc.js b/packages/@aws-cdk/aws-cloudformation/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-cloudformation/.eslintrc.js +++ b/packages/@aws-cdk/aws-cloudformation/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloudformation/.gitignore b/packages/@aws-cdk/aws-cloudformation/.gitignore index dcc1dc41e477f..dd44a9ab1feb0 100644 --- a/packages/@aws-cdk/aws-cloudformation/.gitignore +++ b/packages/@aws-cdk/aws-cloudformation/.gitignore @@ -15,4 +15,6 @@ nyc.config.js *.snk !.eslintrc.js -junit.xml \ No newline at end of file +junit.xml + +!jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudformation/.npmignore b/packages/@aws-cdk/aws-cloudformation/.npmignore index 9a032ae80868c..e8acf10a468a1 100644 --- a/packages/@aws-cdk/aws-cloudformation/.npmignore +++ b/packages/@aws-cdk/aws-cloudformation/.npmignore @@ -24,4 +24,5 @@ tsconfig.json **/cdk.out junit.xml test/ -!*.lit.ts \ No newline at end of file +!*.lit.ts +jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudformation/jest.config.js b/packages/@aws-cdk/aws-cloudformation/jest.config.js new file mode 100644 index 0000000000000..34818e1593f6b --- /dev/null +++ b/packages/@aws-cdk/aws-cloudformation/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloudformation/package.json b/packages/@aws-cdk/aws-cloudformation/package.json index b3d32b8636b09..c5145ca7127b9 100644 --- a/packages/@aws-cdk/aws-cloudformation/package.json +++ b/packages/@aws-cdk/aws-cloudformation/package.json @@ -69,19 +69,19 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/aws-sns-subscriptions": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", - "@types/aws-lambda": "^8.10.79", - "@types/nodeunit": "^0.0.32", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "nodeunit": "^0.11.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/aws-lambda": "^8.10.83", + "@types/jest": "^26.0.24", + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudformation/test/deps.test.ts b/packages/@aws-cdk/aws-cloudformation/test/deps.test.ts new file mode 100644 index 0000000000000..50014ed1b10e4 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudformation/test/deps.test.ts @@ -0,0 +1,339 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import { ResourcePart } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +import { App, CfnResource, Stack } from '@aws-cdk/core'; +import * as cxapi from '@aws-cdk/cx-api'; +import { NestedStack } from '../lib'; + +describe('resource dependencies', () => { + test('between two resources in a top-level stack', () => { + // GIVEN + const app = new App(); + const stack = new Stack(app, 'Stack'); + const r1 = new CfnResource(stack, 'r1', { type: 'r1' }); + const r2 = new CfnResource(stack, 'r2', { type: 'r2' }); + + // WHEN + r1.addDependsOn(r2); + + // THEN + expect(app.synth().getStackArtifact(stack.artifactId).template).toEqual({ + Resources: + { r1: { Type: 'r1', DependsOn: ['r2'] }, r2: { Type: 'r2' } }, + }); + }); + + // eslint-disable-next-line jest/valid-describe + describe('resource in nested stack depends on a resource in the parent stack', matrixForResourceDependencyTest((addDep) => { + // GIVEN + const parent = new Stack(undefined, 'root'); + const nested = new NestedStack(parent, 'Nested'); + const resourceInParent = new CfnResource(parent, 'ResourceInParent', { type: 'PARENT' }); + const resourceInNested = new CfnResource(nested, 'ResourceInNested', { type: 'NESTED' }); + + // WHEN + addDep(resourceInNested, resourceInParent); + + // THEN: the dependency needs to transfer from the resource within the + // nested stack to the nested stack resource itself so the nested stack + // will only be deployed the dependent resource + expect(parent).toHaveResource('AWS::CloudFormation::Stack', { DependsOn: ['ResourceInParent'] }, ResourcePart.CompleteDefinition); + expect(nested).toMatchTemplate({ Resources: { ResourceInNested: { Type: 'NESTED' } } }); // no DependsOn for the actual resource + })); + + // eslint-disable-next-line jest/valid-describe + describe('resource in nested stack depends on a resource in a grandparent stack', matrixForResourceDependencyTest((addDep) => { + // GIVEN + const grantparent = new Stack(undefined, 'Grandparent'); + const parent = new NestedStack(grantparent, 'Parent'); + const nested = new NestedStack(parent, 'Nested'); + const resourceInGrandparent = new CfnResource(grantparent, 'ResourceInGrandparent', { type: 'GRANDPARENT' }); + const resourceInNested = new CfnResource(nested, 'ResourceInNested', { type: 'NESTED' }); + + // WHEN + addDep(resourceInNested, resourceInGrandparent); + + // THEN: the dependency needs to transfer from the resource within the + // nested stack to the *parent* nested stack + expect(grantparent).toHaveResource('AWS::CloudFormation::Stack', { DependsOn: ['ResourceInGrandparent'] }, ResourcePart.CompleteDefinition); + expect(nested).toMatchTemplate({ Resources: { ResourceInNested: { Type: 'NESTED' } } }); // no DependsOn for the actual resource + })); + + // eslint-disable-next-line jest/valid-describe + describe('resource in parent stack depends on resource in nested stack', matrixForResourceDependencyTest((addDep) => { + // GIVEN + const parent = new Stack(undefined, 'root'); + const nested = new NestedStack(parent, 'Nested'); + const resourceInParent = new CfnResource(parent, 'ResourceInParent', { type: 'PARENT' }); + const resourceInNested = new CfnResource(nested, 'ResourceInNested', { type: 'NESTED' }); + + // WHEN + addDep(resourceInParent, resourceInNested); + + // THEN: resource in parent needs to depend on the nested stack + expect(parent).toHaveResource('PARENT', { + DependsOn: [parent.resolve(nested.nestedStackResource!.logicalId)], + }, ResourcePart.CompleteDefinition); + })); + + // eslint-disable-next-line jest/valid-describe + describe('resource in grantparent stack depends on resource in nested stack', matrixForResourceDependencyTest((addDep) => { + // GIVEN + const grandparent = new Stack(undefined, 'Grandparent'); + const parent = new NestedStack(grandparent, 'Parent'); + const nested = new NestedStack(parent, 'Nested'); + const resourceInGrandparent = new CfnResource(grandparent, 'ResourceInGrandparent', { type: 'GRANDPARENT' }); + const resourceInNested = new CfnResource(nested, 'ResourceInNested', { type: 'NESTED' }); + + // WHEN + addDep(resourceInGrandparent, resourceInNested); + + // THEN: resource in grantparent needs to depend on the top-level nested stack + expect(grandparent).toHaveResource('GRANDPARENT', { + DependsOn: [grandparent.resolve(parent.nestedStackResource!.logicalId)], + }, ResourcePart.CompleteDefinition); + })); + + // eslint-disable-next-line jest/valid-describe + describe('resource in sibling stack depends on a resource in nested stack', matrixForResourceDependencyTest((addDep) => { + // GIVEN + const app = new App(); + const stack1 = new Stack(app, 'Stack1'); + const nested1 = new NestedStack(stack1, 'Nested1'); + const resourceInNested1 = new CfnResource(nested1, 'ResourceInNested', { type: 'NESTED' }); + const stack2 = new Stack(app, 'Stack2'); + const resourceInStack2 = new CfnResource(stack2, 'ResourceInSibling', { type: 'SIBLING' }); + + // WHEN + addDep(resourceInStack2, resourceInNested1); + + // THEN: stack2 should depend on stack1 and no "DependsOn" inside templates + const assembly = app.synth(); + assertAssemblyDependency(assembly, stack1, []); + assertAssemblyDependency(assembly, stack2, ['Stack1']); + assertNoDependsOn(assembly, stack1); + assertNoDependsOn(assembly, stack2); + assertNoDependsOn(assembly, nested1); + })); + + // eslint-disable-next-line jest/valid-describe + describe('resource in nested stack depends on a resource in sibling stack', matrixForResourceDependencyTest((addDep) => { + // GIVEN + const app = new App(); + const stack1 = new Stack(app, 'Stack1'); + const nested1 = new NestedStack(stack1, 'Nested1'); + const resourceInNested1 = new CfnResource(nested1, 'ResourceInNested', { type: 'NESTED' }); + const stack2 = new Stack(app, 'Stack2'); + const resourceInStack2 = new CfnResource(stack2, 'ResourceInSibling', { type: 'SIBLING' }); + + // WHEN + addDep(resourceInNested1, resourceInStack2); + + // THEN: stack1 should depend on stack2 and no "DependsOn" inside templates + const assembly = app.synth(); + assertAssemblyDependency(assembly, stack1, ['Stack2']); + assertAssemblyDependency(assembly, stack2, []); + assertNoDependsOn(assembly, stack1); + assertNoDependsOn(assembly, stack2); + assertNoDependsOn(assembly, nested1); + })); + + // eslint-disable-next-line jest/valid-describe + describe('resource in nested stack depends on a resource in nested sibling stack', matrixForResourceDependencyTest((addDep) => { + // GIVEN + const app = new App(); + const stack = new Stack(app, 'Stack1'); + const nested1 = new NestedStack(stack, 'Nested1'); + const nested2 = new NestedStack(stack, 'Nested2'); + const resourceInNested1 = new CfnResource(nested1, 'ResourceInNested1', { type: 'NESTED1' }); + const resourceInNested2 = new CfnResource(nested2, 'ResourceInNested2', { type: 'NESTED2' }); + + // WHEN + addDep(resourceInNested1, resourceInNested2); + + // THEN: dependency transfered to nested stack resources + expect(stack).toHaveResource('AWS::CloudFormation::Stack', { + DependsOn: [stack.resolve(nested2.nestedStackResource!.logicalId)], + }, ResourcePart.CompleteDefinition); + + expect(stack).not.toHaveResource('AWS::CloudFormation::Stack', { + DependsOn: [stack.resolve(nested1.nestedStackResource!.logicalId)], + }, ResourcePart.CompleteDefinition); + })); +}); + +describe('stack dependencies', () => { + test('top level stack depends on itself', () => { + // GIVEN + const app = new App(); + const stack = new Stack(app, 'Stack'); + + // WHEN + stack.addDependency(stack); + + // THEN + const assembly = app.synth(); + assertAssemblyDependency(assembly, stack, []); + assertNoDependsOn(assembly, stack); + }); + + test('nested stack depends on itself', () => { + // GIVEN + const app = new App(); + const parent = new Stack(app, 'Parent'); + const nested = new NestedStack(parent, 'Nested'); + + // WHEN + nested.addDependency(nested); + + // THEN + assertNoDependsOn(app.synth(), parent); + }); + + test('nested stack cannot depend on any of its parents', () => { + // GIVEN + const root = new Stack(); + const nested1 = new NestedStack(root, 'Nested1'); + const nested2 = new NestedStack(nested1, 'Nested2'); + + // THEN + expect(() => nested1.addDependency(root)).toThrow(/Nested stack 'Default\/Nested1' cannot depend on a parent stack 'Default'/); + expect(() => nested2.addDependency(nested1)).toThrow(/Nested stack 'Default\/Nested1\/Nested2' cannot depend on a parent stack 'Default\/Nested1'/); + expect(() => nested2.addDependency(root)).toThrow(/Nested stack 'Default\/Nested1\/Nested2' cannot depend on a parent stack 'Default'/); + }); + + test('any parent stack is by definition dependent on the nested stack so dependency is ignored', () => { + // GIVEN + const root = new Stack(); + const nested1 = new NestedStack(root, 'Nested1'); + const nested2 = new NestedStack(nested1, 'Nested2'); + + // WHEN + root.addDependency(nested1); + root.addDependency(nested2); + nested1.addDependency(nested2); + }); + + test('sibling nested stacks transfer to resources', () => { + // GIVEN + const stack = new Stack(); + const nested1 = new NestedStack(stack, 'Nested1'); + const nested2 = new NestedStack(stack, 'Nested2'); + + // WHEN + nested1.addDependency(nested2); + + // THEN + expect(stack).toHaveResource('AWS::CloudFormation::Stack', { + DependsOn: [stack.resolve(nested2.nestedStackResource!.logicalId)], + }, ResourcePart.CompleteDefinition); + }); + + test('nested stack depends on a deeply nested stack', () => { + // GIVEN + const stack = new Stack(); + const nested1 = new NestedStack(stack, 'Nested1'); + const nested2 = new NestedStack(stack, 'Nested2'); + const nested21 = new NestedStack(nested2, 'Nested21'); + + // WHEN + nested1.addDependency(nested21); + + // THEN: transfered to a resource dep between the resources in the common stack + expect(stack).toHaveResource('AWS::CloudFormation::Stack', { + DependsOn: [stack.resolve(nested2.nestedStackResource!.logicalId)], + }, ResourcePart.CompleteDefinition); + }); + + test('deeply nested stack depends on a parent nested stack', () => { + // GIVEN + const stack = new Stack(); + const nested1 = new NestedStack(stack, 'Nested1'); + const nested2 = new NestedStack(stack, 'Nested2'); + const nested21 = new NestedStack(nested2, 'Nested21'); + + // WHEN + nested21.addDependency(nested1); + + // THEN: transfered to a resource dep between the resources in the common stack + expect(stack).toHaveResource('AWS::CloudFormation::Stack', { + DependsOn: [stack.resolve(nested1.nestedStackResource!.logicalId)], + }, ResourcePart.CompleteDefinition); + }); + + test('top-level stack depends on a nested stack within a sibling', () => { + // GIVEN + const app = new App(); + const stack1 = new Stack(app, 'Stack1'); + const nested1 = new NestedStack(stack1, 'Nested1'); + const stack2 = new Stack(app, 'Stack2'); + + // WHEN + stack2.addDependency(nested1); + + // THEN: assembly-level dependency between stack2 and stack1 + const assembly = app.synth(); + assertAssemblyDependency(assembly, stack2, ['Stack1']); + assertAssemblyDependency(assembly, stack1, []); + assertNoDependsOn(assembly, stack1); + assertNoDependsOn(assembly, stack2); + assertNoDependsOn(assembly, nested1); + }); + + test('nested stack within a sibling depends on top-level stack', () => { + // GIVEN + const app = new App(); + const stack1 = new Stack(app, 'Stack1'); + const nested1 = new NestedStack(stack1, 'Nested1'); + const stack2 = new Stack(app, 'Stack2'); + + // WHEN + nested1.addDependency(stack2); + + // THEN: assembly-level dependency between stack2 and stack1 + const assembly = app.synth(); + assertAssemblyDependency(assembly, stack2, []); + assertAssemblyDependency(assembly, stack1, ['Stack2']); + assertNoDependsOn(assembly, stack1); + assertNoDependsOn(assembly, stack2); + assertNoDependsOn(assembly, nested1); + }); +}); + +/** + * Given a test function which sets the stage and verifies a dependency scenario + * between two CloudFormation resources, returns two tests which exercise both + * "construct dependency" (i.e. node.addDependency) and "resource dependency" + * (i.e. resource.addDependsOn). + * + * @param testFunction The test function + */ +function matrixForResourceDependencyTest(testFunction: (addDep: (source: CfnResource, target: CfnResource) => void) => void) { + return () => { + test('construct dependency', () => { + testFunction((source, target) => source.node.addDependency(target)); + }); + test('resource dependency', () => { + testFunction((source, target) => source.addDependsOn(target)); + }); + }; +} + +function assertAssemblyDependency(assembly: cxapi.CloudAssembly, stack: Stack, expectedDeps: string[]) { + const stack1Art = assembly.getStackArtifact(stack.artifactId); + const stack1Deps = stack1Art.dependencies.map(x => x.id); + expect(stack1Deps).toEqual(expectedDeps); +} + +function assertNoDependsOn(assembly: cxapi.CloudAssembly, stack: Stack) { + let templateText; + if (!(stack instanceof NestedStack)) { + templateText = JSON.stringify(assembly.getStackArtifact(stack.artifactId).template); + } else { + templateText = fs.readFileSync(path.join(assembly.directory, stack.templateFile), 'utf-8'); + } + + // verify templates do not have any "DependsOn" + expect(templateText.includes('DependsOn')).toBeFalsy(); +} diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.core-custom-resources.ts b/packages/@aws-cdk/aws-cloudformation/test/integ.core-custom-resources.ts index bdd4ae31af241..0b3fe66814d63 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.core-custom-resources.ts +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.core-custom-resources.ts @@ -13,7 +13,7 @@ import { App, CfnOutput, CustomResource, CustomResourceProvider, CustomResourceP // eslint-disable-next-line no-duplicate-imports, import/order import { Construct } from '@aws-cdk/core'; -/* eslint-disable cdk/no-core-construct */ +/* eslint-disable @aws-cdk/no-core-construct */ class TestStack extends Stack { constructor(scope: Construct, id: string) { diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stack.ts b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stack.ts index 77e008ac6872c..3b3a26346c2be 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stack.ts +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stack.ts @@ -9,7 +9,7 @@ import * as cfn from '../lib'; // eslint-disable-next-line no-duplicate-imports, import/order import { Construct } from '@aws-cdk/core'; -/* eslint-disable cdk/no-core-construct */ +/* eslint-disable @aws-cdk/no-core-construct */ interface MyNestedStackProps { readonly subscriber?: sqs.Queue; diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-assets.ts b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-assets.ts index dd3a74360e934..996ef461b0d2c 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-assets.ts +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-assets.ts @@ -8,7 +8,7 @@ import * as cfn from '../lib'; // eslint-disable-next-line no-duplicate-imports, import/order import { Construct } from '@aws-cdk/core'; -/* eslint-disable cdk/no-core-construct */ +/* eslint-disable @aws-cdk/no-core-construct */ class NestedStack extends cfn.NestedStack { constructor(scope: Construct, id: string) { diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-multi.ts b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-multi.ts index 67f11d0f31878..768f69cb93209 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-multi.ts +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-multi.ts @@ -7,7 +7,7 @@ import * as cfn from '../lib'; // eslint-disable-next-line no-duplicate-imports, import/order import { Construct } from '@aws-cdk/core'; -/* eslint-disable cdk/no-core-construct */ +/* eslint-disable @aws-cdk/no-core-construct */ class YourNestedStack extends cfn.NestedStack { constructor(scope: Construct, id: string) { diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs1.ts b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs1.ts index 1240d8d39e5b3..11ab60d5c80cf 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs1.ts +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs1.ts @@ -2,7 +2,7 @@ // nested stack references a resource from a non-nested non-parent stack -/* eslint-disable cdk/no-core-construct */ +/* eslint-disable @aws-cdk/no-core-construct */ import * as sns from '@aws-cdk/aws-sns'; import { App, Stack } from '@aws-cdk/core'; diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs2.ts b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs2.ts index 712de493fa9a3..03bfc0998a30e 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs2.ts +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs2.ts @@ -9,7 +9,7 @@ import { Construct } from '@aws-cdk/core'; // non-nested non-parent stack consumes a resource from a nested stack -/* eslint-disable cdk/no-core-construct */ +/* eslint-disable @aws-cdk/no-core-construct */ class ProducerNestedStack extends cfn.NestedStack { public readonly topic: sns.Topic; diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs3.ts b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs3.ts index f44eb1b1f731a..3266d08e027f0 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs3.ts +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.nested-stacks-refs3.ts @@ -9,7 +9,7 @@ import { Construct } from '@aws-cdk/core'; // references between siblings -/* eslint-disable cdk/no-core-construct */ +/* eslint-disable @aws-cdk/no-core-construct */ class ProducerNestedStack extends cfn.NestedStack { public readonly topic: sns.Topic; diff --git a/packages/@aws-cdk/aws-cloudformation/test/integ.trivial-lambda-resource.ts b/packages/@aws-cdk/aws-cloudformation/test/integ.trivial-lambda-resource.ts index 5d2b63f9b88b0..e88b7113cb113 100644 --- a/packages/@aws-cdk/aws-cloudformation/test/integ.trivial-lambda-resource.ts +++ b/packages/@aws-cdk/aws-cloudformation/test/integ.trivial-lambda-resource.ts @@ -7,7 +7,7 @@ import { CustomResource, CustomResourceProvider } from '../lib'; // eslint-disable-next-line no-duplicate-imports, import/order import { Construct } from '@aws-cdk/core'; -/* eslint-disable cdk/no-core-construct */ +/* eslint-disable @aws-cdk/no-core-construct */ interface DemoResourceProps { /** diff --git a/packages/@aws-cdk/aws-cloudformation/test/nested-stack.test.ts b/packages/@aws-cdk/aws-cloudformation/test/nested-stack.test.ts new file mode 100644 index 0000000000000..90c39268ec7bb --- /dev/null +++ b/packages/@aws-cdk/aws-cloudformation/test/nested-stack.test.ts @@ -0,0 +1,1083 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import { SynthUtils } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +import * as s3_assets from '@aws-cdk/aws-s3-assets'; +import * as sns from '@aws-cdk/aws-sns'; +import { App, CfnParameter, CfnResource, ContextProvider, LegacyStackSynthesizer, Names, Stack } from '@aws-cdk/core'; +import { NestedStack } from '../lib/nested-stack'; + +// keep this import separate from other imports to reduce chance for merge conflicts with v2-main +// eslint-disable-next-line no-duplicate-imports, import/order +import { Construct } from '@aws-cdk/core'; + +/* eslint-disable @aws-cdk/no-core-construct */ +/* eslint-disable max-len */ + +test('fails if defined as a root', () => { + // THEN + expect(() => new NestedStack(undefined as any, 'boom')).toThrow(/Nested stacks cannot be defined as a root construct/); +}); + +test('fails if defined without a parent stack', () => { + // GIVEN + const app = new App(); + const group = new Construct(app, 'group'); + + // THEN + expect(() => new NestedStack(app, 'boom')).toThrow(/must be defined within scope of another non-nested stack/); + expect(() => new NestedStack(group, 'bam')).toThrow(/must be defined within scope of another non-nested stack/); +}); + +test('can be defined as a direct child or an indirect child of a Stack', () => { + // GIVEN + const parent = new Stack(); + + // THEN + expect(() => new NestedStack(parent, 'direct')).not.toThrow(); + expect(() => new NestedStack(new Construct(parent, 'group'), 'indirect')).not.toThrow(); +}); + +test('nested stack is not synthesized as a stack artifact into the assembly', () => { + // GIVEN + const app = new App(); + const parentStack = new Stack(app, 'parent-stack'); + new NestedStack(parentStack, 'nested-stack'); + + // WHEN + const assembly = app.synth(); + + // THEN + expect(assembly.artifacts.length).toEqual(2); +}); + +test('the template of the nested stack is synthesized into the cloud assembly', () => { + // GIVEN + const app = new App(); + const parent = new Stack(app, 'parent-stack'); + const nested = new NestedStack(parent, 'nested-stack'); + new CfnResource(nested, 'ResourceInNestedStack', { type: 'AWS::Resource::Nested' }); + + // WHEN + const assembly = app.synth(); + + // THEN + const template = JSON.parse(fs.readFileSync(path.join(assembly.directory, `${Names.uniqueId(nested)}.nested.template.json`), 'utf-8')); + expect(template).toEqual({ + Resources: { + ResourceInNestedStack: { + Type: 'AWS::Resource::Nested', + }, + }, + }); +}); + +test('file asset metadata is associated with the parent stack', () => { + // GIVEN + const app = new App(); + const parent = new Stack(app, 'parent-stack'); + const nested = new NestedStack(parent, 'nested-stack'); + new CfnResource(nested, 'ResourceInNestedStack', { type: 'AWS::Resource::Nested' }); + + // WHEN + const assembly = app.synth(); + + // THEN + expect(assembly.getStackByName(parent.stackName).assets).toEqual([{ + path: 'parentstacknestedstack844892C0.nested.template.json', + id: 'c639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096', + packaging: 'file', + sourceHash: 'c639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096', + s3BucketParameter: 'AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096S3BucketDA8C3345', + s3KeyParameter: 'AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096S3VersionKey09D03EE6', + artifactHashParameter: 'AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096ArtifactHash8DE450C7', + }]); +}); + +test('aws::cloudformation::stack is synthesized in the parent scope', () => { + // GIVEN + const app = new App(); + const parent = new Stack(app, 'parent-stack'); + + // WHEN + const nested = new NestedStack(parent, 'nested-stack'); + new CfnResource(nested, 'ResourceInNestedStack', { type: 'AWS::Resource::Nested' }); + + // THEN + const assembly = app.synth(); + + // assembly has one stack (the parent) + expect(assembly.stacks.length).toEqual(1); + + // but this stack has an asset that points to the synthesized template + expect(assembly.stacks[0].assets[0].path).toEqual('parentstacknestedstack844892C0.nested.template.json'); + + // the template includes our resource + const filePath = path.join(assembly.directory, assembly.stacks[0].assets[0].path); + expect(JSON.parse(fs.readFileSync(filePath).toString('utf-8'))).toEqual({ + Resources: { ResourceInNestedStack: { Type: 'AWS::Resource::Nested' } }, + }); + + // the parent template includes the parameters and the nested stack resource which points to the s3 url + expect(parent).toMatchTemplate({ + Resources: { + nestedstackNestedStacknestedstackNestedStackResource71CDD241: { + Type: 'AWS::CloudFormation::Stack', + DeletionPolicy: 'Delete', + UpdateReplacePolicy: 'Delete', + Properties: { + TemplateURL: { + 'Fn::Join': [ + '', + [ + 'https://s3.', + { + Ref: 'AWS::Region', + }, + '.', + { + Ref: 'AWS::URLSuffix', + }, + '/', + { + Ref: 'AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096S3BucketDA8C3345', + }, + '/', + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + { + Ref: 'AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096S3VersionKey09D03EE6', + }, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + { + Ref: 'AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096S3VersionKey09D03EE6', + }, + ], + }, + ], + }, + ], + ], + }, + }, + }, + }, + Parameters: { + AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096S3BucketDA8C3345: { + Type: 'String', + Description: 'S3 bucket for asset "c639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096"', + }, + AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096S3VersionKey09D03EE6: { + Type: 'String', + Description: 'S3 key for asset version "c639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096"', + }, + AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096ArtifactHash8DE450C7: { + Type: 'String', + Description: 'Artifact hash for asset "c639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096"', + }, + }, + }); +}); + +test('Stack.of()', () => { + class MyNestedStack extends NestedStack { + public readonly stackOfChild: Stack; + + constructor(scope: Construct, id: string) { + super(scope, id); + + const param = new CfnParameter(this, 'param', { type: 'String' }); + this.stackOfChild = Stack.of(param); + } + } + + const parent = new Stack(); + const nested = new MyNestedStack(parent, 'nested'); + + expect(nested.stackOfChild).toEqual(nested); + expect(Stack.of(nested)).toEqual(nested); +}); + +test('references within the nested stack are not reported as cross stack references', () => { + class MyNestedStack extends NestedStack { + constructor(scope: Construct, id: string) { + super(scope, id); + + const param = new CfnParameter(this, 'param', { type: 'String' }); + new CfnResource(this, 'resource', { + type: 'My::Resource', + properties: { + SomeProp: param.valueAsString, + }, + }); + } + } + + const app = new App(); + const parent = new Stack(app, 'parent'); + + new MyNestedStack(parent, 'nested'); + + // references are added during "prepare" + const assembly = app.synth(); + + expect(assembly.stacks.length).toEqual(1); + expect(assembly.stacks[0].dependencies).toEqual([]); +}); + +test('references to a resource from the parent stack in a nested stack is translated into a cfn parameter', () => { + // WHEN + class MyNestedStack extends NestedStack { + + constructor(scope: Construct, id: string, resourceFromParent: CfnResource) { + super(scope, id); + + new CfnResource(this, 'resource', { + type: 'AWS::Child::Resource', + properties: { + ReferenceToResourceInParentStack: resourceFromParent.ref, + }, + }); + + new CfnResource(this, 'resource2', { + type: 'My::Resource::2', + properties: { + Prop1: resourceFromParent.getAtt('Attr'), + Prop2: resourceFromParent.ref, + }, + }); + } + } + + const app = new App(); + const parentStack = new Stack(app, 'parent'); + + const resource = new CfnResource(parentStack, 'parent-resource', { type: 'AWS::Parent::Resource' }); + + const nested = new MyNestedStack(parentStack, 'nested', resource); + + // THEN + app.synth(); + + // nested template should use a parameter to reference the resource from the parent stack + expect(nested).toMatchTemplate({ + Resources: + { + resource: + { + Type: 'AWS::Child::Resource', + Properties: + { ReferenceToResourceInParentStack: { Ref: 'referencetoparentparentresourceD56EA8F7Ref' } }, + }, + resource2: + { + Type: 'My::Resource::2', + Properties: + { + Prop1: { Ref: 'referencetoparentparentresourceD56EA8F7Attr' }, + Prop2: { Ref: 'referencetoparentparentresourceD56EA8F7Ref' }, + }, + }, + }, + Parameters: + { + referencetoparentparentresourceD56EA8F7Ref: { Type: 'String' }, + referencetoparentparentresourceD56EA8F7Attr: { Type: 'String' }, + }, + }); + + // parent template should pass in the value through the parameter + expect(parentStack).toHaveResource('AWS::CloudFormation::Stack', { + Parameters: { + referencetoparentparentresourceD56EA8F7Ref: { + Ref: 'parentresource', + }, + referencetoparentparentresourceD56EA8F7Attr: { + 'Fn::GetAtt': [ + 'parentresource', + 'Attr', + ], + }, + }, + }); +}); + +test('references to a resource in the nested stack in the parent is translated into a cfn output', () => { + class MyNestedStack extends NestedStack { + public readonly resourceFromChild: CfnResource; + + constructor(scope: Construct, id: string) { + super(scope, id); + + this.resourceFromChild = new CfnResource(this, 'resource', { + type: 'AWS::Child::Resource', + }); + } + } + + const app = new App(); + const parentStack = new Stack(app, 'parent'); + + const nested = new MyNestedStack(parentStack, 'nested'); + + new CfnResource(parentStack, 'another-parent-resource', { + type: 'AWS::Parent::Resource', + properties: { + RefToResourceInNestedStack: nested.resourceFromChild.ref, + }, + }); + + // references are added during "prepare" + app.synth(); + + // nested template should use a parameter to reference the resource from the parent stack + expect(nested).toMatchTemplate({ + Resources: { + resource: { Type: 'AWS::Child::Resource' }, + }, + Outputs: { + parentnestedresource4D680677Ref: { Value: { Ref: 'resource' } }, + }, + }); + + // parent template should pass in the value through the parameter + expect(parentStack).toHaveResource('AWS::Parent::Resource', { + RefToResourceInNestedStack: { + 'Fn::GetAtt': [ + 'nestedNestedStacknestedNestedStackResource3DD143BF', + 'Outputs.parentnestedresource4D680677Ref', + ], + }, + }); +}); + +test('nested stack references a resource from another non-nested stack (not the parent)', () => { + // GIVEN + const app = new App(); + const stack1 = new Stack(app, 'Stack1'); + const stack2 = new Stack(app, 'Stack2'); + const nestedUnderStack1 = new NestedStack(stack1, 'NestedUnderStack1'); + const resourceInStack2 = new CfnResource(stack2, 'ResourceInStack2', { type: 'MyResource' }); + + // WHEN + new CfnResource(nestedUnderStack1, 'ResourceInNestedStack1', { + type: 'Nested::Resource', + properties: { + RefToSibling: resourceInStack2.getAtt('MyAttribute'), + }, + }); + + // THEN + const assembly = app.synth(); + + // producing stack should have an export + expect(stack2).toMatchTemplate({ + Resources: { + ResourceInStack2: { Type: 'MyResource' }, + }, + Outputs: { + ExportsOutputFnGetAttResourceInStack2MyAttributeC15F1009: { + Value: { 'Fn::GetAtt': ['ResourceInStack2', 'MyAttribute'] }, + Export: { Name: 'Stack2:ExportsOutputFnGetAttResourceInStack2MyAttributeC15F1009' }, + }, + }, + }); + + // nested stack uses Fn::ImportValue like normal + expect(nestedUnderStack1).toMatchTemplate({ + Resources: { + ResourceInNestedStack1: { + Type: 'Nested::Resource', + Properties: { + RefToSibling: { + 'Fn::ImportValue': 'Stack2:ExportsOutputFnGetAttResourceInStack2MyAttributeC15F1009', + }, + }, + }, + }, + }); + + // verify a depedency was established between the parents + const stack1Artifact = assembly.getStackByName(stack1.stackName); + const stack2Artifact = assembly.getStackByName(stack2.stackName); + expect(stack1Artifact.dependencies.length).toEqual(1); + expect(stack2Artifact.dependencies.length).toEqual(0); + expect(stack1Artifact.dependencies[0]).toEqual(stack2Artifact); +}); + +test('nested stack within a nested stack references a resource in a sibling top-level stack', () => { + // GIVEN + const app = new App(); + const consumerTopLevel = new Stack(app, 'ConsumerTopLevel'); + const consumerNested1 = new NestedStack(consumerTopLevel, 'ConsumerNested1'); + const consumerNested2 = new NestedStack(consumerNested1, 'ConsumerNested2'); + const producerTopLevel = new Stack(app, 'ProducerTopLevel'); + const producer = new CfnResource(producerTopLevel, 'Producer', { type: 'Producer' }); + + // WHEN + new CfnResource(consumerNested2, 'Consumer', { + type: 'Consumer', + properties: { + Ref: producer.ref, + }, + }); + + // THEN + const manifest = app.synth(); + const consumerDeps = manifest.getStackArtifact(consumerTopLevel.artifactId).dependencies.map(d => d.id); + expect(consumerDeps).toEqual(['ProducerTopLevel']); +}); + +test('another non-nested stack takes a reference on a resource within the nested stack (the parent exports)', () => { + // GIVEN + const app = new App(); + const stack1 = new Stack(app, 'Stack1'); + const stack2 = new Stack(app, 'Stack2'); + const nestedUnderStack1 = new NestedStack(stack1, 'NestedUnderStack1'); + const resourceInNestedStack = new CfnResource(nestedUnderStack1, 'ResourceInNestedStack', { type: 'MyResource' }); + + // WHEN + new CfnResource(stack2, 'ResourceInStack2', { + type: 'JustResource', + properties: { + RefToSibling: resourceInNestedStack.getAtt('MyAttribute'), + }, + }); + + // THEN + const assembly = app.synth(); + + // nested stack should output this value as if it was referenced by the parent (without the export) + expect(nestedUnderStack1).toMatchTemplate({ + Resources: { + ResourceInNestedStack: { + Type: 'MyResource', + }, + }, + Outputs: { + Stack1NestedUnderStack1ResourceInNestedStack6EE9DCD2MyAttribute: { + Value: { + 'Fn::GetAtt': [ + 'ResourceInNestedStack', + 'MyAttribute', + ], + }, + }, + }, + }); + + // parent stack (stack1) should export this value + expect(assembly.getStackByName(stack1.stackName).template.Outputs).toEqual({ + ExportsOutputFnGetAttNestedUnderStack1NestedStackNestedUnderStack1NestedStackResourceF616305BOutputsStack1NestedUnderStack1ResourceInNestedStack6EE9DCD2MyAttribute564EECF3: { + Value: { 'Fn::GetAtt': ['NestedUnderStack1NestedStackNestedUnderStack1NestedStackResourceF616305B', 'Outputs.Stack1NestedUnderStack1ResourceInNestedStack6EE9DCD2MyAttribute'] }, + Export: { Name: 'Stack1:ExportsOutputFnGetAttNestedUnderStack1NestedStackNestedUnderStack1NestedStackResourceF616305BOutputsStack1NestedUnderStack1ResourceInNestedStack6EE9DCD2MyAttribute564EECF3' }, + }, + }); + + // consuming stack should use ImportValue to import the value from the parent stack + expect(stack2).toMatchTemplate({ + Resources: { + ResourceInStack2: { + Type: 'JustResource', + Properties: { + RefToSibling: { + 'Fn::ImportValue': 'Stack1:ExportsOutputFnGetAttNestedUnderStack1NestedStackNestedUnderStack1NestedStackResourceF616305BOutputsStack1NestedUnderStack1ResourceInNestedStack6EE9DCD2MyAttribute564EECF3', + }, + }, + }, + }, + }); + + expect(assembly.stacks.length).toEqual(2); + const stack1Artifact = assembly.getStackByName(stack1.stackName); + const stack2Artifact = assembly.getStackByName(stack2.stackName); + expect(stack1Artifact.dependencies.length).toEqual(0); + expect(stack2Artifact.dependencies.length).toEqual(1); + expect(stack2Artifact.dependencies[0]).toEqual(stack1Artifact); +}); + +test('references between sibling nested stacks should output from one and getAtt from the other', () => { + // GIVEN + const app = new App(); + const parent = new Stack(app, 'Parent'); + const nested1 = new NestedStack(parent, 'Nested1'); + const nested2 = new NestedStack(parent, 'Nested2'); + const resource1 = new CfnResource(nested1, 'Resource1', { type: 'Resource1' }); + + // WHEN + new CfnResource(nested2, 'Resource2', { + type: 'Resource2', + properties: { + RefToResource1: resource1.ref, + }, + }); + + // THEN + app.synth(); + + // producing nested stack + expect(nested1).toMatchTemplate({ + Resources: { + Resource1: { + Type: 'Resource1', + }, + }, + Outputs: { + ParentNested1Resource15F3F0657Ref: { + Value: { + Ref: 'Resource1', + }, + }, + }, + }); + + // consuming nested stack + expect(nested2).toMatchTemplate({ + Resources: { + Resource2: { + Type: 'Resource2', + Properties: { + RefToResource1: { + Ref: 'referencetoParentNested1NestedStackNested1NestedStackResource9C05342COutputsParentNested1Resource15F3F0657Ref', + }, + }, + }, + }, + Parameters: { + referencetoParentNested1NestedStackNested1NestedStackResource9C05342COutputsParentNested1Resource15F3F0657Ref: { + Type: 'String', + }, + }, + }); + + // parent + expect(parent).toHaveResource('AWS::CloudFormation::Stack', { + Parameters: { + referencetoParentNested1NestedStackNested1NestedStackResource9C05342COutputsParentNested1Resource15F3F0657Ref: { + 'Fn::GetAtt': [ + 'Nested1NestedStackNested1NestedStackResourceCD0AD36B', + 'Outputs.ParentNested1Resource15F3F0657Ref', + ], + }, + }, + }); +}); + +test('stackId returns AWS::StackId when referenced from the context of the nested stack', () => { + // GIVEN + const parent = new Stack(); + const nested = new NestedStack(parent, 'NestedStack'); + + // WHEN + new CfnResource(nested, 'NestedResource', { + type: 'Nested::Resource', + properties: { MyStackId: nested.stackId }, + }); + + // THEN + expect(nested).toHaveResource('Nested::Resource', { + MyStackId: { Ref: 'AWS::StackId' }, + }); +}); + +test('stackId returns the REF of the CloudFormation::Stack resource when referenced from the parent stack', () => { + // GIVEN + const parent = new Stack(); + const nested = new NestedStack(parent, 'NestedStack'); + + // WHEN + new CfnResource(parent, 'ParentResource', { + type: 'Parent::Resource', + properties: { NestedStackId: nested.stackId }, + }); + + // THEN + expect(parent).toHaveResource('Parent::Resource', { + NestedStackId: { Ref: 'NestedStackNestedStackNestedStackNestedStackResourceB70834FD' }, + }); +}); + +test('stackName returns AWS::StackName when referenced from the context of the nested stack', () => { + // GIVEN + const parent = new Stack(); + const nested = new NestedStack(parent, 'NestedStack'); + + // WHEN + new CfnResource(nested, 'NestedResource', { + type: 'Nested::Resource', + properties: { MyStackName: nested.stackName }, + }); + + // THEN + expect(nested).toHaveResource('Nested::Resource', { + MyStackName: { Ref: 'AWS::StackName' }, + }); +}); + +test('stackName returns the REF of the CloudFormation::Stack resource when referenced from the parent stack', () => { + // GIVEN + const parent = new Stack(); + const nested = new NestedStack(parent, 'NestedStack'); + + // WHEN + new CfnResource(parent, 'ParentResource', { + type: 'Parent::Resource', + properties: { NestedStackName: nested.stackName }, + }); + + // THEN + expect(parent).toHaveResource('Parent::Resource', { + NestedStackName: { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '/', + { + Ref: 'NestedStackNestedStackNestedStackNestedStackResourceB70834FD', + }, + ], + }, + ], + }, + }); +}); + +test('"account", "region" and "environment" are all derived from the parent', () => { + // GIVEN + const app = new App(); + const parent = new Stack(app, 'ParentStack', { env: { account: '1234account', region: 'us-east-44' } }); + + // WHEN + const nested = new NestedStack(parent, 'NestedStack'); + + // THEN + expect(nested.environment).toEqual(parent.environment); + expect(nested.account).toEqual(parent.account); + expect(nested.region).toEqual(parent.region); +}); + +test('double-nested stack', () => { + // GIVEN + const app = new App(); + const parent = new Stack(app, 'stack'); + + // WHEN + const nested1 = new NestedStack(parent, 'Nested1'); + const nested2 = new NestedStack(nested1, 'Nested2'); + + new CfnResource(nested1, 'Resource1', { type: 'Resource::1' }); + new CfnResource(nested2, 'Resource2', { type: 'Resource::2' }); + + // THEN + const assembly = app.synth(); + + // nested2 is a "leaf", so it's just the resource + expect(nested2).toMatchTemplate({ + Resources: { + Resource2: { Type: 'Resource::2' }, + }, + }); + + const middleStackHash = '7c426f7299a739900279ac1ece040397c1913cdf786f5228677b289f4d5e4c48'; + const bucketSuffix = 'C706B101'; + const versionSuffix = '4B193AA5'; + const hashSuffix = 'E28F0693'; + + // nested1 wires the nested2 template through parameters, so we expect those + expect(nested1).toHaveResource('Resource::1'); + const nested2Template = SynthUtils.toCloudFormation(nested1); + expect(nested2Template.Parameters).toEqual({ + referencetostackAssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3BucketE8768F5CRef: { Type: 'String' }, + referencetostackAssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3VersionKey49DD83A2Ref: { Type: 'String' }, + }); + + // parent stack should have two sets of parameters. one for the first nested stack and the second + // for the second nested stack, passed in as parameters to the first + const template = SynthUtils.toCloudFormation(parent); + expect(template.Parameters).toEqual({ + AssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3BucketDE3B88D6: { Type: 'String', Description: 'S3 bucket for asset "8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235c"' }, + AssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3VersionKey3A62EFEA: { Type: 'String', Description: 'S3 key for asset version "8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235c"' }, + AssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cArtifactHash7DC546E0: { Type: 'String', Description: 'Artifact hash for asset "8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235c"' }, + [`AssetParameters${middleStackHash}S3Bucket${bucketSuffix}`]: { Type: 'String', Description: `S3 bucket for asset "${middleStackHash}"` }, + [`AssetParameters${middleStackHash}S3VersionKey${versionSuffix}`]: { Type: 'String', Description: `S3 key for asset version "${middleStackHash}"` }, + [`AssetParameters${middleStackHash}ArtifactHash${hashSuffix}`]: { Type: 'String', Description: `Artifact hash for asset "${middleStackHash}"` }, + }); + + // proxy asset params to nested stack + expect(parent).toHaveResource('AWS::CloudFormation::Stack', { + Parameters: { + referencetostackAssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3BucketE8768F5CRef: { Ref: 'AssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3BucketDE3B88D6' }, + referencetostackAssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3VersionKey49DD83A2Ref: { Ref: 'AssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3VersionKey3A62EFEA' }, + }, + }); + + // parent stack should have 2 assets + expect(assembly.getStackByName(parent.stackName).assets.length).toEqual(2); +}); + +test('reference resource in a double nested stack (#15155)', () => { + // GIVEN + const app = new App(); + const producerStack = new Stack(app, 'Producer'); + const nested2 = new NestedStack(new NestedStack(producerStack, 'Nested1'), 'Nested2'); + const producerResource = new CfnResource(nested2, 'Resource', { type: 'MyResource' }); + const consumerStack = new Stack(app, 'Consumer'); + + // WHEN + new CfnResource(consumerStack, 'ConsumingResource', { + type: 'YourResource', + properties: { RefToResource: producerResource.ref }, + }); + + // THEN + const casm = app.synth(); // before #15155 was fixed this threw an error + + const producerTemplate = casm.getStackArtifact(producerStack.artifactId).template; + const consumerTemplate = casm.getStackArtifact(consumerStack.artifactId).template; + + // check that the consuming resource references the expected export name + const outputName = 'ExportsOutputFnGetAttNested1NestedStackNested1NestedStackResourceCD0AD36BOutputsProducerNested1Nested2NestedStackNested2NestedStackResource1E6FA3C3OutputsProducerNested1Nested238A89CC5Ref2E9E52EA'; + const exportName = producerTemplate.Outputs[outputName].Export.Name; + const importName = consumerTemplate.Resources.ConsumingResource.Properties.RefToResource['Fn::ImportValue']; + expect(exportName).toEqual(importName); +}); + +test('assets within nested stacks are proxied from the parent', () => { + // GIVEN + const app = new App(); + const parent = new Stack(app, 'ParentStack'); + const nested = new NestedStack(parent, 'NestedStack'); + + // WHEN + const asset = new s3_assets.Asset(nested, 'asset', { + path: path.join(__dirname, 'asset-fixture.txt'), + }); + + new CfnResource(nested, 'NestedResource', { + type: 'Nested::Resource', + properties: { + AssetBucket: asset.s3BucketName, + AssetKey: asset.s3ObjectKey, + }, + }); + + // THEN + const assembly = app.synth(); + const template = SynthUtils.toCloudFormation(parent); + + // two sets of asset parameters: one for the nested stack itself and one as a proxy for the asset within the stack + expect(template.Parameters).toEqual({ + AssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281S3BucketC188F637: { Type: 'String', Description: 'S3 bucket for asset "db01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281"' }, + AssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281S3VersionKeyC7F4DBF2: { Type: 'String', Description: 'S3 key for asset version "db01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281"' }, + AssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281ArtifactHash373B14D2: { Type: 'String', Description: 'Artifact hash for asset "db01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281"' }, + AssetParameters46b107d6db798ca46046b8669d057a4debcbdbaaddb6170400748c2f9e4f9d71S3Bucket3C4265E9: { Type: 'String', Description: 'S3 bucket for asset "46b107d6db798ca46046b8669d057a4debcbdbaaddb6170400748c2f9e4f9d71"' }, + AssetParameters46b107d6db798ca46046b8669d057a4debcbdbaaddb6170400748c2f9e4f9d71S3VersionKey8E981535: { Type: 'String', Description: 'S3 key for asset version "46b107d6db798ca46046b8669d057a4debcbdbaaddb6170400748c2f9e4f9d71"' }, + AssetParameters46b107d6db798ca46046b8669d057a4debcbdbaaddb6170400748c2f9e4f9d71ArtifactHash45A28583: { Type: 'String', Description: 'Artifact hash for asset "46b107d6db798ca46046b8669d057a4debcbdbaaddb6170400748c2f9e4f9d71"' }, + }); + + // asset proxy parameters are passed to the nested stack + expect(parent).toHaveResource('AWS::CloudFormation::Stack', { + Parameters: { + referencetoParentStackAssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281S3Bucket82C55B96Ref: { Ref: 'AssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281S3BucketC188F637' }, + referencetoParentStackAssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281S3VersionKeyA43C3CC6Ref: { Ref: 'AssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281S3VersionKeyC7F4DBF2' }, + }, + }); + + // parent stack should have 2 assets + expect(assembly.getStackByName(parent.stackName).assets.length).toEqual(2); +}); + +test('docker image assets are wired through the top-level stack', () => { + // GIVEN + const app = new App(); + const parent = new Stack(app, 'my-stack'); + const nested = new NestedStack(parent, 'nested-stack'); + + // WHEN + const location = nested.synthesizer.addDockerImageAsset({ + directoryName: 'my-image', + dockerBuildArgs: { key: 'value', boom: 'bam' }, + dockerBuildTarget: 'buildTarget', + sourceHash: 'hash-of-source', + }); + + // use the asset, so the parameters will be wired. + new sns.Topic(nested, 'MyTopic', { + displayName: `image location is ${location.imageUri}`, + }); + + // THEN + const asm = app.synth(); + expect(asm.getStackArtifact(parent.artifactId).assets).toEqual([ + { + repositoryName: 'aws-cdk/assets', + imageTag: 'hash-of-source', + id: 'hash-of-source', + packaging: 'container-image', + path: 'my-image', + sourceHash: 'hash-of-source', + buildArgs: { key: 'value', boom: 'bam' }, + target: 'buildTarget', + }, + { + path: 'mystacknestedstackFAE12FB5.nested.template.json', + id: 'fcdaee79eb79f37eca3a9b1cc0cc9ba150e4eea8c5d6d0c343cb6cd9dc68e2e5', + packaging: 'file', + sourceHash: 'fcdaee79eb79f37eca3a9b1cc0cc9ba150e4eea8c5d6d0c343cb6cd9dc68e2e5', + s3BucketParameter: 'AssetParametersfcdaee79eb79f37eca3a9b1cc0cc9ba150e4eea8c5d6d0c343cb6cd9dc68e2e5S3Bucket67A749F8', + s3KeyParameter: 'AssetParametersfcdaee79eb79f37eca3a9b1cc0cc9ba150e4eea8c5d6d0c343cb6cd9dc68e2e5S3VersionKeyE1E6A8D4', + artifactHashParameter: 'AssetParametersfcdaee79eb79f37eca3a9b1cc0cc9ba150e4eea8c5d6d0c343cb6cd9dc68e2e5ArtifactHash0AEDBE8A', + }, + ]); +}); + +test('metadata defined in nested stacks is reported at the parent stack level in the cloud assembly', () => { + // GIVEN + const app = new App({ stackTraces: false }); + const parent = new Stack(app, 'parent'); + const child = new Stack(parent, 'child'); + const nested = new NestedStack(child, 'nested'); + const resource = new CfnResource(nested, 'resource', { type: 'foo' }); + + // WHEN + resource.node.addMetadata('foo', 'bar'); + + // THEN: the first non-nested stack records the assembly metadata + const asm = app.synth(); + expect(asm.stacks.length).toEqual(2); // only one stack is defined as an artifact + expect(asm.getStackByName(parent.stackName).findMetadataByType('foo')).toEqual([]); + expect(asm.getStackByName(child.stackName).findMetadataByType('foo')).toEqual([ + { + path: '/parent/child/nested/resource', + type: 'foo', + data: 'bar', + }, + ]); +}); + +test('referencing attributes with period across stacks', () => { + // GIVEN + const parent = new Stack(); + const nested = new NestedStack(parent, 'nested'); + const consumed = new CfnResource(nested, 'resource-in-nested', { type: 'CONSUMED' }); + + // WHEN + new CfnResource(parent, 'resource-in-parent', { + type: 'CONSUMER', + properties: { + ConsumedAttribute: consumed.getAtt('Consumed.Attribute'), + }, + }); + + // THEN + expect(nested).toMatchTemplate({ + Resources: { + resourceinnested: { + Type: 'CONSUMED', + }, + }, + Outputs: { + nestedresourceinnested59B1F01CConsumedAttribute: { + Value: { + 'Fn::GetAtt': [ + 'resourceinnested', + 'Consumed.Attribute', + ], + }, + }, + }, + }); + + expect(parent).toHaveResource('CONSUMER', { + ConsumedAttribute: { + 'Fn::GetAtt': [ + 'nestedNestedStacknestedNestedStackResource3DD143BF', + 'Outputs.nestedresourceinnested59B1F01CConsumedAttribute', + ], + }, + }); +}); + +test('missing context in nested stack is reported if the context is not available', () => { + // GIVEN + const app = new App(); + const stack = new Stack(app, 'ParentStack', { env: { account: '1234account', region: 'us-east-44' } }); + const nestedStack = new NestedStack(stack, 'nested'); + const provider = 'availability-zones'; + const expectedKey = ContextProvider.getKey(nestedStack, { + provider, + }).key; + + // WHEN + ContextProvider.getValue(nestedStack, { + provider, + dummyValue: ['dummy1a', 'dummy1b', 'dummy1c'], + }); + + // THEN: missing context is reported in the cloud assembly + const asm = app.synth(); + const missing = asm.manifest.missing; + + expect(missing && missing.find(m => { + return (m.key === expectedKey); + })).toBeTruthy(); +}); + +test('3-level stacks: legacy synthesizer parameters are added to the middle-level stack', () => { + // GIVEN + const app = new App(); + const top = new Stack(app, 'stack', { + synthesizer: new LegacyStackSynthesizer(), + }); + const middle = new NestedStack(top, 'nested1'); + const bottom = new NestedStack(middle, 'nested2'); + + // WHEN + new CfnResource(bottom, 'Something', { + type: 'BottomLevel', + }); + + // THEN + const asm = app.synth(); + const middleTemplate = JSON.parse(fs.readFileSync(path.join(asm.directory, middle.templateFile), { encoding: 'utf-8' })); + + const hash = 'bc3c51e4d3545ee0a0069401e5a32c37b66d044b983f12de416ba1576ecaf0a4'; + expect(middleTemplate.Parameters ?? {}).toEqual({ + [`referencetostackAssetParameters${hash}S3BucketD7C30435Ref`]: { + Type: 'String', + }, + [`referencetostackAssetParameters${hash}S3VersionKeyB667DBE1Ref`]: { + Type: 'String', + }, + }); +}); + +test('references to a resource from a deeply nested stack', () => { + // GIVEN + const app = new App(); + const top = new Stack(app, 'stack'); + const topLevel = new CfnResource(top, 'toplevel', { type: 'TopLevel' }); + const nested1 = new NestedStack(top, 'nested1'); + const nested2 = new NestedStack(nested1, 'nested2'); + + // WHEN + new CfnResource(nested2, 'refToTopLevel', { + type: 'BottomLevel', + properties: { RefToTopLevel: topLevel.ref }, + }); + + // THEN + expect(top).toHaveResource('AWS::CloudFormation::Stack', { + Parameters: { + referencetostackAssetParameters842982bd421cce9742ba27151ef12ed699d44d22801f41e8029f63f2358a3f2fS3Bucket5DA5D2E7Ref: { + Ref: 'AssetParameters842982bd421cce9742ba27151ef12ed699d44d22801f41e8029f63f2358a3f2fS3BucketDD4D96B5', + }, + referencetostackAssetParameters842982bd421cce9742ba27151ef12ed699d44d22801f41e8029f63f2358a3f2fS3VersionKey8FBE5C12Ref: { + Ref: 'AssetParameters842982bd421cce9742ba27151ef12ed699d44d22801f41e8029f63f2358a3f2fS3VersionKey83E381F3', + }, + referencetostacktoplevelBB16BF13Ref: { + Ref: 'toplevel', + }, + }, + }); + + expect(nested1).toHaveResource('AWS::CloudFormation::Stack', { + Parameters: { + referencetostacktoplevelBB16BF13Ref: { + Ref: 'referencetostacktoplevelBB16BF13Ref', + }, + }, + }); + + expect(nested2).toMatchTemplate({ + Resources: { + refToTopLevel: { + Type: 'BottomLevel', + Properties: { + RefToTopLevel: { + Ref: 'referencetostacktoplevelBB16BF13Ref', + }, + }, + }, + }, + Parameters: { + referencetostacktoplevelBB16BF13Ref: { + Type: 'String', + }, + }, + }); +}); + +test('bottom nested stack consumes value from a top-level stack through a parameter in a middle nested stack', () => { + // GIVEN + const app = new App(); + const top = new Stack(app, 'Grandparent'); + const middle = new NestedStack(top, 'Parent'); + const bottom = new NestedStack(middle, 'Child'); + const resourceInGrandparent = new CfnResource(top, 'ResourceInGrandparent', { type: 'ResourceInGrandparent' }); + + // WHEN + new CfnResource(bottom, 'ResourceInChild', { + type: 'ResourceInChild', + properties: { + RefToGrandparent: resourceInGrandparent.ref, + }, + }); + + // THEN + + // this is the name allocated for the parameter that's propagated through + // the hierarchy. + const paramName = 'referencetoGrandparentResourceInGrandparent010E997ARef'; + + // child (bottom) references through a parameter. + expect(bottom).toMatchTemplate({ + Resources: { + ResourceInChild: { + Type: 'ResourceInChild', + Properties: { + RefToGrandparent: { Ref: paramName }, + }, + }, + }, + Parameters: { + [paramName]: { Type: 'String' }, + }, + }); + + // the parent (middle) sets the value of this parameter to be a reference to another parameter + expect(middle).toHaveResource('AWS::CloudFormation::Stack', { + Parameters: { + [paramName]: { Ref: paramName }, + }, + }); + + // grandparent (top) assigns the actual value to the parameter + expect(top).toHaveResource('AWS::CloudFormation::Stack', { + Parameters: { + [paramName]: { Ref: 'ResourceInGrandparent' }, + + // these are for the asset of the bottom nested stack + referencetoGrandparentAssetParameters3208f43b793a1dbe28ca02cf31fb975489071beb42c492b22dc3d32decc3b4b7S3Bucket06EEE58DRef: { + Ref: 'AssetParameters3208f43b793a1dbe28ca02cf31fb975489071beb42c492b22dc3d32decc3b4b7S3Bucket01877C2E', + }, + referencetoGrandparentAssetParameters3208f43b793a1dbe28ca02cf31fb975489071beb42c492b22dc3d32decc3b4b7S3VersionKeyD3B04909Ref: { + Ref: 'AssetParameters3208f43b793a1dbe28ca02cf31fb975489071beb42c492b22dc3d32decc3b4b7S3VersionKey5765F084', + }, + }, + }); +}); diff --git a/packages/@aws-cdk/aws-cloudformation/test/resource.test.ts b/packages/@aws-cdk/aws-cloudformation/test/resource.test.ts new file mode 100644 index 0000000000000..a3bd1944625ae --- /dev/null +++ b/packages/@aws-cdk/aws-cloudformation/test/resource.test.ts @@ -0,0 +1,220 @@ +import { ResourcePart } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +import * as lambda from '@aws-cdk/aws-lambda'; +import * as sns from '@aws-cdk/aws-sns'; +import * as cdk from '@aws-cdk/core'; +import { CustomResource, CustomResourceProvider } from '../lib'; + +// keep this import separate from other imports to reduce chance for merge conflicts with v2-main +// eslint-disable-next-line no-duplicate-imports, import/order +import { Construct } from '@aws-cdk/core'; + +/* eslint-disable @aws-cdk/no-core-construct */ +/* eslint-disable quote-props */ + +describe('custom resources honor removalPolicy', () => { + test('unspecified (aka .Destroy)', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Test'); + + // WHEN + new TestCustomResource(stack, 'Custom'); + + // THEN + expect(stack).toHaveResource('AWS::CloudFormation::CustomResource', {}, ResourcePart.CompleteDefinition); + expect(app.synth().tryGetArtifact(stack.stackName)!.findMetadataByType('aws:cdk:protected').length).toEqual(0); + }); + + test('.Destroy', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Test'); + + // WHEN + new TestCustomResource(stack, 'Custom', { removalPolicy: cdk.RemovalPolicy.DESTROY }); + + // THEN + expect(stack).toHaveResource('AWS::CloudFormation::CustomResource', {}, ResourcePart.CompleteDefinition); + expect(app.synth().tryGetArtifact(stack.stackName)!.findMetadataByType('aws:cdk:protected').length).toEqual(0); + }); + + test('.Retain', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Test'); + + // WHEN + new TestCustomResource(stack, 'Custom', { removalPolicy: cdk.RemovalPolicy.RETAIN }); + + // THEN + expect(stack).toHaveResource('AWS::CloudFormation::CustomResource', { + DeletionPolicy: 'Retain', + UpdateReplacePolicy: 'Retain', + }, ResourcePart.CompleteDefinition); + }); +}); + +test('custom resource is added twice, lambda is added once', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Test'); + + // WHEN + new TestCustomResource(stack, 'Custom1'); + new TestCustomResource(stack, 'Custom2'); + + // THEN + expect(stack).toMatchTemplate({ + 'Resources': { + 'SingletonLambdaTestCustomResourceProviderServiceRole81FEAB5C': { + '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', + ]], + }, + ], + }, + }, + 'SingletonLambdaTestCustomResourceProviderA9255269': { + 'Type': 'AWS::Lambda::Function', + 'Properties': { + 'Code': { + 'ZipFile': 'def hello(): pass', + }, + 'Handler': 'index.hello', + 'Role': { + 'Fn::GetAtt': [ + 'SingletonLambdaTestCustomResourceProviderServiceRole81FEAB5C', + 'Arn', + ], + }, + 'Runtime': 'python2.7', + 'Timeout': 300, + }, + 'DependsOn': [ + 'SingletonLambdaTestCustomResourceProviderServiceRole81FEAB5C', + ], + }, + 'Custom1D319B237': { + 'Type': 'AWS::CloudFormation::CustomResource', + 'DeletionPolicy': 'Delete', + 'UpdateReplacePolicy': 'Delete', + 'Properties': { + 'ServiceToken': { + 'Fn::GetAtt': [ + 'SingletonLambdaTestCustomResourceProviderA9255269', + 'Arn', + ], + }, + }, + }, + 'Custom2DD5FB44D': { + 'Type': 'AWS::CloudFormation::CustomResource', + 'DeletionPolicy': 'Delete', + 'UpdateReplacePolicy': 'Delete', + 'Properties': { + 'ServiceToken': { + 'Fn::GetAtt': [ + 'SingletonLambdaTestCustomResourceProviderA9255269', + 'Arn', + ], + }, + }, + }, + }, + }); +}); + +test('custom resources can specify a resource type that starts with Custom::', () => { + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Test'); + new CustomResource(stack, 'MyCustomResource', { + resourceType: 'Custom::MyCustomResourceType', + provider: CustomResourceProvider.fromTopic(new sns.Topic(stack, 'Provider')), + }); + expect(stack).toHaveResource('Custom::MyCustomResourceType'); +}); + +describe('fails if custom resource type is invalid', () => { + test('does not start with "Custom::"', () => { + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Test'); + + expect(() => { + new CustomResource(stack, 'MyCustomResource', { + resourceType: 'NoCustom::MyCustomResourceType', + provider: CustomResourceProvider.fromTopic(new sns.Topic(stack, 'Provider')), + }); + }).toThrow(/Custom resource type must begin with "Custom::"/); + }); + + test('has invalid characters', () => { + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Test'); + + expect(() => { + new CustomResource(stack, 'MyCustomResource', { + resourceType: 'Custom::My Custom?ResourceType', + provider: CustomResourceProvider.fromTopic(new sns.Topic(stack, 'Provider')), + }); + }).toThrow(/Custom resource type name can only include alphanumeric characters and/); + }); + + test('is longer than 60 characters', () => { + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Test'); + + expect(() => { + new CustomResource(stack, 'MyCustomResource', { + resourceType: 'Custom::0123456789012345678901234567890123456789012345678901234567891', + provider: CustomResourceProvider.fromTopic(new sns.Topic(stack, 'Provider')), + }); + }).toThrow(/Custom resource type length > 60/); + }); +}); + +test('.ref returns the intrinsic reference (physical name)', () => { + // GIVEN + const stack = new cdk.Stack(); + const res = new TestCustomResource(stack, 'myResource'); + + // THEN + expect(stack.resolve(res.resource.ref)).toEqual({ Ref: 'myResourceC6A188A9' }); +}); + +class TestCustomResource extends Construct { + public readonly resource: CustomResource; + + constructor(scope: Construct, id: string, opts: { removalPolicy?: cdk.RemovalPolicy } = {}) { + super(scope, id); + + const singletonLambda = new lambda.SingletonFunction(this, 'Lambda', { + uuid: 'TestCustomResourceProvider', + code: new lambda.InlineCode('def hello(): pass'), + runtime: lambda.Runtime.PYTHON_2_7, + handler: 'index.hello', + timeout: cdk.Duration.minutes(5), + }); + + this.resource = new CustomResource(this, 'Resource', { + ...opts, + provider: CustomResourceProvider.fromLambda(singletonLambda), + }); + } +} diff --git a/packages/@aws-cdk/aws-cloudformation/test/test.deps.ts b/packages/@aws-cdk/aws-cloudformation/test/test.deps.ts deleted file mode 100644 index de239daffb9a8..0000000000000 --- a/packages/@aws-cdk/aws-cloudformation/test/test.deps.ts +++ /dev/null @@ -1,362 +0,0 @@ -import * as fs from 'fs'; -import * as path from 'path'; -import { expect, haveResource, ResourcePart } from '@aws-cdk/assert-internal'; -import { App, CfnResource, Stack } from '@aws-cdk/core'; -import * as cxapi from '@aws-cdk/cx-api'; -import { Test } from 'nodeunit'; -import { NestedStack } from '../lib'; - -export = { - - 'resource dependencies': { - - 'between two resources in a top-level stack'(test: Test) { - // GIVEN - const app = new App(); - const stack = new Stack(app, 'Stack'); - const r1 = new CfnResource(stack, 'r1', { type: 'r1' }); - const r2 = new CfnResource(stack, 'r2', { type: 'r2' }); - - // WHEN - r1.addDependsOn(r2); - - // THEN - test.deepEqual(app.synth().getStackArtifact(stack.artifactId).template, { - Resources: - { r1: { Type: 'r1', DependsOn: ['r2'] }, r2: { Type: 'r2' } }, - }); - - test.done(); - }, - - 'resource in nested stack depends on a resource in the parent stack': matrixForResourceDependencyTest((test, addDep) => { - // GIVEN - const parent = new Stack(undefined, 'root'); - const nested = new NestedStack(parent, 'Nested'); - const resourceInParent = new CfnResource(parent, 'ResourceInParent', { type: 'PARENT' }); - const resourceInNested = new CfnResource(nested, 'ResourceInNested', { type: 'NESTED' }); - - // WHEN - addDep(resourceInNested, resourceInParent); - - // THEN: the dependency needs to transfer from the resource within the - // nested stack to the nested stack resource itself so the nested stack - // will only be deployed the dependent resource - expect(parent).to(haveResource('AWS::CloudFormation::Stack', { DependsOn: ['ResourceInParent'] }, ResourcePart.CompleteDefinition)); - expect(nested).toMatch({ Resources: { ResourceInNested: { Type: 'NESTED' } } }); // no DependsOn for the actual resource - test.done(); - }), - - 'resource in nested stack depends on a resource in a grandparent stack': matrixForResourceDependencyTest((test, addDep) => { - // GIVEN - const grantparent = new Stack(undefined, 'Grandparent'); - const parent = new NestedStack(grantparent, 'Parent'); - const nested = new NestedStack(parent, 'Nested'); - const resourceInGrandparent = new CfnResource(grantparent, 'ResourceInGrandparent', { type: 'GRANDPARENT' }); - const resourceInNested = new CfnResource(nested, 'ResourceInNested', { type: 'NESTED' }); - - // WHEN - addDep(resourceInNested, resourceInGrandparent); - - // THEN: the dependency needs to transfer from the resource within the - // nested stack to the *parent* nested stack - expect(grantparent).to(haveResource('AWS::CloudFormation::Stack', { DependsOn: ['ResourceInGrandparent'] }, ResourcePart.CompleteDefinition)); - expect(nested).toMatch({ Resources: { ResourceInNested: { Type: 'NESTED' } } }); // no DependsOn for the actual resource - test.done(); - }), - - 'resource in parent stack depends on resource in nested stack': matrixForResourceDependencyTest((test, addDep) => { - // GIVEN - const parent = new Stack(undefined, 'root'); - const nested = new NestedStack(parent, 'Nested'); - const resourceInParent = new CfnResource(parent, 'ResourceInParent', { type: 'PARENT' }); - const resourceInNested = new CfnResource(nested, 'ResourceInNested', { type: 'NESTED' }); - - // WHEN - addDep(resourceInParent, resourceInNested); - - // THEN: resource in parent needs to depend on the nested stack - expect(parent).to(haveResource('PARENT', { - DependsOn: [parent.resolve(nested.nestedStackResource!.logicalId)], - }, ResourcePart.CompleteDefinition)); - test.done(); - }), - - 'resource in grantparent stack depends on resource in nested stack': matrixForResourceDependencyTest((test, addDep) => { - // GIVEN - const grandparent = new Stack(undefined, 'Grandparent'); - const parent = new NestedStack(grandparent, 'Parent'); - const nested = new NestedStack(parent, 'Nested'); - const resourceInGrandparent = new CfnResource(grandparent, 'ResourceInGrandparent', { type: 'GRANDPARENT' }); - const resourceInNested = new CfnResource(nested, 'ResourceInNested', { type: 'NESTED' }); - - // WHEN - addDep(resourceInGrandparent, resourceInNested); - - // THEN: resource in grantparent needs to depend on the top-level nested stack - expect(grandparent).to(haveResource('GRANDPARENT', { - DependsOn: [grandparent.resolve(parent.nestedStackResource!.logicalId)], - }, ResourcePart.CompleteDefinition)); - - test.done(); - }), - - 'resource in sibling stack depends on a resource in nested stack': matrixForResourceDependencyTest((test, addDep) => { - // GIVEN - const app = new App(); - const stack1 = new Stack(app, 'Stack1'); - const nested1 = new NestedStack(stack1, 'Nested1'); - const resourceInNested1 = new CfnResource(nested1, 'ResourceInNested', { type: 'NESTED' }); - const stack2 = new Stack(app, 'Stack2'); - const resourceInStack2 = new CfnResource(stack2, 'ResourceInSibling', { type: 'SIBLING' }); - - // WHEN - addDep(resourceInStack2, resourceInNested1); - - // THEN: stack2 should depend on stack1 and no "DependsOn" inside templates - const assembly = app.synth(); - assertAssemblyDependency(test, assembly, stack1, []); - assertAssemblyDependency(test, assembly, stack2, ['Stack1']); - assertNoDependsOn(test, assembly, stack1); - assertNoDependsOn(test, assembly, stack2); - assertNoDependsOn(test, assembly, nested1); - test.done(); - }), - - 'resource in nested stack depends on a resource in sibling stack': matrixForResourceDependencyTest((test, addDep) => { - // GIVEN - const app = new App(); - const stack1 = new Stack(app, 'Stack1'); - const nested1 = new NestedStack(stack1, 'Nested1'); - const resourceInNested1 = new CfnResource(nested1, 'ResourceInNested', { type: 'NESTED' }); - const stack2 = new Stack(app, 'Stack2'); - const resourceInStack2 = new CfnResource(stack2, 'ResourceInSibling', { type: 'SIBLING' }); - - // WHEN - addDep(resourceInNested1, resourceInStack2); - - // THEN: stack1 should depend on stack2 and no "DependsOn" inside templates - const assembly = app.synth(); - assertAssemblyDependency(test, assembly, stack1, ['Stack2']); - assertAssemblyDependency(test, assembly, stack2, []); - assertNoDependsOn(test, assembly, stack1); - assertNoDependsOn(test, assembly, stack2); - assertNoDependsOn(test, assembly, nested1); - test.done(); - }), - - 'resource in nested stack depends on a resource in nested sibling stack': matrixForResourceDependencyTest((test, addDep) => { - // GIVEN - const app = new App(); - const stack = new Stack(app, 'Stack1'); - const nested1 = new NestedStack(stack, 'Nested1'); - const nested2 = new NestedStack(stack, 'Nested2'); - const resourceInNested1 = new CfnResource(nested1, 'ResourceInNested1', { type: 'NESTED1' }); - const resourceInNested2 = new CfnResource(nested2, 'ResourceInNested2', { type: 'NESTED2' }); - - // WHEN - addDep(resourceInNested1, resourceInNested2); - - // THEN: dependency transfered to nested stack resources - expect(stack).to(haveResource('AWS::CloudFormation::Stack', { - DependsOn: [stack.resolve(nested2.nestedStackResource!.logicalId)], - }, ResourcePart.CompleteDefinition)); - - expect(stack).notTo(haveResource('AWS::CloudFormation::Stack', { - DependsOn: [stack.resolve(nested1.nestedStackResource!.logicalId)], - }, ResourcePart.CompleteDefinition)); - - test.done(); - }), - - }, - - 'stack dependencies': { - - 'top level stack depends on itself'(test: Test) { - // GIVEN - const app = new App(); - const stack = new Stack(app, 'Stack'); - - // WHEN - stack.addDependency(stack); - - // THEN - const assembly = app.synth(); - assertAssemblyDependency(test, assembly, stack, []); - assertNoDependsOn(test, assembly, stack); - test.done(); - }, - - 'nested stack depends on itself'(test: Test) { - // GIVEN - const app = new App(); - const parent = new Stack(app, 'Parent'); - const nested = new NestedStack(parent, 'Nested'); - - // WHEN - nested.addDependency(nested); - - // THEN - assertNoDependsOn(test, app.synth(), parent); - test.done(); - }, - - 'nested stack cannot depend on any of its parents'(test: Test) { - // GIVEN - const root = new Stack(); - const nested1 = new NestedStack(root, 'Nested1'); - const nested2 = new NestedStack(nested1, 'Nested2'); - - // THEN - test.throws(() => nested1.addDependency(root), /Nested stack 'Default\/Nested1' cannot depend on a parent stack 'Default'/); - test.throws(() => nested2.addDependency(nested1), /Nested stack 'Default\/Nested1\/Nested2' cannot depend on a parent stack 'Default\/Nested1'/); - test.throws(() => nested2.addDependency(root), /Nested stack 'Default\/Nested1\/Nested2' cannot depend on a parent stack 'Default'/); - test.done(); - }, - - 'any parent stack is by definition dependent on the nested stack so dependency is ignored'(test: Test) { - // GIVEN - const root = new Stack(); - const nested1 = new NestedStack(root, 'Nested1'); - const nested2 = new NestedStack(nested1, 'Nested2'); - - // WHEN - root.addDependency(nested1); - root.addDependency(nested2); - nested1.addDependency(nested2); - - // THEN - test.done(); - }, - - 'sibling nested stacks transfer to resources'(test: Test) { - // GIVEN - const stack = new Stack(); - const nested1 = new NestedStack(stack, 'Nested1'); - const nested2 = new NestedStack(stack, 'Nested2'); - - // WHEN - nested1.addDependency(nested2); - - // THEN - expect(stack).to(haveResource('AWS::CloudFormation::Stack', { - DependsOn: [stack.resolve(nested2.nestedStackResource!.logicalId)], - }, ResourcePart.CompleteDefinition)); - test.done(); - }, - - 'nested stack depends on a deeply nested stack'(test: Test) { - // GIVEN - const stack = new Stack(); - const nested1 = new NestedStack(stack, 'Nested1'); - const nested2 = new NestedStack(stack, 'Nested2'); - const nested21 = new NestedStack(nested2, 'Nested21'); - - // WHEN - nested1.addDependency(nested21); - - // THEN: transfered to a resource dep between the resources in the common stack - expect(stack).to(haveResource('AWS::CloudFormation::Stack', { - DependsOn: [stack.resolve(nested2.nestedStackResource!.logicalId)], - }, ResourcePart.CompleteDefinition)); - test.done(); - }, - - 'deeply nested stack depends on a parent nested stack'(test: Test) { - // GIVEN - const stack = new Stack(); - const nested1 = new NestedStack(stack, 'Nested1'); - const nested2 = new NestedStack(stack, 'Nested2'); - const nested21 = new NestedStack(nested2, 'Nested21'); - - // WHEN - nested21.addDependency(nested1); - - // THEN: transfered to a resource dep between the resources in the common stack - expect(stack).to(haveResource('AWS::CloudFormation::Stack', { - DependsOn: [stack.resolve(nested1.nestedStackResource!.logicalId)], - }, ResourcePart.CompleteDefinition)); - test.done(); - }, - - 'top-level stack depends on a nested stack within a sibling'(test: Test) { - // GIVEN - const app = new App(); - const stack1 = new Stack(app, 'Stack1'); - const nested1 = new NestedStack(stack1, 'Nested1'); - const stack2 = new Stack(app, 'Stack2'); - - // WHEN - stack2.addDependency(nested1); - - // THEN: assembly-level dependency between stack2 and stack1 - const assembly = app.synth(); - assertAssemblyDependency(test, assembly, stack2, ['Stack1']); - assertAssemblyDependency(test, assembly, stack1, []); - assertNoDependsOn(test, assembly, stack1); - assertNoDependsOn(test, assembly, stack2); - assertNoDependsOn(test, assembly, nested1); - test.done(); - }, - - 'nested stack within a sibling depends on top-level stack'(test: Test) { - // GIVEN - const app = new App(); - const stack1 = new Stack(app, 'Stack1'); - const nested1 = new NestedStack(stack1, 'Nested1'); - const stack2 = new Stack(app, 'Stack2'); - - // WHEN - nested1.addDependency(stack2); - - // THEN: assembly-level dependency between stack2 and stack1 - const assembly = app.synth(); - assertAssemblyDependency(test, assembly, stack2, []); - assertAssemblyDependency(test, assembly, stack1, ['Stack2']); - assertNoDependsOn(test, assembly, stack1); - assertNoDependsOn(test, assembly, stack2); - assertNoDependsOn(test, assembly, nested1); - test.done(); - }, - - }, - -}; - -/** - * Given a test function which sets the stage and verifies a dependency scenario - * between two CloudFormation resources, returns two tests which exercise both - * "construct dependency" (i.e. node.addDependency) and "resource dependency" - * (i.e. resource.addDependsOn). - * - * @param testFunction The test function - */ -function matrixForResourceDependencyTest(testFunction: (test: Test, addDep: (source: CfnResource, target: CfnResource) => void) => void) { - return { - 'construct dependency'(test: Test) { - testFunction(test, (source, target) => source.node.addDependency(target)); - }, - 'resource dependency'(test: Test) { - testFunction(test, (source, target) => source.addDependsOn(target)); - }, - }; -} - -function assertAssemblyDependency(test: Test, assembly: cxapi.CloudAssembly, stack: Stack, expectedDeps: string[]) { - const stack1Art = assembly.getStackArtifact(stack.artifactId); - const stack1Deps = stack1Art.dependencies.map(x => x.id); - test.deepEqual(stack1Deps, expectedDeps); -} - -function assertNoDependsOn(test: Test, assembly: cxapi.CloudAssembly, stack: Stack) { - let templateText; - if (!(stack instanceof NestedStack)) { - templateText = JSON.stringify(assembly.getStackArtifact(stack.artifactId).template); - } else { - templateText = fs.readFileSync(path.join(assembly.directory, stack.templateFile), 'utf-8'); - } - - // verify templates do not have any "DependsOn" - test.ok(!templateText.includes('DependsOn')); -} diff --git a/packages/@aws-cdk/aws-cloudformation/test/test.nested-stack.ts b/packages/@aws-cdk/aws-cloudformation/test/test.nested-stack.ts deleted file mode 100644 index 29358708b0796..0000000000000 --- a/packages/@aws-cdk/aws-cloudformation/test/test.nested-stack.ts +++ /dev/null @@ -1,1127 +0,0 @@ -import * as fs from 'fs'; -import * as path from 'path'; -import { expect, haveResource, matchTemplate, SynthUtils } from '@aws-cdk/assert-internal'; -import * as s3_assets from '@aws-cdk/aws-s3-assets'; -import * as sns from '@aws-cdk/aws-sns'; -import { App, CfnParameter, CfnResource, ContextProvider, LegacyStackSynthesizer, Names, Stack } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; -import { NestedStack } from '../lib/nested-stack'; - -// keep this import separate from other imports to reduce chance for merge conflicts with v2-main -// eslint-disable-next-line no-duplicate-imports, import/order -import { Construct } from '@aws-cdk/core'; - -/* eslint-disable cdk/no-core-construct */ -/* eslint-disable max-len */ - -export = { - 'fails if defined as a root'(test: Test) { - // THEN - test.throws(() => new NestedStack(undefined as any, 'boom'), /Nested stacks cannot be defined as a root construct/); - test.done(); - }, - - 'fails if defined without a parent stack'(test: Test) { - // GIVEN - const app = new App(); - const group = new Construct(app, 'group'); - - // THEN - test.throws(() => new NestedStack(app, 'boom'), /must be defined within scope of another non-nested stack/); - test.throws(() => new NestedStack(group, 'bam'), /must be defined within scope of another non-nested stack/); - test.done(); - }, - - 'can be defined as a direct child or an indirect child of a Stack'(test: Test) { - // GIVEN - const parent = new Stack(); - - // THEN - new NestedStack(parent, 'direct'); - new NestedStack(new Construct(parent, 'group'), 'indirect'); - test.done(); - }, - - 'nested stack is not synthesized as a stack artifact into the assembly'(test: Test) { - // GIVEN - const app = new App(); - const parentStack = new Stack(app, 'parent-stack'); - new NestedStack(parentStack, 'nested-stack'); - - // WHEN - const assembly = app.synth(); - - // THEN - test.deepEqual(assembly.artifacts.length, 2); - test.done(); - }, - - 'the template of the nested stack is synthesized into the cloud assembly'(test: Test) { - // GIVEN - const app = new App(); - const parent = new Stack(app, 'parent-stack'); - const nested = new NestedStack(parent, 'nested-stack'); - new CfnResource(nested, 'ResourceInNestedStack', { type: 'AWS::Resource::Nested' }); - - // WHEN - const assembly = app.synth(); - - // THEN - const template = JSON.parse(fs.readFileSync(path.join(assembly.directory, `${Names.uniqueId(nested)}.nested.template.json`), 'utf-8')); - test.deepEqual(template, { - Resources: { - ResourceInNestedStack: { - Type: 'AWS::Resource::Nested', - }, - }, - }); - test.done(); - }, - - 'file asset metadata is associated with the parent stack'(test: Test) { - // GIVEN - const app = new App(); - const parent = new Stack(app, 'parent-stack'); - const nested = new NestedStack(parent, 'nested-stack'); - new CfnResource(nested, 'ResourceInNestedStack', { type: 'AWS::Resource::Nested' }); - - // WHEN - const assembly = app.synth(); - - // THEN - test.deepEqual(assembly.getStackByName(parent.stackName).assets, [{ - path: 'parentstacknestedstack844892C0.nested.template.json', - id: 'c639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096', - packaging: 'file', - sourceHash: 'c639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096', - s3BucketParameter: 'AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096S3BucketDA8C3345', - s3KeyParameter: 'AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096S3VersionKey09D03EE6', - artifactHashParameter: 'AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096ArtifactHash8DE450C7', - }]); - test.done(); - }, - - 'aws::cloudformation::stack is synthesized in the parent scope'(test: Test) { - // GIVEN - const app = new App(); - const parent = new Stack(app, 'parent-stack'); - - // WHEN - const nested = new NestedStack(parent, 'nested-stack'); - new CfnResource(nested, 'ResourceInNestedStack', { type: 'AWS::Resource::Nested' }); - - // THEN - const assembly = app.synth(); - - // assembly has one stack (the parent) - test.deepEqual(assembly.stacks.length, 1); - - // but this stack has an asset that points to the synthesized template - test.deepEqual(assembly.stacks[0].assets[0].path, 'parentstacknestedstack844892C0.nested.template.json'); - - // the template includes our resource - const filePath = path.join(assembly.directory, assembly.stacks[0].assets[0].path); - test.deepEqual(JSON.parse(fs.readFileSync(filePath).toString('utf-8')), { - Resources: { ResourceInNestedStack: { Type: 'AWS::Resource::Nested' } }, - }); - - // the parent template includes the parameters and the nested stack resource which points to the s3 url - expect(parent).toMatch({ - Resources: { - nestedstackNestedStacknestedstackNestedStackResource71CDD241: { - Type: 'AWS::CloudFormation::Stack', - DeletionPolicy: 'Delete', - UpdateReplacePolicy: 'Delete', - Properties: { - TemplateURL: { - 'Fn::Join': [ - '', - [ - 'https://s3.', - { - Ref: 'AWS::Region', - }, - '.', - { - Ref: 'AWS::URLSuffix', - }, - '/', - { - Ref: 'AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096S3BucketDA8C3345', - }, - '/', - { - 'Fn::Select': [ - 0, - { - 'Fn::Split': [ - '||', - { - Ref: 'AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096S3VersionKey09D03EE6', - }, - ], - }, - ], - }, - { - 'Fn::Select': [ - 1, - { - 'Fn::Split': [ - '||', - { - Ref: 'AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096S3VersionKey09D03EE6', - }, - ], - }, - ], - }, - ], - ], - }, - }, - }, - }, - Parameters: { - AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096S3BucketDA8C3345: { - Type: 'String', - Description: 'S3 bucket for asset "c639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096"', - }, - AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096S3VersionKey09D03EE6: { - Type: 'String', - Description: 'S3 key for asset version "c639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096"', - }, - AssetParametersc639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096ArtifactHash8DE450C7: { - Type: 'String', - Description: 'Artifact hash for asset "c639c0a5e7320758aa22589669ecebc98f185b711300b074f53998c8f9a45096"', - }, - }, - }); - test.done(); - }, - - 'Stack.of()'(test: Test) { - class MyNestedStack extends NestedStack { - public readonly stackOfChild: Stack; - - constructor(scope: Construct, id: string) { - super(scope, id); - - const param = new CfnParameter(this, 'param', { type: 'String' }); - this.stackOfChild = Stack.of(param); - } - } - - const parent = new Stack(); - const nested = new MyNestedStack(parent, 'nested'); - - test.ok(nested.stackOfChild === nested); - test.ok(Stack.of(nested) === nested); - test.done(); - }, - - 'references within the nested stack are not reported as cross stack references'(test: Test) { - class MyNestedStack extends NestedStack { - constructor(scope: Construct, id: string) { - super(scope, id); - - const param = new CfnParameter(this, 'param', { type: 'String' }); - new CfnResource(this, 'resource', { - type: 'My::Resource', - properties: { - SomeProp: param.valueAsString, - }, - }); - } - } - - const app = new App(); - const parent = new Stack(app, 'parent'); - - new MyNestedStack(parent, 'nested'); - - // references are added during "prepare" - const assembly = app.synth(); - - test.deepEqual(assembly.stacks.length, 1); - test.deepEqual(assembly.stacks[0].dependencies, []); - test.done(); - }, - - 'references to a resource from the parent stack in a nested stack is translated into a cfn parameter'(test: Test) { - // WHEN - class MyNestedStack extends NestedStack { - - constructor(scope: Construct, id: string, resourceFromParent: CfnResource) { - super(scope, id); - - new CfnResource(this, 'resource', { - type: 'AWS::Child::Resource', - properties: { - ReferenceToResourceInParentStack: resourceFromParent.ref, - }, - }); - - new CfnResource(this, 'resource2', { - type: 'My::Resource::2', - properties: { - Prop1: resourceFromParent.getAtt('Attr'), - Prop2: resourceFromParent.ref, - }, - }); - } - } - - const app = new App(); - const parentStack = new Stack(app, 'parent'); - - const resource = new CfnResource(parentStack, 'parent-resource', { type: 'AWS::Parent::Resource' }); - - const nested = new MyNestedStack(parentStack, 'nested', resource); - - // THEN - app.synth(); - - // nested template should use a parameter to reference the resource from the parent stack - expect(nested).toMatch({ - Resources: - { - resource: - { - Type: 'AWS::Child::Resource', - Properties: - { ReferenceToResourceInParentStack: { Ref: 'referencetoparentparentresourceD56EA8F7Ref' } }, - }, - resource2: - { - Type: 'My::Resource::2', - Properties: - { - Prop1: { Ref: 'referencetoparentparentresourceD56EA8F7Attr' }, - Prop2: { Ref: 'referencetoparentparentresourceD56EA8F7Ref' }, - }, - }, - }, - Parameters: - { - referencetoparentparentresourceD56EA8F7Ref: { Type: 'String' }, - referencetoparentparentresourceD56EA8F7Attr: { Type: 'String' }, - }, - }); - - // parent template should pass in the value through the parameter - expect(parentStack).to(haveResource('AWS::CloudFormation::Stack', { - Parameters: { - referencetoparentparentresourceD56EA8F7Ref: { - Ref: 'parentresource', - }, - referencetoparentparentresourceD56EA8F7Attr: { - 'Fn::GetAtt': [ - 'parentresource', - 'Attr', - ], - }, - }, - })); - - test.done(); - }, - - 'references to a resource in the nested stack in the parent is translated into a cfn output'(test: Test) { - class MyNestedStack extends NestedStack { - public readonly resourceFromChild: CfnResource; - - constructor(scope: Construct, id: string) { - super(scope, id); - - this.resourceFromChild = new CfnResource(this, 'resource', { - type: 'AWS::Child::Resource', - }); - } - } - - const app = new App(); - const parentStack = new Stack(app, 'parent'); - - const nested = new MyNestedStack(parentStack, 'nested'); - - new CfnResource(parentStack, 'another-parent-resource', { - type: 'AWS::Parent::Resource', - properties: { - RefToResourceInNestedStack: nested.resourceFromChild.ref, - }, - }); - - // references are added during "prepare" - app.synth(); - - // nested template should use a parameter to reference the resource from the parent stack - expect(nested).toMatch({ - Resources: { - resource: { Type: 'AWS::Child::Resource' }, - }, - Outputs: { - parentnestedresource4D680677Ref: { Value: { Ref: 'resource' } }, - }, - }); - - // parent template should pass in the value through the parameter - expect(parentStack).to(haveResource('AWS::Parent::Resource', { - RefToResourceInNestedStack: { - 'Fn::GetAtt': [ - 'nestedNestedStacknestedNestedStackResource3DD143BF', - 'Outputs.parentnestedresource4D680677Ref', - ], - }, - })); - - test.done(); - }, - - 'nested stack references a resource from another non-nested stack (not the parent)'(test: Test) { - // GIVEN - const app = new App(); - const stack1 = new Stack(app, 'Stack1'); - const stack2 = new Stack(app, 'Stack2'); - const nestedUnderStack1 = new NestedStack(stack1, 'NestedUnderStack1'); - const resourceInStack2 = new CfnResource(stack2, 'ResourceInStack2', { type: 'MyResource' }); - - // WHEN - new CfnResource(nestedUnderStack1, 'ResourceInNestedStack1', { - type: 'Nested::Resource', - properties: { - RefToSibling: resourceInStack2.getAtt('MyAttribute'), - }, - }); - - // THEN - const assembly = app.synth(); - - // producing stack should have an export - expect(stack2).toMatch({ - Resources: { - ResourceInStack2: { Type: 'MyResource' }, - }, - Outputs: { - ExportsOutputFnGetAttResourceInStack2MyAttributeC15F1009: { - Value: { 'Fn::GetAtt': ['ResourceInStack2', 'MyAttribute'] }, - Export: { Name: 'Stack2:ExportsOutputFnGetAttResourceInStack2MyAttributeC15F1009' }, - }, - }, - }); - - // nested stack uses Fn::ImportValue like normal - expect(nestedUnderStack1).toMatch({ - Resources: { - ResourceInNestedStack1: { - Type: 'Nested::Resource', - Properties: { - RefToSibling: { - 'Fn::ImportValue': 'Stack2:ExportsOutputFnGetAttResourceInStack2MyAttributeC15F1009', - }, - }, - }, - }, - }); - - // verify a depedency was established between the parents - const stack1Artifact = assembly.getStackByName(stack1.stackName); - const stack2Artifact = assembly.getStackByName(stack2.stackName); - test.deepEqual(stack1Artifact.dependencies.length, 1); - test.deepEqual(stack2Artifact.dependencies.length, 0); - test.same(stack1Artifact.dependencies[0], stack2Artifact); - test.done(); - }, - - 'nested stack within a nested stack references a resource in a sibling top-level stack'(test: Test) { - // GIVEN - const app = new App(); - const consumerTopLevel = new Stack(app, 'ConsumerTopLevel'); - const consumerNested1 = new NestedStack(consumerTopLevel, 'ConsumerNested1'); - const consumerNested2 = new NestedStack(consumerNested1, 'ConsumerNested2'); - const producerTopLevel = new Stack(app, 'ProducerTopLevel'); - const producer = new CfnResource(producerTopLevel, 'Producer', { type: 'Producer' }); - - // WHEN - new CfnResource(consumerNested2, 'Consumer', { - type: 'Consumer', - properties: { - Ref: producer.ref, - }, - }); - - // THEN - const manifest = app.synth(); - const consumerDeps = manifest.getStackArtifact(consumerTopLevel.artifactId).dependencies.map(d => d.id); - test.deepEqual(consumerDeps, ['ProducerTopLevel']); - test.done(); - }, - - 'another non-nested stack takes a reference on a resource within the nested stack (the parent exports)'(test: Test) { - // GIVEN - const app = new App(); - const stack1 = new Stack(app, 'Stack1'); - const stack2 = new Stack(app, 'Stack2'); - const nestedUnderStack1 = new NestedStack(stack1, 'NestedUnderStack1'); - const resourceInNestedStack = new CfnResource(nestedUnderStack1, 'ResourceInNestedStack', { type: 'MyResource' }); - - // WHEN - new CfnResource(stack2, 'ResourceInStack2', { - type: 'JustResource', - properties: { - RefToSibling: resourceInNestedStack.getAtt('MyAttribute'), - }, - }); - - // THEN - const assembly = app.synth(); - - // nested stack should output this value as if it was referenced by the parent (without the export) - expect(nestedUnderStack1).toMatch({ - Resources: { - ResourceInNestedStack: { - Type: 'MyResource', - }, - }, - Outputs: { - Stack1NestedUnderStack1ResourceInNestedStack6EE9DCD2MyAttribute: { - Value: { - 'Fn::GetAtt': [ - 'ResourceInNestedStack', - 'MyAttribute', - ], - }, - }, - }, - }); - - // parent stack (stack1) should export this value - test.deepEqual(assembly.getStackByName(stack1.stackName).template.Outputs, { - ExportsOutputFnGetAttNestedUnderStack1NestedStackNestedUnderStack1NestedStackResourceF616305BOutputsStack1NestedUnderStack1ResourceInNestedStack6EE9DCD2MyAttribute564EECF3: { - Value: { 'Fn::GetAtt': ['NestedUnderStack1NestedStackNestedUnderStack1NestedStackResourceF616305B', 'Outputs.Stack1NestedUnderStack1ResourceInNestedStack6EE9DCD2MyAttribute'] }, - Export: { Name: 'Stack1:ExportsOutputFnGetAttNestedUnderStack1NestedStackNestedUnderStack1NestedStackResourceF616305BOutputsStack1NestedUnderStack1ResourceInNestedStack6EE9DCD2MyAttribute564EECF3' }, - }, - }); - - // consuming stack should use ImportValue to import the value from the parent stack - expect(stack2).toMatch({ - Resources: { - ResourceInStack2: { - Type: 'JustResource', - Properties: { - RefToSibling: { - 'Fn::ImportValue': 'Stack1:ExportsOutputFnGetAttNestedUnderStack1NestedStackNestedUnderStack1NestedStackResourceF616305BOutputsStack1NestedUnderStack1ResourceInNestedStack6EE9DCD2MyAttribute564EECF3', - }, - }, - }, - }, - }); - - test.deepEqual(assembly.stacks.length, 2); - const stack1Artifact = assembly.getStackByName(stack1.stackName); - const stack2Artifact = assembly.getStackByName(stack2.stackName); - test.deepEqual(stack1Artifact.dependencies.length, 0); - test.deepEqual(stack2Artifact.dependencies.length, 1); - test.same(stack2Artifact.dependencies[0], stack1Artifact); - test.done(); - }, - - 'references between sibling nested stacks should output from one and getAtt from the other'(test: Test) { - // GIVEN - const app = new App(); - const parent = new Stack(app, 'Parent'); - const nested1 = new NestedStack(parent, 'Nested1'); - const nested2 = new NestedStack(parent, 'Nested2'); - const resource1 = new CfnResource(nested1, 'Resource1', { type: 'Resource1' }); - - // WHEN - new CfnResource(nested2, 'Resource2', { - type: 'Resource2', - properties: { - RefToResource1: resource1.ref, - }, - }); - - // THEN - app.synth(); - - // producing nested stack - expect(nested1).toMatch({ - Resources: { - Resource1: { - Type: 'Resource1', - }, - }, - Outputs: { - ParentNested1Resource15F3F0657Ref: { - Value: { - Ref: 'Resource1', - }, - }, - }, - }); - - // consuming nested stack - expect(nested2).toMatch({ - Resources: { - Resource2: { - Type: 'Resource2', - Properties: { - RefToResource1: { - Ref: 'referencetoParentNested1NestedStackNested1NestedStackResource9C05342COutputsParentNested1Resource15F3F0657Ref', - }, - }, - }, - }, - Parameters: { - referencetoParentNested1NestedStackNested1NestedStackResource9C05342COutputsParentNested1Resource15F3F0657Ref: { - Type: 'String', - }, - }, - }); - - // parent - expect(parent).to(haveResource('AWS::CloudFormation::Stack', { - Parameters: { - referencetoParentNested1NestedStackNested1NestedStackResource9C05342COutputsParentNested1Resource15F3F0657Ref: { - 'Fn::GetAtt': [ - 'Nested1NestedStackNested1NestedStackResourceCD0AD36B', - 'Outputs.ParentNested1Resource15F3F0657Ref', - ], - }, - }, - })); - - test.done(); - }, - - 'stackId returns AWS::StackId when referenced from the context of the nested stack'(test: Test) { - // GIVEN - const parent = new Stack(); - const nested = new NestedStack(parent, 'NestedStack'); - - // WHEN - new CfnResource(nested, 'NestedResource', { - type: 'Nested::Resource', - properties: { MyStackId: nested.stackId }, - }); - - // THEN - expect(nested).to(haveResource('Nested::Resource', { - MyStackId: { Ref: 'AWS::StackId' }, - })); - - test.done(); - }, - - 'stackId returns the REF of the CloudFormation::Stack resource when referenced from the parent stack'(test: Test) { - // GIVEN - const parent = new Stack(); - const nested = new NestedStack(parent, 'NestedStack'); - - // WHEN - new CfnResource(parent, 'ParentResource', { - type: 'Parent::Resource', - properties: { NestedStackId: nested.stackId }, - }); - - // THEN - expect(parent).to(haveResource('Parent::Resource', { - NestedStackId: { Ref: 'NestedStackNestedStackNestedStackNestedStackResourceB70834FD' }, - })); - - test.done(); - }, - - 'stackName returns AWS::StackName when referenced from the context of the nested stack'(test: Test) { - // GIVEN - const parent = new Stack(); - const nested = new NestedStack(parent, 'NestedStack'); - - // WHEN - new CfnResource(nested, 'NestedResource', { - type: 'Nested::Resource', - properties: { MyStackName: nested.stackName }, - }); - - // THEN - expect(nested).to(haveResource('Nested::Resource', { - MyStackName: { Ref: 'AWS::StackName' }, - })); - - test.done(); - }, - - 'stackName returns the REF of the CloudFormation::Stack resource when referenced from the parent stack'(test: Test) { - // GIVEN - const parent = new Stack(); - const nested = new NestedStack(parent, 'NestedStack'); - - // WHEN - new CfnResource(parent, 'ParentResource', { - type: 'Parent::Resource', - properties: { NestedStackName: nested.stackName }, - }); - - // THEN - expect(parent).to(haveResource('Parent::Resource', { - NestedStackName: { - 'Fn::Select': [ - 1, - { - 'Fn::Split': [ - '/', - { - Ref: 'NestedStackNestedStackNestedStackNestedStackResourceB70834FD', - }, - ], - }, - ], - }, - })); - - test.done(); - }, - - '"account", "region" and "environment" are all derived from the parent'(test: Test) { - // GIVEN - const app = new App(); - const parent = new Stack(app, 'ParentStack', { env: { account: '1234account', region: 'us-east-44' } }); - - // WHEN - const nested = new NestedStack(parent, 'NestedStack'); - - // THEN - test.deepEqual(nested.environment, parent.environment); - test.deepEqual(nested.account, parent.account); - test.deepEqual(nested.region, parent.region); - test.done(); - }, - - 'double-nested stack'(test: Test) { - // GIVEN - const app = new App(); - const parent = new Stack(app, 'stack'); - - // WHEN - const nested1 = new NestedStack(parent, 'Nested1'); - const nested2 = new NestedStack(nested1, 'Nested2'); - - new CfnResource(nested1, 'Resource1', { type: 'Resource::1' }); - new CfnResource(nested2, 'Resource2', { type: 'Resource::2' }); - - // THEN - const assembly = app.synth(); - - // nested2 is a "leaf", so it's just the resource - expect(nested2).toMatch({ - Resources: { - Resource2: { Type: 'Resource::2' }, - }, - }); - - const middleStackHash = '7c426f7299a739900279ac1ece040397c1913cdf786f5228677b289f4d5e4c48'; - const bucketSuffix = 'C706B101'; - const versionSuffix = '4B193AA5'; - const hashSuffix = 'E28F0693'; - - // nested1 wires the nested2 template through parameters, so we expect those - expect(nested1).to(haveResource('Resource::1')); - const nested2Template = SynthUtils.toCloudFormation(nested1); - test.deepEqual(nested2Template.Parameters, { - referencetostackAssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3BucketE8768F5CRef: { Type: 'String' }, - referencetostackAssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3VersionKey49DD83A2Ref: { Type: 'String' }, - }); - - // parent stack should have two sets of parameters. one for the first nested stack and the second - // for the second nested stack, passed in as parameters to the first - const template = SynthUtils.toCloudFormation(parent); - test.deepEqual(template.Parameters, { - AssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3BucketDE3B88D6: { Type: 'String', Description: 'S3 bucket for asset "8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235c"' }, - AssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3VersionKey3A62EFEA: { Type: 'String', Description: 'S3 key for asset version "8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235c"' }, - AssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cArtifactHash7DC546E0: { Type: 'String', Description: 'Artifact hash for asset "8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235c"' }, - [`AssetParameters${middleStackHash}S3Bucket${bucketSuffix}`]: { Type: 'String', Description: `S3 bucket for asset "${middleStackHash}"` }, - [`AssetParameters${middleStackHash}S3VersionKey${versionSuffix}`]: { Type: 'String', Description: `S3 key for asset version "${middleStackHash}"` }, - [`AssetParameters${middleStackHash}ArtifactHash${hashSuffix}`]: { Type: 'String', Description: `Artifact hash for asset "${middleStackHash}"` }, - }); - - // proxy asset params to nested stack - expect(parent).to(haveResource('AWS::CloudFormation::Stack', { - Parameters: { - referencetostackAssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3BucketE8768F5CRef: { Ref: 'AssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3BucketDE3B88D6' }, - referencetostackAssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3VersionKey49DD83A2Ref: { Ref: 'AssetParameters8169c6f8aaeaf5e2e8620f5f895ffe2099202ccb4b6889df48fe0967a894235cS3VersionKey3A62EFEA' }, - }, - })); - - // parent stack should have 2 assets - test.deepEqual(assembly.getStackByName(parent.stackName).assets.length, 2); - test.done(); - }, - - 'reference resource in a double nested stack (#15155)'(test: Test) { - // GIVEN - const app = new App(); - const producerStack = new Stack(app, 'Producer'); - const nested2 = new NestedStack(new NestedStack(producerStack, 'Nested1'), 'Nested2'); - const producerResource = new CfnResource(nested2, 'Resource', { type: 'MyResource' }); - const consumerStack = new Stack(app, 'Consumer'); - - // WHEN - new CfnResource(consumerStack, 'ConsumingResource', { - type: 'YourResource', - properties: { RefToResource: producerResource.ref }, - }); - - // THEN - const casm = app.synth(); // before #15155 was fixed this threw an error - - const producerTemplate = casm.getStackArtifact(producerStack.artifactId).template; - const consumerTemplate = casm.getStackArtifact(consumerStack.artifactId).template; - - // check that the consuming resource references the expected export name - const outputName = 'ExportsOutputFnGetAttNested1NestedStackNested1NestedStackResourceCD0AD36BOutputsProducerNested1Nested2NestedStackNested2NestedStackResource1E6FA3C3OutputsProducerNested1Nested238A89CC5Ref2E9E52EA'; - const exportName = producerTemplate.Outputs[outputName].Export.Name; - const importName = consumerTemplate.Resources.ConsumingResource.Properties.RefToResource['Fn::ImportValue']; - test.equal(exportName, importName); - - test.done(); - }, - - 'assets within nested stacks are proxied from the parent'(test: Test) { - // GIVEN - const app = new App(); - const parent = new Stack(app, 'ParentStack'); - const nested = new NestedStack(parent, 'NestedStack'); - - // WHEN - const asset = new s3_assets.Asset(nested, 'asset', { - path: path.join(__dirname, 'asset-fixture.txt'), - }); - - new CfnResource(nested, 'NestedResource', { - type: 'Nested::Resource', - properties: { - AssetBucket: asset.s3BucketName, - AssetKey: asset.s3ObjectKey, - }, - }); - - // THEN - const assembly = app.synth(); - const template = SynthUtils.toCloudFormation(parent); - - // two sets of asset parameters: one for the nested stack itself and one as a proxy for the asset within the stack - test.deepEqual(template.Parameters, { - AssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281S3BucketC188F637: { Type: 'String', Description: 'S3 bucket for asset "db01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281"' }, - AssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281S3VersionKeyC7F4DBF2: { Type: 'String', Description: 'S3 key for asset version "db01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281"' }, - AssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281ArtifactHash373B14D2: { Type: 'String', Description: 'Artifact hash for asset "db01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281"' }, - AssetParameters46b107d6db798ca46046b8669d057a4debcbdbaaddb6170400748c2f9e4f9d71S3Bucket3C4265E9: { Type: 'String', Description: 'S3 bucket for asset "46b107d6db798ca46046b8669d057a4debcbdbaaddb6170400748c2f9e4f9d71"' }, - AssetParameters46b107d6db798ca46046b8669d057a4debcbdbaaddb6170400748c2f9e4f9d71S3VersionKey8E981535: { Type: 'String', Description: 'S3 key for asset version "46b107d6db798ca46046b8669d057a4debcbdbaaddb6170400748c2f9e4f9d71"' }, - AssetParameters46b107d6db798ca46046b8669d057a4debcbdbaaddb6170400748c2f9e4f9d71ArtifactHash45A28583: { Type: 'String', Description: 'Artifact hash for asset "46b107d6db798ca46046b8669d057a4debcbdbaaddb6170400748c2f9e4f9d71"' }, - }); - - // asset proxy parameters are passed to the nested stack - expect(parent).to(haveResource('AWS::CloudFormation::Stack', { - Parameters: { - referencetoParentStackAssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281S3Bucket82C55B96Ref: { Ref: 'AssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281S3BucketC188F637' }, - referencetoParentStackAssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281S3VersionKeyA43C3CC6Ref: { Ref: 'AssetParametersdb01ee2eb7adc7915e364dc410d861e569543f9be3761d535a68d5c2cc181281S3VersionKeyC7F4DBF2' }, - }, - })); - - // parent stack should have 2 assets - test.deepEqual(assembly.getStackByName(parent.stackName).assets.length, 2); - test.done(); - }, - - 'docker image assets are wired through the top-level stack'(test: Test) { - // GIVEN - const app = new App(); - const parent = new Stack(app, 'my-stack'); - const nested = new NestedStack(parent, 'nested-stack'); - - // WHEN - const location = nested.synthesizer.addDockerImageAsset({ - directoryName: 'my-image', - dockerBuildArgs: { key: 'value', boom: 'bam' }, - dockerBuildTarget: 'buildTarget', - sourceHash: 'hash-of-source', - }); - - // use the asset, so the parameters will be wired. - new sns.Topic(nested, 'MyTopic', { - displayName: `image location is ${location.imageUri}`, - }); - - // THEN - const asm = app.synth(); - test.deepEqual(asm.getStackArtifact(parent.artifactId).assets, [ - { - repositoryName: 'aws-cdk/assets', - imageTag: 'hash-of-source', - id: 'hash-of-source', - packaging: 'container-image', - path: 'my-image', - sourceHash: 'hash-of-source', - buildArgs: { key: 'value', boom: 'bam' }, - target: 'buildTarget', - }, - { - path: 'mystacknestedstackFAE12FB5.nested.template.json', - id: 'fcdaee79eb79f37eca3a9b1cc0cc9ba150e4eea8c5d6d0c343cb6cd9dc68e2e5', - packaging: 'file', - sourceHash: 'fcdaee79eb79f37eca3a9b1cc0cc9ba150e4eea8c5d6d0c343cb6cd9dc68e2e5', - s3BucketParameter: 'AssetParametersfcdaee79eb79f37eca3a9b1cc0cc9ba150e4eea8c5d6d0c343cb6cd9dc68e2e5S3Bucket67A749F8', - s3KeyParameter: 'AssetParametersfcdaee79eb79f37eca3a9b1cc0cc9ba150e4eea8c5d6d0c343cb6cd9dc68e2e5S3VersionKeyE1E6A8D4', - artifactHashParameter: 'AssetParametersfcdaee79eb79f37eca3a9b1cc0cc9ba150e4eea8c5d6d0c343cb6cd9dc68e2e5ArtifactHash0AEDBE8A', - }, - ]); - - test.done(); - }, - - 'metadata defined in nested stacks is reported at the parent stack level in the cloud assembly'(test: Test) { - // GIVEN - const app = new App({ stackTraces: false }); - const parent = new Stack(app, 'parent'); - const child = new Stack(parent, 'child'); - const nested = new NestedStack(child, 'nested'); - const resource = new CfnResource(nested, 'resource', { type: 'foo' }); - - // WHEN - resource.node.addMetadata('foo', 'bar'); - - // THEN: the first non-nested stack records the assembly metadata - const asm = app.synth(); - test.deepEqual(asm.stacks.length, 2); // only one stack is defined as an artifact - test.deepEqual(asm.getStackByName(parent.stackName).findMetadataByType('foo'), []); - test.deepEqual(asm.getStackByName(child.stackName).findMetadataByType('foo'), [ - { - path: '/parent/child/nested/resource', - type: 'foo', - data: 'bar', - }, - ]); - test.done(); - }, - - 'referencing attributes with period across stacks'(test: Test) { - // GIVEN - const parent = new Stack(); - const nested = new NestedStack(parent, 'nested'); - const consumed = new CfnResource(nested, 'resource-in-nested', { type: 'CONSUMED' }); - - // WHEN - new CfnResource(parent, 'resource-in-parent', { - type: 'CONSUMER', - properties: { - ConsumedAttribute: consumed.getAtt('Consumed.Attribute'), - }, - }); - - // THEN - expect(nested).toMatch({ - Resources: { - resourceinnested: { - Type: 'CONSUMED', - }, - }, - Outputs: { - nestedresourceinnested59B1F01CConsumedAttribute: { - Value: { - 'Fn::GetAtt': [ - 'resourceinnested', - 'Consumed.Attribute', - ], - }, - }, - }, - }); - expect(parent).to(haveResource('CONSUMER', { - ConsumedAttribute: { - 'Fn::GetAtt': [ - 'nestedNestedStacknestedNestedStackResource3DD143BF', - 'Outputs.nestedresourceinnested59B1F01CConsumedAttribute', - ], - }, - })); - - test.done(); - }, - - 'missing context in nested stack is reported if the context is not available'(test: Test) { - // GIVEN - const app = new App(); - const stack = new Stack(app, 'ParentStack', { env: { account: '1234account', region: 'us-east-44' } }); - const nestedStack = new NestedStack(stack, 'nested'); - const provider = 'availability-zones'; - const expectedKey = ContextProvider.getKey(nestedStack, { - provider, - }).key; - - // WHEN - ContextProvider.getValue(nestedStack, { - provider, - dummyValue: ['dummy1a', 'dummy1b', 'dummy1c'], - }); - - // THEN: missing context is reported in the cloud assembly - const asm = app.synth(); - const missing = asm.manifest.missing; - - test.ok(missing && missing.find(m => { - return (m.key === expectedKey); - })); - - test.done(); - }, - - '3-level stacks: legacy synthesizer parameters are added to the middle-level stack'(test: Test) { - // GIVEN - const app = new App(); - const top = new Stack(app, 'stack', { - synthesizer: new LegacyStackSynthesizer(), - }); - const middle = new NestedStack(top, 'nested1'); - const bottom = new NestedStack(middle, 'nested2'); - - // WHEN - new CfnResource(bottom, 'Something', { - type: 'BottomLevel', - }); - - // THEN - const asm = app.synth(); - const middleTemplate = JSON.parse(fs.readFileSync(path.join(asm.directory, middle.templateFile), { encoding: 'utf-8' })); - - const hash = 'bc3c51e4d3545ee0a0069401e5a32c37b66d044b983f12de416ba1576ecaf0a4'; - test.deepEqual(middleTemplate.Parameters ?? {}, { - [`referencetostackAssetParameters${hash}S3BucketD7C30435Ref`]: { - Type: 'String', - }, - [`referencetostackAssetParameters${hash}S3VersionKeyB667DBE1Ref`]: { - Type: 'String', - }, - }); - - test.done(); - }, - - 'references to a resource from a deeply nested stack'(test: Test) { - // GIVEN - const app = new App(); - const top = new Stack(app, 'stack'); - const topLevel = new CfnResource(top, 'toplevel', { type: 'TopLevel' }); - const nested1 = new NestedStack(top, 'nested1'); - const nested2 = new NestedStack(nested1, 'nested2'); - - // WHEN - new CfnResource(nested2, 'refToTopLevel', { - type: 'BottomLevel', - properties: { RefToTopLevel: topLevel.ref }, - }); - - // THEN - expect(top).to(haveResource('AWS::CloudFormation::Stack', { - Parameters: { - referencetostackAssetParameters842982bd421cce9742ba27151ef12ed699d44d22801f41e8029f63f2358a3f2fS3Bucket5DA5D2E7Ref: { - Ref: 'AssetParameters842982bd421cce9742ba27151ef12ed699d44d22801f41e8029f63f2358a3f2fS3BucketDD4D96B5', - }, - referencetostackAssetParameters842982bd421cce9742ba27151ef12ed699d44d22801f41e8029f63f2358a3f2fS3VersionKey8FBE5C12Ref: { - Ref: 'AssetParameters842982bd421cce9742ba27151ef12ed699d44d22801f41e8029f63f2358a3f2fS3VersionKey83E381F3', - }, - referencetostacktoplevelBB16BF13Ref: { - Ref: 'toplevel', - }, - }, - })); - - expect(nested1).to(haveResource('AWS::CloudFormation::Stack', { - Parameters: { - referencetostacktoplevelBB16BF13Ref: { - Ref: 'referencetostacktoplevelBB16BF13Ref', - }, - }, - })); - - expect(nested2).to(matchTemplate({ - Resources: { - refToTopLevel: { - Type: 'BottomLevel', - Properties: { - RefToTopLevel: { - Ref: 'referencetostacktoplevelBB16BF13Ref', - }, - }, - }, - }, - Parameters: { - referencetostacktoplevelBB16BF13Ref: { - Type: 'String', - }, - }, - })); - test.done(); - }, - - 'bottom nested stack consumes value from a top-level stack through a parameter in a middle nested stack'(test: Test) { - // GIVEN - const app = new App(); - const top = new Stack(app, 'Grandparent'); - const middle = new NestedStack(top, 'Parent'); - const bottom = new NestedStack(middle, 'Child'); - const resourceInGrandparent = new CfnResource(top, 'ResourceInGrandparent', { type: 'ResourceInGrandparent' }); - - // WHEN - new CfnResource(bottom, 'ResourceInChild', { - type: 'ResourceInChild', - properties: { - RefToGrandparent: resourceInGrandparent.ref, - }, - }); - - // THEN - - // this is the name allocated for the parameter that's propagated through - // the hierarchy. - const paramName = 'referencetoGrandparentResourceInGrandparent010E997ARef'; - - // child (bottom) references through a parameter. - expect(bottom).toMatch({ - Resources: { - ResourceInChild: { - Type: 'ResourceInChild', - Properties: { - RefToGrandparent: { Ref: paramName }, - }, - }, - }, - Parameters: { - [paramName]: { Type: 'String' }, - }, - }); - - // the parent (middle) sets the value of this parameter to be a reference to another parameter - expect(middle).to(haveResource('AWS::CloudFormation::Stack', { - Parameters: { - [paramName]: { Ref: paramName }, - }, - })); - - // grandparent (top) assigns the actual value to the parameter - expect(top).to(haveResource('AWS::CloudFormation::Stack', { - Parameters: { - [paramName]: { Ref: 'ResourceInGrandparent' }, - - // these are for the asset of the bottom nested stack - referencetoGrandparentAssetParameters3208f43b793a1dbe28ca02cf31fb975489071beb42c492b22dc3d32decc3b4b7S3Bucket06EEE58DRef: { - Ref: 'AssetParameters3208f43b793a1dbe28ca02cf31fb975489071beb42c492b22dc3d32decc3b4b7S3Bucket01877C2E', - }, - referencetoGrandparentAssetParameters3208f43b793a1dbe28ca02cf31fb975489071beb42c492b22dc3d32decc3b4b7S3VersionKeyD3B04909Ref: { - Ref: 'AssetParameters3208f43b793a1dbe28ca02cf31fb975489071beb42c492b22dc3d32decc3b4b7S3VersionKey5765F084', - }, - }, - })); - - test.done(); - }, -}; diff --git a/packages/@aws-cdk/aws-cloudformation/test/test.resource.ts b/packages/@aws-cdk/aws-cloudformation/test/test.resource.ts deleted file mode 100644 index 387aa45240e92..0000000000000 --- a/packages/@aws-cdk/aws-cloudformation/test/test.resource.ts +++ /dev/null @@ -1,238 +0,0 @@ -import { expect, haveResource, ResourcePart } from '@aws-cdk/assert-internal'; -import * as lambda from '@aws-cdk/aws-lambda'; -import * as sns from '@aws-cdk/aws-sns'; -import * as cdk from '@aws-cdk/core'; -import { Test, testCase } from 'nodeunit'; -import { CustomResource, CustomResourceProvider } from '../lib'; - -// keep this import separate from other imports to reduce chance for merge conflicts with v2-main -// eslint-disable-next-line no-duplicate-imports, import/order -import { Construct } from '@aws-cdk/core'; - -/* eslint-disable cdk/no-core-construct */ -/* eslint-disable quote-props */ - -export = testCase({ - 'custom resources honor removalPolicy': { - 'unspecified (aka .Destroy)'(test: Test) { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Test'); - - // WHEN - new TestCustomResource(stack, 'Custom'); - - // THEN - expect(stack).to(haveResource('AWS::CloudFormation::CustomResource', {}, ResourcePart.CompleteDefinition)); - test.equal(app.synth().tryGetArtifact(stack.stackName)!.findMetadataByType('aws:cdk:protected').length, 0); - - test.done(); - }, - - '.Destroy'(test: Test) { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Test'); - - // WHEN - new TestCustomResource(stack, 'Custom', { removalPolicy: cdk.RemovalPolicy.DESTROY }); - - // THEN - expect(stack).to(haveResource('AWS::CloudFormation::CustomResource', {}, ResourcePart.CompleteDefinition)); - test.equal(app.synth().tryGetArtifact(stack.stackName)!.findMetadataByType('aws:cdk:protected').length, 0); - - test.done(); - }, - - '.Retain'(test: Test) { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Test'); - - // WHEN - new TestCustomResource(stack, 'Custom', { removalPolicy: cdk.RemovalPolicy.RETAIN }); - - // THEN - expect(stack).to(haveResource('AWS::CloudFormation::CustomResource', { - DeletionPolicy: 'Retain', - UpdateReplacePolicy: 'Retain', - }, ResourcePart.CompleteDefinition)); - - test.done(); - }, - }, - - 'custom resource is added twice, lambda is added once'(test: Test) { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Test'); - - // WHEN - new TestCustomResource(stack, 'Custom1'); - new TestCustomResource(stack, 'Custom2'); - - // THEN - expect(stack).toMatch({ - 'Resources': { - 'SingletonLambdaTestCustomResourceProviderServiceRole81FEAB5C': { - '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', - ]], - }, - ], - }, - }, - 'SingletonLambdaTestCustomResourceProviderA9255269': { - 'Type': 'AWS::Lambda::Function', - 'Properties': { - 'Code': { - 'ZipFile': 'def hello(): pass', - }, - 'Handler': 'index.hello', - 'Role': { - 'Fn::GetAtt': [ - 'SingletonLambdaTestCustomResourceProviderServiceRole81FEAB5C', - 'Arn', - ], - }, - 'Runtime': 'python2.7', - 'Timeout': 300, - }, - 'DependsOn': [ - 'SingletonLambdaTestCustomResourceProviderServiceRole81FEAB5C', - ], - }, - 'Custom1D319B237': { - 'Type': 'AWS::CloudFormation::CustomResource', - 'DeletionPolicy': 'Delete', - 'UpdateReplacePolicy': 'Delete', - 'Properties': { - 'ServiceToken': { - 'Fn::GetAtt': [ - 'SingletonLambdaTestCustomResourceProviderA9255269', - 'Arn', - ], - }, - }, - }, - 'Custom2DD5FB44D': { - 'Type': 'AWS::CloudFormation::CustomResource', - 'DeletionPolicy': 'Delete', - 'UpdateReplacePolicy': 'Delete', - 'Properties': { - 'ServiceToken': { - 'Fn::GetAtt': [ - 'SingletonLambdaTestCustomResourceProviderA9255269', - 'Arn', - ], - }, - }, - }, - }, - }); - test.done(); - }, - - 'custom resources can specify a resource type that starts with Custom::'(test: Test) { - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Test'); - new CustomResource(stack, 'MyCustomResource', { - resourceType: 'Custom::MyCustomResourceType', - provider: CustomResourceProvider.fromTopic(new sns.Topic(stack, 'Provider')), - }); - expect(stack).to(haveResource('Custom::MyCustomResourceType')); - test.done(); - }, - - 'fails if custom resource type is invalid': { - 'does not start with "Custom::"'(test: Test) { - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Test'); - - test.throws(() => { - new CustomResource(stack, 'MyCustomResource', { - resourceType: 'NoCustom::MyCustomResourceType', - provider: CustomResourceProvider.fromTopic(new sns.Topic(stack, 'Provider')), - }); - }, /Custom resource type must begin with "Custom::"/); - - test.done(); - }, - - 'has invalid characters'(test: Test) { - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Test'); - - test.throws(() => { - new CustomResource(stack, 'MyCustomResource', { - resourceType: 'Custom::My Custom?ResourceType', - provider: CustomResourceProvider.fromTopic(new sns.Topic(stack, 'Provider')), - }); - }, /Custom resource type name can only include alphanumeric characters and/); - - test.done(); - }, - - 'is longer than 60 characters'(test: Test) { - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Test'); - - test.throws(() => { - new CustomResource(stack, 'MyCustomResource', { - resourceType: 'Custom::0123456789012345678901234567890123456789012345678901234567891', - provider: CustomResourceProvider.fromTopic(new sns.Topic(stack, 'Provider')), - }); - }, /Custom resource type length > 60/); - - test.done(); - }, - - }, - - '.ref returns the intrinsic reference (physical name)'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const res = new TestCustomResource(stack, 'myResource'); - - // THEN - test.deepEqual(stack.resolve(res.resource.ref), { Ref: 'myResourceC6A188A9' }); - test.done(); - }, -}); - -class TestCustomResource extends Construct { - public readonly resource: CustomResource; - - constructor(scope: Construct, id: string, opts: { removalPolicy?: cdk.RemovalPolicy } = {}) { - super(scope, id); - - const singletonLambda = new lambda.SingletonFunction(this, 'Lambda', { - uuid: 'TestCustomResourceProvider', - code: new lambda.InlineCode('def hello(): pass'), - runtime: lambda.Runtime.PYTHON_2_7, - handler: 'index.hello', - timeout: cdk.Duration.minutes(5), - }); - - this.resource = new CustomResource(this, 'Resource', { - ...opts, - provider: CustomResourceProvider.fromLambda(singletonLambda), - }); - } -} diff --git a/packages/@aws-cdk/aws-cloudfront-origins/.eslintrc.js b/packages/@aws-cdk/aws-cloudfront-origins/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/.eslintrc.js +++ b/packages/@aws-cdk/aws-cloudfront-origins/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloudfront-origins/jest.config.js b/packages/@aws-cdk/aws-cloudfront-origins/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/jest.config.js +++ b/packages/@aws-cdk/aws-cloudfront-origins/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloudfront-origins/package.json b/packages/@aws-cdk/aws-cloudfront-origins/package.json index e7ef1eb01a94d..9c4476de80fbb 100644 --- a/packages/@aws-cdk/aws-cloudfront-origins/package.json +++ b/packages/@aws-cdk/aws-cloudfront-origins/package.json @@ -52,7 +52,6 @@ "build+test+extract": "yarn build+test && yarn rosetta:extract" }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -71,13 +70,13 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", - "aws-sdk": "^2.848.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", + "aws-sdk": "^2.848.0" }, "dependencies": { "@aws-cdk/aws-cloudfront": "0.0.0", @@ -89,12 +88,12 @@ }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { - "@aws-cdk/core": "0.0.0", - "constructs": "^3.3.69", "@aws-cdk/aws-cloudfront": "0.0.0", "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", - "@aws-cdk/aws-s3": "0.0.0" + "@aws-cdk/aws-s3": "0.0.0", + "@aws-cdk/core": "0.0.0", + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-cloudfront/.eslintrc.js b/packages/@aws-cdk/aws-cloudfront/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-cloudfront/.eslintrc.js +++ b/packages/@aws-cdk/aws-cloudfront/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloudfront/jest.config.js b/packages/@aws-cdk/aws-cloudfront/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-cloudfront/jest.config.js +++ b/packages/@aws-cdk/aws-cloudfront/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts b/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts index 29a63fd681bb3..ab2fbbd44b03c 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/web-distribution.ts @@ -454,6 +454,12 @@ export interface Behavior { */ readonly functionAssociations?: FunctionAssociation[]; + /** + * The viewer policy for this behavior. + * + * @default - the distribution wide viewer protocol policy will be used + */ + readonly viewerProtocolPolicy?: ViewerProtocolPolicy; } export interface LambdaFunctionAssociation { @@ -992,7 +998,7 @@ export class CloudFrontWebDistribution extends cdk.Resource implements IDistribu trustedKeyGroups: input.trustedKeyGroups?.map(key => key.keyGroupId), trustedSigners: input.trustedSigners, targetOriginId: input.targetOriginId, - viewerProtocolPolicy: protoPolicy || ViewerProtocolPolicy.REDIRECT_TO_HTTPS, + viewerProtocolPolicy: input.viewerProtocolPolicy || protoPolicy || ViewerProtocolPolicy.REDIRECT_TO_HTTPS, }; if (!input.isDefaultBehavior) { toReturn = Object.assign(toReturn, { pathPattern: input.pathPattern }); diff --git a/packages/@aws-cdk/aws-cloudfront/package.json b/packages/@aws-cdk/aws-cloudfront/package.json index 36d4ce40952f5..e2b1305049227 100644 --- a/packages/@aws-cdk/aws-cloudfront/package.json +++ b/packages/@aws-cdk/aws-cloudfront/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::CloudFront", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,19 +72,18 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", "aws-sdk": "^2.848.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", - "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", @@ -93,13 +91,13 @@ "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", "@aws-cdk/core": "0.0.0", + "@aws-cdk/cx-api": "0.0.0", "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", - "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", @@ -107,6 +105,7 @@ "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", "@aws-cdk/core": "0.0.0", + "@aws-cdk/cx-api": "0.0.0", "constructs": "^3.3.69" }, "engines": { diff --git a/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts b/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts index 930557098851c..470be56acf0d5 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts @@ -5,7 +5,7 @@ import * as lambda from '@aws-cdk/aws-lambda'; import * as s3 from '@aws-cdk/aws-s3'; import { App, Duration, Stack } from '@aws-cdk/core'; import { CLOUDFRONT_DEFAULT_SECURITY_POLICY_TLS_V1_2_2021 } from '@aws-cdk/cx-api'; -import { testFutureBehavior, testLegacyBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior, testLegacyBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import { CfnDistribution, Distribution, @@ -126,7 +126,7 @@ test('ensure comment prop is not greater than max lenght', () => { const origin = defaultOrigin(); new Distribution(stack, 'MyDist', { defaultBehavior: { origin }, - comment: `Adding a comment longer than 128 characters should be trimmed and added the + comment: `Adding a comment longer than 128 characters should be trimmed and added the\x20 ellipsis so a user would know there was more to read and everything beyond this point should not show up`, }); @@ -138,7 +138,7 @@ ellipsis so a user would know there was more to read and everything beyond this TargetOriginId: 'StackMyDistOrigin1D6D5E535', ViewerProtocolPolicy: 'allow-all', }, - Comment: `Adding a comment longer than 128 characters should be trimmed and added the + Comment: `Adding a comment longer than 128 characters should be trimmed and added the\x20 ellipsis so a user would know there was more to ...`, Enabled: true, HttpVersion: 'http2', diff --git a/packages/@aws-cdk/aws-cloudfront/test/test-origin.ts b/packages/@aws-cdk/aws-cloudfront/test/test-origin.ts index 1c6d3762add4f..4f35bcba4394c 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/test-origin.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/test-origin.ts @@ -14,7 +14,7 @@ export class TestOrigin extends OriginBase { export class TestOriginGroup implements IOrigin { constructor(private readonly primaryDomainName: string, private readonly secondaryDomainName: string) { } - /* eslint-disable cdk/no-core-construct */ + /* eslint-disable @aws-cdk/no-core-construct */ public bind(scope: Construct, options: OriginBindOptions): OriginBindConfig { const primaryOrigin = new TestOrigin(this.primaryDomainName); const secondaryOrigin = new TestOrigin(this.secondaryDomainName); diff --git a/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts b/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts index 9e40e24e3fe42..600750bc4deca 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/web-distribution.test.ts @@ -605,6 +605,109 @@ added the ellipsis so a user would know there was more to ...`, }); + test('distribution with ViewerProtocolPolicy overridden in Behavior', () => { + const stack = new cdk.Stack(); + const sourceBucket = new s3.Bucket(stack, 'Bucket'); + + new CloudFrontWebDistribution(stack, 'AnAmazingWebsiteProbably', { + viewerProtocolPolicy: ViewerProtocolPolicy.ALLOW_ALL, + originConfigs: [ + { + s3OriginSource: { + s3BucketSource: sourceBucket, + }, + behaviors: [ + { + isDefaultBehavior: true, + }, + { + pathPattern: '/test/*', + viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS, + }, + ], + }, + ], + }); + + expect(stack).toMatchTemplate({ + 'Resources': { + 'Bucket83908E77': { + 'Type': 'AWS::S3::Bucket', + 'DeletionPolicy': 'Retain', + 'UpdateReplacePolicy': 'Retain', + }, + 'AnAmazingWebsiteProbablyCFDistribution47E3983B': { + 'Type': 'AWS::CloudFront::Distribution', + 'Properties': { + 'DistributionConfig': { + 'CacheBehaviors': [ + { + 'AllowedMethods': [ + 'GET', + 'HEAD', + ], + 'CachedMethods': [ + 'GET', + 'HEAD', + ], + 'Compress': true, + 'ForwardedValues': { + 'Cookies': { + 'Forward': 'none', + }, + 'QueryString': false, + }, + 'PathPattern': '/test/*', + 'TargetOriginId': 'origin1', + 'ViewerProtocolPolicy': 'redirect-to-https', + }, + ], + 'DefaultRootObject': 'index.html', + 'Origins': [ + { + 'ConnectionAttempts': 3, + 'ConnectionTimeout': 10, + 'DomainName': { + 'Fn::GetAtt': [ + 'Bucket83908E77', + 'RegionalDomainName', + ], + }, + 'Id': 'origin1', + 'S3OriginConfig': {}, + }, + ], + 'ViewerCertificate': { + 'CloudFrontDefaultCertificate': true, + }, + 'PriceClass': 'PriceClass_100', + 'DefaultCacheBehavior': { + 'AllowedMethods': [ + 'GET', + 'HEAD', + ], + 'CachedMethods': [ + 'GET', + 'HEAD', + ], + 'TargetOriginId': 'origin1', + 'ViewerProtocolPolicy': 'allow-all', + 'ForwardedValues': { + 'QueryString': false, + 'Cookies': { 'Forward': 'none' }, + }, + 'Compress': true, + }, + 'Enabled': true, + 'IPV6Enabled': true, + 'HttpVersion': 'http2', + }, + }, + }, + }, + }); + }); + test('distribution with disabled compression', () => { const stack = new cdk.Stack(); const sourceBucket = new s3.Bucket(stack, 'Bucket'); diff --git a/packages/@aws-cdk/aws-cloudtrail/.eslintrc.js b/packages/@aws-cdk/aws-cloudtrail/.eslintrc.js index ced30c8435282..92484d9f02ab4 100644 --- a/packages/@aws-cdk/aws-cloudtrail/.eslintrc.js +++ b/packages/@aws-cdk/aws-cloudtrail/.eslintrc.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloudtrail/jest.config.js b/packages/@aws-cdk/aws-cloudtrail/jest.config.js index b2dbd8ec76f4f..da69fabe154d9 100644 --- a/packages/@aws-cdk/aws-cloudtrail/jest.config.js +++ b/packages/@aws-cdk/aws-cloudtrail/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/aws-cloudtrail/package.json b/packages/@aws-cdk/aws-cloudtrail/package.json index 526442259cddb..c7d55ac99bf69 100644 --- a/packages/@aws-cdk/aws-cloudtrail/package.json +++ b/packages/@aws-cdk/aws-cloudtrail/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::CloudTrail", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,15 +72,15 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", "aws-sdk": "^2.848.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", "colors": "^1.4.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-events": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudwatch-actions/.eslintrc.js b/packages/@aws-cdk/aws-cloudwatch-actions/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-cloudwatch-actions/.eslintrc.js +++ b/packages/@aws-cdk/aws-cloudwatch-actions/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloudwatch-actions/jest.config.js b/packages/@aws-cdk/aws-cloudwatch-actions/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-cloudwatch-actions/jest.config.js +++ b/packages/@aws-cdk/aws-cloudwatch-actions/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloudwatch-actions/package.json b/packages/@aws-cdk/aws-cloudwatch-actions/package.json index 0869c60941c8f..0b687b88aee14 100644 --- a/packages/@aws-cdk/aws-cloudwatch-actions/package.json +++ b/packages/@aws-cdk/aws-cloudwatch-actions/package.json @@ -64,14 +64,14 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-applicationautoscaling": "0.0.0", @@ -101,7 +101,6 @@ }, "maturity": "stable", "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-cloudwatch/.eslintrc.js b/packages/@aws-cdk/aws-cloudwatch/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-cloudwatch/.eslintrc.js +++ b/packages/@aws-cdk/aws-cloudwatch/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloudwatch/README.md b/packages/@aws-cdk/aws-cloudwatch/README.md index bdcf58e61024f..450fc8ca9821a 100644 --- a/packages/@aws-cdk/aws-cloudwatch/README.md +++ b/packages/@aws-cdk/aws-cloudwatch/README.md @@ -43,7 +43,7 @@ const metric = new Metric({ dimensionsMap: { HostedZoneId: hostedZone.hostedZoneId } -}) +}); ``` ### Instantiating a new Metric object @@ -73,7 +73,7 @@ const allProblems = new MathExpression({ errors: myConstruct.metricErrors(), faults: myConstruct.metricFaults(), } -}) +}); ``` You can use `MathExpression` objects like any other metric, including using @@ -86,9 +86,25 @@ const problemPercentage = new MathExpression({ problems: allProblems, invocations: myConstruct.metricInvocations() } -}) +}); +``` + +### Search Expressions + +Math expressions also support search expressions. For example, the following +search expression returns all CPUUtilization metrics that it finds, with the +graph showing the Average statistic with an aggregation period of 5 minutes: + +```ts +const cpuUtilization = new MathExpression({ + expression: "SEARCH('{AWS/EC2,InstanceId} MetricName=\"CPUUtilization\"', 'Average', 300)" +}); ``` +Cross-account and cross-region search expressions are also supported. Use +the `searchAccount` and `searchRegion` properties to specify the account +and/or region to evaluate the search expression against. + ### Aggregation To graph or alarm on metrics you must aggregate them first, using a function diff --git a/packages/@aws-cdk/aws-cloudwatch/jest.config.js b/packages/@aws-cdk/aws-cloudwatch/jest.config.js index cd664e1d069e5..34818e1593f6b 100644 --- a/packages/@aws-cdk/aws-cloudwatch/jest.config.js +++ b/packages/@aws-cdk/aws-cloudwatch/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloudwatch/lib/alarm.ts b/packages/@aws-cdk/aws-cloudwatch/lib/alarm.ts index e0692478c8457..e09b5d714af69 100644 --- a/packages/@aws-cdk/aws-cloudwatch/lib/alarm.ts +++ b/packages/@aws-cdk/aws-cloudwatch/lib/alarm.ts @@ -334,6 +334,8 @@ export class Alarm extends AlarmBase { assertSubmetricsCount(expr); } + self.validateMetricExpression(expr); + return { expression: expr.expression, id: entry.id || uniqueMetricId(), @@ -358,6 +360,16 @@ export class Alarm extends AlarmBase { throw new Error(`Cannot create an Alarm in region '${stack.region}' based on metric '${metric}' in '${stat.region}'`); } } + + /** + * Validates that the expression config does not specify searchAccount or searchRegion props + * as search expressions are not supported by Alarms. + */ + private validateMetricExpression(expr: MetricExpressionConfig) { + if (expr.searchAccount !== undefined || expr.searchRegion !== undefined) { + throw new Error('Cannot create an Alarm based on a MathExpression which specifies a searchAccount or searchRegion'); + } + } } function definitelyDifferent(x: string | undefined, y: string) { diff --git a/packages/@aws-cdk/aws-cloudwatch/lib/metric-types.ts b/packages/@aws-cdk/aws-cloudwatch/lib/metric-types.ts index 296400ee7f910..e8506fde53140 100644 --- a/packages/@aws-cdk/aws-cloudwatch/lib/metric-types.ts +++ b/packages/@aws-cdk/aws-cloudwatch/lib/metric-types.ts @@ -322,6 +322,20 @@ export interface MetricExpressionConfig { * How many seconds to aggregate over */ readonly period: number; + + /** + * Account to evaluate search expressions within. + * + * @default - Deployment account. + */ + readonly searchAccount?: string; + + /** + * Region to evaluate search expressions within. + * + * @default - Deployment region. + */ + readonly searchRegion?: string; } /** diff --git a/packages/@aws-cdk/aws-cloudwatch/lib/metric.ts b/packages/@aws-cdk/aws-cloudwatch/lib/metric.ts index cf4051f74ffd4..d306978c93733 100644 --- a/packages/@aws-cdk/aws-cloudwatch/lib/metric.ts +++ b/packages/@aws-cdk/aws-cloudwatch/lib/metric.ts @@ -149,6 +149,26 @@ export interface MathExpressionOptions { * @default Duration.minutes(5) */ readonly period?: cdk.Duration; + + /** + * Account to evaluate search expressions within. + * + * Specifying a searchAccount has no effect to the account used + * for metrics within the expression (passed via usingMetrics). + * + * @default - Deployment account. + */ + readonly searchAccount?: string; + + /** + * Region to evaluate search expressions within. + * + * Specifying a searchRegion has no effect to the region used + * for metrics within the expression (passed via usingMetrics). + * + * @default - Deployment region. + */ + readonly searchRegion?: string; } /** @@ -157,6 +177,9 @@ export interface MathExpressionOptions { export interface MathExpressionProps extends MathExpressionOptions { /** * The expression defining the metric. + * + * When an expression contains a SEARCH function, it cannot be used + * within an Alarm. */ readonly expression: string; @@ -165,8 +188,10 @@ export interface MathExpressionProps extends MathExpressionOptions { * * The key is the identifier that represents the given metric in the * expression, and the value is the actual Metric object. + * + * @default - Empty map. */ - readonly usingMetrics: Record; + readonly usingMetrics?: Record; } /** @@ -451,6 +476,10 @@ function asString(x?: unknown): string | undefined { * It makes sense to embed this in here, so that compound constructs can attach * that metadata to metrics they expose. * + * MathExpression can also be used for search expressions. In this case, + * it also optionally accepts a searchRegion and searchAccount property for cross-environment + * search expressions. + * * This class does not represent a resource, so hence is not a construct. Instead, * MathExpression is an abstraction that makes it easy to specify metrics for use in both * alarms and graphs. @@ -482,14 +511,26 @@ export class MathExpression implements IMetric { */ public readonly period: cdk.Duration; + /** + * Account to evaluate search expressions within. + */ + public readonly searchAccount?: string; + + /** + * Region to evaluate search expressions within. + */ + public readonly searchRegion?: string; + constructor(props: MathExpressionProps) { this.period = props.period || cdk.Duration.minutes(5); this.expression = props.expression; - this.usingMetrics = changeAllPeriods(props.usingMetrics, this.period); + this.usingMetrics = changeAllPeriods(props.usingMetrics ?? {}, this.period); this.label = props.label; this.color = props.color; + this.searchAccount = props.searchAccount; + this.searchRegion = props.searchRegion; - const invalidVariableNames = Object.keys(props.usingMetrics).filter(x => !validVariableName(x)); + const invalidVariableNames = Object.keys(this.usingMetrics).filter(x => !validVariableName(x)); if (invalidVariableNames.length > 0) { throw new Error(`Invalid variable names in expression: ${invalidVariableNames}. Must start with lowercase letter and only contain alphanumerics.`); } @@ -508,7 +549,9 @@ export class MathExpression implements IMetric { // Short-circuit creating a new object if there would be no effective change if ((props.label === undefined || props.label === this.label) && (props.color === undefined || props.color === this.color) - && (props.period === undefined || props.period.toSeconds() === this.period.toSeconds())) { + && (props.period === undefined || props.period.toSeconds() === this.period.toSeconds()) + && (props.searchAccount === undefined || props.searchAccount === this.searchAccount) + && (props.searchRegion === undefined || props.searchRegion === this.searchRegion)) { return this; } @@ -518,6 +561,8 @@ export class MathExpression implements IMetric { label: ifUndefined(props.label, this.label), color: ifUndefined(props.color, this.color), period: ifUndefined(props.period, this.period), + searchAccount: ifUndefined(props.searchAccount, this.searchAccount), + searchRegion: ifUndefined(props.searchRegion, this.searchRegion), }); } @@ -541,6 +586,8 @@ export class MathExpression implements IMetric { period: this.period.toSeconds(), expression: this.expression, usingMetrics: this.usingMetrics, + searchAccount: this.searchAccount, + searchRegion: this.searchRegion, }, renderingProperties: { label: this.label, diff --git a/packages/@aws-cdk/aws-cloudwatch/lib/private/metric-util.ts b/packages/@aws-cdk/aws-cloudwatch/lib/private/metric-util.ts index 589e3d99ad474..8988148c16b3b 100644 --- a/packages/@aws-cdk/aws-cloudwatch/lib/private/metric-util.ts +++ b/packages/@aws-cdk/aws-cloudwatch/lib/private/metric-util.ts @@ -25,6 +25,12 @@ export function metricKey(metric: IMetric): string { parts.push(id); parts.push(metricKey(conf.mathExpression.usingMetrics[id])); } + if (conf.mathExpression.searchRegion) { + parts.push(conf.mathExpression.searchRegion); + } + if (conf.mathExpression.searchAccount) { + parts.push(conf.mathExpression.searchAccount); + } } if (conf.metricStat) { parts.push(conf.metricStat.namespace); diff --git a/packages/@aws-cdk/aws-cloudwatch/lib/private/rendering.ts b/packages/@aws-cdk/aws-cloudwatch/lib/private/rendering.ts index 8553d9ad5c486..9223695a96c67 100644 --- a/packages/@aws-cdk/aws-cloudwatch/lib/private/rendering.ts +++ b/packages/@aws-cdk/aws-cloudwatch/lib/private/rendering.ts @@ -55,6 +55,8 @@ function metricGraphJson(metric: IMetric, yAxis?: string, id?: string) { withExpression(expr) { options.expression = expr.expression; + if (expr.searchAccount) { options.accountId = accountIfDifferentFromStack(expr.searchAccount); } + if (expr.searchRegion) { options.region = regionIfDifferentFromStack(expr.searchRegion); } if (expr.period && expr.period !== 300) { options.period = expr.period; } }, }); diff --git a/packages/@aws-cdk/aws-cloudwatch/package.json b/packages/@aws-cdk/aws-cloudwatch/package.json index 683ca79bde154..9e5d8892953a1 100644 --- a/packages/@aws-cdk/aws-cloudwatch/package.json +++ b/packages/@aws-cdk/aws-cloudwatch/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::CloudWatch", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -74,12 +73,12 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", diff --git a/packages/@aws-cdk/aws-cloudwatch/test/cross-environment.test.ts b/packages/@aws-cdk/aws-cloudwatch/test/cross-environment.test.ts index 50278d9a83d54..668807c89bfef 100644 --- a/packages/@aws-cdk/aws-cloudwatch/test/cross-environment.test.ts +++ b/packages/@aws-cdk/aws-cloudwatch/test/cross-environment.test.ts @@ -78,6 +78,35 @@ describe('cross environment', () => { }); + + test('math expressions with explicit account and region will render in environment agnostic stack', () => { + // GIVEN + const expression = 'SEARCH(\'MetricName="ACount"\', \'Sum\', 300)'; + + const b = new MathExpression({ + expression, + usingMetrics: {}, + label: 'Test label', + searchAccount: '5678', + searchRegion: 'mars', + }); + + const graph = new GraphWidget({ + left: [ + b, + ], + }); + + // THEN + graphMetricsAre(new Stack(), graph, [ + [{ + expression, + accountId: '5678', + region: 'mars', + label: 'Test label', + }], + ]); + }); }); describe('in alarms', () => { @@ -234,6 +263,56 @@ describe('cross environment', () => { ], }); }); + + test('math expression with different searchAccount will throw', () => { + // GIVEN + const b = new Metric({ + namespace: 'Test', + metricName: 'ACount', + account: '1234', + }); + + const c = new MathExpression({ + expression: 'a + b', + usingMetrics: { a: a.attachTo(stack3), b }, + period: Duration.minutes(1), + searchAccount: '5678', + }); + + // THEN + expect(() => { + new Alarm(stack1, 'Alarm', { + threshold: 1, + evaluationPeriods: 1, + metric: c, + }); + }).toThrow(/Cannot create an Alarm based on a MathExpression which specifies a searchAccount or searchRegion/); + }); + + test('match expression with different searchRegion will throw', () => { + // GIVEN + const b = new Metric({ + namespace: 'Test', + metricName: 'ACount', + account: '1234', + }); + + const c = new MathExpression({ + expression: 'a + b', + usingMetrics: { a: a.attachTo(stack3), b }, + period: Duration.minutes(1), + searchRegion: 'mars', + }); + + // THEN + expect(() => { + new Alarm(stack1, 'Alarm', { + threshold: 1, + evaluationPeriods: 1, + metric: c, + }); + }).toThrow(/Cannot create an Alarm based on a MathExpression which specifies a searchAccount or searchRegion/); + }); }); }); diff --git a/packages/@aws-cdk/aws-codeartifact/.eslintrc.js b/packages/@aws-cdk/aws-codeartifact/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-codeartifact/.eslintrc.js +++ b/packages/@aws-cdk/aws-codeartifact/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codeartifact/jest.config.js b/packages/@aws-cdk/aws-codeartifact/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-codeartifact/jest.config.js +++ b/packages/@aws-cdk/aws-codeartifact/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codeartifact/package.json b/packages/@aws-cdk/aws-codeartifact/package.json index 3dc1f03908775..3d2410610103b 100644 --- a/packages/@aws-cdk/aws-codeartifact/package.json +++ b/packages/@aws-cdk/aws-codeartifact/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::CodeArtifact", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-codebuild/.eslintrc.js b/packages/@aws-cdk/aws-codebuild/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-codebuild/.eslintrc.js +++ b/packages/@aws-cdk/aws-codebuild/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codebuild/.gitignore b/packages/@aws-cdk/aws-codebuild/.gitignore index dcc1dc41e477f..17a41566f0002 100644 --- a/packages/@aws-cdk/aws-codebuild/.gitignore +++ b/packages/@aws-cdk/aws-codebuild/.gitignore @@ -15,4 +15,5 @@ nyc.config.js *.snk !.eslintrc.js -junit.xml \ No newline at end of file +junit.xml +!jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codebuild/.npmignore b/packages/@aws-cdk/aws-codebuild/.npmignore index 9a032ae80868c..e8acf10a468a1 100644 --- a/packages/@aws-cdk/aws-codebuild/.npmignore +++ b/packages/@aws-cdk/aws-codebuild/.npmignore @@ -24,4 +24,5 @@ tsconfig.json **/cdk.out junit.xml test/ -!*.lit.ts \ No newline at end of file +!*.lit.ts +jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codebuild/jest.config.js b/packages/@aws-cdk/aws-codebuild/jest.config.js new file mode 100644 index 0000000000000..34818e1593f6b --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codebuild/package.json b/packages/@aws-cdk/aws-codebuild/package.json index e7591a3ab4fbb..9b54a075fce61 100644 --- a/packages/@aws-cdk/aws-codebuild/package.json +++ b/packages/@aws-cdk/aws-codebuild/package.json @@ -76,16 +76,16 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/aws-sqs": "0.0.0", - "@types/nodeunit": "^0.0.32", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", "aws-sdk": "^2.848.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "nodeunit": "^0.11.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", diff --git a/packages/@aws-cdk/aws-codebuild/test/build-spec.test.ts b/packages/@aws-cdk/aws-codebuild/test/build-spec.test.ts new file mode 100644 index 0000000000000..e250a2c7fd6c4 --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/test/build-spec.test.ts @@ -0,0 +1,409 @@ +// import * as cdk from '@aws-cdk/core'; +import * as codebuild from '../lib'; + +/* eslint-disable quote-props */ +/* eslint-disable quotes */ + +describe('Test BuildSpec merge', () => { + test('merge two simple specs', () => { + const lhs = codebuild.BuildSpec.fromObject({ + phases: { + pre_build: { + commands: [ + 'install', + ], + }, + }, + }); + const rhs = codebuild.BuildSpec.fromObject({ + phases: { + build: { + commands: 'build', + }, + }, + }); + + const merged = codebuild.mergeBuildSpecs(lhs, rhs); + + expect((merged as any).spec).toEqual({ + phases: { + pre_build: { + commands: [ + 'install', + ], + }, + build: { + commands: [ + 'build', + ], + }, + }, + }); + }); + + test('merge command lists', () => { + const lhs = codebuild.BuildSpec.fromObject({ + phases: { + build: { + commands: [ + 'build1', + ], + }, + }, + }); + const rhs = codebuild.BuildSpec.fromObject({ + phases: { + build: { + commands: 'build2', + }, + }, + }); + + const merged = codebuild.mergeBuildSpecs(lhs, rhs); + + expect((merged as any).spec).toEqual({ + phases: { + build: { + commands: [ + 'build1', + 'build2', + ], + }, + }, + }); + }); + + test('do not merge artifacts', () => { + const lhs = codebuild.BuildSpec.fromObject({ + phases: { + build: { + commands: [ + 'build1', + ], + }, + }, + artifacts: { + 'base-directory': 'subdir/cdk.out', + }, + }); + const rhs = codebuild.BuildSpec.fromObject({ + phases: { + build: { + commands: [ + 'build2', + ], + }, + }, + artifacts: { + 'base-directory': 'subdir/cdk.out', + }, + }); + + expect(() => { + codebuild.mergeBuildSpecs(lhs, rhs); + }).toThrow(); + }); + + test('merge complex example', () => { + const cdkSpec = codebuild.BuildSpec.fromObject({ + env: { + 'variables': { + NPM_TOKEN: 'supersecret', + }, + }, + phases: { + pre_build: { + commands: [ + 'install1', + ], + }, + build: { + commands: [ + 'build1', + 'test1', + 'cdk synth', + ], + }, + }, + }); + const userSpec = codebuild.BuildSpec.fromObject({ + version: 0.2, + env: { + 'variables': { + JAVA_HOME: '/usr/lib/jvm/java-8-openjdk-amd64', + }, + 'parameter-store': { + LOGIN_PASSWORD: '/CodeBuild/dockerLoginPassword', + }, + }, + phases: { + install: { + commands: [ + 'echo Entered the install phase...', + 'apt-get update -y', + 'apt-get install -y maven', + ], + finally: [ + 'echo This always runs even if the update or install command fails', + ], + }, + pre_build: { + commands: [ + 'echo Entered the pre_build phase...', + 'docker login -u User -p $LOGIN_PASSWORD', + ], + finally: [ + 'echo This always runs even if the login command fails', + ], + }, + build: { + commands: [ + 'echo Entered the build phase...', + 'echo Build started on `date`', + 'mvn install', + ], + finally: [ + 'echo This always runs even if the install command fails', + ], + }, + post_build: { + commands: [ + 'echo Entered the post_build phase...', + 'echo Build completed on `date`', + ], + }, + }, + reports: { + 'arn:aws:codebuild:your-region:your-aws-account-id:report-group/report-group-name-1': { + 'files': [ + '**/*', + ], + 'base-directory': 'target/tests/reports', + 'discard-paths': 'no', + }, + 'reportGroupCucumberJson': { + 'files': [ + 'cucumber/target/cucumber-tests.xml', + ], + 'discard-paths': 'yes', + 'file-format': 'CUCUMBERJSON', + }, + }, + artifacts: { + 'files': [ + 'target/messageUtil-1.0.jar', + ], + 'discard-paths': 'yes', + 'secondary-artifacts': { + artifact1: { + 'files': [ + 'target/artifact-1.0.jar', + ], + 'discard-paths': 'yes', + }, + artifact2: { + 'files': [ + 'target/artifact-2.0.jar', + ], + 'discard-paths': 'yes', + }, + }, + }, + cache: { + paths: [ + '/root/.m2/**/*', + ], + }, + }); + + const merged = codebuild.mergeBuildSpecs(userSpec, cdkSpec); + + expect((merged as any).spec).toEqual({ + version: 0.2, + env: { + 'variables': { + JAVA_HOME: '/usr/lib/jvm/java-8-openjdk-amd64', + NPM_TOKEN: 'supersecret', + }, + 'parameter-store': { + LOGIN_PASSWORD: '/CodeBuild/dockerLoginPassword', + }, + }, + phases: { + install: { + commands: [ + 'echo Entered the install phase...', + 'apt-get update -y', + 'apt-get install -y maven', + ], + finally: [ + 'echo This always runs even if the update or install command fails', + ], + }, + pre_build: { + commands: [ + 'echo Entered the pre_build phase...', + 'docker login -u User -p $LOGIN_PASSWORD', + 'install1', + ], + finally: [ + 'echo This always runs even if the login command fails', + ], + }, + build: { + commands: [ + 'echo Entered the build phase...', + 'echo Build started on `date`', + 'mvn install', + 'build1', + 'test1', + 'cdk synth', + ], + finally: [ + 'echo This always runs even if the install command fails', + ], + }, + post_build: { + commands: [ + 'echo Entered the post_build phase...', + 'echo Build completed on `date`', + ], + }, + }, + reports: { + 'arn:aws:codebuild:your-region:your-aws-account-id:report-group/report-group-name-1': { + 'files': [ + '**/*', + ], + 'base-directory': 'target/tests/reports', + 'discard-paths': 'no', + }, + 'reportGroupCucumberJson': { + 'files': [ + 'cucumber/target/cucumber-tests.xml', + ], + 'discard-paths': 'yes', + 'file-format': 'CUCUMBERJSON', + }, + }, + artifacts: { + 'files': [ + 'target/messageUtil-1.0.jar', + ], + 'discard-paths': 'yes', + 'secondary-artifacts': { + artifact1: { + 'files': [ + 'target/artifact-1.0.jar', + ], + 'discard-paths': 'yes', + }, + artifact2: { + 'files': [ + 'target/artifact-2.0.jar', + ], + 'discard-paths': 'yes', + }, + }, + }, + cache: { + paths: [ + '/root/.m2/**/*', + ], + }, + }); + }); + + test('override duplicate reports', () => { + const lhs = codebuild.BuildSpec.fromObject({ + phases: { + pre_build: { + commands: [ + 'install', + ], + }, + }, + reports: { + 'report1': { + 'files': [ + 'report1/a', + ], + 'discard-paths': 'no', + 'base-directory': 'target/tests/reports', + }, + 'report2': { + 'files': [ + 'cucumber/target/cucumber-tests.xml', + ], + 'discard-paths': 'yes', + 'file-format': 'CUCUMBERJSON', + }, + }, + }); + const rhs = codebuild.BuildSpec.fromObject({ + phases: { + build: { + commands: [ + 'build', + ], + }, + }, + reports: { + 'report1': { + 'files': [ + 'report1/b', + 'report1/b2', + ], + 'base-directory': 'target/tests/reportsB', + }, + 'report3': { + 'files': [ + 'cucumber/target/cucumber-tests.xml', + ], + 'discard-paths': 'yes', + 'file-format': 'CUCUMBERJSON', + }, + }, + }); + + const merged = codebuild.mergeBuildSpecs(lhs, rhs); + + expect((merged as any).spec).toEqual({ + phases: { + pre_build: { + commands: [ + 'install', + ], + }, + build: { + commands: [ + 'build', + ], + }, + }, + reports: { + 'report1': { + 'files': [ + 'report1/b', + 'report1/b2', + ], + 'base-directory': 'target/tests/reportsB', + }, + 'report2': { + 'files': [ + 'cucumber/target/cucumber-tests.xml', + ], + 'discard-paths': 'yes', + 'file-format': 'CUCUMBERJSON', + }, + 'report3': { + 'files': [ + 'cucumber/target/cucumber-tests.xml', + ], + 'discard-paths': 'yes', + 'file-format': 'CUCUMBERJSON', + }, + }, + }); + }); +}); diff --git a/packages/@aws-cdk/aws-codebuild/test/codebuild.test.ts b/packages/@aws-cdk/aws-codebuild/test/codebuild.test.ts new file mode 100644 index 0000000000000..cc8f9309bcb44 --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/test/codebuild.test.ts @@ -0,0 +1,1887 @@ +import { ABSENT, SynthUtils } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +import * as codecommit from '@aws-cdk/aws-codecommit'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as kms from '@aws-cdk/aws-kms'; +import * as s3 from '@aws-cdk/aws-s3'; +import * as cdk from '@aws-cdk/core'; +import * as codebuild from '../lib'; +import { CodePipelineSource } from '../lib/codepipeline-source'; +import { NoSource } from '../lib/no-source'; + +/* eslint-disable quote-props */ + +describe('default properties', () => { + test('with CodePipeline source', () => { + const stack = new cdk.Stack(); + + new codebuild.PipelineProject(stack, 'MyProject'); + + expect(stack).toMatchTemplate({ + 'Resources': { + 'MyProjectRole9BBE5233': { + 'Type': 'AWS::IAM::Role', + 'Properties': { + 'AssumeRolePolicyDocument': { + 'Statement': [ + { + 'Action': 'sts:AssumeRole', + 'Effect': 'Allow', + 'Principal': { + 'Service': 'codebuild.amazonaws.com', + }, + }, + ], + 'Version': '2012-10-17', + }, + }, + }, + 'MyProjectRoleDefaultPolicyB19B7C29': { + 'Type': 'AWS::IAM::Policy', + 'Properties': { + 'PolicyDocument': { + 'Statement': [ + { + 'Action': [ + 'logs:CreateLogGroup', + 'logs:CreateLogStream', + 'logs:PutLogEvents', + ], + 'Effect': 'Allow', + 'Resource': [ + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + 'Ref': 'AWS::Partition', + }, + ':logs:', + { + 'Ref': 'AWS::Region', + }, + ':', + { + 'Ref': 'AWS::AccountId', + }, + ':log-group:/aws/codebuild/', + { + 'Ref': 'MyProject39F7B0AE', + }, + ], + ], + }, + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + 'Ref': 'AWS::Partition', + }, + ':logs:', + { + 'Ref': 'AWS::Region', + }, + ':', + { + 'Ref': 'AWS::AccountId', + }, + ':log-group:/aws/codebuild/', + { + 'Ref': 'MyProject39F7B0AE', + }, + ':*', + ], + ], + }, + ], + }, + { + 'Action': [ + 'codebuild:CreateReportGroup', + 'codebuild:CreateReport', + 'codebuild:UpdateReport', + 'codebuild:BatchPutTestCases', + 'codebuild:BatchPutCodeCoverages', + ], + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': ['', [ + 'arn:', + { 'Ref': 'AWS::Partition' }, + ':codebuild:', + { 'Ref': 'AWS::Region' }, + ':', + { 'Ref': 'AWS::AccountId' }, + ':report-group/', + { 'Ref': 'MyProject39F7B0AE' }, + '-*', + ]], + }, + }, + ], + 'Version': '2012-10-17', + }, + 'PolicyName': 'MyProjectRoleDefaultPolicyB19B7C29', + 'Roles': [ + { + 'Ref': 'MyProjectRole9BBE5233', + }, + ], + }, + }, + 'MyProject39F7B0AE': { + 'Type': 'AWS::CodeBuild::Project', + 'Properties': { + 'Source': { + 'Type': 'CODEPIPELINE', + }, + 'Artifacts': { + 'Type': 'CODEPIPELINE', + }, + 'ServiceRole': { + 'Fn::GetAtt': [ + 'MyProjectRole9BBE5233', + 'Arn', + ], + }, + 'Environment': { + 'Type': 'LINUX_CONTAINER', + 'PrivilegedMode': false, + 'Image': 'aws/codebuild/standard:1.0', + 'ImagePullCredentialsType': 'CODEBUILD', + 'ComputeType': 'BUILD_GENERAL1_SMALL', + }, + 'EncryptionKey': 'alias/aws/s3', + }, + }, + }, + }); + }); + + test('with CodeCommit source', () => { + const stack = new cdk.Stack(); + + const repo = new codecommit.Repository(stack, 'MyRepo', { + repositoryName: 'hello-cdk', + }); + + const source = codebuild.Source.codeCommit({ repository: repo, cloneDepth: 2 }); + + new codebuild.Project(stack, 'MyProject', { + source, + }); + + expect(stack).toMatchTemplate({ + 'Resources': { + 'MyRepoF4F48043': { + 'Type': 'AWS::CodeCommit::Repository', + 'Properties': { + 'RepositoryName': 'hello-cdk', + }, + }, + 'MyProjectRole9BBE5233': { + 'Type': 'AWS::IAM::Role', + 'Properties': { + 'AssumeRolePolicyDocument': { + 'Statement': [ + { + 'Action': 'sts:AssumeRole', + 'Effect': 'Allow', + 'Principal': { + 'Service': 'codebuild.amazonaws.com', + }, + }, + ], + 'Version': '2012-10-17', + }, + }, + }, + 'MyProjectRoleDefaultPolicyB19B7C29': { + 'Type': 'AWS::IAM::Policy', + 'Properties': { + 'PolicyDocument': { + 'Statement': [ + { + 'Action': 'codecommit:GitPull', + 'Effect': 'Allow', + 'Resource': { + 'Fn::GetAtt': [ + 'MyRepoF4F48043', + 'Arn', + ], + }, + }, + { + 'Action': [ + 'logs:CreateLogGroup', + 'logs:CreateLogStream', + 'logs:PutLogEvents', + ], + 'Effect': 'Allow', + 'Resource': [ + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + 'Ref': 'AWS::Partition', + }, + ':logs:', + { + 'Ref': 'AWS::Region', + }, + ':', + { + 'Ref': 'AWS::AccountId', + }, + ':log-group:/aws/codebuild/', + { + 'Ref': 'MyProject39F7B0AE', + }, + ], + ], + }, + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + 'Ref': 'AWS::Partition', + }, + ':logs:', + { + 'Ref': 'AWS::Region', + }, + ':', + { + 'Ref': 'AWS::AccountId', + }, + ':log-group:/aws/codebuild/', + { + 'Ref': 'MyProject39F7B0AE', + }, + ':*', + ], + ], + }, + ], + }, + { + 'Action': [ + 'codebuild:CreateReportGroup', + 'codebuild:CreateReport', + 'codebuild:UpdateReport', + 'codebuild:BatchPutTestCases', + 'codebuild:BatchPutCodeCoverages', + ], + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': ['', [ + 'arn:', + { 'Ref': 'AWS::Partition' }, + ':codebuild:', + { 'Ref': 'AWS::Region' }, + ':', + { 'Ref': 'AWS::AccountId' }, + ':report-group/', + { 'Ref': 'MyProject39F7B0AE' }, + '-*', + ]], + }, + }, + ], + 'Version': '2012-10-17', + }, + 'PolicyName': 'MyProjectRoleDefaultPolicyB19B7C29', + 'Roles': [ + { + 'Ref': 'MyProjectRole9BBE5233', + }, + ], + }, + }, + 'MyProject39F7B0AE': { + 'Type': 'AWS::CodeBuild::Project', + 'Properties': { + 'Artifacts': { + 'Type': 'NO_ARTIFACTS', + }, + 'Environment': { + 'ComputeType': 'BUILD_GENERAL1_SMALL', + 'Image': 'aws/codebuild/standard:1.0', + 'ImagePullCredentialsType': 'CODEBUILD', + 'PrivilegedMode': false, + 'Type': 'LINUX_CONTAINER', + }, + 'ServiceRole': { + 'Fn::GetAtt': [ + 'MyProjectRole9BBE5233', + 'Arn', + ], + }, + 'Source': { + 'Location': { + 'Fn::GetAtt': [ + 'MyRepoF4F48043', + 'CloneUrlHttp', + ], + }, + 'GitCloneDepth': 2, + 'Type': 'CODECOMMIT', + }, + 'EncryptionKey': 'alias/aws/s3', + }, + }, + }, + }); + }); + + test('with S3Bucket source', () => { + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'MyBucket'); + + new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.s3({ + bucket, + path: 'path/to/source.zip', + }), + environment: { + buildImage: codebuild.WindowsBuildImage.WINDOWS_BASE_2_0, + }, + }); + + expect(stack).toMatchTemplate({ + 'Resources': { + 'MyBucketF68F3FF0': { + 'Type': 'AWS::S3::Bucket', + 'DeletionPolicy': 'Retain', + 'UpdateReplacePolicy': 'Retain', + }, + 'MyProjectRole9BBE5233': { + 'Type': 'AWS::IAM::Role', + 'Properties': { + 'AssumeRolePolicyDocument': { + 'Statement': [ + { + 'Action': 'sts:AssumeRole', + 'Effect': 'Allow', + 'Principal': { + 'Service': 'codebuild.amazonaws.com', + }, + }, + ], + 'Version': '2012-10-17', + }, + }, + }, + 'MyProjectRoleDefaultPolicyB19B7C29': { + 'Type': 'AWS::IAM::Policy', + 'Properties': { + 'PolicyDocument': { + 'Statement': [ + { + 'Action': [ + 's3:GetObject*', + 's3:GetBucket*', + 's3:List*', + ], + 'Effect': 'Allow', + 'Resource': [ + { + 'Fn::GetAtt': [ + 'MyBucketF68F3FF0', + 'Arn', + ], + }, + { + 'Fn::Join': [ + '', + [ + { + 'Fn::GetAtt': [ + 'MyBucketF68F3FF0', + 'Arn', + ], + }, + '/path/to/source.zip', + ], + ], + }, + ], + }, + { + 'Action': [ + 'logs:CreateLogGroup', + 'logs:CreateLogStream', + 'logs:PutLogEvents', + ], + 'Effect': 'Allow', + 'Resource': [ + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + 'Ref': 'AWS::Partition', + }, + ':logs:', + { + 'Ref': 'AWS::Region', + }, + ':', + { + 'Ref': 'AWS::AccountId', + }, + ':log-group:/aws/codebuild/', + { + 'Ref': 'MyProject39F7B0AE', + }, + ], + ], + }, + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + 'Ref': 'AWS::Partition', + }, + ':logs:', + { + 'Ref': 'AWS::Region', + }, + ':', + { + 'Ref': 'AWS::AccountId', + }, + ':log-group:/aws/codebuild/', + { + 'Ref': 'MyProject39F7B0AE', + }, + ':*', + ], + ], + }, + ], + }, + { + 'Action': [ + 'codebuild:CreateReportGroup', + 'codebuild:CreateReport', + 'codebuild:UpdateReport', + 'codebuild:BatchPutTestCases', + 'codebuild:BatchPutCodeCoverages', + ], + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': ['', [ + 'arn:', + { 'Ref': 'AWS::Partition' }, + ':codebuild:', + { 'Ref': 'AWS::Region' }, + ':', + { 'Ref': 'AWS::AccountId' }, + ':report-group/', + { 'Ref': 'MyProject39F7B0AE' }, + '-*', + ]], + }, + }, + ], + 'Version': '2012-10-17', + }, + 'PolicyName': 'MyProjectRoleDefaultPolicyB19B7C29', + 'Roles': [ + { + 'Ref': 'MyProjectRole9BBE5233', + }, + ], + }, + }, + 'MyProject39F7B0AE': { + 'Type': 'AWS::CodeBuild::Project', + 'Properties': { + 'Artifacts': { + 'Type': 'NO_ARTIFACTS', + }, + 'Environment': { + 'ComputeType': 'BUILD_GENERAL1_MEDIUM', + 'Image': 'aws/codebuild/windows-base:2.0', + 'ImagePullCredentialsType': 'CODEBUILD', + 'PrivilegedMode': false, + 'Type': 'WINDOWS_CONTAINER', + }, + 'ServiceRole': { + 'Fn::GetAtt': [ + 'MyProjectRole9BBE5233', + 'Arn', + ], + }, + 'Source': { + 'Location': { + 'Fn::Join': [ + '', + [ + { + 'Ref': 'MyBucketF68F3FF0', + }, + '/path/to/source.zip', + ], + ], + }, + 'Type': 'S3', + }, + 'EncryptionKey': 'alias/aws/s3', + }, + }, + }, + }); + }); + + test('with GitHub source', () => { + const stack = new cdk.Stack(); + + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHub({ + owner: 'testowner', + repo: 'testrepo', + cloneDepth: 3, + fetchSubmodules: true, + webhook: true, + reportBuildStatus: false, + webhookFilters: [ + codebuild.FilterGroup.inEventOf(codebuild.EventAction.PUSH).andTagIsNot('stable'), + codebuild.FilterGroup.inEventOf(codebuild.EventAction.PULL_REQUEST_REOPENED).andBaseBranchIs('master'), + ], + }), + }); + + expect(stack).toHaveResource('AWS::CodeBuild::Project', { + Source: { + Type: 'GITHUB', + Location: 'https://github.com/testowner/testrepo.git', + ReportBuildStatus: false, + GitCloneDepth: 3, + GitSubmodulesConfig: { + FetchSubmodules: true, + }, + }, + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Triggers: { + Webhook: true, + FilterGroups: [ + [ + { Type: 'EVENT', Pattern: 'PUSH' }, + { Type: 'HEAD_REF', Pattern: 'refs/tags/stable', ExcludeMatchedPattern: true }, + ], + [ + { Type: 'EVENT', Pattern: 'PULL_REQUEST_REOPENED' }, + { Type: 'BASE_REF', Pattern: 'refs/heads/master' }, + ], + ], + }, + }); + }); + + test('with GitHubEnterprise source', () => { + const stack = new cdk.Stack(); + + const pushFilterGroup = codebuild.FilterGroup.inEventOf(codebuild.EventAction.PUSH); + new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.gitHubEnterprise({ + httpsCloneUrl: 'https://github.testcompany.com/testowner/testrepo', + ignoreSslErrors: true, + cloneDepth: 4, + webhook: true, + reportBuildStatus: false, + webhookFilters: [ + pushFilterGroup.andBranchIs('master'), + pushFilterGroup.andBranchIs('develop'), + pushFilterGroup.andFilePathIs('ReadMe.md'), + ], + }), + }); + + expect(stack).toHaveResource('AWS::CodeBuild::Project', { + Source: { + Type: 'GITHUB_ENTERPRISE', + InsecureSsl: true, + GitCloneDepth: 4, + ReportBuildStatus: false, + Location: 'https://github.testcompany.com/testowner/testrepo', + }, + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Triggers: { + Webhook: true, + FilterGroups: [ + [ + { Type: 'EVENT', Pattern: 'PUSH' }, + { Type: 'HEAD_REF', Pattern: 'refs/heads/master' }, + ], + [ + { Type: 'EVENT', Pattern: 'PUSH' }, + { Type: 'HEAD_REF', Pattern: 'refs/heads/develop' }, + ], + [ + { Type: 'EVENT', Pattern: 'PUSH' }, + { Type: 'FILE_PATH', Pattern: 'ReadMe.md' }, + ], + ], + }, + }); + }); + + test('with Bitbucket source', () => { + const stack = new cdk.Stack(); + + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.bitBucket({ + owner: 'testowner', + repo: 'testrepo', + cloneDepth: 5, + reportBuildStatus: false, + webhookFilters: [ + codebuild.FilterGroup.inEventOf( + codebuild.EventAction.PULL_REQUEST_CREATED, + codebuild.EventAction.PULL_REQUEST_UPDATED, + codebuild.EventAction.PULL_REQUEST_MERGED, + ).andTagIs('v.*'), + // duplicate event actions are fine + codebuild.FilterGroup.inEventOf(codebuild.EventAction.PUSH, codebuild.EventAction.PUSH).andActorAccountIsNot('aws-cdk-dev'), + ], + }), + }); + + expect(stack).toHaveResource('AWS::CodeBuild::Project', { + Source: { + Type: 'BITBUCKET', + Location: 'https://bitbucket.org/testowner/testrepo.git', + GitCloneDepth: 5, + ReportBuildStatus: false, + }, + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Triggers: { + Webhook: true, + FilterGroups: [ + [ + { Type: 'EVENT', Pattern: 'PULL_REQUEST_CREATED, PULL_REQUEST_UPDATED, PULL_REQUEST_MERGED' }, + { Type: 'HEAD_REF', Pattern: 'refs/tags/v.*' }, + ], + [ + { Type: 'EVENT', Pattern: 'PUSH' }, + { Type: 'ACTOR_ACCOUNT_ID', Pattern: 'aws-cdk-dev', ExcludeMatchedPattern: true }, + ], + ], + }, + }); + }); + + test('with webhookTriggersBatchBuild option', () => { + const stack = new cdk.Stack(); + + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHub({ + owner: 'testowner', + repo: 'testrepo', + webhook: true, + webhookTriggersBatchBuild: true, + }), + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Triggers: { + Webhook: true, + BuildType: 'BUILD_BATCH', + }, + BuildBatchConfig: { + ServiceRole: { + 'Fn::GetAtt': [ + 'ProjectBatchServiceRoleF97A1CFB', + 'Arn', + ], + }, + }, + }); + + expect(stack).toHaveResourceLike('AWS::IAM::Role', { + AssumeRolePolicyDocument: { + Statement: [ + { + Action: 'sts:AssumeRole', + Effect: 'Allow', + Principal: { + Service: 'codebuild.amazonaws.com', + }, + }, + ], + Version: '2012-10-17', + }, + }); + + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: [ + 'codebuild:StartBuild', + 'codebuild:StopBuild', + 'codebuild:RetryBuild', + ], + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': [ + 'ProjectC78D97AD', + 'Arn', + ], + }, + }, + ], + Version: '2012-10-17', + }, + }); + }); + + test('fail creating a Project when webhook false and webhookTriggersBatchBuild option', () => { + [false, undefined].forEach((webhook) => { + const stack = new cdk.Stack(); + + expect(() => { + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHub({ + owner: 'testowner', + repo: 'testrepo', + webhook, + webhookTriggersBatchBuild: true, + }), + }); + }).toThrow(/`webhookTriggersBatchBuild` cannot be used when `webhook` is `false`/); + }); + }); + + test('fail creating a Project when no build spec is given', () => { + const stack = new cdk.Stack(); + + expect(() => { + new codebuild.Project(stack, 'MyProject', { + }); + }).toThrow(/buildSpec/); + }); + + test('with VPC configuration', () => { + const stack = new cdk.Stack(); + + const bucket = new s3.Bucket(stack, 'MyBucket'); + const vpc = new ec2.Vpc(stack, 'MyVPC'); + const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup1', { + securityGroupName: 'Bob', + vpc, + allowAllOutbound: true, + description: 'Example', + }); + const project = new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.s3({ + bucket, + path: 'path/to/source.zip', + }), + vpc, + securityGroups: [securityGroup], + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'VpcConfig': { + 'SecurityGroupIds': [ + { + 'Fn::GetAtt': [ + 'SecurityGroup1F554B36F', + 'GroupId', + ], + }, + ], + 'Subnets': [ + { + 'Ref': 'MyVPCPrivateSubnet1Subnet641543F4', + }, + { + 'Ref': 'MyVPCPrivateSubnet2SubnetA420D3F0', + }, + ], + 'VpcId': { + 'Ref': 'MyVPCAFB07A31', + }, + }, + }); + + expect(project.connections).toBeDefined(); + }); + + test('without VPC configuration but security group identified', () => { + const stack = new cdk.Stack(); + + const bucket = new s3.Bucket(stack, 'MyBucket'); + const vpc = new ec2.Vpc(stack, 'MyVPC'); + const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup1', { + securityGroupName: 'Bob', + vpc, + allowAllOutbound: true, + description: 'Example', + }); + + expect(() => + new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.s3({ + bucket, + path: 'path/to/source.zip', + }), + securityGroups: [securityGroup], + }), + ).toThrow(/Cannot configure 'securityGroup' or 'allowAllOutbound' without configuring a VPC/); + }); + + test('with VPC configuration but allowAllOutbound identified', () => { + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'MyBucket'); + const vpc = new ec2.Vpc(stack, 'MyVPC'); + const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup1', { + securityGroupName: 'Bob', + vpc, + allowAllOutbound: true, + description: 'Example', + }); + + expect(() => + new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.s3({ + bucket, + path: 'path/to/source.zip', + }), + vpc, + allowAllOutbound: true, + securityGroups: [securityGroup], + }), + ).toThrow(/Configure 'allowAllOutbound' directly on the supplied SecurityGroup/); + }); + + test('without passing a VPC cannot access the connections property', () => { + const stack = new cdk.Stack(); + + const project = new codebuild.PipelineProject(stack, 'MyProject'); + + expect(() => project.connections).toThrow( + /Only VPC-associated Projects have security groups to manage. Supply the "vpc" parameter when creating the Project/); + }); + + test('no KMS Key defaults to default S3 managed key', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.PipelineProject(stack, 'MyProject'); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + EncryptionKey: 'alias/aws/s3', + }); + }); + + test('with a KMS Key adds decrypt permissions to the CodeBuild Role', () => { + const stack = new cdk.Stack(); + + const key = new kms.Key(stack, 'MyKey'); + + new codebuild.PipelineProject(stack, 'MyProject', { + encryptionKey: key, + grantReportGroupPermissions: false, + }); + + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': [ + {}, // CloudWatch logs + { + 'Action': [ + 'kms:Decrypt', + 'kms:Encrypt', + 'kms:ReEncrypt*', + 'kms:GenerateDataKey*', + ], + 'Effect': 'Allow', + 'Resource': { + 'Fn::GetAtt': [ + 'MyKey6AB29FA6', + 'Arn', + ], + }, + }, + ], + }, + 'Roles': [ + { + 'Ref': 'MyProjectRole9BBE5233', + }, + ], + }); + }); +}); + +test('using timeout and path in S3 artifacts sets it correctly', () => { + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'Bucket'); + new codebuild.Project(stack, 'Project', { + buildSpec: codebuild.BuildSpec.fromObject({ + version: '0.2', + }), + artifacts: codebuild.Artifacts.s3({ + path: 'some/path', + name: 'some_name', + bucket, + }), + timeout: cdk.Duration.minutes(123), + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Artifacts': { + 'Path': 'some/path', + 'Name': 'some_name', + 'Type': 'S3', + }, + 'TimeoutInMinutes': 123, + }); +}); + +describe('secondary sources', () => { + test('require providing an identifier when creating a Project', () => { + const stack = new cdk.Stack(); + + expect(() => { + new codebuild.Project(stack, 'MyProject', { + buildSpec: codebuild.BuildSpec.fromObject({ + version: '0.2', + }), + secondarySources: [ + codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'MyBucket'), + path: 'path', + }), + ], + }); + }).toThrow(/identifier/); + }); + + test('are not allowed for a Project with CodePipeline as Source', () => { + const stack = new cdk.Stack(); + const project = new codebuild.PipelineProject(stack, 'MyProject'); + + project.addSecondarySource(codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'MyBucket'), + path: 'some/path', + identifier: 'id', + })); + + expect(() => SynthUtils.synthesize(stack)).toThrow(/secondary sources/); + }); + + test('added with an identifer after the Project has been created are rendered in the template', () => { + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'MyBucket'); + const project = new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.s3({ + bucket, + path: 'some/path', + }), + }); + + project.addSecondarySource(codebuild.Source.s3({ + bucket, + path: 'another/path', + identifier: 'source1', + })); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'SecondarySources': [ + { + 'SourceIdentifier': 'source1', + 'Type': 'S3', + }, + ], + }); + }); +}); + +describe('secondary source versions', () => { + test('allow secondary source versions', () => { + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'MyBucket'); + const project = new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.s3({ + bucket, + path: 'some/path', + }), + }); + + project.addSecondarySource(codebuild.Source.s3({ + bucket, + path: 'another/path', + identifier: 'source1', + version: 'someversion', + })); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'SecondarySources': [ + { + 'SourceIdentifier': 'source1', + 'Type': 'S3', + }, + ], + 'SecondarySourceVersions': [ + { + 'SourceIdentifier': 'source1', + 'SourceVersion': 'someversion', + }, + ], + }); + }); + + test('allow not to specify secondary source versions', () => { + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'MyBucket'); + const project = new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.s3({ + bucket, + path: 'some/path', + }), + }); + + project.addSecondarySource(codebuild.Source.s3({ + bucket, + path: 'another/path', + identifier: 'source1', + })); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'SecondarySources': [ + { + 'SourceIdentifier': 'source1', + 'Type': 'S3', + }, + ], + }); + }); +}); + +describe('fileSystemLocations', () => { + test('create fileSystemLocation and validate attributes', () => { + const stack = new cdk.Stack(); + new codebuild.Project(stack, 'MyProject', { + buildSpec: codebuild.BuildSpec.fromObject({ + version: '0.2', + }), + fileSystemLocations: [codebuild.FileSystemLocation.efs({ + identifier: 'myidentifier2', + location: 'myclodation.mydnsroot.com:/loc', + mountPoint: '/media', + mountOptions: 'opts', + })], + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'FileSystemLocations': [ + { + 'Identifier': 'myidentifier2', + 'MountPoint': '/media', + 'MountOptions': 'opts', + 'Location': 'myclodation.mydnsroot.com:/loc', + 'Type': 'EFS', + }, + ], + }); + }); + + test('Multiple fileSystemLocation created', () => { + const stack = new cdk.Stack(); + const project = new codebuild.Project(stack, 'MyProject', { + buildSpec: codebuild.BuildSpec.fromObject({ + version: '0.2', + }), + }); + project.addFileSystemLocation(codebuild.FileSystemLocation.efs({ + identifier: 'myidentifier3', + location: 'myclodation.mydnsroot.com:/loc', + mountPoint: '/media', + mountOptions: 'opts', + })); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'FileSystemLocations': [ + { + 'Identifier': 'myidentifier3', + 'MountPoint': '/media', + 'MountOptions': 'opts', + 'Location': 'myclodation.mydnsroot.com:/loc', + 'Type': 'EFS', + }, + ], + }); + }); +}); + +describe('secondary artifacts', () => { + test('require providing an identifier when creating a Project', () => { + const stack = new cdk.Stack(); + + expect(() => { + new codebuild.Project(stack, 'MyProject', { + buildSpec: codebuild.BuildSpec.fromObject({ + version: '0.2', + }), + secondaryArtifacts: [ + codebuild.Artifacts.s3({ + bucket: new s3.Bucket(stack, 'MyBucket'), + path: 'some/path', + name: 'name', + }), + ], + }); + }).toThrow(/identifier/); + }); + + test('are not allowed for a Project with CodePipeline as Source', () => { + const stack = new cdk.Stack(); + const project = new codebuild.PipelineProject(stack, 'MyProject'); + + project.addSecondaryArtifact(codebuild.Artifacts.s3({ + bucket: new s3.Bucket(stack, 'MyBucket'), + path: 'some/path', + name: 'name', + identifier: 'id', + })); + + expect(() => SynthUtils.synthesize(stack)).toThrow(/secondary artifacts/); + }); + + test('added with an identifier after the Project has been created are rendered in the template', () => { + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'MyBucket'); + const project = new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.s3({ + bucket, + path: 'some/path', + }), + }); + + project.addSecondaryArtifact(codebuild.Artifacts.s3({ + bucket, + path: 'another/path', + name: 'name', + identifier: 'artifact1', + })); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'SecondaryArtifacts': [ + { + 'ArtifactIdentifier': 'artifact1', + 'Type': 'S3', + }, + ], + }); + }); + + test('disabledEncryption is set', () => { + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'MyBucket'); + const project = new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.s3({ + bucket, + path: 'some/path', + }), + }); + + project.addSecondaryArtifact(codebuild.Artifacts.s3({ + bucket, + path: 'another/path', + name: 'name', + identifier: 'artifact1', + encryption: false, + })); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'SecondaryArtifacts': [ + { + 'ArtifactIdentifier': 'artifact1', + 'EncryptionDisabled': true, + }, + ], + }); + }); +}); + +describe('artifacts', () => { + describe('CodePipeline', () => { + test('both source and artifacs are set to CodePipeline', () => { + const stack = new cdk.Stack(); + + new codebuild.PipelineProject(stack, 'MyProject'); + + expect(stack).toHaveResource('AWS::CodeBuild::Project', { + 'Source': { + 'Type': 'CODEPIPELINE', + }, + 'Artifacts': { + 'Type': 'CODEPIPELINE', + }, + 'ServiceRole': { + 'Fn::GetAtt': [ + 'MyProjectRole9BBE5233', + 'Arn', + ], + }, + 'Environment': { + 'Type': 'LINUX_CONTAINER', + 'PrivilegedMode': false, + 'Image': 'aws/codebuild/standard:1.0', + 'ImagePullCredentialsType': 'CODEBUILD', + 'ComputeType': 'BUILD_GENERAL1_SMALL', + }, + }); + }); + }); + + describe('S3', () => { + test('name is not set so use buildspec', () => { + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'MyBucket'); + new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.s3({ + bucket, + path: 'some/path', + }), + artifacts: codebuild.Artifacts.s3({ + bucket, + path: 'another/path', + identifier: 'artifact1', + }), + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Artifacts': { + 'Name': ABSENT, + 'ArtifactIdentifier': 'artifact1', + 'OverrideArtifactName': true, + }, + }); + }); + + test('name is set so use it', () => { + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'MyBucket'); + new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.s3({ + bucket, + path: 'some/path', + }), + artifacts: codebuild.Artifacts.s3({ + bucket, + path: 'another/path', + name: 'specificname', + identifier: 'artifact1', + }), + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Artifacts': { + 'ArtifactIdentifier': 'artifact1', + 'Name': 'specificname', + 'OverrideArtifactName': ABSENT, + }, + }); + }); + }); +}); + +test('events', () => { + const stack = new cdk.Stack(); + const project = new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'MyBucket'), + path: 'path', + }), + }); + + project.onBuildFailed('OnBuildFailed', { target: { bind: () => ({ arn: 'ARN', id: 'ID' }) } }); + project.onBuildSucceeded('OnBuildSucceeded', { target: { bind: () => ({ arn: 'ARN', id: 'ID' }) } }); + project.onPhaseChange('OnPhaseChange', { target: { bind: () => ({ arn: 'ARN', id: 'ID' }) } }); + project.onStateChange('OnStateChange', { target: { bind: () => ({ arn: 'ARN', id: 'ID' }) } }); + project.onBuildStarted('OnBuildStarted', { target: { bind: () => ({ arn: 'ARN', id: 'ID' }) } }); + + expect(stack).toHaveResource('AWS::Events::Rule', { + 'EventPattern': { + 'source': [ + 'aws.codebuild', + ], + 'detail-type': [ + 'CodeBuild Build State Change', + ], + 'detail': { + 'project-name': [ + { + 'Ref': 'MyProject39F7B0AE', + }, + ], + 'build-status': [ + 'FAILED', + ], + }, + }, + 'State': 'ENABLED', + }); + + expect(stack).toHaveResource('AWS::Events::Rule', { + 'EventPattern': { + 'source': [ + 'aws.codebuild', + ], + 'detail-type': [ + 'CodeBuild Build State Change', + ], + 'detail': { + 'project-name': [ + { + 'Ref': 'MyProject39F7B0AE', + }, + ], + 'build-status': [ + 'SUCCEEDED', + ], + }, + }, + 'State': 'ENABLED', + }); + + expect(stack).toHaveResource('AWS::Events::Rule', { + 'EventPattern': { + 'source': [ + 'aws.codebuild', + ], + 'detail-type': [ + 'CodeBuild Build Phase Change', + ], + 'detail': { + 'project-name': [ + { + 'Ref': 'MyProject39F7B0AE', + }, + ], + }, + }, + 'State': 'ENABLED', + }); + + expect(stack).toHaveResource('AWS::Events::Rule', { + 'EventPattern': { + 'source': [ + 'aws.codebuild', + ], + 'detail-type': [ + 'CodeBuild Build State Change', + ], + 'detail': { + 'project-name': [ + { + 'Ref': 'MyProject39F7B0AE', + }, + ], + }, + }, + 'State': 'ENABLED', + }); + + expect(stack).toHaveResource('AWS::Events::Rule', { + 'EventPattern': { + 'source': [ + 'aws.codebuild', + ], + 'detail-type': [ + 'CodeBuild Build State Change', + ], + 'detail': { + 'project-name': [ + { + 'Ref': 'MyProject39F7B0AE', + }, + ], + 'build-status': [ + 'IN_PROGRESS', + ], + }, + }, + 'State': 'ENABLED', + }); +}); + +test('environment variables can be overridden at the project level', () => { + const stack = new cdk.Stack(); + + new codebuild.PipelineProject(stack, 'Project', { + environment: { + environmentVariables: { + FOO: { value: '1234' }, + BAR: { value: `111${cdk.Token.asString({ twotwotwo: '222' })}`, type: codebuild.BuildEnvironmentVariableType.PARAMETER_STORE }, + }, + }, + environmentVariables: { + GOO: { value: 'ABC' }, + FOO: { value: 'OVERRIDE!' }, + }, + }); + + expect(stack).toHaveResource('AWS::CodeBuild::Project', { + 'Source': { + 'Type': 'CODEPIPELINE', + }, + 'Artifacts': { + 'Type': 'CODEPIPELINE', + }, + 'ServiceRole': { + 'Fn::GetAtt': [ + 'ProjectRole4CCB274E', + 'Arn', + ], + }, + 'Environment': { + 'Type': 'LINUX_CONTAINER', + 'EnvironmentVariables': [ + { + 'Type': 'PLAINTEXT', + 'Value': 'OVERRIDE!', + 'Name': 'FOO', + }, + { + 'Type': 'PARAMETER_STORE', + 'Value': { + 'Fn::Join': [ + '', + [ + '111', + { twotwotwo: '222' }, + ], + ], + }, + 'Name': 'BAR', + }, + { + 'Type': 'PLAINTEXT', + 'Value': 'ABC', + 'Name': 'GOO', + }, + ], + 'PrivilegedMode': false, + 'Image': 'aws/codebuild/standard:1.0', + 'ImagePullCredentialsType': 'CODEBUILD', + 'ComputeType': 'BUILD_GENERAL1_SMALL', + }, + }); +}); + +test('.metricXxx() methods can be used to obtain Metrics for CodeBuild projects', () => { + const stack = new cdk.Stack(); + + const project = new codebuild.Project(stack, 'MyBuildProject', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'MyBucket'), + path: 'path', + }), + }); + + const metricBuilds = project.metricBuilds(); + expect(metricBuilds.dimensions!.ProjectName).toEqual(project.projectName); + expect(metricBuilds.namespace).toEqual('AWS/CodeBuild'); + expect(metricBuilds.statistic).toEqual('Sum'); + expect(metricBuilds.metricName).toEqual('Builds'); + + const metricDuration = project.metricDuration({ label: 'hello' }); + + expect(metricDuration.metricName).toEqual('Duration'); + expect(metricDuration.label).toEqual('hello'); + + expect(project.metricFailedBuilds().metricName).toEqual('FailedBuilds'); + expect(project.metricSucceededBuilds().metricName).toEqual('SucceededBuilds'); +}); + +test('using ComputeType.Small with a Windows image fails validation', () => { + const stack = new cdk.Stack(); + const invalidEnvironment: codebuild.BuildEnvironment = { + buildImage: codebuild.WindowsBuildImage.WINDOWS_BASE_2_0, + computeType: codebuild.ComputeType.SMALL, + }; + + expect(() => { + new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'MyBucket'), + path: 'path', + }), + environment: invalidEnvironment, + }); + }).toThrow(/Windows images do not support the Small ComputeType/); +}); + +test('fromCodebuildImage', () => { + const stack = new cdk.Stack(); + new codebuild.PipelineProject(stack, 'Project', { + environment: { + buildImage: codebuild.LinuxBuildImage.fromCodeBuildImageId('aws/codebuild/standard:4.0'), + }, + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'Image': 'aws/codebuild/standard:4.0', + }, + }); +}); + +describe('Windows2019 image', () => { + describe('WIN_SERVER_CORE_2016_BASE', () => { + test('has type WINDOWS_SERVER_2019_CONTAINER and default ComputeType MEDIUM', () => { + const stack = new cdk.Stack(); + new codebuild.PipelineProject(stack, 'Project', { + environment: { + buildImage: codebuild.WindowsBuildImage.WIN_SERVER_CORE_2019_BASE, + }, + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'Type': 'WINDOWS_SERVER_2019_CONTAINER', + 'ComputeType': 'BUILD_GENERAL1_MEDIUM', + }, + }); + }); + }); +}); + +describe('ARM image', () => { + describe('AMAZON_LINUX_2_ARM', () => { + test('has type ARM_CONTAINER and default ComputeType LARGE', () => { + const stack = new cdk.Stack(); + new codebuild.PipelineProject(stack, 'Project', { + environment: { + buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_ARM, + }, + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'Type': 'ARM_CONTAINER', + 'ComputeType': 'BUILD_GENERAL1_LARGE', + }, + }); + }); + + test('cannot be used in conjunction with ComputeType SMALL', () => { + const stack = new cdk.Stack(); + + expect(() => { + new codebuild.PipelineProject(stack, 'Project', { + environment: { + buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_ARM, + computeType: codebuild.ComputeType.SMALL, + }, + }); + }).toThrow(/ARM images only support ComputeType 'BUILD_GENERAL1_LARGE' - 'BUILD_GENERAL1_SMALL' was given/); + }); + + test('cannot be used in conjunction with ComputeType MEDIUM', () => { + const stack = new cdk.Stack(); + + expect(() => { + new codebuild.PipelineProject(stack, 'Project', { + environment: { + buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_ARM, + computeType: codebuild.ComputeType.MEDIUM, + }, + }); + }).toThrow(/ARM images only support ComputeType 'BUILD_GENERAL1_LARGE' - 'BUILD_GENERAL1_MEDIUM' was given/); + }); + + test('cannot be used in conjunction with ComputeType X2_LARGE', () => { + const stack = new cdk.Stack(); + + expect(() => { + new codebuild.PipelineProject(stack, 'Project', { + environment: { + buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_ARM, + computeType: codebuild.ComputeType.X2_LARGE, + }, + }); + }).toThrow(/ARM images only support ComputeType 'BUILD_GENERAL1_LARGE' - 'BUILD_GENERAL1_2XLARGE' was given/); + }); + }); +}); + +test('badge support test', () => { + const stack = new cdk.Stack(); + + interface BadgeValidationTestCase { + source: codebuild.Source, + allowsBadge: boolean + } + + const repo = new codecommit.Repository(stack, 'MyRepo', { + repositoryName: 'hello-cdk', + }); + const bucket = new s3.Bucket(stack, 'MyBucket'); + + const cases: BadgeValidationTestCase[] = [ + { source: new NoSource(), allowsBadge: false }, + { source: new CodePipelineSource(), allowsBadge: false }, + { source: codebuild.Source.codeCommit({ repository: repo }), allowsBadge: true }, + { source: codebuild.Source.s3({ bucket, path: 'path/to/source.zip' }), allowsBadge: false }, + { source: codebuild.Source.gitHub({ owner: 'awslabs', repo: 'aws-cdk' }), allowsBadge: true }, + { source: codebuild.Source.gitHubEnterprise({ httpsCloneUrl: 'url' }), allowsBadge: true }, + { source: codebuild.Source.bitBucket({ owner: 'awslabs', repo: 'aws-cdk' }), allowsBadge: true }, + ]; + + cases.forEach(testCase => { + const source = testCase.source; + const validationBlock = () => { new codebuild.Project(stack, `MyProject-${source.type}`, { source, badge: true }); }; + if (testCase.allowsBadge) { + expect(validationBlock).not.toThrow(); + } else { + expect(validationBlock).toThrow(/Badge is not supported for source type /); + } + }); +}); + +describe('webhook Filters', () => { + test('a Group cannot be created with an empty set of event actions', () => { + expect(() => { + codebuild.FilterGroup.inEventOf(); + }).toThrow(/A filter group must contain at least one event action/); + }); + + test('cannot have base ref conditions if the Group contains the PUSH action', () => { + const filterGroup = codebuild.FilterGroup.inEventOf(codebuild.EventAction.PULL_REQUEST_CREATED, + codebuild.EventAction.PUSH); + + expect(() => { + filterGroup.andBaseRefIs('.*'); + }).toThrow(/A base reference condition cannot be added if a Group contains a PUSH event action/); + }); + + test('cannot be used when webhook is false', () => { + const stack = new cdk.Stack(); + + expect(() => { + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.bitBucket({ + owner: 'owner', + repo: 'repo', + webhook: false, + webhookFilters: [ + codebuild.FilterGroup.inEventOf(codebuild.EventAction.PUSH), + ], + }), + }); + }).toThrow(/`webhookFilters` cannot be used when `webhook` is `false`/); + }); + + test('can have FILE_PATH filters if the Group contains PUSH and PR_CREATED events', () => { + codebuild.FilterGroup.inEventOf( + codebuild.EventAction.PULL_REQUEST_CREATED, + codebuild.EventAction.PUSH) + .andFilePathIsNot('.*\\.java'); + }); + + test('BitBucket sources do not support the PULL_REQUEST_REOPENED event action', () => { + const stack = new cdk.Stack(); + + expect(() => { + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.bitBucket({ + owner: 'owner', + repo: 'repo', + webhookFilters: [ + codebuild.FilterGroup.inEventOf(codebuild.EventAction.PULL_REQUEST_REOPENED), + ], + }), + }); + }).toThrow(/BitBucket sources do not support the PULL_REQUEST_REOPENED webhook event action/); + }); + + test('BitBucket sources support file path conditions', () => { + const stack = new cdk.Stack(); + const filterGroup = codebuild.FilterGroup.inEventOf(codebuild.EventAction.PUSH).andFilePathIs('.*'); + + expect(() => { + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.bitBucket({ + owner: 'owner', + repo: 'repo', + webhookFilters: [filterGroup], + }), + }); + }).not.toThrow(); + }); + + test('GitHub Enterprise Server sources do not support FILE_PATH filters on PR events', () => { + const stack = new cdk.Stack(); + const pullFilterGroup = codebuild.FilterGroup.inEventOf( + codebuild.EventAction.PULL_REQUEST_CREATED, + codebuild.EventAction.PULL_REQUEST_MERGED, + codebuild.EventAction.PULL_REQUEST_REOPENED, + codebuild.EventAction.PULL_REQUEST_UPDATED, + ); + + expect(() => { + new codebuild.Project(stack, 'MyFilePathProject', { + source: codebuild.Source.gitHubEnterprise({ + httpsCloneUrl: 'https://github.testcompany.com/testowner/testrepo', + webhookFilters: [ + pullFilterGroup.andFilePathIs('ReadMe.md'), + ], + }), + }); + }).toThrow(/FILE_PATH filters cannot be used with GitHub Enterprise Server pull request events/); + }); + + describe('COMMIT_MESSAGE Filter', () => { + test('GitHub Enterprise Server sources do not support COMMIT_MESSAGE filters on PR events', () => { + const stack = new cdk.Stack(); + const pullFilterGroup = codebuild.FilterGroup.inEventOf( + codebuild.EventAction.PULL_REQUEST_CREATED, + codebuild.EventAction.PULL_REQUEST_MERGED, + codebuild.EventAction.PULL_REQUEST_REOPENED, + codebuild.EventAction.PULL_REQUEST_UPDATED, + ); + + expect(() => { + new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.gitHubEnterprise({ + httpsCloneUrl: 'https://github.testcompany.com/testowner/testrepo', + webhookFilters: [ + pullFilterGroup.andCommitMessageIs('the commit message'), + ], + }), + }); + }).toThrow(/COMMIT_MESSAGE filters cannot be used with GitHub Enterprise Server pull request events/); + }); + + test('GitHub Enterprise Server sources support COMMIT_MESSAGE filters on PUSH events', () => { + const stack = new cdk.Stack(); + const pushFilterGroup = codebuild.FilterGroup.inEventOf(codebuild.EventAction.PUSH); + + expect(() => { + new codebuild.Project(stack, 'MyProject', { + source: codebuild.Source.gitHubEnterprise({ + httpsCloneUrl: 'https://github.testcompany.com/testowner/testrepo', + webhookFilters: [ + pushFilterGroup.andCommitMessageIs('the commit message'), + ], + }), + }); + }).not.toThrow(); + }); + + test('BitBucket and GitHub sources support a COMMIT_MESSAGE filter', () => { + const stack = new cdk.Stack(); + const filterGroup = codebuild + .FilterGroup + .inEventOf(codebuild.EventAction.PUSH, codebuild.EventAction.PULL_REQUEST_CREATED) + .andCommitMessageIs('the commit message'); + + expect(() => { + new codebuild.Project(stack, 'BitBucket Project', { + source: codebuild.Source.bitBucket({ + owner: 'owner', + repo: 'repo', + webhookFilters: [filterGroup], + }), + }); + new codebuild.Project(stack, 'GitHub Project', { + source: codebuild.Source.gitHub({ + owner: 'owner', + repo: 'repo', + webhookFilters: [filterGroup], + }), + }); + }).not.toThrow(); + }); + }); +}); + +test('enableBatchBuilds()', () => { + const stack = new cdk.Stack(); + + const project = new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHub({ + owner: 'testowner', + repo: 'testrepo', + }), + }); + + const returnVal = project.enableBatchBuilds(); + if (!returnVal?.role) { + throw new Error('Expecting return value with role'); + } + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + BuildBatchConfig: { + ServiceRole: { + 'Fn::GetAtt': [ + 'ProjectBatchServiceRoleF97A1CFB', + 'Arn', + ], + }, + }, + }); + + expect(stack).toHaveResourceLike('AWS::IAM::Role', { + AssumeRolePolicyDocument: { + Statement: [ + { + Action: 'sts:AssumeRole', + Effect: 'Allow', + Principal: { + Service: 'codebuild.amazonaws.com', + }, + }, + ], + Version: '2012-10-17', + }, + }); + + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: [ + 'codebuild:StartBuild', + 'codebuild:StopBuild', + 'codebuild:RetryBuild', + ], + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': [ + 'ProjectC78D97AD', + 'Arn', + ], + }, + }, + ], + Version: '2012-10-17', + }, + }); +}); diff --git a/packages/@aws-cdk/aws-codebuild/test/linux-gpu-build-image.test.ts b/packages/@aws-cdk/aws-codebuild/test/linux-gpu-build-image.test.ts new file mode 100644 index 0000000000000..7e32ab033c68c --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/test/linux-gpu-build-image.test.ts @@ -0,0 +1,61 @@ +import { arrayWith, objectLike } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +import * as cdk from '@aws-cdk/core'; +import * as codebuild from '../lib'; + +describe('Linux GPU build image', () => { + describe('AWS Deep Learning Container images', () => { + test('allows passing the account that the repository of the image is hosted in', () => { + const stack = new cdk.Stack(); + + new codebuild.Project(stack, 'Project', { + buildSpec: codebuild.BuildSpec.fromObject({ + version: '0.2', + phases: { + build: { commands: ['ls'] }, + }, + }), + environment: { + buildImage: codebuild.LinuxGpuBuildImage.awsDeepLearningContainersImage( + 'my-repo', 'my-tag', '123456789012'), + }, + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Environment: { + ComputeType: 'BUILD_GENERAL1_LARGE', + Image: { + 'Fn::Join': ['', [ + '123456789012.dkr.ecr.', + { Ref: 'AWS::Region' }, + '.', + { Ref: 'AWS::URLSuffix' }, + '/my-repo:my-tag', + ]], + }, + }, + }); + + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + PolicyDocument: { + Statement: arrayWith(objectLike({ + Action: [ + 'ecr:BatchCheckLayerAvailability', + 'ecr:GetDownloadUrlForLayer', + 'ecr:BatchGetImage', + ], + Resource: { + 'Fn::Join': ['', [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':ecr:', + { Ref: 'AWS::Region' }, + ':123456789012:repository/my-repo', + ]], + }, + })), + }, + }); + }); + }); +}); diff --git a/packages/@aws-cdk/aws-codebuild/test/notification-rule.test.ts b/packages/@aws-cdk/aws-codebuild/test/notification-rule.test.ts new file mode 100644 index 0000000000000..45d6a65d76ce4 --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/test/notification-rule.test.ts @@ -0,0 +1,70 @@ +import '@aws-cdk/assert-internal/jest'; +import * as sns from '@aws-cdk/aws-sns'; +import * as cdk from '@aws-cdk/core'; +import * as codebuild from '../lib'; + +test('notifications rule', () => { + const stack = new cdk.Stack(); + const project = new codebuild.Project(stack, 'MyCodebuildProject', { + buildSpec: codebuild.BuildSpec.fromObject({ + version: '0.2', + phases: { + build: { + commands: [ + 'echo "Hello, CodeBuild!"', + ], + }, + }, + }), + }); + + const target = new sns.Topic(stack, 'MyTopic'); + + project.notifyOnBuildSucceeded('NotifyOnBuildSucceeded', target); + + project.notifyOnBuildFailed('NotifyOnBuildFailed', target); + + expect(stack).toHaveResource('AWS::CodeStarNotifications::NotificationRule', { + Name: 'MyCodebuildProjectNotifyOnBuildSucceeded77719592', + DetailType: 'FULL', + EventTypeIds: [ + 'codebuild-project-build-state-succeeded', + ], + Resource: { + 'Fn::GetAtt': [ + 'MyCodebuildProjectB0479580', + 'Arn', + ], + }, + Targets: [ + { + TargetAddress: { + Ref: 'MyTopic86869434', + }, + TargetType: 'SNS', + }, + ], + }); + + expect(stack).toHaveResource('AWS::CodeStarNotifications::NotificationRule', { + Name: 'MyCodebuildProjectNotifyOnBuildFailedF680E310', + DetailType: 'FULL', + EventTypeIds: [ + 'codebuild-project-build-state-failed', + ], + Resource: { + 'Fn::GetAtt': [ + 'MyCodebuildProjectB0479580', + 'Arn', + ], + }, + Targets: [ + { + TargetAddress: { + Ref: 'MyTopic86869434', + }, + TargetType: 'SNS', + }, + ], + }); +}); diff --git a/packages/@aws-cdk/aws-codebuild/test/project.test.ts b/packages/@aws-cdk/aws-codebuild/test/project.test.ts new file mode 100644 index 0000000000000..08fbe3e8f8768 --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/test/project.test.ts @@ -0,0 +1,1780 @@ +import { objectLike, ResourcePart, arrayWith } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +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 s3 from '@aws-cdk/aws-s3'; +import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; +import * as cdk from '@aws-cdk/core'; +import * as codebuild from '../lib'; + +/* eslint-disable quote-props */ + +test('can use filename as buildspec', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + buildSpec: codebuild.BuildSpec.fromSourceFilename('hello.yml'), + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Source: { + BuildSpec: 'hello.yml', + }, + }); +}); + +test('can use buildspec literal', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + buildSpec: codebuild.BuildSpec.fromObject({ phases: ['say hi'] }), + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Source: { + BuildSpec: '{\n "phases": [\n "say hi"\n ]\n}', + }, + }); +}); + +test('can use yamlbuildspec literal', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + buildSpec: codebuild.BuildSpec.fromObjectToYaml({ + text: 'text', + decimal: 10, + list: ['say hi'], + obj: { + text: 'text', + decimal: 10, + list: ['say hi'], + }, + }), + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Source: { + BuildSpec: 'text: text\ndecimal: 10\nlist:\n - say hi\nobj:\n text: text\n decimal: 10\n list:\n - say hi\n', + }, + }); +}); + +test('must supply buildspec when using nosource', () => { + // GIVEN + const stack = new cdk.Stack(); + + expect(() => { + new codebuild.Project(stack, 'Project', { + }); + }).toThrow(/you need to provide a concrete buildSpec/); +}); + +test('must supply literal buildspec when using nosource', () => { + // GIVEN + const stack = new cdk.Stack(); + + expect(() => { + new codebuild.Project(stack, 'Project', { + buildSpec: codebuild.BuildSpec.fromSourceFilename('bla.yml'), + }); + }).toThrow(/you need to provide a concrete buildSpec/); +}); + +describe('GitHub source', () => { + test('has reportBuildStatus on by default', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHub({ + owner: 'testowner', + repo: 'testrepo', + cloneDepth: 3, + }), + }); + + // THEN + expect(stack).toHaveResource('AWS::CodeBuild::Project', { + Source: { + Type: 'GITHUB', + Location: 'https://github.com/testowner/testrepo.git', + ReportBuildStatus: true, + GitCloneDepth: 3, + }, + }); + }); + + test('can set a branch as the SourceVersion', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHub({ + owner: 'testowner', + repo: 'testrepo', + branchOrRef: 'testbranch', + }), + }); + + // THEN + expect(stack).toHaveResource('AWS::CodeBuild::Project', { + SourceVersion: 'testbranch', + }); + }); + + test('can explicitly set reportBuildStatus to false', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHub({ + owner: 'testowner', + repo: 'testrepo', + reportBuildStatus: false, + }), + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Source: { + ReportBuildStatus: false, + }, + }); + }); + + test('can explicitly set webhook to true', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHub({ + owner: 'testowner', + repo: 'testrepo', + webhook: true, + }), + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Triggers: { + Webhook: true, + }, + }); + }); + + test('can be added to a CodePipeline', () => { + const stack = new cdk.Stack(); + const project = new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHub({ + owner: 'testowner', + repo: 'testrepo', + }), + }); + + expect(() => { + project.bindToCodePipeline(project, { + artifactBucket: new s3.Bucket(stack, 'Bucket'), + }); + }).not.toThrow(); // no exception + }); + + test('can provide credentials to use with the source', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.GitHubSourceCredentials(stack, 'GitHubSourceCredentials', { + accessToken: cdk.SecretValue.plainText('my-access-token'), + }); + + // THEN + expect(stack).toHaveResource('AWS::CodeBuild::SourceCredential', { + 'ServerType': 'GITHUB', + 'AuthType': 'PERSONAL_ACCESS_TOKEN', + 'Token': 'my-access-token', + }); + }); +}); + +describe('GitHub Enterprise source', () => { + test('can use branchOrRef to set the source version', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHubEnterprise({ + httpsCloneUrl: 'https://mygithub-enterprise.com/myuser/myrepo', + branchOrRef: 'testbranch', + }), + }); + + // THEN + expect(stack).toHaveResource('AWS::CodeBuild::Project', { + SourceVersion: 'testbranch', + }); + }); + + test('can provide credentials to use with the source', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.GitHubEnterpriseSourceCredentials(stack, 'GitHubEnterpriseSourceCredentials', { + accessToken: cdk.SecretValue.plainText('my-access-token'), + }); + + // THEN + expect(stack).toHaveResource('AWS::CodeBuild::SourceCredential', { + 'ServerType': 'GITHUB_ENTERPRISE', + 'AuthType': 'PERSONAL_ACCESS_TOKEN', + 'Token': 'my-access-token', + }); + }); +}); + +describe('BitBucket source', () => { + test('can use branchOrRef to set the source version', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.bitBucket({ + owner: 'testowner', + repo: 'testrepo', + branchOrRef: 'testbranch', + }), + }); + + // THEN + expect(stack).toHaveResource('AWS::CodeBuild::Project', { + SourceVersion: 'testbranch', + }); + }); + + test('can provide credentials to use with the source', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.BitBucketSourceCredentials(stack, 'BitBucketSourceCredentials', { + username: cdk.SecretValue.plainText('my-username'), + password: cdk.SecretValue.plainText('password'), + }); + + // THEN + expect(stack).toHaveResource('AWS::CodeBuild::SourceCredential', { + 'ServerType': 'BITBUCKET', + 'AuthType': 'BASIC_AUTH', + 'Username': 'my-username', + 'Token': 'password', + }); + }); +}); + +test('project with s3 cache bucket', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'SourceBucket'), + path: 'path', + }), + cache: codebuild.Cache.bucket(new s3.Bucket(stack, 'Bucket'), { + prefix: 'cache-prefix', + }), + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Cache: { + Type: 'S3', + Location: { + 'Fn::Join': [ + '/', + [ + { + 'Ref': 'Bucket83908E77', + }, + 'cache-prefix', + ], + ], + }, + }, + }); +}); + +test('s3 codebuild project with sourceVersion', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + version: 's3version', + }), + cache: codebuild.Cache.local(codebuild.LocalCacheMode.CUSTOM, codebuild.LocalCacheMode.DOCKER_LAYER, + codebuild.LocalCacheMode.SOURCE), + }); + + // THEN + expect(stack).toHaveResource('AWS::CodeBuild::Project', { + SourceVersion: 's3version', + }); +}); + +test('project with local cache modes', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + cache: codebuild.Cache.local(codebuild.LocalCacheMode.CUSTOM, codebuild.LocalCacheMode.DOCKER_LAYER, + codebuild.LocalCacheMode.SOURCE), + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Cache: { + Type: 'LOCAL', + Modes: [ + 'LOCAL_CUSTOM_CACHE', + 'LOCAL_DOCKER_LAYER_CACHE', + 'LOCAL_SOURCE_CACHE', + ], + }, + }); +}); + +test('project by default has no cache modes', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + }); + + // THEN + expect(stack).not.toHaveResourceLike('AWS::CodeBuild::Project', { + Cache: {}, + }); +}); + +test('if a role is shared between projects in a VPC, the VPC Policy is only attached once', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc'); + const role = new iam.Role(stack, 'Role', { + assumedBy: new iam.ServicePrincipal('codebuild.amazonaws.com'), + }); + const source = codebuild.Source.gitHubEnterprise({ + httpsCloneUrl: 'https://mygithub-enterprise.com/myuser/myrepo', + }); + + // WHEN + new codebuild.Project(stack, 'Project1', { source, role, vpc, projectName: 'P1' }); + new codebuild.Project(stack, 'Project2', { source, role, vpc, projectName: 'P2' }); + + // THEN + // - 1 is for `ec2:CreateNetworkInterfacePermission`, deduplicated as they're part of a single policy + // - 1 is for `ec2:CreateNetworkInterface`, this is the separate Policy we're deduplicating + // We would have found 3 if the deduplication didn't work. + expect(stack).toCountResources('AWS::IAM::Policy', 2); + + // THEN - both Projects have a DependsOn on the same policy + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Properties: { Name: 'P1' }, + DependsOn: ['Project1PolicyDocumentF9761562'], + }, ResourcePart.CompleteDefinition); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Properties: { Name: 'P1' }, + DependsOn: ['Project1PolicyDocumentF9761562'], + }, ResourcePart.CompleteDefinition); +}); + +test('can use an imported Role for a Project within a VPC', () => { + const stack = new cdk.Stack(); + + const importedRole = iam.Role.fromRoleArn(stack, 'Role', 'arn:aws:iam::1234567890:role/service-role/codebuild-bruiser-service-role'); + const vpc = new ec2.Vpc(stack, 'Vpc'); + + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHubEnterprise({ + httpsCloneUrl: 'https://mygithub-enterprise.com/myuser/myrepo', + }), + role: importedRole, + vpc, + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + // no need to do any assertions + }); +}); + +test('can use an imported Role with mutable = false for a Project within a VPC', () => { + const stack = new cdk.Stack(); + + const importedRole = iam.Role.fromRoleArn(stack, 'Role', + 'arn:aws:iam::1234567890:role/service-role/codebuild-bruiser-service-role', { + mutable: false, + }); + const vpc = new ec2.Vpc(stack, 'Vpc'); + + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHubEnterprise({ + httpsCloneUrl: 'https://mygithub-enterprise.com/myuser/myrepo', + }), + role: importedRole, + vpc, + }); + + expect(stack).toCountResources('AWS::IAM::Policy', 0); + + // Check that the CodeBuild project does not have a DependsOn + expect(stack).toHaveResource('AWS::CodeBuild::Project', (res: any) => { + if (res.DependsOn && res.DependsOn.length > 0) { + throw new Error(`CodeBuild project should have no DependsOn, but got: ${JSON.stringify(res, undefined, 2)}`); + } + return true; + }, ResourcePart.CompleteDefinition); +}); + +test('can use an ImmutableRole for a Project within a VPC', () => { + const stack = new cdk.Stack(); + + const role = new iam.Role(stack, 'Role', { + assumedBy: new iam.ServicePrincipal('codebuild.amazonaws.com'), + }); + + const vpc = new ec2.Vpc(stack, 'Vpc'); + + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHubEnterprise({ + httpsCloneUrl: 'https://mygithub-enterprise.com/myuser/myrepo', + }), + role: role.withoutPolicyUpdates(), + vpc, + }); + + expect(stack).toCountResources('AWS::IAM::Policy', 0); + + // Check that the CodeBuild project does not have a DependsOn + expect(stack).toHaveResource('AWS::CodeBuild::Project', (res: any) => { + if (res.DependsOn && res.DependsOn.length > 0) { + throw new Error(`CodeBuild project should have no DependsOn, but got: ${JSON.stringify(res, undefined, 2)}`); + } + return true; + }, ResourcePart.CompleteDefinition); +}); + +test('metric method generates a valid CloudWatch metric', () => { + const stack = new cdk.Stack(); + + const project = new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHubEnterprise({ + httpsCloneUrl: 'https://mygithub-enterprise.com/myuser/myrepo', + }), + }); + + const metric = project.metric('Builds'); + expect(metric.metricName).toEqual('Builds'); + expect(metric.period.toSeconds()).toEqual(cdk.Duration.minutes(5).toSeconds()); + expect(metric.statistic).toEqual('Average'); +}); + +describe('CodeBuild test reports group', () => { + test('adds the appropriate permissions when reportGroup.grantWrite() is called', () => { + const stack = new cdk.Stack(); + + const reportGroup = new codebuild.ReportGroup(stack, 'ReportGroup'); + + const project = new codebuild.Project(stack, 'Project', { + buildSpec: codebuild.BuildSpec.fromObject({ + version: '0.2', + reports: { + [reportGroup.reportGroupArn]: { + files: '**/*', + }, + }, + }), + grantReportGroupPermissions: false, + }); + reportGroup.grantWrite(project); + + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': [ + {}, + { + 'Action': [ + 'codebuild:CreateReport', + 'codebuild:UpdateReport', + 'codebuild:BatchPutTestCases', + ], + 'Resource': { + 'Fn::GetAtt': [ + 'ReportGroup8A84C76D', + 'Arn', + ], + }, + }, + ], + }, + }); + }); +}); + +describe('Environment', () => { + test('build image - can use secret to access build image', () => { + // GIVEN + const stack = new cdk.Stack(); + const secret = new secretsmanager.Secret(stack, 'Secret'); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + environment: { + buildImage: codebuild.LinuxBuildImage.fromDockerRegistry('myimage', { secretsManagerCredentials: secret }), + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Environment: objectLike({ + RegistryCredential: { + CredentialProvider: 'SECRETS_MANAGER', + Credential: { 'Ref': 'SecretA720EF05' }, + }, + }), + }); + }); + + test('build image - can use imported secret by name', () => { + // GIVEN + const stack = new cdk.Stack(); + const secret = secretsmanager.Secret.fromSecretNameV2(stack, 'Secret', 'MySecretName'); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + environment: { + buildImage: codebuild.LinuxBuildImage.fromDockerRegistry('myimage', { secretsManagerCredentials: secret }), + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Environment: objectLike({ + RegistryCredential: { + CredentialProvider: 'SECRETS_MANAGER', + Credential: 'MySecretName', + }, + }), + }); + }); + + test('logs config - cloudWatch', () => { + // GIVEN + const stack = new cdk.Stack(); + const logGroup = logs.LogGroup.fromLogGroupName(stack, 'LogGroup', 'MyLogGroupName'); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + logging: { + cloudWatch: { + logGroup, + prefix: '/my-logs', + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + LogsConfig: objectLike({ + CloudWatchLogs: { + GroupName: 'MyLogGroupName', + Status: 'ENABLED', + StreamName: '/my-logs', + }, + }), + }); + }); + + test('logs config - cloudWatch disabled', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + logging: { + cloudWatch: { + enabled: false, + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + LogsConfig: objectLike({ + CloudWatchLogs: { + Status: 'DISABLED', + }, + }), + }); + }); + + test('logs config - s3', () => { + // GIVEN + const stack = new cdk.Stack(); + const bucket = s3.Bucket.fromBucketName(stack, 'LogBucket', 'MyBucketName'); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + logging: { + s3: { + bucket, + prefix: 'my-logs', + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + LogsConfig: objectLike({ + S3Logs: { + Location: 'MyBucketName/my-logs', + Status: 'ENABLED', + }, + }), + }); + }); + + test('logs config - cloudWatch and s3', () => { + // GIVEN + const stack = new cdk.Stack(); + const bucket = s3.Bucket.fromBucketName(stack, 'LogBucket2', 'MyBucketName'); + const logGroup = logs.LogGroup.fromLogGroupName(stack, 'LogGroup2', 'MyLogGroupName'); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + logging: { + cloudWatch: { + logGroup, + }, + s3: { + bucket, + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + LogsConfig: objectLike({ + CloudWatchLogs: { + GroupName: 'MyLogGroupName', + Status: 'ENABLED', + }, + S3Logs: { + Location: 'MyBucketName', + Status: 'ENABLED', + }, + }), + }); + }); + + test('certificate arn', () => { + // GIVEN + const stack = new cdk.Stack(); + const bucket = s3.Bucket.fromBucketName(stack, 'Bucket', 'my-bucket'); // (stack, 'Bucket'); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket, + path: 'path', + }), + environment: { + certificate: { + bucket, + objectKey: 'path', + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Environment: objectLike({ + Certificate: { + 'Fn::Join': ['', [ + 'arn:', + { 'Ref': 'AWS::Partition' }, + ':s3:::my-bucket/path', + ]], + }, + }), + }); + }); +}); + +describe('EnvironmentVariables', () => { + describe('from SSM', () => { + test('can use environment variables', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + environment: { + buildImage: codebuild.LinuxBuildImage.fromDockerRegistry('myimage'), + }, + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.PARAMETER_STORE, + value: '/params/param1', + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + Environment: objectLike({ + EnvironmentVariables: [{ + Name: 'ENV_VAR1', + Type: 'PARAMETER_STORE', + Value: '/params/param1', + }], + }), + }); + }); + + test('grants the correct read permissions', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + environment: { + buildImage: codebuild.LinuxBuildImage.fromDockerRegistry('myimage'), + }, + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.PARAMETER_STORE, + value: '/params/param1', + }, + 'ENV_VAR2': { + type: codebuild.BuildEnvironmentVariableType.PARAMETER_STORE, + value: 'params/param2', + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith(objectLike({ + 'Action': 'ssm:GetParameters', + 'Effect': 'Allow', + 'Resource': [{ + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':ssm:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':parameter/params/param1', + ], + ], + }, + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':ssm:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':parameter/params/param2', + ], + ], + }], + })), + }, + }); + }); + + test('does not grant read permissions when variables are not from parameter store', () => { + + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + environment: { + buildImage: codebuild.LinuxBuildImage.fromDockerRegistry('myimage'), + }, + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.PLAINTEXT, + value: 'var1-value', + }, + }, + }); + + // THEN + expect(stack).not.toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith(objectLike({ + 'Action': 'ssm:GetParameters', + 'Effect': 'Allow', + })), + }, + }); + }); + }); + + describe('from SecretsManager', () => { + test('can be provided as a verbatim secret name', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: 'my-secret', + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': 'my-secret', + }, + ], + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': ['', [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':secretsmanager:', + { Ref: 'AWS::Region' }, + ':', + { Ref: 'AWS::AccountId' }, + ':secret:my-secret-??????', + ]], + }, + }), + }, + }); + }); + + test('can be provided as a verbatim secret name followed by a JSON key', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: 'my-secret:json-key', + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': 'my-secret:json-key', + }, + ], + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': ['', [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':secretsmanager:', + { Ref: 'AWS::Region' }, + ':', + { Ref: 'AWS::AccountId' }, + ':secret:my-secret-??????', + ]], + }, + }), + }, + }); + }); + + test('can be provided as a verbatim full secret ARN followed by a JSON key', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: 'arn:aws:secretsmanager:us-west-2:123456789012:secret:my-secret-123456:json-key', + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:my-secret-123456:json-key', + }, + ], + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:my-secret-123456*', + }), + }, + }); + + // THEN + expect(stack).not.toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'kms:Decrypt', + 'Effect': 'Allow', + 'Resource': 'arn:aws:kms:us-west-2:123456789012:key/*', + }), + }, + }); + }); + + test('can be provided as a verbatim partial secret ARN', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret', + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret', + }, + ], + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret*', + }), + }, + }); + + // THEN + expect(stack).not.toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'kms:Decrypt', + 'Effect': 'Allow', + 'Resource': 'arn:aws:kms:us-west-2:123456789012:key/*', + }), + }, + }); + }); + + test("when provided as a verbatim partial secret ARN from another account, adds permission to decrypt keys in the Secret's account", () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'ProjectStack', { + env: { account: '123456789012' }, + }); + + // WHEN + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: 'arn:aws:secretsmanager:us-west-2:901234567890:secret:mysecret', + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'kms:Decrypt', + 'Effect': 'Allow', + 'Resource': 'arn:aws:kms:us-west-2:901234567890:key/*', + }), + }, + }); + }); + + test('when two secrets from another account are provided as verbatim partial secret ARNs, adds only one permission for decrypting', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'ProjectStack', { + env: { account: '123456789012' }, + }); + + // WHEN + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: 'arn:aws:secretsmanager:us-west-2:901234567890:secret:mysecret', + }, + 'ENV_VAR2': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: 'arn:aws:secretsmanager:us-west-2:901234567890:secret:other-secret', + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'kms:Decrypt', + 'Effect': 'Allow', + 'Resource': 'arn:aws:kms:us-west-2:901234567890:key/*', + }), + }, + }); + }); + + test('can be provided as the ARN attribute of a new Secret', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const secret = new secretsmanager.Secret(stack, 'Secret'); + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: secret.secretArn, + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': { 'Ref': 'SecretA720EF05' }, + }, + ], + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': { 'Ref': 'SecretA720EF05' }, + }), + }, + }); + }); + + test('when the same new secret is provided with different JSON keys, only adds the resource once', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const secret = new secretsmanager.Secret(stack, 'Secret'); + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: `${secret.secretArn}:json-key1`, + }, + 'ENV_VAR2': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: `${secret.secretArn}:json-key2`, + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': { 'Fn::Join': ['', [{ 'Ref': 'SecretA720EF05' }, ':json-key1']] }, + }, + { + 'Name': 'ENV_VAR2', + 'Type': 'SECRETS_MANAGER', + 'Value': { 'Fn::Join': ['', [{ 'Ref': 'SecretA720EF05' }, ':json-key2']] }, + }, + ], + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': { 'Ref': 'SecretA720EF05' }, + }), + }, + }); + }); + + test('can be provided as the ARN attribute of a new Secret, followed by a JSON key', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const secret = new secretsmanager.Secret(stack, 'Secret'); + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: `${secret.secretArn}:json-key:version-stage`, + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': { + 'Fn::Join': ['', [ + { 'Ref': 'SecretA720EF05' }, + ':json-key:version-stage', + ]], + }, + }, + ], + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': { 'Ref': 'SecretA720EF05' }, + }), + }, + }); + }); + + test('can be provided as the name attribute of a Secret imported by name', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const secret = secretsmanager.Secret.fromSecretNameV2(stack, 'Secret', 'mysecret'); + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: secret.secretName, + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': 'mysecret', + }, + ], + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': ['', [ + 'arn:', + { 'Ref': 'AWS::Partition' }, + ':secretsmanager:', + { 'Ref': 'AWS::Region' }, + ':', + { 'Ref': 'AWS::AccountId' }, + ':secret:mysecret-??????', + ]], + }, + }), + }, + }); + }); + + test('can be provided as the ARN attribute of a Secret imported by partial ARN, followed by a JSON key', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const secret = secretsmanager.Secret.fromSecretPartialArn(stack, 'Secret', + 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret'); + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: `${secret.secretArn}:json-key`, + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret:json-key', + }, + ], + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret*', + }), + }, + }); + }); + + test('can be provided as the ARN attribute of a Secret imported by complete ARN, followed by a JSON key', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const secret = secretsmanager.Secret.fromSecretCompleteArn(stack, 'Secret', + 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret-123456'); + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: `${secret.secretArn}:json-key`, + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret-123456:json-key', + }, + ], + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret-123456*', + }), + }, + }); + }); + + test('can be provided as a SecretArn of a new Secret, with its physical name set, created in a different account', () => { + // GIVEN + const app = new cdk.App(); + const secretStack = new cdk.Stack(app, 'SecretStack', { + env: { account: '012345678912' }, + }); + const stack = new cdk.Stack(app, 'ProjectStack', { + env: { account: '123456789012' }, + }); + + // WHEN + const secret = new secretsmanager.Secret(secretStack, 'Secret', { secretName: 'secret-name' }); + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: secret.secretArn, + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': { + 'Fn::Join': ['', [ + 'arn:', + { 'Ref': 'AWS::Partition' }, + ':secretsmanager:', + { 'Ref': 'AWS::Region' }, + ':012345678912:secret:secret-name', + ]], + }, + }, + ], + }, + }); + + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': ['', [ + 'arn:', + { 'Ref': 'AWS::Partition' }, + ':secretsmanager:', + { 'Ref': 'AWS::Region' }, + ':012345678912:secret:secret-name-??????', + ]], + }, + }), + }, + }); + + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'kms:Decrypt', + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': ['', [ + 'arn:', + { 'Ref': 'AWS::Partition' }, + ':kms:', + { 'Ref': 'AWS::Region' }, + ':012345678912:key/*', + ]], + }, + }), + }, + }); + }); + + test('can be provided as a SecretArn of a Secret imported by name in a different account', () => { + // GIVEN + const app = new cdk.App(); + const secretStack = new cdk.Stack(app, 'SecretStack', { + env: { account: '012345678912' }, + }); + const stack = new cdk.Stack(app, 'ProjectStack', { + env: { account: '123456789012' }, + }); + + // WHEN + const secret = secretsmanager.Secret.fromSecretNameV2(secretStack, 'Secret', 'secret-name'); + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: `${secret.secretArn}:json-key`, + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': { + 'Fn::Join': ['', [ + 'arn:', + { 'Ref': 'AWS::Partition' }, + ':secretsmanager:', + { 'Ref': 'AWS::Region' }, + ':012345678912:secret:secret-name:json-key', + ]], + }, + }, + ], + }, + }); + + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': ['', [ + 'arn:', + { 'Ref': 'AWS::Partition' }, + ':secretsmanager:', + { 'Ref': 'AWS::Region' }, + ':012345678912:secret:secret-name*', + ]], + }, + }), + }, + }); + + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'kms:Decrypt', + 'Effect': 'Allow', + 'Resource': { + 'Fn::Join': ['', [ + 'arn:', + { 'Ref': 'AWS::Partition' }, + ':kms:', + { 'Ref': 'AWS::Region' }, + ':012345678912:key/*', + ]], + }, + }), + }, + }); + }); + + test('can be provided as a SecretArn of a Secret imported by complete ARN from a different account', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'ProjectStack', { + env: { account: '123456789012' }, + }); + const secretArn = 'arn:aws:secretsmanager:us-west-2:901234567890:secret:mysecret-123456'; + + // WHEN + const secret = secretsmanager.Secret.fromSecretCompleteArn(stack, 'Secret', secretArn); + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: secret.secretArn, + }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + 'Environment': { + 'EnvironmentVariables': [ + { + 'Name': 'ENV_VAR1', + 'Type': 'SECRETS_MANAGER', + 'Value': secretArn, + }, + ], + }, + }); + + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'secretsmanager:GetSecretValue', + 'Effect': 'Allow', + 'Resource': `${secretArn}*`, + }), + }, + }); + + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': arrayWith({ + 'Action': 'kms:Decrypt', + 'Effect': 'Allow', + 'Resource': 'arn:aws:kms:us-west-2:901234567890:key/*', + }), + }, + }); + }); + + test('should fail when the parsed Arn does not contain a secret name', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + expect(() => { + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'ENV_VAR1': { + type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, + value: 'arn:aws:secretsmanager:us-west-2:123456789012:secret', + }, + }, + }); + }).toThrow(/SecretManager ARN is missing the name of the secret:/); + }); + }); + + test('should fail creating when using a secret value in a plaintext variable', () => { + // GIVEN + const stack = new cdk.Stack(); + + // THEN + expect(() => { + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'a': { + value: `a_${cdk.SecretValue.secretsManager('my-secret')}_b`, + }, + }, + }); + }).toThrow(/Plaintext environment variable 'a' contains a secret value!/); + }); + + test("should allow opting out of the 'secret value in a plaintext variable' validation", () => { + // GIVEN + const stack = new cdk.Stack(); + + // THEN + expect(() => { + new codebuild.PipelineProject(stack, 'Project', { + environmentVariables: { + 'b': { + value: cdk.SecretValue.secretsManager('my-secret'), + }, + }, + checkSecretsInPlainTextEnvVariables: false, + }); + }).not.toThrow(); + }); +}); + +describe('Timeouts', () => { + test('can add queued timeout', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + queuedTimeout: cdk.Duration.minutes(30), + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + QueuedTimeoutInMinutes: 30, + }); + }); + + test('can override build timeout', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + timeout: cdk.Duration.minutes(30), + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + TimeoutInMinutes: 30, + }); + }); +}); + +describe('Maximum concurrency', () => { + test('can limit maximum concurrency', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new codebuild.Project(stack, 'Project', { + source: codebuild.Source.s3({ + bucket: new s3.Bucket(stack, 'Bucket'), + path: 'path', + }), + concurrentBuildLimit: 1, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::CodeBuild::Project', { + ConcurrentBuildLimit: 1, + }); + }); +}); + +describe('can be imported', () => { + test('by ARN', () => { + const stack = new cdk.Stack(); + const project = codebuild.Project.fromProjectArn(stack, 'Project', + 'arn:aws:codebuild:us-west-2:123456789012:project/My-Project'); + + expect(project.projectName).toEqual('My-Project'); + expect(project.env.account).toEqual('123456789012'); + expect(project.env.region).toEqual('us-west-2'); + }); +}); diff --git a/packages/@aws-cdk/aws-codebuild/test/report-group.test.ts b/packages/@aws-cdk/aws-codebuild/test/report-group.test.ts new file mode 100644 index 0000000000000..4459ef4672f0c --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/test/report-group.test.ts @@ -0,0 +1,146 @@ +import { ABSENT, ResourcePart } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +import * as iam from '@aws-cdk/aws-iam'; +import * as kms from '@aws-cdk/aws-kms'; +import * as s3 from '@aws-cdk/aws-s3'; +import * as cdk from '@aws-cdk/core'; +import * as codebuild from '../lib'; + +/* eslint-disable quote-props */ +/* eslint-disable quotes */ + +describe('Test Reports Groups', () => { + test('get created with type=TEST and exportConfig=NO_EXPORT by default', () => { + const stack = new cdk.Stack(); + + new codebuild.ReportGroup(stack, 'ReportGroup'); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::ReportGroup', { + "Type": "TEST", + "ExportConfig": { + "ExportConfigType": "NO_EXPORT", + "S3Destination": ABSENT, + }, + }); + }); + + test('can be created with name', () => { + const stack = new cdk.Stack(); + + new codebuild.ReportGroup(stack, 'ReportGroup', { + reportGroupName: 'my-report-group', + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::ReportGroup', { + "Name": 'my-report-group', + }); + }); + + test('can be imported by name', () => { + const stack = new cdk.Stack(); + + const reportGroup = codebuild.ReportGroup.fromReportGroupName(stack, + 'ReportGroup', 'my-report-group'); + + const role = new iam.Role(stack, 'Role', { + assumedBy: new iam.AnyPrincipal(), + }); + role.addToPolicy(new iam.PolicyStatement({ + actions: ['codebuild:*'], + resources: [reportGroup.reportGroupArn], + })); + + expect(reportGroup.reportGroupName).toEqual('my-report-group'); + expect(stack).toHaveResourceLike('AWS::IAM::Policy', { + "PolicyDocument": { + "Statement": [ + { + "Action": "codebuild:*", + "Resource": { + "Fn::Join": ["", [ + "arn:", + { "Ref": "AWS::Partition" }, + ":codebuild:", + { "Ref": "AWS::Region" }, + ":", + { "Ref": "AWS::AccountId" }, + ":report-group/my-report-group", + ]], + }, + }, + ], + }, + }); + }); + + test('specify exportConfig=S3 when providing an exportBucket', () => { + const stack = new cdk.Stack(); + + new codebuild.ReportGroup(stack, 'ReportGroup', { + exportBucket: s3.Bucket.fromBucketName(stack, 'Bucket', 'my-bucket'), + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::ReportGroup', { + "Type": "TEST", + "ExportConfig": { + "ExportConfigType": "S3", + "S3Destination": { + "Bucket": "my-bucket", + "EncryptionKey": ABSENT, + "EncryptionDisabled": ABSENT, + "Packaging": ABSENT, + }, + }, + }); + }); + + test('specify encryptionKey in ExportConfig.S3Destination if exportBucket has a Key', () => { + const stack = new cdk.Stack(); + + new codebuild.ReportGroup(stack, 'ReportGroup', { + exportBucket: s3.Bucket.fromBucketAttributes(stack, 'Bucket', { + bucketName: 'my-bucket', + encryptionKey: kms.Key.fromKeyArn(stack, 'Key', + 'arn:aws:kms:us-east-1:123456789012:key/my-key'), + }), + zipExport: true, + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::ReportGroup', { + "Type": "TEST", + "ExportConfig": { + "ExportConfigType": "S3", + "S3Destination": { + "Bucket": "my-bucket", + "EncryptionDisabled": false, + "EncryptionKey": "arn:aws:kms:us-east-1:123456789012:key/my-key", + "Packaging": "ZIP", + }, + }, + }); + }); + + test('get created with RemovalPolicy.RETAIN by default', () => { + const stack = new cdk.Stack(); + + new codebuild.ReportGroup(stack, 'ReportGroup'); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::ReportGroup', { + "DeletionPolicy": "Retain", + "UpdateReplacePolicy": "Retain", + }, ResourcePart.CompleteDefinition); + }); + + test('can be created with RemovalPolicy.DESTROY', () => { + const stack = new cdk.Stack(); + + new codebuild.ReportGroup(stack, 'ReportGroup', { + removalPolicy: cdk.RemovalPolicy.DESTROY, + }); + + expect(stack).toHaveResourceLike('AWS::CodeBuild::ReportGroup', { + "DeletionPolicy": "Delete", + "UpdateReplacePolicy": "Delete", + }, ResourcePart.CompleteDefinition); + }); +}); diff --git a/packages/@aws-cdk/aws-codebuild/test/test.build-spec.ts b/packages/@aws-cdk/aws-codebuild/test/test.build-spec.ts deleted file mode 100644 index ad625d39c2087..0000000000000 --- a/packages/@aws-cdk/aws-codebuild/test/test.build-spec.ts +++ /dev/null @@ -1,421 +0,0 @@ -// import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; -import * as codebuild from '../lib'; - -/* eslint-disable quote-props */ -/* eslint-disable quotes */ - -export = { - 'Test BuildSpec merge': { - 'merge two simple specs'(test: Test) { - const lhs = codebuild.BuildSpec.fromObject({ - phases: { - pre_build: { - commands: [ - 'install', - ], - }, - }, - }); - const rhs = codebuild.BuildSpec.fromObject({ - phases: { - build: { - commands: 'build', - }, - }, - }); - - const merged = codebuild.mergeBuildSpecs(lhs, rhs); - - test.deepEqual((merged as any).spec, { - phases: { - pre_build: { - commands: [ - 'install', - ], - }, - build: { - commands: [ - 'build', - ], - }, - }, - }); - - test.done(); - }, - - 'merge command lists'(test: Test) { - const lhs = codebuild.BuildSpec.fromObject({ - phases: { - build: { - commands: [ - 'build1', - ], - }, - }, - }); - const rhs = codebuild.BuildSpec.fromObject({ - phases: { - build: { - commands: 'build2', - }, - }, - }); - - const merged = codebuild.mergeBuildSpecs(lhs, rhs); - - test.deepEqual((merged as any).spec, { - phases: { - build: { - commands: [ - 'build1', - 'build2', - ], - }, - }, - }); - - test.done(); - }, - - 'do not merge artifacts'(test: Test) { - const lhs = codebuild.BuildSpec.fromObject({ - phases: { - build: { - commands: [ - 'build1', - ], - }, - }, - artifacts: { - 'base-directory': 'subdir/cdk.out', - }, - }); - const rhs = codebuild.BuildSpec.fromObject({ - phases: { - build: { - commands: [ - 'build2', - ], - }, - }, - artifacts: { - 'base-directory': 'subdir/cdk.out', - }, - }); - - test.throws(() => { - codebuild.mergeBuildSpecs(lhs, rhs); - }); - test.done(); - }, - - 'merge complex example'(test: Test) { - const cdkSpec = codebuild.BuildSpec.fromObject({ - env: { - 'variables': { - NPM_TOKEN: 'supersecret', - }, - }, - phases: { - pre_build: { - commands: [ - 'install1', - ], - }, - build: { - commands: [ - 'build1', - 'test1', - 'cdk synth', - ], - }, - }, - }); - const userSpec = codebuild.BuildSpec.fromObject({ - version: 0.2, - env: { - 'variables': { - JAVA_HOME: '/usr/lib/jvm/java-8-openjdk-amd64', - }, - 'parameter-store': { - LOGIN_PASSWORD: '/CodeBuild/dockerLoginPassword', - }, - }, - phases: { - install: { - commands: [ - 'echo Entered the install phase...', - 'apt-get update -y', - 'apt-get install -y maven', - ], - finally: [ - 'echo This always runs even if the update or install command fails', - ], - }, - pre_build: { - commands: [ - 'echo Entered the pre_build phase...', - 'docker login -u User -p $LOGIN_PASSWORD', - ], - finally: [ - 'echo This always runs even if the login command fails', - ], - }, - build: { - commands: [ - 'echo Entered the build phase...', - 'echo Build started on `date`', - 'mvn install', - ], - finally: [ - 'echo This always runs even if the install command fails', - ], - }, - post_build: { - commands: [ - 'echo Entered the post_build phase...', - 'echo Build completed on `date`', - ], - }, - }, - reports: { - 'arn:aws:codebuild:your-region:your-aws-account-id:report-group/report-group-name-1': { - 'files': [ - '**/*', - ], - 'base-directory': 'target/tests/reports', - 'discard-paths': 'no', - }, - 'reportGroupCucumberJson': { - 'files': [ - 'cucumber/target/cucumber-tests.xml', - ], - 'discard-paths': 'yes', - 'file-format': 'CUCUMBERJSON', - }, - }, - artifacts: { - 'files': [ - 'target/messageUtil-1.0.jar', - ], - 'discard-paths': 'yes', - 'secondary-artifacts': { - artifact1: { - 'files': [ - 'target/artifact-1.0.jar', - ], - 'discard-paths': 'yes', - }, - artifact2: { - 'files': [ - 'target/artifact-2.0.jar', - ], - 'discard-paths': 'yes', - }, - }, - }, - cache: { - paths: [ - '/root/.m2/**/*', - ], - }, - }); - - const merged = codebuild.mergeBuildSpecs(userSpec, cdkSpec); - - test.deepEqual((merged as any).spec, { - version: 0.2, - env: { - 'variables': { - JAVA_HOME: '/usr/lib/jvm/java-8-openjdk-amd64', - NPM_TOKEN: 'supersecret', - }, - 'parameter-store': { - LOGIN_PASSWORD: '/CodeBuild/dockerLoginPassword', - }, - }, - phases: { - install: { - commands: [ - 'echo Entered the install phase...', - 'apt-get update -y', - 'apt-get install -y maven', - ], - finally: [ - 'echo This always runs even if the update or install command fails', - ], - }, - pre_build: { - commands: [ - 'echo Entered the pre_build phase...', - 'docker login -u User -p $LOGIN_PASSWORD', - 'install1', - ], - finally: [ - 'echo This always runs even if the login command fails', - ], - }, - build: { - commands: [ - 'echo Entered the build phase...', - 'echo Build started on `date`', - 'mvn install', - 'build1', - 'test1', - 'cdk synth', - ], - finally: [ - 'echo This always runs even if the install command fails', - ], - }, - post_build: { - commands: [ - 'echo Entered the post_build phase...', - 'echo Build completed on `date`', - ], - }, - }, - reports: { - 'arn:aws:codebuild:your-region:your-aws-account-id:report-group/report-group-name-1': { - 'files': [ - '**/*', - ], - 'base-directory': 'target/tests/reports', - 'discard-paths': 'no', - }, - 'reportGroupCucumberJson': { - 'files': [ - 'cucumber/target/cucumber-tests.xml', - ], - 'discard-paths': 'yes', - 'file-format': 'CUCUMBERJSON', - }, - }, - artifacts: { - 'files': [ - 'target/messageUtil-1.0.jar', - ], - 'discard-paths': 'yes', - 'secondary-artifacts': { - artifact1: { - 'files': [ - 'target/artifact-1.0.jar', - ], - 'discard-paths': 'yes', - }, - artifact2: { - 'files': [ - 'target/artifact-2.0.jar', - ], - 'discard-paths': 'yes', - }, - }, - }, - cache: { - paths: [ - '/root/.m2/**/*', - ], - }, - }); - - test.done(); - }, - - 'override duplicate reports'(test: Test) { - const lhs = codebuild.BuildSpec.fromObject({ - phases: { - pre_build: { - commands: [ - 'install', - ], - }, - }, - reports: { - 'report1': { - 'files': [ - 'report1/a', - ], - 'discard-paths': 'no', - 'base-directory': 'target/tests/reports', - }, - 'report2': { - 'files': [ - 'cucumber/target/cucumber-tests.xml', - ], - 'discard-paths': 'yes', - 'file-format': 'CUCUMBERJSON', - }, - }, - }); - const rhs = codebuild.BuildSpec.fromObject({ - phases: { - build: { - commands: [ - 'build', - ], - }, - }, - reports: { - 'report1': { - 'files': [ - 'report1/b', - 'report1/b2', - ], - 'base-directory': 'target/tests/reportsB', - }, - 'report3': { - 'files': [ - 'cucumber/target/cucumber-tests.xml', - ], - 'discard-paths': 'yes', - 'file-format': 'CUCUMBERJSON', - }, - }, - }); - - const merged = codebuild.mergeBuildSpecs(lhs, rhs); - - test.deepEqual((merged as any).spec, { - phases: { - pre_build: { - commands: [ - 'install', - ], - }, - build: { - commands: [ - 'build', - ], - }, - }, - reports: { - 'report1': { - 'files': [ - 'report1/b', - 'report1/b2', - ], - 'base-directory': 'target/tests/reportsB', - }, - 'report2': { - 'files': [ - 'cucumber/target/cucumber-tests.xml', - ], - 'discard-paths': 'yes', - 'file-format': 'CUCUMBERJSON', - }, - 'report3': { - 'files': [ - 'cucumber/target/cucumber-tests.xml', - ], - 'discard-paths': 'yes', - 'file-format': 'CUCUMBERJSON', - }, - }, - }); - - test.done(); - }, - }, -}; diff --git a/packages/@aws-cdk/aws-codebuild/test/test.codebuild.ts b/packages/@aws-cdk/aws-codebuild/test/test.codebuild.ts deleted file mode 100644 index b287b7de0b2b2..0000000000000 --- a/packages/@aws-cdk/aws-codebuild/test/test.codebuild.ts +++ /dev/null @@ -1,1972 +0,0 @@ -import { ABSENT, expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; -import * as codecommit from '@aws-cdk/aws-codecommit'; -import * as ec2 from '@aws-cdk/aws-ec2'; -import * as kms from '@aws-cdk/aws-kms'; -import * as s3 from '@aws-cdk/aws-s3'; -import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; -import * as codebuild from '../lib'; -import { CodePipelineSource } from '../lib/codepipeline-source'; -import { NoSource } from '../lib/no-source'; - -/* eslint-disable quote-props */ - -export = { - 'default properties': { - 'with CodePipeline source'(test: Test) { - const stack = new cdk.Stack(); - - new codebuild.PipelineProject(stack, 'MyProject'); - - expect(stack).toMatch({ - 'Resources': { - 'MyProjectRole9BBE5233': { - 'Type': 'AWS::IAM::Role', - 'Properties': { - 'AssumeRolePolicyDocument': { - 'Statement': [ - { - 'Action': 'sts:AssumeRole', - 'Effect': 'Allow', - 'Principal': { - 'Service': 'codebuild.amazonaws.com', - }, - }, - ], - 'Version': '2012-10-17', - }, - }, - }, - 'MyProjectRoleDefaultPolicyB19B7C29': { - 'Type': 'AWS::IAM::Policy', - 'Properties': { - 'PolicyDocument': { - 'Statement': [ - { - 'Action': [ - 'logs:CreateLogGroup', - 'logs:CreateLogStream', - 'logs:PutLogEvents', - ], - 'Effect': 'Allow', - 'Resource': [ - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - 'Ref': 'AWS::Partition', - }, - ':logs:', - { - 'Ref': 'AWS::Region', - }, - ':', - { - 'Ref': 'AWS::AccountId', - }, - ':log-group:/aws/codebuild/', - { - 'Ref': 'MyProject39F7B0AE', - }, - ], - ], - }, - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - 'Ref': 'AWS::Partition', - }, - ':logs:', - { - 'Ref': 'AWS::Region', - }, - ':', - { - 'Ref': 'AWS::AccountId', - }, - ':log-group:/aws/codebuild/', - { - 'Ref': 'MyProject39F7B0AE', - }, - ':*', - ], - ], - }, - ], - }, - { - 'Action': [ - 'codebuild:CreateReportGroup', - 'codebuild:CreateReport', - 'codebuild:UpdateReport', - 'codebuild:BatchPutTestCases', - 'codebuild:BatchPutCodeCoverages', - ], - 'Effect': 'Allow', - 'Resource': { - 'Fn::Join': ['', [ - 'arn:', - { 'Ref': 'AWS::Partition' }, - ':codebuild:', - { 'Ref': 'AWS::Region' }, - ':', - { 'Ref': 'AWS::AccountId' }, - ':report-group/', - { 'Ref': 'MyProject39F7B0AE' }, - '-*', - ]], - }, - }, - ], - 'Version': '2012-10-17', - }, - 'PolicyName': 'MyProjectRoleDefaultPolicyB19B7C29', - 'Roles': [ - { - 'Ref': 'MyProjectRole9BBE5233', - }, - ], - }, - }, - 'MyProject39F7B0AE': { - 'Type': 'AWS::CodeBuild::Project', - 'Properties': { - 'Source': { - 'Type': 'CODEPIPELINE', - }, - 'Artifacts': { - 'Type': 'CODEPIPELINE', - }, - 'ServiceRole': { - 'Fn::GetAtt': [ - 'MyProjectRole9BBE5233', - 'Arn', - ], - }, - 'Environment': { - 'Type': 'LINUX_CONTAINER', - 'PrivilegedMode': false, - 'Image': 'aws/codebuild/standard:1.0', - 'ImagePullCredentialsType': 'CODEBUILD', - 'ComputeType': 'BUILD_GENERAL1_SMALL', - }, - 'EncryptionKey': 'alias/aws/s3', - }, - }, - }, - }); - - test.done(); - }, - 'with CodeCommit source'(test: Test) { - const stack = new cdk.Stack(); - - const repo = new codecommit.Repository(stack, 'MyRepo', { - repositoryName: 'hello-cdk', - }); - - const source = codebuild.Source.codeCommit({ repository: repo, cloneDepth: 2 }); - - new codebuild.Project(stack, 'MyProject', { - source, - }); - - expect(stack).toMatch({ - 'Resources': { - 'MyRepoF4F48043': { - 'Type': 'AWS::CodeCommit::Repository', - 'Properties': { - 'RepositoryName': 'hello-cdk', - }, - }, - 'MyProjectRole9BBE5233': { - 'Type': 'AWS::IAM::Role', - 'Properties': { - 'AssumeRolePolicyDocument': { - 'Statement': [ - { - 'Action': 'sts:AssumeRole', - 'Effect': 'Allow', - 'Principal': { - 'Service': 'codebuild.amazonaws.com', - }, - }, - ], - 'Version': '2012-10-17', - }, - }, - }, - 'MyProjectRoleDefaultPolicyB19B7C29': { - 'Type': 'AWS::IAM::Policy', - 'Properties': { - 'PolicyDocument': { - 'Statement': [ - { - 'Action': 'codecommit:GitPull', - 'Effect': 'Allow', - 'Resource': { - 'Fn::GetAtt': [ - 'MyRepoF4F48043', - 'Arn', - ], - }, - }, - { - 'Action': [ - 'logs:CreateLogGroup', - 'logs:CreateLogStream', - 'logs:PutLogEvents', - ], - 'Effect': 'Allow', - 'Resource': [ - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - 'Ref': 'AWS::Partition', - }, - ':logs:', - { - 'Ref': 'AWS::Region', - }, - ':', - { - 'Ref': 'AWS::AccountId', - }, - ':log-group:/aws/codebuild/', - { - 'Ref': 'MyProject39F7B0AE', - }, - ], - ], - }, - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - 'Ref': 'AWS::Partition', - }, - ':logs:', - { - 'Ref': 'AWS::Region', - }, - ':', - { - 'Ref': 'AWS::AccountId', - }, - ':log-group:/aws/codebuild/', - { - 'Ref': 'MyProject39F7B0AE', - }, - ':*', - ], - ], - }, - ], - }, - { - 'Action': [ - 'codebuild:CreateReportGroup', - 'codebuild:CreateReport', - 'codebuild:UpdateReport', - 'codebuild:BatchPutTestCases', - 'codebuild:BatchPutCodeCoverages', - ], - 'Effect': 'Allow', - 'Resource': { - 'Fn::Join': ['', [ - 'arn:', - { 'Ref': 'AWS::Partition' }, - ':codebuild:', - { 'Ref': 'AWS::Region' }, - ':', - { 'Ref': 'AWS::AccountId' }, - ':report-group/', - { 'Ref': 'MyProject39F7B0AE' }, - '-*', - ]], - }, - }, - ], - 'Version': '2012-10-17', - }, - 'PolicyName': 'MyProjectRoleDefaultPolicyB19B7C29', - 'Roles': [ - { - 'Ref': 'MyProjectRole9BBE5233', - }, - ], - }, - }, - 'MyProject39F7B0AE': { - 'Type': 'AWS::CodeBuild::Project', - 'Properties': { - 'Artifacts': { - 'Type': 'NO_ARTIFACTS', - }, - 'Environment': { - 'ComputeType': 'BUILD_GENERAL1_SMALL', - 'Image': 'aws/codebuild/standard:1.0', - 'ImagePullCredentialsType': 'CODEBUILD', - 'PrivilegedMode': false, - 'Type': 'LINUX_CONTAINER', - }, - 'ServiceRole': { - 'Fn::GetAtt': [ - 'MyProjectRole9BBE5233', - 'Arn', - ], - }, - 'Source': { - 'Location': { - 'Fn::GetAtt': [ - 'MyRepoF4F48043', - 'CloneUrlHttp', - ], - }, - 'GitCloneDepth': 2, - 'Type': 'CODECOMMIT', - }, - 'EncryptionKey': 'alias/aws/s3', - }, - }, - }, - }); - test.done(); - }, - 'with S3Bucket source'(test: Test) { - const stack = new cdk.Stack(); - const bucket = new s3.Bucket(stack, 'MyBucket'); - - new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.s3({ - bucket, - path: 'path/to/source.zip', - }), - environment: { - buildImage: codebuild.WindowsBuildImage.WINDOWS_BASE_2_0, - }, - }); - - expect(stack).toMatch({ - 'Resources': { - 'MyBucketF68F3FF0': { - 'Type': 'AWS::S3::Bucket', - 'DeletionPolicy': 'Retain', - 'UpdateReplacePolicy': 'Retain', - }, - 'MyProjectRole9BBE5233': { - 'Type': 'AWS::IAM::Role', - 'Properties': { - 'AssumeRolePolicyDocument': { - 'Statement': [ - { - 'Action': 'sts:AssumeRole', - 'Effect': 'Allow', - 'Principal': { - 'Service': 'codebuild.amazonaws.com', - }, - }, - ], - 'Version': '2012-10-17', - }, - }, - }, - 'MyProjectRoleDefaultPolicyB19B7C29': { - 'Type': 'AWS::IAM::Policy', - 'Properties': { - 'PolicyDocument': { - 'Statement': [ - { - 'Action': [ - 's3:GetObject*', - 's3:GetBucket*', - 's3:List*', - ], - 'Effect': 'Allow', - 'Resource': [ - { - 'Fn::GetAtt': [ - 'MyBucketF68F3FF0', - 'Arn', - ], - }, - { - 'Fn::Join': [ - '', - [ - { - 'Fn::GetAtt': [ - 'MyBucketF68F3FF0', - 'Arn', - ], - }, - '/path/to/source.zip', - ], - ], - }, - ], - }, - { - 'Action': [ - 'logs:CreateLogGroup', - 'logs:CreateLogStream', - 'logs:PutLogEvents', - ], - 'Effect': 'Allow', - 'Resource': [ - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - 'Ref': 'AWS::Partition', - }, - ':logs:', - { - 'Ref': 'AWS::Region', - }, - ':', - { - 'Ref': 'AWS::AccountId', - }, - ':log-group:/aws/codebuild/', - { - 'Ref': 'MyProject39F7B0AE', - }, - ], - ], - }, - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - 'Ref': 'AWS::Partition', - }, - ':logs:', - { - 'Ref': 'AWS::Region', - }, - ':', - { - 'Ref': 'AWS::AccountId', - }, - ':log-group:/aws/codebuild/', - { - 'Ref': 'MyProject39F7B0AE', - }, - ':*', - ], - ], - }, - ], - }, - { - 'Action': [ - 'codebuild:CreateReportGroup', - 'codebuild:CreateReport', - 'codebuild:UpdateReport', - 'codebuild:BatchPutTestCases', - 'codebuild:BatchPutCodeCoverages', - ], - 'Effect': 'Allow', - 'Resource': { - 'Fn::Join': ['', [ - 'arn:', - { 'Ref': 'AWS::Partition' }, - ':codebuild:', - { 'Ref': 'AWS::Region' }, - ':', - { 'Ref': 'AWS::AccountId' }, - ':report-group/', - { 'Ref': 'MyProject39F7B0AE' }, - '-*', - ]], - }, - }, - ], - 'Version': '2012-10-17', - }, - 'PolicyName': 'MyProjectRoleDefaultPolicyB19B7C29', - 'Roles': [ - { - 'Ref': 'MyProjectRole9BBE5233', - }, - ], - }, - }, - 'MyProject39F7B0AE': { - 'Type': 'AWS::CodeBuild::Project', - 'Properties': { - 'Artifacts': { - 'Type': 'NO_ARTIFACTS', - }, - 'Environment': { - 'ComputeType': 'BUILD_GENERAL1_MEDIUM', - 'Image': 'aws/codebuild/windows-base:2.0', - 'ImagePullCredentialsType': 'CODEBUILD', - 'PrivilegedMode': false, - 'Type': 'WINDOWS_CONTAINER', - }, - 'ServiceRole': { - 'Fn::GetAtt': [ - 'MyProjectRole9BBE5233', - 'Arn', - ], - }, - 'Source': { - 'Location': { - 'Fn::Join': [ - '', - [ - { - 'Ref': 'MyBucketF68F3FF0', - }, - '/path/to/source.zip', - ], - ], - }, - 'Type': 'S3', - }, - 'EncryptionKey': 'alias/aws/s3', - }, - }, - }, - }); - test.done(); - }, - 'with GitHub source'(test: Test) { - const stack = new cdk.Stack(); - - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHub({ - owner: 'testowner', - repo: 'testrepo', - cloneDepth: 3, - fetchSubmodules: true, - webhook: true, - reportBuildStatus: false, - webhookFilters: [ - codebuild.FilterGroup.inEventOf(codebuild.EventAction.PUSH).andTagIsNot('stable'), - codebuild.FilterGroup.inEventOf(codebuild.EventAction.PULL_REQUEST_REOPENED).andBaseBranchIs('master'), - ], - }), - }); - - expect(stack).to(haveResource('AWS::CodeBuild::Project', { - Source: { - Type: 'GITHUB', - Location: 'https://github.com/testowner/testrepo.git', - ReportBuildStatus: false, - GitCloneDepth: 3, - GitSubmodulesConfig: { - FetchSubmodules: true, - }, - }, - })); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Triggers: { - Webhook: true, - FilterGroups: [ - [ - { Type: 'EVENT', Pattern: 'PUSH' }, - { Type: 'HEAD_REF', Pattern: 'refs/tags/stable', ExcludeMatchedPattern: true }, - ], - [ - { Type: 'EVENT', Pattern: 'PULL_REQUEST_REOPENED' }, - { Type: 'BASE_REF', Pattern: 'refs/heads/master' }, - ], - ], - }, - })); - - test.done(); - }, - 'with GitHubEnterprise source'(test: Test) { - const stack = new cdk.Stack(); - - const pushFilterGroup = codebuild.FilterGroup.inEventOf(codebuild.EventAction.PUSH); - new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.gitHubEnterprise({ - httpsCloneUrl: 'https://github.testcompany.com/testowner/testrepo', - ignoreSslErrors: true, - cloneDepth: 4, - webhook: true, - reportBuildStatus: false, - webhookFilters: [ - pushFilterGroup.andBranchIs('master'), - pushFilterGroup.andBranchIs('develop'), - pushFilterGroup.andFilePathIs('ReadMe.md'), - ], - }), - }); - - expect(stack).to(haveResource('AWS::CodeBuild::Project', { - Source: { - Type: 'GITHUB_ENTERPRISE', - InsecureSsl: true, - GitCloneDepth: 4, - ReportBuildStatus: false, - Location: 'https://github.testcompany.com/testowner/testrepo', - }, - })); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Triggers: { - Webhook: true, - FilterGroups: [ - [ - { Type: 'EVENT', Pattern: 'PUSH' }, - { Type: 'HEAD_REF', Pattern: 'refs/heads/master' }, - ], - [ - { Type: 'EVENT', Pattern: 'PUSH' }, - { Type: 'HEAD_REF', Pattern: 'refs/heads/develop' }, - ], - [ - { Type: 'EVENT', Pattern: 'PUSH' }, - { Type: 'FILE_PATH', Pattern: 'ReadMe.md' }, - ], - ], - }, - })); - - test.done(); - }, - 'with Bitbucket source'(test: Test) { - const stack = new cdk.Stack(); - - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.bitBucket({ - owner: 'testowner', - repo: 'testrepo', - cloneDepth: 5, - reportBuildStatus: false, - webhookFilters: [ - codebuild.FilterGroup.inEventOf( - codebuild.EventAction.PULL_REQUEST_CREATED, - codebuild.EventAction.PULL_REQUEST_UPDATED, - codebuild.EventAction.PULL_REQUEST_MERGED, - ).andTagIs('v.*'), - // duplicate event actions are fine - codebuild.FilterGroup.inEventOf(codebuild.EventAction.PUSH, codebuild.EventAction.PUSH).andActorAccountIsNot('aws-cdk-dev'), - ], - }), - }); - - expect(stack).to(haveResource('AWS::CodeBuild::Project', { - Source: { - Type: 'BITBUCKET', - Location: 'https://bitbucket.org/testowner/testrepo.git', - GitCloneDepth: 5, - ReportBuildStatus: false, - }, - })); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Triggers: { - Webhook: true, - FilterGroups: [ - [ - { Type: 'EVENT', Pattern: 'PULL_REQUEST_CREATED, PULL_REQUEST_UPDATED, PULL_REQUEST_MERGED' }, - { Type: 'HEAD_REF', Pattern: 'refs/tags/v.*' }, - ], - [ - { Type: 'EVENT', Pattern: 'PUSH' }, - { Type: 'ACTOR_ACCOUNT_ID', Pattern: 'aws-cdk-dev', ExcludeMatchedPattern: true }, - ], - ], - }, - })); - - test.done(); - }, - - 'with webhookTriggersBatchBuild option'(test: Test) { - const stack = new cdk.Stack(); - - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHub({ - owner: 'testowner', - repo: 'testrepo', - webhook: true, - webhookTriggersBatchBuild: true, - }), - }); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Triggers: { - Webhook: true, - BuildType: 'BUILD_BATCH', - }, - BuildBatchConfig: { - ServiceRole: { - 'Fn::GetAtt': [ - 'ProjectBatchServiceRoleF97A1CFB', - 'Arn', - ], - }, - }, - })); - - expect(stack).to(haveResourceLike('AWS::IAM::Role', { - AssumeRolePolicyDocument: { - Statement: [ - { - Action: 'sts:AssumeRole', - Effect: 'Allow', - Principal: { - Service: 'codebuild.amazonaws.com', - }, - }, - ], - Version: '2012-10-17', - }, - })); - - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - PolicyDocument: { - Statement: [ - { - Action: [ - 'codebuild:StartBuild', - 'codebuild:StopBuild', - 'codebuild:RetryBuild', - ], - Effect: 'Allow', - Resource: { - 'Fn::GetAtt': [ - 'ProjectC78D97AD', - 'Arn', - ], - }, - }, - ], - Version: '2012-10-17', - }, - })); - - test.done(); - }, - - 'fail creating a Project when webhook false and webhookTriggersBatchBuild option'(test: Test) { - [false, undefined].forEach((webhook) => { - const stack = new cdk.Stack(); - - test.throws(() => { - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHub({ - owner: 'testowner', - repo: 'testrepo', - webhook, - webhookTriggersBatchBuild: true, - }), - }); - }, /`webhookTriggersBatchBuild` cannot be used when `webhook` is `false`/); - }); - - test.done(); - }, - - 'fail creating a Project when no build spec is given'(test: Test) { - const stack = new cdk.Stack(); - - test.throws(() => { - new codebuild.Project(stack, 'MyProject', { - }); - }, /buildSpec/); - - test.done(); - }, - 'with VPC configuration'(test: Test) { - const stack = new cdk.Stack(); - - const bucket = new s3.Bucket(stack, 'MyBucket'); - const vpc = new ec2.Vpc(stack, 'MyVPC'); - const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup1', { - securityGroupName: 'Bob', - vpc, - allowAllOutbound: true, - description: 'Example', - }); - const project = new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.s3({ - bucket, - path: 'path/to/source.zip', - }), - vpc, - securityGroups: [securityGroup], - }); - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'VpcConfig': { - 'SecurityGroupIds': [ - { - 'Fn::GetAtt': [ - 'SecurityGroup1F554B36F', - 'GroupId', - ], - }, - ], - 'Subnets': [ - { - 'Ref': 'MyVPCPrivateSubnet1Subnet641543F4', - }, - { - 'Ref': 'MyVPCPrivateSubnet2SubnetA420D3F0', - }, - ], - 'VpcId': { - 'Ref': 'MyVPCAFB07A31', - }, - }, - })); - - test.notEqual(project.connections, undefined); - - test.done(); - }, - 'without VPC configuration but security group identified'(test: Test) { - const stack = new cdk.Stack(); - - const bucket = new s3.Bucket(stack, 'MyBucket'); - const vpc = new ec2.Vpc(stack, 'MyVPC'); - const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup1', { - securityGroupName: 'Bob', - vpc, - allowAllOutbound: true, - description: 'Example', - }); - - test.throws(() => - new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.s3({ - bucket, - path: 'path/to/source.zip', - }), - securityGroups: [securityGroup], - }) - , /Cannot configure 'securityGroup' or 'allowAllOutbound' without configuring a VPC/); - test.done(); - }, - 'with VPC configuration but allowAllOutbound identified'(test: Test) { - const stack = new cdk.Stack(); - const bucket = new s3.Bucket(stack, 'MyBucket'); - const vpc = new ec2.Vpc(stack, 'MyVPC'); - const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup1', { - securityGroupName: 'Bob', - vpc, - allowAllOutbound: true, - description: 'Example', - }); - test.throws(() => - new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.s3({ - bucket, - path: 'path/to/source.zip', - }), - vpc, - allowAllOutbound: true, - securityGroups: [securityGroup], - }) - , /Configure 'allowAllOutbound' directly on the supplied SecurityGroup/); - test.done(); - }, - - 'without passing a VPC cannot access the connections property'(test: Test) { - const stack = new cdk.Stack(); - - const project = new codebuild.PipelineProject(stack, 'MyProject'); - - test.throws(() => project.connections, - /Only VPC-associated Projects have security groups to manage. Supply the "vpc" parameter when creating the Project/); - - test.done(); - }, - - 'no KMS Key defaults to default S3 managed key'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.PipelineProject(stack, 'MyProject'); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - EncryptionKey: 'alias/aws/s3', - })); - - test.done(); - }, - - 'with a KMS Key adds decrypt permissions to the CodeBuild Role'(test: Test) { - const stack = new cdk.Stack(); - - const key = new kms.Key(stack, 'MyKey'); - - new codebuild.PipelineProject(stack, 'MyProject', { - encryptionKey: key, - grantReportGroupPermissions: false, - }); - - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': [ - {}, // CloudWatch logs - { - 'Action': [ - 'kms:Decrypt', - 'kms:Encrypt', - 'kms:ReEncrypt*', - 'kms:GenerateDataKey*', - ], - 'Effect': 'Allow', - 'Resource': { - 'Fn::GetAtt': [ - 'MyKey6AB29FA6', - 'Arn', - ], - }, - }, - ], - }, - 'Roles': [ - { - 'Ref': 'MyProjectRole9BBE5233', - }, - ], - })); - - test.done(); - }, - }, - - 'using timeout and path in S3 artifacts sets it correctly'(test: Test) { - const stack = new cdk.Stack(); - const bucket = new s3.Bucket(stack, 'Bucket'); - new codebuild.Project(stack, 'Project', { - buildSpec: codebuild.BuildSpec.fromObject({ - version: '0.2', - }), - artifacts: codebuild.Artifacts.s3({ - path: 'some/path', - name: 'some_name', - bucket, - }), - timeout: cdk.Duration.minutes(123), - }); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Artifacts': { - 'Path': 'some/path', - 'Name': 'some_name', - 'Type': 'S3', - }, - 'TimeoutInMinutes': 123, - })); - - test.done(); - }, - - 'secondary sources': { - 'require providing an identifier when creating a Project'(test: Test) { - const stack = new cdk.Stack(); - - test.throws(() => { - new codebuild.Project(stack, 'MyProject', { - buildSpec: codebuild.BuildSpec.fromObject({ - version: '0.2', - }), - secondarySources: [ - codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'MyBucket'), - path: 'path', - }), - ], - }); - }, /identifier/); - - test.done(); - }, - - 'are not allowed for a Project with CodePipeline as Source'(test: Test) { - const stack = new cdk.Stack(); - const project = new codebuild.PipelineProject(stack, 'MyProject'); - - project.addSecondarySource(codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'MyBucket'), - path: 'some/path', - identifier: 'id', - })); - - test.throws(() => { - expect(stack); - }, /secondary sources/); - - test.done(); - }, - - 'added with an identifer after the Project has been created are rendered in the template'(test: Test) { - const stack = new cdk.Stack(); - const bucket = new s3.Bucket(stack, 'MyBucket'); - const project = new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.s3({ - bucket, - path: 'some/path', - }), - }); - - project.addSecondarySource(codebuild.Source.s3({ - bucket, - path: 'another/path', - identifier: 'source1', - })); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'SecondarySources': [ - { - 'SourceIdentifier': 'source1', - 'Type': 'S3', - }, - ], - })); - - test.done(); - }, - }, - - 'secondary source versions': { - 'allow secondary source versions'(test: Test) { - const stack = new cdk.Stack(); - const bucket = new s3.Bucket(stack, 'MyBucket'); - const project = new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.s3({ - bucket, - path: 'some/path', - }), - }); - - project.addSecondarySource(codebuild.Source.s3({ - bucket, - path: 'another/path', - identifier: 'source1', - version: 'someversion', - })); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'SecondarySources': [ - { - 'SourceIdentifier': 'source1', - 'Type': 'S3', - }, - ], - 'SecondarySourceVersions': [ - { - 'SourceIdentifier': 'source1', - 'SourceVersion': 'someversion', - }, - ], - })); - - test.done(); - }, - - 'allow not to specify secondary source versions'(test: Test) { - const stack = new cdk.Stack(); - const bucket = new s3.Bucket(stack, 'MyBucket'); - const project = new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.s3({ - bucket, - path: 'some/path', - }), - }); - - project.addSecondarySource(codebuild.Source.s3({ - bucket, - path: 'another/path', - identifier: 'source1', - })); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'SecondarySources': [ - { - 'SourceIdentifier': 'source1', - 'Type': 'S3', - }, - ], - })); - - test.done(); - }, - }, - - 'fileSystemLocations': { - 'create fileSystemLocation and validate attributes'(test: Test) { - const stack = new cdk.Stack(); - new codebuild.Project(stack, 'MyProject', { - buildSpec: codebuild.BuildSpec.fromObject({ - version: '0.2', - }), - fileSystemLocations: [codebuild.FileSystemLocation.efs({ - identifier: 'myidentifier2', - location: 'myclodation.mydnsroot.com:/loc', - mountPoint: '/media', - mountOptions: 'opts', - })], - }); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'FileSystemLocations': [ - { - 'Identifier': 'myidentifier2', - 'MountPoint': '/media', - 'MountOptions': 'opts', - 'Location': 'myclodation.mydnsroot.com:/loc', - 'Type': 'EFS', - }, - ], - })); - - test.done(); - }, - 'Multiple fileSystemLocation created'(test: Test) { - const stack = new cdk.Stack(); - const project = new codebuild.Project(stack, 'MyProject', { - buildSpec: codebuild.BuildSpec.fromObject({ - version: '0.2', - }), - }); - project.addFileSystemLocation(codebuild.FileSystemLocation.efs({ - identifier: 'myidentifier3', - location: 'myclodation.mydnsroot.com:/loc', - mountPoint: '/media', - mountOptions: 'opts', - })); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'FileSystemLocations': [ - { - 'Identifier': 'myidentifier3', - 'MountPoint': '/media', - 'MountOptions': 'opts', - 'Location': 'myclodation.mydnsroot.com:/loc', - 'Type': 'EFS', - }, - ], - })); - - test.done(); - }, - }, - - 'secondary artifacts': { - 'require providing an identifier when creating a Project'(test: Test) { - const stack = new cdk.Stack(); - - test.throws(() => { - new codebuild.Project(stack, 'MyProject', { - buildSpec: codebuild.BuildSpec.fromObject({ - version: '0.2', - }), - secondaryArtifacts: [ - codebuild.Artifacts.s3({ - bucket: new s3.Bucket(stack, 'MyBucket'), - path: 'some/path', - name: 'name', - }), - ], - }); - }, /identifier/); - - test.done(); - }, - - 'are not allowed for a Project with CodePipeline as Source'(test: Test) { - const stack = new cdk.Stack(); - const project = new codebuild.PipelineProject(stack, 'MyProject'); - - project.addSecondaryArtifact(codebuild.Artifacts.s3({ - bucket: new s3.Bucket(stack, 'MyBucket'), - path: 'some/path', - name: 'name', - identifier: 'id', - })); - - test.throws(() => { - expect(stack); - }, /secondary artifacts/); - - test.done(); - }, - - 'added with an identifier after the Project has been created are rendered in the template'(test: Test) { - const stack = new cdk.Stack(); - const bucket = new s3.Bucket(stack, 'MyBucket'); - const project = new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.s3({ - bucket, - path: 'some/path', - }), - }); - - project.addSecondaryArtifact(codebuild.Artifacts.s3({ - bucket, - path: 'another/path', - name: 'name', - identifier: 'artifact1', - })); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'SecondaryArtifacts': [ - { - 'ArtifactIdentifier': 'artifact1', - 'Type': 'S3', - }, - ], - })); - - test.done(); - }, - - 'disabledEncryption is set'(test: Test) { - const stack = new cdk.Stack(); - const bucket = new s3.Bucket(stack, 'MyBucket'); - const project = new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.s3({ - bucket, - path: 'some/path', - }), - }); - - project.addSecondaryArtifact(codebuild.Artifacts.s3({ - bucket, - path: 'another/path', - name: 'name', - identifier: 'artifact1', - encryption: false, - })); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'SecondaryArtifacts': [ - { - 'ArtifactIdentifier': 'artifact1', - 'EncryptionDisabled': true, - }, - ], - })); - - test.done(); - }, - }, - - 'artifacts': { - 'CodePipeline': { - 'both source and artifacs are set to CodePipeline'(test: Test) { - const stack = new cdk.Stack(); - - new codebuild.PipelineProject(stack, 'MyProject'); - - expect(stack).to(haveResource('AWS::CodeBuild::Project', { - 'Source': { - 'Type': 'CODEPIPELINE', - }, - 'Artifacts': { - 'Type': 'CODEPIPELINE', - }, - 'ServiceRole': { - 'Fn::GetAtt': [ - 'MyProjectRole9BBE5233', - 'Arn', - ], - }, - 'Environment': { - 'Type': 'LINUX_CONTAINER', - 'PrivilegedMode': false, - 'Image': 'aws/codebuild/standard:1.0', - 'ImagePullCredentialsType': 'CODEBUILD', - 'ComputeType': 'BUILD_GENERAL1_SMALL', - }, - })); - - test.done(); - }, - }, - 'S3': { - 'name is not set so use buildspec'(test: Test) { - const stack = new cdk.Stack(); - const bucket = new s3.Bucket(stack, 'MyBucket'); - new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.s3({ - bucket, - path: 'some/path', - }), - artifacts: codebuild.Artifacts.s3({ - bucket, - path: 'another/path', - identifier: 'artifact1', - }), - }); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Artifacts': { - 'Name': ABSENT, - 'ArtifactIdentifier': 'artifact1', - 'OverrideArtifactName': true, - }, - })); - - test.done(); - }, - 'name is set so use it'(test: Test) { - const stack = new cdk.Stack(); - const bucket = new s3.Bucket(stack, 'MyBucket'); - new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.s3({ - bucket, - path: 'some/path', - }), - artifacts: codebuild.Artifacts.s3({ - bucket, - path: 'another/path', - name: 'specificname', - identifier: 'artifact1', - }), - }); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Artifacts': { - 'ArtifactIdentifier': 'artifact1', - 'Name': 'specificname', - 'OverrideArtifactName': ABSENT, - }, - })); - - test.done(); - }, - }, - }, - - 'events'(test: Test) { - const stack = new cdk.Stack(); - const project = new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'MyBucket'), - path: 'path', - }), - }); - - project.onBuildFailed('OnBuildFailed', { target: { bind: () => ({ arn: 'ARN', id: 'ID' }) } }); - project.onBuildSucceeded('OnBuildSucceeded', { target: { bind: () => ({ arn: 'ARN', id: 'ID' }) } }); - project.onPhaseChange('OnPhaseChange', { target: { bind: () => ({ arn: 'ARN', id: 'ID' }) } }); - project.onStateChange('OnStateChange', { target: { bind: () => ({ arn: 'ARN', id: 'ID' }) } }); - project.onBuildStarted('OnBuildStarted', { target: { bind: () => ({ arn: 'ARN', id: 'ID' }) } }); - - expect(stack).to(haveResource('AWS::Events::Rule', { - 'EventPattern': { - 'source': [ - 'aws.codebuild', - ], - 'detail-type': [ - 'CodeBuild Build State Change', - ], - 'detail': { - 'project-name': [ - { - 'Ref': 'MyProject39F7B0AE', - }, - ], - 'build-status': [ - 'FAILED', - ], - }, - }, - 'State': 'ENABLED', - })); - - expect(stack).to(haveResource('AWS::Events::Rule', { - 'EventPattern': { - 'source': [ - 'aws.codebuild', - ], - 'detail-type': [ - 'CodeBuild Build State Change', - ], - 'detail': { - 'project-name': [ - { - 'Ref': 'MyProject39F7B0AE', - }, - ], - 'build-status': [ - 'SUCCEEDED', - ], - }, - }, - 'State': 'ENABLED', - })); - - expect(stack).to(haveResource('AWS::Events::Rule', { - 'EventPattern': { - 'source': [ - 'aws.codebuild', - ], - 'detail-type': [ - 'CodeBuild Build Phase Change', - ], - 'detail': { - 'project-name': [ - { - 'Ref': 'MyProject39F7B0AE', - }, - ], - }, - }, - 'State': 'ENABLED', - })); - - expect(stack).to(haveResource('AWS::Events::Rule', { - 'EventPattern': { - 'source': [ - 'aws.codebuild', - ], - 'detail-type': [ - 'CodeBuild Build State Change', - ], - 'detail': { - 'project-name': [ - { - 'Ref': 'MyProject39F7B0AE', - }, - ], - }, - }, - 'State': 'ENABLED', - })); - - expect(stack).to(haveResource('AWS::Events::Rule', { - 'EventPattern': { - 'source': [ - 'aws.codebuild', - ], - 'detail-type': [ - 'CodeBuild Build State Change', - ], - 'detail': { - 'project-name': [ - { - 'Ref': 'MyProject39F7B0AE', - }, - ], - 'build-status': [ - 'IN_PROGRESS', - ], - }, - }, - 'State': 'ENABLED', - })); - - test.done(); - }, - - 'environment variables can be overridden at the project level'(test: Test) { - const stack = new cdk.Stack(); - - new codebuild.PipelineProject(stack, 'Project', { - environment: { - environmentVariables: { - FOO: { value: '1234' }, - BAR: { value: `111${cdk.Token.asString({ twotwotwo: '222' })}`, type: codebuild.BuildEnvironmentVariableType.PARAMETER_STORE }, - }, - }, - environmentVariables: { - GOO: { value: 'ABC' }, - FOO: { value: 'OVERRIDE!' }, - }, - }); - - expect(stack).to(haveResource('AWS::CodeBuild::Project', { - 'Source': { - 'Type': 'CODEPIPELINE', - }, - 'Artifacts': { - 'Type': 'CODEPIPELINE', - }, - 'ServiceRole': { - 'Fn::GetAtt': [ - 'ProjectRole4CCB274E', - 'Arn', - ], - }, - 'Environment': { - 'Type': 'LINUX_CONTAINER', - 'EnvironmentVariables': [ - { - 'Type': 'PLAINTEXT', - 'Value': 'OVERRIDE!', - 'Name': 'FOO', - }, - { - 'Type': 'PARAMETER_STORE', - 'Value': { - 'Fn::Join': [ - '', - [ - '111', - { twotwotwo: '222' }, - ], - ], - }, - 'Name': 'BAR', - }, - { - 'Type': 'PLAINTEXT', - 'Value': 'ABC', - 'Name': 'GOO', - }, - ], - 'PrivilegedMode': false, - 'Image': 'aws/codebuild/standard:1.0', - 'ImagePullCredentialsType': 'CODEBUILD', - 'ComputeType': 'BUILD_GENERAL1_SMALL', - }, - })); - - test.done(); - }, - - '.metricXxx() methods can be used to obtain Metrics for CodeBuild projects'(test: Test) { - const stack = new cdk.Stack(); - - const project = new codebuild.Project(stack, 'MyBuildProject', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'MyBucket'), - path: 'path', - }), - }); - - const metricBuilds = project.metricBuilds(); - test.same(metricBuilds.dimensions!.ProjectName, project.projectName); - test.deepEqual(metricBuilds.namespace, 'AWS/CodeBuild'); - test.deepEqual(metricBuilds.statistic, 'Sum', 'default stat is SUM'); - test.deepEqual(metricBuilds.metricName, 'Builds'); - - const metricDuration = project.metricDuration({ label: 'hello' }); - - test.deepEqual(metricDuration.metricName, 'Duration'); - test.deepEqual(metricDuration.label, 'hello'); - - test.deepEqual(project.metricFailedBuilds().metricName, 'FailedBuilds'); - test.deepEqual(project.metricSucceededBuilds().metricName, 'SucceededBuilds'); - - test.done(); - }, - - 'using ComputeType.Small with a Windows image fails validation'(test: Test) { - const stack = new cdk.Stack(); - const invalidEnvironment: codebuild.BuildEnvironment = { - buildImage: codebuild.WindowsBuildImage.WINDOWS_BASE_2_0, - computeType: codebuild.ComputeType.SMALL, - }; - - test.throws(() => { - new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'MyBucket'), - path: 'path', - }), - environment: invalidEnvironment, - }); - }, /Windows images do not support the Small ComputeType/); - - test.done(); - }, - - 'fromCodebuildImage'(test: Test) { - const stack = new cdk.Stack(); - new codebuild.PipelineProject(stack, 'Project', { - environment: { - buildImage: codebuild.LinuxBuildImage.fromCodeBuildImageId('aws/codebuild/standard:4.0'), - }, - }); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'Image': 'aws/codebuild/standard:4.0', - }, - })); - - test.done(); - }, - - 'Windows2019 image': { - 'WIN_SERVER_CORE_2016_BASE': { - 'has type WINDOWS_SERVER_2019_CONTAINER and default ComputeType MEDIUM'(test: Test) { - const stack = new cdk.Stack(); - new codebuild.PipelineProject(stack, 'Project', { - environment: { - buildImage: codebuild.WindowsBuildImage.WIN_SERVER_CORE_2019_BASE, - }, - }); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'Type': 'WINDOWS_SERVER_2019_CONTAINER', - 'ComputeType': 'BUILD_GENERAL1_MEDIUM', - }, - })); - - test.done(); - }, - }, - }, - - 'ARM image': { - 'AMAZON_LINUX_2_ARM': { - 'has type ARM_CONTAINER and default ComputeType LARGE'(test: Test) { - const stack = new cdk.Stack(); - new codebuild.PipelineProject(stack, 'Project', { - environment: { - buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_ARM, - }, - }); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'Type': 'ARM_CONTAINER', - 'ComputeType': 'BUILD_GENERAL1_LARGE', - }, - })); - - test.done(); - }, - - 'cannot be used in conjunction with ComputeType SMALL'(test: Test) { - const stack = new cdk.Stack(); - - test.throws(() => { - new codebuild.PipelineProject(stack, 'Project', { - environment: { - buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_ARM, - computeType: codebuild.ComputeType.SMALL, - }, - }); - }, /ARM images only support ComputeType 'BUILD_GENERAL1_LARGE' - 'BUILD_GENERAL1_SMALL' was given/); - - test.done(); - }, - - 'cannot be used in conjunction with ComputeType MEDIUM'(test: Test) { - const stack = new cdk.Stack(); - - test.throws(() => { - new codebuild.PipelineProject(stack, 'Project', { - environment: { - buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_ARM, - computeType: codebuild.ComputeType.MEDIUM, - }, - }); - }, /ARM images only support ComputeType 'BUILD_GENERAL1_LARGE' - 'BUILD_GENERAL1_MEDIUM' was given/); - - test.done(); - }, - - 'cannot be used in conjunction with ComputeType X2_LARGE'(test: Test) { - const stack = new cdk.Stack(); - - test.throws(() => { - new codebuild.PipelineProject(stack, 'Project', { - environment: { - buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_ARM, - computeType: codebuild.ComputeType.X2_LARGE, - }, - }); - }, /ARM images only support ComputeType 'BUILD_GENERAL1_LARGE' - 'BUILD_GENERAL1_2XLARGE' was given/); - - test.done(); - }, - }, - }, - - 'badge support test'(test: Test) { - const stack = new cdk.Stack(); - - interface BadgeValidationTestCase { - source: codebuild.Source, - allowsBadge: boolean - } - - const repo = new codecommit.Repository(stack, 'MyRepo', { - repositoryName: 'hello-cdk', - }); - const bucket = new s3.Bucket(stack, 'MyBucket'); - - const cases: BadgeValidationTestCase[] = [ - { source: new NoSource(), allowsBadge: false }, - { source: new CodePipelineSource(), allowsBadge: false }, - { source: codebuild.Source.codeCommit({ repository: repo }), allowsBadge: true }, - { source: codebuild.Source.s3({ bucket, path: 'path/to/source.zip' }), allowsBadge: false }, - { source: codebuild.Source.gitHub({ owner: 'awslabs', repo: 'aws-cdk' }), allowsBadge: true }, - { source: codebuild.Source.gitHubEnterprise({ httpsCloneUrl: 'url' }), allowsBadge: true }, - { source: codebuild.Source.bitBucket({ owner: 'awslabs', repo: 'aws-cdk' }), allowsBadge: true }, - ]; - - cases.forEach(testCase => { - const source = testCase.source; - const validationBlock = () => { new codebuild.Project(stack, `MyProject-${source.type}`, { source, badge: true }); }; - if (testCase.allowsBadge) { - test.doesNotThrow(validationBlock); - } else { - test.throws(validationBlock, /Badge is not supported for source type /); - } - }); - - test.done(); - }, - - 'webhook Filters': { - 'a Group cannot be created with an empty set of event actions'(test: Test) { - test.throws(() => { - codebuild.FilterGroup.inEventOf(); - }, /A filter group must contain at least one event action/); - - test.done(); - }, - - 'cannot have base ref conditions if the Group contains the PUSH action'(test: Test) { - const filterGroup = codebuild.FilterGroup.inEventOf(codebuild.EventAction.PULL_REQUEST_CREATED, - codebuild.EventAction.PUSH); - - test.throws(() => { - filterGroup.andBaseRefIs('.*'); - }, /A base reference condition cannot be added if a Group contains a PUSH event action/); - - test.done(); - }, - - 'cannot be used when webhook is false'(test: Test) { - const stack = new cdk.Stack(); - - test.throws(() => { - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.bitBucket({ - owner: 'owner', - repo: 'repo', - webhook: false, - webhookFilters: [ - codebuild.FilterGroup.inEventOf(codebuild.EventAction.PUSH), - ], - }), - }); - }, /`webhookFilters` cannot be used when `webhook` is `false`/); - - test.done(); - }, - - 'can have FILE_PATH filters if the Group contains PUSH and PR_CREATED events'(test: Test) { - codebuild.FilterGroup.inEventOf( - codebuild.EventAction.PULL_REQUEST_CREATED, - codebuild.EventAction.PUSH) - .andFilePathIsNot('.*\\.java'); - - test.done(); - }, - - 'BitBucket sources do not support the PULL_REQUEST_REOPENED event action'(test: Test) { - const stack = new cdk.Stack(); - - test.throws(() => { - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.bitBucket({ - owner: 'owner', - repo: 'repo', - webhookFilters: [ - codebuild.FilterGroup.inEventOf(codebuild.EventAction.PULL_REQUEST_REOPENED), - ], - }), - }); - }, /BitBucket sources do not support the PULL_REQUEST_REOPENED webhook event action/); - - test.done(); - }, - - 'BitBucket sources support file path conditions'(test: Test) { - const stack = new cdk.Stack(); - const filterGroup = codebuild.FilterGroup.inEventOf(codebuild.EventAction.PUSH).andFilePathIs('.*'); - - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.bitBucket({ - owner: 'owner', - repo: 'repo', - webhookFilters: [filterGroup], - }), - }); - - test.done(); - }, - - 'GitHub Enterprise Server sources do not support FILE_PATH filters on PR events'(test: Test) { - const stack = new cdk.Stack(); - const pullFilterGroup = codebuild.FilterGroup.inEventOf( - codebuild.EventAction.PULL_REQUEST_CREATED, - codebuild.EventAction.PULL_REQUEST_MERGED, - codebuild.EventAction.PULL_REQUEST_REOPENED, - codebuild.EventAction.PULL_REQUEST_UPDATED, - ); - - test.throws(() => { - new codebuild.Project(stack, 'MyFilePathProject', { - source: codebuild.Source.gitHubEnterprise({ - httpsCloneUrl: 'https://github.testcompany.com/testowner/testrepo', - webhookFilters: [ - pullFilterGroup.andFilePathIs('ReadMe.md'), - ], - }), - }); - }, /FILE_PATH filters cannot be used with GitHub Enterprise Server pull request events/); - test.done(); - }, - - 'COMMIT_MESSAGE Filter': { - 'GitHub Enterprise Server sources do not support COMMIT_MESSAGE filters on PR events'(test: Test) { - const stack = new cdk.Stack(); - const pullFilterGroup = codebuild.FilterGroup.inEventOf( - codebuild.EventAction.PULL_REQUEST_CREATED, - codebuild.EventAction.PULL_REQUEST_MERGED, - codebuild.EventAction.PULL_REQUEST_REOPENED, - codebuild.EventAction.PULL_REQUEST_UPDATED, - ); - - test.throws(() => { - new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.gitHubEnterprise({ - httpsCloneUrl: 'https://github.testcompany.com/testowner/testrepo', - webhookFilters: [ - pullFilterGroup.andCommitMessageIs('the commit message'), - ], - }), - }); - }, /COMMIT_MESSAGE filters cannot be used with GitHub Enterprise Server pull request events/); - test.done(); - }, - 'GitHub Enterprise Server sources support COMMIT_MESSAGE filters on PUSH events'(test: Test) { - const stack = new cdk.Stack(); - const pushFilterGroup = codebuild.FilterGroup.inEventOf(codebuild.EventAction.PUSH); - - test.doesNotThrow(() => { - new codebuild.Project(stack, 'MyProject', { - source: codebuild.Source.gitHubEnterprise({ - httpsCloneUrl: 'https://github.testcompany.com/testowner/testrepo', - webhookFilters: [ - pushFilterGroup.andCommitMessageIs('the commit message'), - ], - }), - }); - }); - test.done(); - }, - 'BitBucket and GitHub sources support a COMMIT_MESSAGE filter'(test: Test) { - const stack = new cdk.Stack(); - const filterGroup = codebuild - .FilterGroup - .inEventOf(codebuild.EventAction.PUSH, codebuild.EventAction.PULL_REQUEST_CREATED) - .andCommitMessageIs('the commit message'); - - test.doesNotThrow(() => { - new codebuild.Project(stack, 'BitBucket Project', { - source: codebuild.Source.bitBucket({ - owner: 'owner', - repo: 'repo', - webhookFilters: [filterGroup], - }), - }); - new codebuild.Project(stack, 'GitHub Project', { - source: codebuild.Source.gitHub({ - owner: 'owner', - repo: 'repo', - webhookFilters: [filterGroup], - }), - }); - }); - test.done(); - }, - }, - }, - - 'enableBatchBuilds()'(test: Test) { - const stack = new cdk.Stack(); - - const project = new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHub({ - owner: 'testowner', - repo: 'testrepo', - }), - }); - - const returnVal = project.enableBatchBuilds(); - if (!returnVal?.role) { - throw new Error('Expecting return value with role'); - } - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - BuildBatchConfig: { - ServiceRole: { - 'Fn::GetAtt': [ - 'ProjectBatchServiceRoleF97A1CFB', - 'Arn', - ], - }, - }, - })); - - expect(stack).to(haveResourceLike('AWS::IAM::Role', { - AssumeRolePolicyDocument: { - Statement: [ - { - Action: 'sts:AssumeRole', - Effect: 'Allow', - Principal: { - Service: 'codebuild.amazonaws.com', - }, - }, - ], - Version: '2012-10-17', - }, - })); - - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - PolicyDocument: { - Statement: [ - { - Action: [ - 'codebuild:StartBuild', - 'codebuild:StopBuild', - 'codebuild:RetryBuild', - ], - Effect: 'Allow', - Resource: { - 'Fn::GetAtt': [ - 'ProjectC78D97AD', - 'Arn', - ], - }, - }, - ], - Version: '2012-10-17', - }, - })); - - test.done(); - }, -}; diff --git a/packages/@aws-cdk/aws-codebuild/test/test.linux-gpu-build-image.ts b/packages/@aws-cdk/aws-codebuild/test/test.linux-gpu-build-image.ts deleted file mode 100644 index 60d3b17ca3043..0000000000000 --- a/packages/@aws-cdk/aws-codebuild/test/test.linux-gpu-build-image.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { arrayWith, expect, haveResourceLike, objectLike } from '@aws-cdk/assert-internal'; -import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; -import * as codebuild from '../lib'; - -export = { - 'Linux GPU build image': { - 'AWS Deep Learning Container images': { - 'allows passing the account that the repository of the image is hosted in'(test: Test) { - const stack = new cdk.Stack(); - - new codebuild.Project(stack, 'Project', { - buildSpec: codebuild.BuildSpec.fromObject({ - version: '0.2', - phases: { - build: { commands: ['ls'] }, - }, - }), - environment: { - buildImage: codebuild.LinuxGpuBuildImage.awsDeepLearningContainersImage( - 'my-repo', 'my-tag', '123456789012'), - }, - }); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Environment: { - ComputeType: 'BUILD_GENERAL1_LARGE', - Image: { - 'Fn::Join': ['', [ - '123456789012.dkr.ecr.', - { Ref: 'AWS::Region' }, - '.', - { Ref: 'AWS::URLSuffix' }, - '/my-repo:my-tag', - ]], - }, - }, - })); - - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - PolicyDocument: { - Statement: arrayWith(objectLike({ - Action: [ - 'ecr:BatchCheckLayerAvailability', - 'ecr:GetDownloadUrlForLayer', - 'ecr:BatchGetImage', - ], - Resource: { - 'Fn::Join': ['', [ - 'arn:', - { Ref: 'AWS::Partition' }, - ':ecr:', - { Ref: 'AWS::Region' }, - ':123456789012:repository/my-repo', - ]], - }, - })), - }, - })); - - test.done(); - }, - }, - }, -}; diff --git a/packages/@aws-cdk/aws-codebuild/test/test.notification-rule.ts b/packages/@aws-cdk/aws-codebuild/test/test.notification-rule.ts deleted file mode 100644 index 4ebb4eed3578e..0000000000000 --- a/packages/@aws-cdk/aws-codebuild/test/test.notification-rule.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { expect, haveResource } from '@aws-cdk/assert-internal'; -import * as sns from '@aws-cdk/aws-sns'; -import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; -import * as codebuild from '../lib'; - -export = { - 'notifications rule'(test: Test) { - const stack = new cdk.Stack(); - const project = new codebuild.Project(stack, 'MyCodebuildProject', { - buildSpec: codebuild.BuildSpec.fromObject({ - version: '0.2', - phases: { - build: { - commands: [ - 'echo "Hello, CodeBuild!"', - ], - }, - }, - }), - }); - - const target = new sns.Topic(stack, 'MyTopic'); - - project.notifyOnBuildSucceeded('NotifyOnBuildSucceeded', target); - - project.notifyOnBuildFailed('NotifyOnBuildFailed', target); - - expect(stack).to(haveResource('AWS::CodeStarNotifications::NotificationRule', { - Name: 'MyCodebuildProjectNotifyOnBuildSucceeded77719592', - DetailType: 'FULL', - EventTypeIds: [ - 'codebuild-project-build-state-succeeded', - ], - Resource: { - 'Fn::GetAtt': [ - 'MyCodebuildProjectB0479580', - 'Arn', - ], - }, - Targets: [ - { - TargetAddress: { - Ref: 'MyTopic86869434', - }, - TargetType: 'SNS', - }, - ], - })); - - expect(stack).to(haveResource('AWS::CodeStarNotifications::NotificationRule', { - Name: 'MyCodebuildProjectNotifyOnBuildFailedF680E310', - DetailType: 'FULL', - EventTypeIds: [ - 'codebuild-project-build-state-failed', - ], - Resource: { - 'Fn::GetAtt': [ - 'MyCodebuildProjectB0479580', - 'Arn', - ], - }, - Targets: [ - { - TargetAddress: { - Ref: 'MyTopic86869434', - }, - TargetType: 'SNS', - }, - ], - })); - - test.done(); - }, -}; diff --git a/packages/@aws-cdk/aws-codebuild/test/test.project.ts b/packages/@aws-cdk/aws-codebuild/test/test.project.ts deleted file mode 100644 index 2b778c9d843cb..0000000000000 --- a/packages/@aws-cdk/aws-codebuild/test/test.project.ts +++ /dev/null @@ -1,1893 +0,0 @@ -import { countResources, expect, haveResource, haveResourceLike, objectLike, not, ResourcePart, arrayWith } from '@aws-cdk/assert-internal'; -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 s3 from '@aws-cdk/aws-s3'; -import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; -import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; -import * as codebuild from '../lib'; - -/* eslint-disable quote-props */ - -export = { - 'can use filename as buildspec'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - buildSpec: codebuild.BuildSpec.fromSourceFilename('hello.yml'), - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Source: { - BuildSpec: 'hello.yml', - }, - })); - - test.done(); - }, - - 'can use buildspec literal'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - buildSpec: codebuild.BuildSpec.fromObject({ phases: ['say hi'] }), - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Source: { - BuildSpec: '{\n "phases": [\n "say hi"\n ]\n}', - }, - })); - - test.done(); - }, - - 'can use yamlbuildspec literal'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - buildSpec: codebuild.BuildSpec.fromObjectToYaml({ - text: 'text', - decimal: 10, - list: ['say hi'], - obj: { - text: 'text', - decimal: 10, - list: ['say hi'], - }, - }), - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Source: { - BuildSpec: 'text: text\ndecimal: 10\nlist:\n - say hi\nobj:\n text: text\n decimal: 10\n list:\n - say hi\n', - }, - })); - - test.done(); - }, - - 'must supply buildspec when using nosource'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - test.throws(() => { - new codebuild.Project(stack, 'Project', { - }); - }, /you need to provide a concrete buildSpec/); - - test.done(); - }, - - 'must supply literal buildspec when using nosource'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - test.throws(() => { - new codebuild.Project(stack, 'Project', { - buildSpec: codebuild.BuildSpec.fromSourceFilename('bla.yml'), - }); - }, /you need to provide a concrete buildSpec/); - - test.done(); - }, - - 'GitHub source': { - 'has reportBuildStatus on by default'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHub({ - owner: 'testowner', - repo: 'testrepo', - cloneDepth: 3, - }), - }); - - // THEN - expect(stack).to(haveResource('AWS::CodeBuild::Project', { - Source: { - Type: 'GITHUB', - Location: 'https://github.com/testowner/testrepo.git', - ReportBuildStatus: true, - GitCloneDepth: 3, - }, - })); - - test.done(); - }, - - 'can set a branch as the SourceVersion'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHub({ - owner: 'testowner', - repo: 'testrepo', - branchOrRef: 'testbranch', - }), - }); - - // THEN - expect(stack).to(haveResource('AWS::CodeBuild::Project', { - SourceVersion: 'testbranch', - })); - - test.done(); - }, - - 'can explicitly set reportBuildStatus to false'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHub({ - owner: 'testowner', - repo: 'testrepo', - reportBuildStatus: false, - }), - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Source: { - ReportBuildStatus: false, - }, - })); - - test.done(); - }, - - 'can explicitly set webhook to true'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHub({ - owner: 'testowner', - repo: 'testrepo', - webhook: true, - }), - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Triggers: { - Webhook: true, - }, - })); - - test.done(); - }, - - 'can be added to a CodePipeline'(test: Test) { - const stack = new cdk.Stack(); - const project = new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHub({ - owner: 'testowner', - repo: 'testrepo', - }), - }); - - project.bindToCodePipeline(project, { - artifactBucket: new s3.Bucket(stack, 'Bucket'), - }); // no exception - - test.done(); - }, - - 'can provide credentials to use with the source'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.GitHubSourceCredentials(stack, 'GitHubSourceCredentials', { - accessToken: cdk.SecretValue.plainText('my-access-token'), - }); - - // THEN - expect(stack).to(haveResource('AWS::CodeBuild::SourceCredential', { - 'ServerType': 'GITHUB', - 'AuthType': 'PERSONAL_ACCESS_TOKEN', - 'Token': 'my-access-token', - })); - - test.done(); - }, - }, - - 'GitHub Enterprise source': { - 'can use branchOrRef to set the source version'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHubEnterprise({ - httpsCloneUrl: 'https://mygithub-enterprise.com/myuser/myrepo', - branchOrRef: 'testbranch', - }), - }); - - // THEN - expect(stack).to(haveResource('AWS::CodeBuild::Project', { - SourceVersion: 'testbranch', - })); - - test.done(); - }, - - 'can provide credentials to use with the source'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.GitHubEnterpriseSourceCredentials(stack, 'GitHubEnterpriseSourceCredentials', { - accessToken: cdk.SecretValue.plainText('my-access-token'), - }); - - // THEN - expect(stack).to(haveResource('AWS::CodeBuild::SourceCredential', { - 'ServerType': 'GITHUB_ENTERPRISE', - 'AuthType': 'PERSONAL_ACCESS_TOKEN', - 'Token': 'my-access-token', - })); - - test.done(); - }, - }, - - 'BitBucket source': { - 'can use branchOrRef to set the source version'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.bitBucket({ - owner: 'testowner', - repo: 'testrepo', - branchOrRef: 'testbranch', - }), - }); - - // THEN - expect(stack).to(haveResource('AWS::CodeBuild::Project', { - SourceVersion: 'testbranch', - })); - - test.done(); - }, - - 'can provide credentials to use with the source'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.BitBucketSourceCredentials(stack, 'BitBucketSourceCredentials', { - username: cdk.SecretValue.plainText('my-username'), - password: cdk.SecretValue.plainText('password'), - }); - - // THEN - expect(stack).to(haveResource('AWS::CodeBuild::SourceCredential', { - 'ServerType': 'BITBUCKET', - 'AuthType': 'BASIC_AUTH', - 'Username': 'my-username', - 'Token': 'password', - })); - - test.done(); - }, - }, - - 'project with s3 cache bucket'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'SourceBucket'), - path: 'path', - }), - cache: codebuild.Cache.bucket(new s3.Bucket(stack, 'Bucket'), { - prefix: 'cache-prefix', - }), - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Cache: { - Type: 'S3', - Location: { - 'Fn::Join': [ - '/', - [ - { - 'Ref': 'Bucket83908E77', - }, - 'cache-prefix', - ], - ], - }, - }, - })); - - test.done(); - }, - - 's3 codebuild project with sourceVersion'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - version: 's3version', - }), - cache: codebuild.Cache.local(codebuild.LocalCacheMode.CUSTOM, codebuild.LocalCacheMode.DOCKER_LAYER, - codebuild.LocalCacheMode.SOURCE), - }); - - // THEN - expect(stack).to(haveResource('AWS::CodeBuild::Project', { - SourceVersion: 's3version', - })); - - test.done(); - }, - - 'project with local cache modes'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - cache: codebuild.Cache.local(codebuild.LocalCacheMode.CUSTOM, codebuild.LocalCacheMode.DOCKER_LAYER, - codebuild.LocalCacheMode.SOURCE), - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Cache: { - Type: 'LOCAL', - Modes: [ - 'LOCAL_CUSTOM_CACHE', - 'LOCAL_DOCKER_LAYER_CACHE', - 'LOCAL_SOURCE_CACHE', - ], - }, - })); - - test.done(); - }, - - 'project by default has no cache modes'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - }); - - // THEN - expect(stack).to(not(haveResourceLike('AWS::CodeBuild::Project', { - Cache: {}, - }))); - - test.done(); - }, - - 'if a role is shared between projects in a VPC, the VPC Policy is only attached once'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc'); - const role = new iam.Role(stack, 'Role', { - assumedBy: new iam.ServicePrincipal('codebuild.amazonaws.com'), - }); - const source = codebuild.Source.gitHubEnterprise({ - httpsCloneUrl: 'https://mygithub-enterprise.com/myuser/myrepo', - }); - - // WHEN - new codebuild.Project(stack, 'Project1', { source, role, vpc, projectName: 'P1' }); - new codebuild.Project(stack, 'Project2', { source, role, vpc, projectName: 'P2' }); - - // THEN - // - 1 is for `ec2:CreateNetworkInterfacePermission`, deduplicated as they're part of a single policy - // - 1 is for `ec2:CreateNetworkInterface`, this is the separate Policy we're deduplicating - // We would have found 3 if the deduplication didn't work. - expect(stack).to(countResources('AWS::IAM::Policy', 2)); - - // THEN - both Projects have a DependsOn on the same policy - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Properties: { Name: 'P1' }, - DependsOn: ['Project1PolicyDocumentF9761562'], - }, ResourcePart.CompleteDefinition)); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Properties: { Name: 'P1' }, - DependsOn: ['Project1PolicyDocumentF9761562'], - }, ResourcePart.CompleteDefinition)); - - test.done(); - }, - - 'can use an imported Role for a Project within a VPC'(test: Test) { - const stack = new cdk.Stack(); - - const importedRole = iam.Role.fromRoleArn(stack, 'Role', 'arn:aws:iam::1234567890:role/service-role/codebuild-bruiser-service-role'); - const vpc = new ec2.Vpc(stack, 'Vpc'); - - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHubEnterprise({ - httpsCloneUrl: 'https://mygithub-enterprise.com/myuser/myrepo', - }), - role: importedRole, - vpc, - }); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - // no need to do any assertions - })); - - test.done(); - }, - - 'can use an imported Role with mutable = false for a Project within a VPC'(test: Test) { - const stack = new cdk.Stack(); - - const importedRole = iam.Role.fromRoleArn(stack, 'Role', - 'arn:aws:iam::1234567890:role/service-role/codebuild-bruiser-service-role', { - mutable: false, - }); - const vpc = new ec2.Vpc(stack, 'Vpc'); - - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHubEnterprise({ - httpsCloneUrl: 'https://mygithub-enterprise.com/myuser/myrepo', - }), - role: importedRole, - vpc, - }); - - expect(stack).to(countResources('AWS::IAM::Policy', 0)); - - // Check that the CodeBuild project does not have a DependsOn - expect(stack).to(haveResource('AWS::CodeBuild::Project', (res: any) => { - if (res.DependsOn && res.DependsOn.length > 0) { - throw new Error(`CodeBuild project should have no DependsOn, but got: ${JSON.stringify(res, undefined, 2)}`); - } - return true; - }, ResourcePart.CompleteDefinition)); - - test.done(); - }, - - 'can use an ImmutableRole for a Project within a VPC'(test: Test) { - const stack = new cdk.Stack(); - - const role = new iam.Role(stack, 'Role', { - assumedBy: new iam.ServicePrincipal('codebuild.amazonaws.com'), - }); - - const vpc = new ec2.Vpc(stack, 'Vpc'); - - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHubEnterprise({ - httpsCloneUrl: 'https://mygithub-enterprise.com/myuser/myrepo', - }), - role: role.withoutPolicyUpdates(), - vpc, - }); - - expect(stack).to(countResources('AWS::IAM::Policy', 0)); - - // Check that the CodeBuild project does not have a DependsOn - expect(stack).to(haveResource('AWS::CodeBuild::Project', (res: any) => { - if (res.DependsOn && res.DependsOn.length > 0) { - throw new Error(`CodeBuild project should have no DependsOn, but got: ${JSON.stringify(res, undefined, 2)}`); - } - return true; - }, ResourcePart.CompleteDefinition)); - - test.done(); - }, - - 'metric method generates a valid CloudWatch metric'(test: Test) { - const stack = new cdk.Stack(); - - const project = new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHubEnterprise({ - httpsCloneUrl: 'https://mygithub-enterprise.com/myuser/myrepo', - }), - }); - - const metric = project.metric('Builds'); - test.equal(metric.metricName, 'Builds'); - test.equal(metric.period.toSeconds(), cdk.Duration.minutes(5).toSeconds()); - test.equal(metric.statistic, 'Average'); - - test.done(); - }, - - 'CodeBuild test reports group': { - 'adds the appropriate permissions when reportGroup.grantWrite() is called'(test: Test) { - const stack = new cdk.Stack(); - - const reportGroup = new codebuild.ReportGroup(stack, 'ReportGroup'); - - const project = new codebuild.Project(stack, 'Project', { - buildSpec: codebuild.BuildSpec.fromObject({ - version: '0.2', - reports: { - [reportGroup.reportGroupArn]: { - files: '**/*', - }, - }, - }), - grantReportGroupPermissions: false, - }); - reportGroup.grantWrite(project); - - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': [ - {}, - { - 'Action': [ - 'codebuild:CreateReport', - 'codebuild:UpdateReport', - 'codebuild:BatchPutTestCases', - ], - 'Resource': { - 'Fn::GetAtt': [ - 'ReportGroup8A84C76D', - 'Arn', - ], - }, - }, - ], - }, - })); - - test.done(); - }, - }, - - 'Environment': { - 'build image - can use secret to access build image'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const secret = new secretsmanager.Secret(stack, 'Secret'); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - environment: { - buildImage: codebuild.LinuxBuildImage.fromDockerRegistry('myimage', { secretsManagerCredentials: secret }), - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Environment: objectLike({ - RegistryCredential: { - CredentialProvider: 'SECRETS_MANAGER', - Credential: { 'Ref': 'SecretA720EF05' }, - }, - }), - })); - - test.done(); - }, - - 'build image - can use imported secret by name'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const secret = secretsmanager.Secret.fromSecretNameV2(stack, 'Secret', 'MySecretName'); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - environment: { - buildImage: codebuild.LinuxBuildImage.fromDockerRegistry('myimage', { secretsManagerCredentials: secret }), - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Environment: objectLike({ - RegistryCredential: { - CredentialProvider: 'SECRETS_MANAGER', - Credential: 'MySecretName', - }, - }), - })); - - test.done(); - }, - - 'logs config - cloudWatch'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const logGroup = logs.LogGroup.fromLogGroupName(stack, 'LogGroup', 'MyLogGroupName'); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - logging: { - cloudWatch: { - logGroup, - prefix: '/my-logs', - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - LogsConfig: objectLike({ - CloudWatchLogs: { - GroupName: 'MyLogGroupName', - Status: 'ENABLED', - StreamName: '/my-logs', - }, - }), - })); - - test.done(); - }, - - 'logs config - cloudWatch disabled'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - logging: { - cloudWatch: { - enabled: false, - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - LogsConfig: objectLike({ - CloudWatchLogs: { - Status: 'DISABLED', - }, - }), - })); - - test.done(); - }, - - 'logs config - s3'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const bucket = s3.Bucket.fromBucketName(stack, 'LogBucket', 'MyBucketName'); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - logging: { - s3: { - bucket, - prefix: 'my-logs', - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - LogsConfig: objectLike({ - S3Logs: { - Location: 'MyBucketName/my-logs', - Status: 'ENABLED', - }, - }), - })); - - test.done(); - }, - - 'logs config - cloudWatch and s3'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const bucket = s3.Bucket.fromBucketName(stack, 'LogBucket2', 'MyBucketName'); - const logGroup = logs.LogGroup.fromLogGroupName(stack, 'LogGroup2', 'MyLogGroupName'); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - logging: { - cloudWatch: { - logGroup, - }, - s3: { - bucket, - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - LogsConfig: objectLike({ - CloudWatchLogs: { - GroupName: 'MyLogGroupName', - Status: 'ENABLED', - }, - S3Logs: { - Location: 'MyBucketName', - Status: 'ENABLED', - }, - }), - })); - - test.done(); - }, - - 'certificate arn'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const bucket = s3.Bucket.fromBucketName(stack, 'Bucket', 'my-bucket'); // (stack, 'Bucket'); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket, - path: 'path', - }), - environment: { - certificate: { - bucket, - objectKey: 'path', - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Environment: objectLike({ - Certificate: { - 'Fn::Join': ['', [ - 'arn:', - { 'Ref': 'AWS::Partition' }, - ':s3:::my-bucket/path', - ]], - }, - }), - })); - - test.done(); - }, - }, - - 'EnvironmentVariables': { - 'from SSM': { - 'can use environment variables'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - environment: { - buildImage: codebuild.LinuxBuildImage.fromDockerRegistry('myimage'), - }, - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.PARAMETER_STORE, - value: '/params/param1', - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - Environment: objectLike({ - EnvironmentVariables: [{ - Name: 'ENV_VAR1', - Type: 'PARAMETER_STORE', - Value: '/params/param1', - }], - }), - })); - - test.done(); - }, - - 'grants the correct read permissions'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - environment: { - buildImage: codebuild.LinuxBuildImage.fromDockerRegistry('myimage'), - }, - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.PARAMETER_STORE, - value: '/params/param1', - }, - 'ENV_VAR2': { - type: codebuild.BuildEnvironmentVariableType.PARAMETER_STORE, - value: 'params/param2', - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith(objectLike({ - 'Action': 'ssm:GetParameters', - 'Effect': 'Allow', - 'Resource': [{ - 'Fn::Join': [ - '', - [ - 'arn:', - { - Ref: 'AWS::Partition', - }, - ':ssm:', - { - Ref: 'AWS::Region', - }, - ':', - { - Ref: 'AWS::AccountId', - }, - ':parameter/params/param1', - ], - ], - }, - { - 'Fn::Join': [ - '', - [ - 'arn:', - { - Ref: 'AWS::Partition', - }, - ':ssm:', - { - Ref: 'AWS::Region', - }, - ':', - { - Ref: 'AWS::AccountId', - }, - ':parameter/params/param2', - ], - ], - }], - })), - }, - })); - - - test.done(); - }, - - 'does not grant read permissions when variables are not from parameter store'(test: Test) { - - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - environment: { - buildImage: codebuild.LinuxBuildImage.fromDockerRegistry('myimage'), - }, - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.PLAINTEXT, - value: 'var1-value', - }, - }, - }); - - // THEN - expect(stack).notTo(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith(objectLike({ - 'Action': 'ssm:GetParameters', - 'Effect': 'Allow', - })), - }, - })); - - test.done(); - }, - }, - - 'from SecretsManager': { - 'can be provided as a verbatim secret name'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: 'my-secret', - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'EnvironmentVariables': [ - { - 'Name': 'ENV_VAR1', - 'Type': 'SECRETS_MANAGER', - 'Value': 'my-secret', - }, - ], - }, - })); - - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'secretsmanager:GetSecretValue', - 'Effect': 'Allow', - 'Resource': { - 'Fn::Join': ['', [ - 'arn:', - { Ref: 'AWS::Partition' }, - ':secretsmanager:', - { Ref: 'AWS::Region' }, - ':', - { Ref: 'AWS::AccountId' }, - ':secret:my-secret-??????', - ]], - }, - }), - }, - })); - - test.done(); - }, - - 'can be provided as a verbatim secret name followed by a JSON key'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: 'my-secret:json-key', - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'EnvironmentVariables': [ - { - 'Name': 'ENV_VAR1', - 'Type': 'SECRETS_MANAGER', - 'Value': 'my-secret:json-key', - }, - ], - }, - })); - - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'secretsmanager:GetSecretValue', - 'Effect': 'Allow', - 'Resource': { - 'Fn::Join': ['', [ - 'arn:', - { Ref: 'AWS::Partition' }, - ':secretsmanager:', - { Ref: 'AWS::Region' }, - ':', - { Ref: 'AWS::AccountId' }, - ':secret:my-secret-??????', - ]], - }, - }), - }, - })); - - test.done(); - }, - - 'can be provided as a verbatim full secret ARN followed by a JSON key'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: 'arn:aws:secretsmanager:us-west-2:123456789012:secret:my-secret-123456:json-key', - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'EnvironmentVariables': [ - { - 'Name': 'ENV_VAR1', - 'Type': 'SECRETS_MANAGER', - 'Value': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:my-secret-123456:json-key', - }, - ], - }, - })); - - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'secretsmanager:GetSecretValue', - 'Effect': 'Allow', - 'Resource': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:my-secret-123456*', - }), - }, - })); - - // THEN - expect(stack).to(not(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'kms:Decrypt', - 'Effect': 'Allow', - 'Resource': 'arn:aws:kms:us-west-2:123456789012:key/*', - }), - }, - }))); - - test.done(); - }, - - 'can be provided as a verbatim partial secret ARN'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret', - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'EnvironmentVariables': [ - { - 'Name': 'ENV_VAR1', - 'Type': 'SECRETS_MANAGER', - 'Value': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret', - }, - ], - }, - })); - - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'secretsmanager:GetSecretValue', - 'Effect': 'Allow', - 'Resource': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret*', - }), - }, - })); - - // THEN - expect(stack).to(not(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'kms:Decrypt', - 'Effect': 'Allow', - 'Resource': 'arn:aws:kms:us-west-2:123456789012:key/*', - }), - }, - }))); - - test.done(); - }, - - "when provided as a verbatim partial secret ARN from another account, adds permission to decrypt keys in the Secret's account"(test: Test) { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'ProjectStack', { - env: { account: '123456789012' }, - }); - - // WHEN - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: 'arn:aws:secretsmanager:us-west-2:901234567890:secret:mysecret', - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'kms:Decrypt', - 'Effect': 'Allow', - 'Resource': 'arn:aws:kms:us-west-2:901234567890:key/*', - }), - }, - })); - - test.done(); - }, - - 'when two secrets from another account are provided as verbatim partial secret ARNs, adds only one permission for decrypting'(test: Test) { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'ProjectStack', { - env: { account: '123456789012' }, - }); - - // WHEN - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: 'arn:aws:secretsmanager:us-west-2:901234567890:secret:mysecret', - }, - 'ENV_VAR2': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: 'arn:aws:secretsmanager:us-west-2:901234567890:secret:other-secret', - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'kms:Decrypt', - 'Effect': 'Allow', - 'Resource': 'arn:aws:kms:us-west-2:901234567890:key/*', - }), - }, - })); - - test.done(); - }, - - 'can be provided as the ARN attribute of a new Secret'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - const secret = new secretsmanager.Secret(stack, 'Secret'); - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: secret.secretArn, - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'EnvironmentVariables': [ - { - 'Name': 'ENV_VAR1', - 'Type': 'SECRETS_MANAGER', - 'Value': { 'Ref': 'SecretA720EF05' }, - }, - ], - }, - })); - - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'secretsmanager:GetSecretValue', - 'Effect': 'Allow', - 'Resource': { 'Ref': 'SecretA720EF05' }, - }), - }, - })); - - test.done(); - }, - - 'when the same new secret is provided with different JSON keys, only adds the resource once'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - const secret = new secretsmanager.Secret(stack, 'Secret'); - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: `${secret.secretArn}:json-key1`, - }, - 'ENV_VAR2': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: `${secret.secretArn}:json-key2`, - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'EnvironmentVariables': [ - { - 'Name': 'ENV_VAR1', - 'Type': 'SECRETS_MANAGER', - 'Value': { 'Fn::Join': ['', [{ 'Ref': 'SecretA720EF05' }, ':json-key1']] }, - }, - { - 'Name': 'ENV_VAR2', - 'Type': 'SECRETS_MANAGER', - 'Value': { 'Fn::Join': ['', [{ 'Ref': 'SecretA720EF05' }, ':json-key2']] }, - }, - ], - }, - })); - - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'secretsmanager:GetSecretValue', - 'Effect': 'Allow', - 'Resource': { 'Ref': 'SecretA720EF05' }, - }), - }, - })); - - test.done(); - }, - - 'can be provided as the ARN attribute of a new Secret, followed by a JSON key'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - const secret = new secretsmanager.Secret(stack, 'Secret'); - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: `${secret.secretArn}:json-key:version-stage`, - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'EnvironmentVariables': [ - { - 'Name': 'ENV_VAR1', - 'Type': 'SECRETS_MANAGER', - 'Value': { - 'Fn::Join': ['', [ - { 'Ref': 'SecretA720EF05' }, - ':json-key:version-stage', - ]], - }, - }, - ], - }, - })); - - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'secretsmanager:GetSecretValue', - 'Effect': 'Allow', - 'Resource': { 'Ref': 'SecretA720EF05' }, - }), - }, - })); - - test.done(); - }, - - 'can be provided as the name attribute of a Secret imported by name'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - const secret = secretsmanager.Secret.fromSecretNameV2(stack, 'Secret', 'mysecret'); - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: secret.secretName, - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'EnvironmentVariables': [ - { - 'Name': 'ENV_VAR1', - 'Type': 'SECRETS_MANAGER', - 'Value': 'mysecret', - }, - ], - }, - })); - - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'secretsmanager:GetSecretValue', - 'Effect': 'Allow', - 'Resource': { - 'Fn::Join': ['', [ - 'arn:', - { 'Ref': 'AWS::Partition' }, - ':secretsmanager:', - { 'Ref': 'AWS::Region' }, - ':', - { 'Ref': 'AWS::AccountId' }, - ':secret:mysecret-??????', - ]], - }, - }), - }, - })); - - test.done(); - }, - - 'can be provided as the ARN attribute of a Secret imported by partial ARN, followed by a JSON key'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - const secret = secretsmanager.Secret.fromSecretPartialArn(stack, 'Secret', - 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret'); - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: `${secret.secretArn}:json-key`, - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'EnvironmentVariables': [ - { - 'Name': 'ENV_VAR1', - 'Type': 'SECRETS_MANAGER', - 'Value': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret:json-key', - }, - ], - }, - })); - - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'secretsmanager:GetSecretValue', - 'Effect': 'Allow', - 'Resource': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret*', - }), - }, - })); - - test.done(); - }, - - 'can be provided as the ARN attribute of a Secret imported by complete ARN, followed by a JSON key'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - const secret = secretsmanager.Secret.fromSecretCompleteArn(stack, 'Secret', - 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret-123456'); - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: `${secret.secretArn}:json-key`, - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'EnvironmentVariables': [ - { - 'Name': 'ENV_VAR1', - 'Type': 'SECRETS_MANAGER', - 'Value': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret-123456:json-key', - }, - ], - }, - })); - - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'secretsmanager:GetSecretValue', - 'Effect': 'Allow', - 'Resource': 'arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret-123456*', - }), - }, - })); - - test.done(); - }, - - 'can be provided as a SecretArn of a new Secret, with its physical name set, created in a different account'(test: Test) { - // GIVEN - const app = new cdk.App(); - const secretStack = new cdk.Stack(app, 'SecretStack', { - env: { account: '012345678912' }, - }); - const stack = new cdk.Stack(app, 'ProjectStack', { - env: { account: '123456789012' }, - }); - - // WHEN - const secret = new secretsmanager.Secret(secretStack, 'Secret', { secretName: 'secret-name' }); - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: secret.secretArn, - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'EnvironmentVariables': [ - { - 'Name': 'ENV_VAR1', - 'Type': 'SECRETS_MANAGER', - 'Value': { - 'Fn::Join': ['', [ - 'arn:', - { 'Ref': 'AWS::Partition' }, - ':secretsmanager:', - { 'Ref': 'AWS::Region' }, - ':012345678912:secret:secret-name', - ]], - }, - }, - ], - }, - })); - - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'secretsmanager:GetSecretValue', - 'Effect': 'Allow', - 'Resource': { - 'Fn::Join': ['', [ - 'arn:', - { 'Ref': 'AWS::Partition' }, - ':secretsmanager:', - { 'Ref': 'AWS::Region' }, - ':012345678912:secret:secret-name-??????', - ]], - }, - }), - }, - })); - - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'kms:Decrypt', - 'Effect': 'Allow', - 'Resource': { - 'Fn::Join': ['', [ - 'arn:', - { 'Ref': 'AWS::Partition' }, - ':kms:', - { 'Ref': 'AWS::Region' }, - ':012345678912:key/*', - ]], - }, - }), - }, - })); - - test.done(); - }, - - 'can be provided as a SecretArn of a Secret imported by name in a different account'(test: Test) { - // GIVEN - const app = new cdk.App(); - const secretStack = new cdk.Stack(app, 'SecretStack', { - env: { account: '012345678912' }, - }); - const stack = new cdk.Stack(app, 'ProjectStack', { - env: { account: '123456789012' }, - }); - - // WHEN - const secret = secretsmanager.Secret.fromSecretNameV2(secretStack, 'Secret', 'secret-name'); - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: `${secret.secretArn}:json-key`, - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'EnvironmentVariables': [ - { - 'Name': 'ENV_VAR1', - 'Type': 'SECRETS_MANAGER', - 'Value': { - 'Fn::Join': ['', [ - 'arn:', - { 'Ref': 'AWS::Partition' }, - ':secretsmanager:', - { 'Ref': 'AWS::Region' }, - ':012345678912:secret:secret-name:json-key', - ]], - }, - }, - ], - }, - })); - - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'secretsmanager:GetSecretValue', - 'Effect': 'Allow', - 'Resource': { - 'Fn::Join': ['', [ - 'arn:', - { 'Ref': 'AWS::Partition' }, - ':secretsmanager:', - { 'Ref': 'AWS::Region' }, - ':012345678912:secret:secret-name*', - ]], - }, - }), - }, - })); - - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'kms:Decrypt', - 'Effect': 'Allow', - 'Resource': { - 'Fn::Join': ['', [ - 'arn:', - { 'Ref': 'AWS::Partition' }, - ':kms:', - { 'Ref': 'AWS::Region' }, - ':012345678912:key/*', - ]], - }, - }), - }, - })); - - test.done(); - }, - - 'can be provided as a SecretArn of a Secret imported by complete ARN from a different account'(test: Test) { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'ProjectStack', { - env: { account: '123456789012' }, - }); - const secretArn = 'arn:aws:secretsmanager:us-west-2:901234567890:secret:mysecret-123456'; - - // WHEN - const secret = secretsmanager.Secret.fromSecretCompleteArn(stack, 'Secret', secretArn); - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: secret.secretArn, - }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - 'Environment': { - 'EnvironmentVariables': [ - { - 'Name': 'ENV_VAR1', - 'Type': 'SECRETS_MANAGER', - 'Value': secretArn, - }, - ], - }, - })); - - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'secretsmanager:GetSecretValue', - 'Effect': 'Allow', - 'Resource': `${secretArn}*`, - }), - }, - })); - - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': arrayWith({ - 'Action': 'kms:Decrypt', - 'Effect': 'Allow', - 'Resource': 'arn:aws:kms:us-west-2:901234567890:key/*', - }), - }, - })); - - test.done(); - }, - - 'should fail when the parsed Arn does not contain a secret name'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - test.throws(() => { - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'ENV_VAR1': { - type: codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER, - value: 'arn:aws:secretsmanager:us-west-2:123456789012:secret', - }, - }, - }); - }, /SecretManager ARN is missing the name of the secret:/); - - test.done(); - }, - }, - - 'should fail creating when using a secret value in a plaintext variable'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // THEN - test.throws(() => { - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'a': { - value: `a_${cdk.SecretValue.secretsManager('my-secret')}_b`, - }, - }, - }); - }, /Plaintext environment variable 'a' contains a secret value!/); - - test.done(); - }, - - "should allow opting out of the 'secret value in a plaintext variable' validation"(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // THEN - new codebuild.PipelineProject(stack, 'Project', { - environmentVariables: { - 'b': { - value: cdk.SecretValue.secretsManager('my-secret'), - }, - }, - checkSecretsInPlainTextEnvVariables: false, - }); - - test.done(); - }, - }, - - 'Timeouts': { - 'can add queued timeout'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - queuedTimeout: cdk.Duration.minutes(30), - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - QueuedTimeoutInMinutes: 30, - })); - - test.done(); - }, - - 'can override build timeout'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - timeout: cdk.Duration.minutes(30), - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - TimeoutInMinutes: 30, - })); - - test.done(); - }, - }, - - 'Maximum concurrency': { - 'can limit maximum concurrency'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new codebuild.Project(stack, 'Project', { - source: codebuild.Source.s3({ - bucket: new s3.Bucket(stack, 'Bucket'), - path: 'path', - }), - concurrentBuildLimit: 1, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::CodeBuild::Project', { - ConcurrentBuildLimit: 1, - })); - - test.done(); - }, - }, - - 'can be imported': { - 'by ARN'(test: Test) { - const stack = new cdk.Stack(); - const project = codebuild.Project.fromProjectArn(stack, 'Project', - 'arn:aws:codebuild:us-west-2:123456789012:project/My-Project'); - - test.equal(project.projectName, 'My-Project'); - test.equal(project.env.account, '123456789012'); - test.equal(project.env.region, 'us-west-2'); - - test.done(); - }, - }, -}; diff --git a/packages/@aws-cdk/aws-codebuild/test/test.report-group.ts b/packages/@aws-cdk/aws-codebuild/test/test.report-group.ts deleted file mode 100644 index 9ea5441aeb5df..0000000000000 --- a/packages/@aws-cdk/aws-codebuild/test/test.report-group.ts +++ /dev/null @@ -1,162 +0,0 @@ -import { ABSENT, expect, haveResourceLike, ResourcePart } from '@aws-cdk/assert-internal'; -import * as iam from '@aws-cdk/aws-iam'; -import * as kms from '@aws-cdk/aws-kms'; -import * as s3 from '@aws-cdk/aws-s3'; -import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; -import * as codebuild from '../lib'; - -/* eslint-disable quote-props */ -/* eslint-disable quotes */ - -export = { - 'Test Reports Groups': { - 'get created with type=TEST and exportConfig=NO_EXPORT by default'(test: Test) { - const stack = new cdk.Stack(); - - new codebuild.ReportGroup(stack, 'ReportGroup'); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::ReportGroup', { - "Type": "TEST", - "ExportConfig": { - "ExportConfigType": "NO_EXPORT", - "S3Destination": ABSENT, - }, - })); - - test.done(); - }, - - 'can be created with name' (test: Test) { - const stack = new cdk.Stack(); - - new codebuild.ReportGroup(stack, 'ReportGroup', { - reportGroupName: 'my-report-group', - }); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::ReportGroup', { - "Name": 'my-report-group', - })); - - test.done(); - }, - - 'can be imported by name'(test: Test) { - const stack = new cdk.Stack(); - - const reportGroup = codebuild.ReportGroup.fromReportGroupName(stack, - 'ReportGroup', 'my-report-group'); - - const role = new iam.Role(stack, 'Role', { - assumedBy: new iam.AnyPrincipal(), - }); - role.addToPolicy(new iam.PolicyStatement({ - actions: ['codebuild:*'], - resources: [reportGroup.reportGroupArn], - })); - - test.equal(reportGroup.reportGroupName, 'my-report-group'); - expect(stack).to(haveResourceLike('AWS::IAM::Policy', { - "PolicyDocument": { - "Statement": [ - { - "Action": "codebuild:*", - "Resource": { - "Fn::Join": ["", [ - "arn:", - { "Ref": "AWS::Partition" }, - ":codebuild:", - { "Ref": "AWS::Region" }, - ":", - { "Ref": "AWS::AccountId" }, - ":report-group/my-report-group", - ]], - }, - }, - ], - }, - })); - - test.done(); - }, - - 'specify exportConfig=S3 when providing an exportBucket'(test: Test) { - const stack = new cdk.Stack(); - - new codebuild.ReportGroup(stack, 'ReportGroup', { - exportBucket: s3.Bucket.fromBucketName(stack, 'Bucket', 'my-bucket'), - }); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::ReportGroup', { - "Type": "TEST", - "ExportConfig": { - "ExportConfigType": "S3", - "S3Destination": { - "Bucket": "my-bucket", - "EncryptionKey": ABSENT, - "EncryptionDisabled": ABSENT, - "Packaging": ABSENT, - }, - }, - })); - - test.done(); - }, - - 'specify encryptionKey in ExportConfig.S3Destination if exportBucket has a Key'(test: Test) { - const stack = new cdk.Stack(); - - new codebuild.ReportGroup(stack, 'ReportGroup', { - exportBucket: s3.Bucket.fromBucketAttributes(stack, 'Bucket', { - bucketName: 'my-bucket', - encryptionKey: kms.Key.fromKeyArn(stack, 'Key', - 'arn:aws:kms:us-east-1:123456789012:key/my-key'), - }), - zipExport: true, - }); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::ReportGroup', { - "Type": "TEST", - "ExportConfig": { - "ExportConfigType": "S3", - "S3Destination": { - "Bucket": "my-bucket", - "EncryptionDisabled": false, - "EncryptionKey": "arn:aws:kms:us-east-1:123456789012:key/my-key", - "Packaging": "ZIP", - }, - }, - })); - - test.done(); - }, - - 'get created with RemovalPolicy.RETAIN by default'(test: Test) { - const stack = new cdk.Stack(); - - new codebuild.ReportGroup(stack, 'ReportGroup'); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::ReportGroup', { - "DeletionPolicy": "Retain", - "UpdateReplacePolicy": "Retain", - }, ResourcePart.CompleteDefinition)); - - test.done(); - }, - - 'can be created with RemovalPolicy.DESTROY'(test: Test) { - const stack = new cdk.Stack(); - - new codebuild.ReportGroup(stack, 'ReportGroup', { - removalPolicy: cdk.RemovalPolicy.DESTROY, - }); - - expect(stack).to(haveResourceLike('AWS::CodeBuild::ReportGroup', { - "DeletionPolicy": "Delete", - "UpdateReplacePolicy": "Delete", - }, ResourcePart.CompleteDefinition)); - - test.done(); - }, - }, -}; diff --git a/packages/@aws-cdk/aws-codebuild/test/test.untrusted-code-boundary.ts b/packages/@aws-cdk/aws-codebuild/test/test.untrusted-code-boundary.ts deleted file mode 100644 index e806e48b58edb..0000000000000 --- a/packages/@aws-cdk/aws-codebuild/test/test.untrusted-code-boundary.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { expect, haveResourceLike, arrayWith } from '@aws-cdk/assert-internal'; -import * as iam from '@aws-cdk/aws-iam'; -import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; -import * as codebuild from '../lib'; - -export = { - 'can attach permissions boundary to Project'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - const project = new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHub({ owner: 'a', repo: 'b' }), - }); - iam.PermissionsBoundary.of(project).apply(new codebuild.UntrustedCodeBoundaryPolicy(stack, 'Boundary')); - - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::Role', { - PermissionsBoundary: { Ref: 'BoundaryEA298153' }, - })); - - test.done(); - }, - - 'can add additional statements Boundary'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - const project = new codebuild.Project(stack, 'Project', { - source: codebuild.Source.gitHub({ owner: 'a', repo: 'b' }), - }); - iam.PermissionsBoundary.of(project).apply(new codebuild.UntrustedCodeBoundaryPolicy(stack, 'Boundary', { - additionalStatements: [ - new iam.PolicyStatement({ - actions: ['a:a'], - resources: ['b'], - }), - ], - })); - - // THEN - expect(stack).to(haveResourceLike('AWS::IAM::ManagedPolicy', { - PolicyDocument: { - Statement: arrayWith({ - Effect: 'Allow', - Action: 'a:a', - Resource: 'b', - }), - }, - })); - - test.done(); - }, -}; \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codebuild/test/untrusted-code-boundary.test.ts b/packages/@aws-cdk/aws-codebuild/test/untrusted-code-boundary.test.ts new file mode 100644 index 0000000000000..89933d11a7ab8 --- /dev/null +++ b/packages/@aws-cdk/aws-codebuild/test/untrusted-code-boundary.test.ts @@ -0,0 +1,50 @@ +import { arrayWith } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +import * as iam from '@aws-cdk/aws-iam'; +import * as cdk from '@aws-cdk/core'; +import * as codebuild from '../lib'; + +test('can attach permissions boundary to Project', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const project = new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHub({ owner: 'a', repo: 'b' }), + }); + iam.PermissionsBoundary.of(project).apply(new codebuild.UntrustedCodeBoundaryPolicy(stack, 'Boundary')); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::Role', { + PermissionsBoundary: { Ref: 'BoundaryEA298153' }, + }); +}); + +test('can add additional statements Boundary', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const project = new codebuild.Project(stack, 'Project', { + source: codebuild.Source.gitHub({ owner: 'a', repo: 'b' }), + }); + iam.PermissionsBoundary.of(project).apply(new codebuild.UntrustedCodeBoundaryPolicy(stack, 'Boundary', { + additionalStatements: [ + new iam.PolicyStatement({ + actions: ['a:a'], + resources: ['b'], + }), + ], + })); + + // THEN + expect(stack).toHaveResourceLike('AWS::IAM::ManagedPolicy', { + PolicyDocument: { + Statement: arrayWith({ + Effect: 'Allow', + Action: 'a:a', + Resource: 'b', + }), + }, + }); +}); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codecommit/.eslintrc.js b/packages/@aws-cdk/aws-codecommit/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-codecommit/.eslintrc.js +++ b/packages/@aws-cdk/aws-codecommit/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codecommit/jest.config.js b/packages/@aws-cdk/aws-codecommit/jest.config.js index c61850f59dabb..7c2e6abe4d7ed 100644 --- a/packages/@aws-cdk/aws-codecommit/jest.config.js +++ b/packages/@aws-cdk/aws-codecommit/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/aws-codecommit/package.json b/packages/@aws-cdk/aws-codecommit/package.json index 3bb2b8b4279a9..d5041d7e5711b 100644 --- a/packages/@aws-cdk/aws-codecommit/package.json +++ b/packages/@aws-cdk/aws-codecommit/package.json @@ -57,8 +57,7 @@ "cloudformation": "AWS::CodeCommit", "env": { "AWSLINT_BASE_CONSTRUCT": true - }, - "jest": true + } }, "nyc": { "statements": 30, @@ -78,15 +77,15 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", "aws-sdk": "^2.848.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-codestarnotifications": "0.0.0", diff --git a/packages/@aws-cdk/aws-codedeploy/.eslintrc.js b/packages/@aws-cdk/aws-codedeploy/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-codedeploy/.eslintrc.js +++ b/packages/@aws-cdk/aws-codedeploy/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codedeploy/jest.config.js b/packages/@aws-cdk/aws-codedeploy/jest.config.js index f5d5c4c8ad18f..34818e1593f6b 100644 --- a/packages/@aws-cdk/aws-codedeploy/jest.config.js +++ b/packages/@aws-cdk/aws-codedeploy/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); -module.exports = baseConfig; \ No newline at end of file +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codedeploy/package.json b/packages/@aws-cdk/aws-codedeploy/package.json index ac67fc09875c2..f8279b5c21e57 100644 --- a/packages/@aws-cdk/aws-codedeploy/package.json +++ b/packages/@aws-cdk/aws-codedeploy/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::CodeDeploy", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -76,13 +75,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-autoscaling": "0.0.0", diff --git a/packages/@aws-cdk/aws-codeguruprofiler/.eslintrc.js b/packages/@aws-cdk/aws-codeguruprofiler/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-codeguruprofiler/.eslintrc.js +++ b/packages/@aws-cdk/aws-codeguruprofiler/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codeguruprofiler/jest.config.js b/packages/@aws-cdk/aws-codeguruprofiler/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-codeguruprofiler/jest.config.js +++ b/packages/@aws-cdk/aws-codeguruprofiler/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codeguruprofiler/package.json b/packages/@aws-cdk/aws-codeguruprofiler/package.json index 1c72b538d5056..247e4696080fe 100644 --- a/packages/@aws-cdk/aws-codeguruprofiler/package.json +++ b/packages/@aws-cdk/aws-codeguruprofiler/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::CodeGuruProfiler", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,12 +74,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", @@ -88,8 +87,8 @@ "constructs": "^3.3.69" }, "peerDependencies": { - "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "engines": { diff --git a/packages/@aws-cdk/aws-codegurureviewer/.eslintrc.js b/packages/@aws-cdk/aws-codegurureviewer/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-codegurureviewer/.eslintrc.js +++ b/packages/@aws-cdk/aws-codegurureviewer/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codegurureviewer/jest.config.js b/packages/@aws-cdk/aws-codegurureviewer/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-codegurureviewer/jest.config.js +++ b/packages/@aws-cdk/aws-codegurureviewer/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codegurureviewer/package.json b/packages/@aws-cdk/aws-codegurureviewer/package.json index c0619789ea414..1ea8076d375ee 100644 --- a/packages/@aws-cdk/aws-codegurureviewer/package.json +++ b/packages/@aws-cdk/aws-codegurureviewer/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::CodeGuruReviewer", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-codepipeline-actions/.eslintrc.js b/packages/@aws-cdk/aws-codepipeline-actions/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/.eslintrc.js +++ b/packages/@aws-cdk/aws-codepipeline-actions/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codepipeline-actions/jest.config.js b/packages/@aws-cdk/aws-codepipeline-actions/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/jest.config.js +++ b/packages/@aws-cdk/aws-codepipeline-actions/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codepipeline-actions/package.json b/packages/@aws-cdk/aws-codepipeline-actions/package.json index e2409aa86db6a..6f08ecc470c28 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/package.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/package.json @@ -68,17 +68,17 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-cloudtrail": "0.0.0", "@aws-cdk/aws-codestarnotifications": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "@types/lodash": "^4.14.171", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", + "@types/lodash": "^4.14.175", "jest": "^26.6.3", - "lodash": "^4.17.21", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "lodash": "^4.17.21" }, "dependencies": { "@aws-cdk/aws-cloudformation": "0.0.0", @@ -180,7 +180,6 @@ }, "maturity": "stable", "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/lambda/lambda-invoke-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/lambda/lambda-invoke-action.test.ts index c3dce7754f70a..c9c694b6cedaf 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/lambda/lambda-invoke-action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/lambda/lambda-invoke-action.test.ts @@ -5,7 +5,7 @@ import * as s3 from '@aws-cdk/aws-s3'; import * as sns from '@aws-cdk/aws-sns'; import { App, Aws, Lazy, SecretValue, Stack, Token } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as cpactions from '../../lib'; /* eslint-disable quote-props */ diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/s3/s3-deploy-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/s3/s3-deploy-action.test.ts index aa8095678043a..580a4dc688e19 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/s3/s3-deploy-action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/s3/s3-deploy-action.test.ts @@ -3,7 +3,7 @@ import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as s3 from '@aws-cdk/aws-s3'; import { App, Duration, SecretValue, Stack } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as cpactions from '../../lib'; /* eslint-disable quote-props */ diff --git a/packages/@aws-cdk/aws-codepipeline/.eslintrc.js b/packages/@aws-cdk/aws-codepipeline/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-codepipeline/.eslintrc.js +++ b/packages/@aws-cdk/aws-codepipeline/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codepipeline/jest.config.js b/packages/@aws-cdk/aws-codepipeline/jest.config.js index ac8c47076506a..6a8dc8ed67646 100644 --- a/packages/@aws-cdk/aws-codepipeline/jest.config.js +++ b/packages/@aws-cdk/aws-codepipeline/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/aws-codepipeline/package.json b/packages/@aws-cdk/aws-codepipeline/package.json index 0f6ff83649093..5f242010eae8b 100644 --- a/packages/@aws-cdk/aws-codepipeline/package.json +++ b/packages/@aws-cdk/aws-codepipeline/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::CodePipeline", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -78,15 +77,14 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "@types/nodeunit": "^0.0.32", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-codestarnotifications": "0.0.0", diff --git a/packages/@aws-cdk/aws-codepipeline/test/artifacts.test.ts b/packages/@aws-cdk/aws-codepipeline/test/artifacts.test.ts index 5009f5fbdefd0..cf4f733d811be 100644 --- a/packages/@aws-cdk/aws-codepipeline/test/artifacts.test.ts +++ b/packages/@aws-cdk/aws-codepipeline/test/artifacts.test.ts @@ -282,9 +282,9 @@ describe('artifacts', () => { }); }); -/* eslint-disable cdk/no-core-construct */ +/* eslint-disable @aws-cdk/no-core-construct */ function validate(construct: cdk.IConstruct): cdk.ValidationError[] { cdk.ConstructNode.prepare(construct.node); return cdk.ConstructNode.validate(construct.node); } -/* eslint-enable cdk/no-core-construct */ +/* eslint-enable @aws-cdk/no-core-construct */ diff --git a/packages/@aws-cdk/aws-codestar/.eslintrc.js b/packages/@aws-cdk/aws-codestar/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-codestar/.eslintrc.js +++ b/packages/@aws-cdk/aws-codestar/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codestar/jest.config.js b/packages/@aws-cdk/aws-codestar/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-codestar/jest.config.js +++ b/packages/@aws-cdk/aws-codestar/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codestar/package.json b/packages/@aws-cdk/aws-codestar/package.json index 7740100ab9d29..40edf4f9fe7a6 100644 --- a/packages/@aws-cdk/aws-codestar/package.json +++ b/packages/@aws-cdk/aws-codestar/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::CodeStar", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -76,11 +75,11 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-s3": "0.0.0", diff --git a/packages/@aws-cdk/aws-codestarconnections/.eslintrc.js b/packages/@aws-cdk/aws-codestarconnections/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-codestarconnections/.eslintrc.js +++ b/packages/@aws-cdk/aws-codestarconnections/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codestarconnections/jest.config.js b/packages/@aws-cdk/aws-codestarconnections/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-codestarconnections/jest.config.js +++ b/packages/@aws-cdk/aws-codestarconnections/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codestarconnections/package.json b/packages/@aws-cdk/aws-codestarconnections/package.json index 76e45df893762..4c60595599eb8 100644 --- a/packages/@aws-cdk/aws-codestarconnections/package.json +++ b/packages/@aws-cdk/aws-codestarconnections/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::CodeStarConnections", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-codestarnotifications/.eslintrc.js b/packages/@aws-cdk/aws-codestarnotifications/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-codestarnotifications/.eslintrc.js +++ b/packages/@aws-cdk/aws-codestarnotifications/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codestarnotifications/jest.config.js b/packages/@aws-cdk/aws-codestarnotifications/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-codestarnotifications/jest.config.js +++ b/packages/@aws-cdk/aws-codestarnotifications/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-codestarnotifications/package.json b/packages/@aws-cdk/aws-codestarnotifications/package.json index 81460dd341e68..ec43414e43e45 100644 --- a/packages/@aws-cdk/aws-codestarnotifications/package.json +++ b/packages/@aws-cdk/aws-codestarnotifications/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::CodeStarNotifications", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,12 +74,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-cognito/.eslintrc.js b/packages/@aws-cdk/aws-cognito/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-cognito/.eslintrc.js +++ b/packages/@aws-cdk/aws-cognito/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cognito/jest.config.js b/packages/@aws-cdk/aws-cognito/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-cognito/jest.config.js +++ b/packages/@aws-cdk/aws-cognito/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cognito/package.json b/packages/@aws-cdk/aws-cognito/package.json index 56cd465f17680..8b280b238a8d4 100644 --- a/packages/@aws-cdk/aws-cognito/package.json +++ b/packages/@aws-cdk/aws-cognito/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::Cognito", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,14 +72,14 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", "@types/punycode": "^2.1.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", diff --git a/packages/@aws-cdk/aws-config/.eslintrc.js b/packages/@aws-cdk/aws-config/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-config/.eslintrc.js +++ b/packages/@aws-cdk/aws-config/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-config/jest.config.js b/packages/@aws-cdk/aws-config/jest.config.js index f5d5c4c8ad18f..34818e1593f6b 100644 --- a/packages/@aws-cdk/aws-config/jest.config.js +++ b/packages/@aws-cdk/aws-config/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); -module.exports = baseConfig; \ No newline at end of file +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-config/lib/rule.ts b/packages/@aws-cdk/aws-config/lib/rule.ts index 05ecebe7d93e5..e1ac4d107ec9e 100644 --- a/packages/@aws-cdk/aws-config/lib/rule.ts +++ b/packages/@aws-cdk/aws-config/lib/rule.ts @@ -355,6 +355,7 @@ export class CustomRule extends RuleNew { props.lambdaFunction.addPermission('Permission', { principal: new iam.ServicePrincipal('config.amazonaws.com'), + sourceAccount: this.env.account, }); if (props.lambdaFunction.role) { diff --git a/packages/@aws-cdk/aws-config/package.json b/packages/@aws-cdk/aws-config/package.json index ee4205b4d9241..1f6458201763a 100644 --- a/packages/@aws-cdk/aws-config/package.json +++ b/packages/@aws-cdk/aws-config/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::Config", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,14 +72,14 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-events-targets": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-events": "0.0.0", diff --git a/packages/@aws-cdk/aws-config/test/integ.rule.lit.expected.json b/packages/@aws-cdk/aws-config/test/integ.rule.lit.expected.json index 234f54351bcd1..172382853b95f 100644 --- a/packages/@aws-cdk/aws-config/test/integ.rule.lit.expected.json +++ b/packages/@aws-cdk/aws-config/test/integ.rule.lit.expected.json @@ -72,7 +72,10 @@ "Arn" ] }, - "Principal": "config.amazonaws.com" + "Principal": "config.amazonaws.com", + "SourceAccount": { + "Ref": "AWS::AccountId" + } } }, "Custom8166710A": { @@ -221,4 +224,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-config/test/integ.scoped-rule.expected.json b/packages/@aws-cdk/aws-config/test/integ.scoped-rule.expected.json index 99d314d0c45af..fced1ede4a8f5 100644 --- a/packages/@aws-cdk/aws-config/test/integ.scoped-rule.expected.json +++ b/packages/@aws-cdk/aws-config/test/integ.scoped-rule.expected.json @@ -72,7 +72,10 @@ "Arn" ] }, - "Principal": "config.amazonaws.com" + "Principal": "config.amazonaws.com", + "SourceAccount": { + "Ref": "AWS::AccountId" + } } }, "Custom8166710A": { @@ -106,4 +109,4 @@ ] } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-config/test/rule.test.ts b/packages/@aws-cdk/aws-config/test/rule.test.ts index 77599b8d95308..259727982a330 100644 --- a/packages/@aws-cdk/aws-config/test/rule.test.ts +++ b/packages/@aws-cdk/aws-config/test/rule.test.ts @@ -101,6 +101,9 @@ describe('rule', () => { expect(stack).toHaveResource('AWS::Lambda::Permission', { Principal: 'config.amazonaws.com', + SourceAccount: { + Ref: 'AWS::AccountId', + }, }); expect(stack).toHaveResource('AWS::IAM::Role', { diff --git a/packages/@aws-cdk/aws-connect/.eslintrc.js b/packages/@aws-cdk/aws-connect/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-connect/.eslintrc.js +++ b/packages/@aws-cdk/aws-connect/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-connect/jest.config.js b/packages/@aws-cdk/aws-connect/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-connect/jest.config.js +++ b/packages/@aws-cdk/aws-connect/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-connect/package.json b/packages/@aws-cdk/aws-connect/package.json index 93d08397cf375..d1ec993751e42 100644 --- a/packages/@aws-cdk/aws-connect/package.json +++ b/packages/@aws-cdk/aws-connect/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::Connect", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-cur/.eslintrc.js b/packages/@aws-cdk/aws-cur/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-cur/.eslintrc.js +++ b/packages/@aws-cdk/aws-cur/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cur/jest.config.js b/packages/@aws-cdk/aws-cur/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-cur/jest.config.js +++ b/packages/@aws-cdk/aws-cur/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cur/package.json b/packages/@aws-cdk/aws-cur/package.json index 8969e73dc4399..73ce922bae440 100644 --- a/packages/@aws-cdk/aws-cur/package.json +++ b/packages/@aws-cdk/aws-cur/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::CUR", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-customerprofiles/.eslintrc.js b/packages/@aws-cdk/aws-customerprofiles/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-customerprofiles/.eslintrc.js +++ b/packages/@aws-cdk/aws-customerprofiles/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-customerprofiles/jest.config.js b/packages/@aws-cdk/aws-customerprofiles/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-customerprofiles/jest.config.js +++ b/packages/@aws-cdk/aws-customerprofiles/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-customerprofiles/package.json b/packages/@aws-cdk/aws-customerprofiles/package.json index 36ccdda69b39d..b05870683b8bf 100644 --- a/packages/@aws-cdk/aws-customerprofiles/package.json +++ b/packages/@aws-cdk/aws-customerprofiles/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::CustomerProfiles", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -78,10 +77,10 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-databrew/.eslintrc.js b/packages/@aws-cdk/aws-databrew/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-databrew/.eslintrc.js +++ b/packages/@aws-cdk/aws-databrew/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-databrew/jest.config.js b/packages/@aws-cdk/aws-databrew/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-databrew/jest.config.js +++ b/packages/@aws-cdk/aws-databrew/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-databrew/package.json b/packages/@aws-cdk/aws-databrew/package.json index bf710a7394d74..9c9ae300c4044 100644 --- a/packages/@aws-cdk/aws-databrew/package.json +++ b/packages/@aws-cdk/aws-databrew/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::DataBrew", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-datapipeline/.eslintrc.js b/packages/@aws-cdk/aws-datapipeline/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-datapipeline/.eslintrc.js +++ b/packages/@aws-cdk/aws-datapipeline/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-datapipeline/jest.config.js b/packages/@aws-cdk/aws-datapipeline/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-datapipeline/jest.config.js +++ b/packages/@aws-cdk/aws-datapipeline/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-datapipeline/package.json b/packages/@aws-cdk/aws-datapipeline/package.json index b0c4cf9bf3218..9c4e850b6f90c 100644 --- a/packages/@aws-cdk/aws-datapipeline/package.json +++ b/packages/@aws-cdk/aws-datapipeline/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::DataPipeline", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-datasync/.eslintrc.js b/packages/@aws-cdk/aws-datasync/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-datasync/.eslintrc.js +++ b/packages/@aws-cdk/aws-datasync/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-datasync/jest.config.js b/packages/@aws-cdk/aws-datasync/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-datasync/jest.config.js +++ b/packages/@aws-cdk/aws-datasync/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-datasync/package.json b/packages/@aws-cdk/aws-datasync/package.json index 3ec205f0d6ee1..80db2e21342e6 100644 --- a/packages/@aws-cdk/aws-datasync/package.json +++ b/packages/@aws-cdk/aws-datasync/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::DataSync", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-dax/.eslintrc.js b/packages/@aws-cdk/aws-dax/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-dax/.eslintrc.js +++ b/packages/@aws-cdk/aws-dax/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-dax/jest.config.js b/packages/@aws-cdk/aws-dax/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-dax/jest.config.js +++ b/packages/@aws-cdk/aws-dax/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-dax/package.json b/packages/@aws-cdk/aws-dax/package.json index 82d88fd70d8d1..e7cc80850e2a6 100644 --- a/packages/@aws-cdk/aws-dax/package.json +++ b/packages/@aws-cdk/aws-dax/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::DAX", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-detective/.eslintrc.js b/packages/@aws-cdk/aws-detective/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-detective/.eslintrc.js +++ b/packages/@aws-cdk/aws-detective/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-detective/jest.config.js b/packages/@aws-cdk/aws-detective/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-detective/jest.config.js +++ b/packages/@aws-cdk/aws-detective/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-detective/package.json b/packages/@aws-cdk/aws-detective/package.json index 3955b883cb2bf..4e7eb64080103 100644 --- a/packages/@aws-cdk/aws-detective/package.json +++ b/packages/@aws-cdk/aws-detective/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Detective", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-devopsguru/.eslintrc.js b/packages/@aws-cdk/aws-devopsguru/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-devopsguru/.eslintrc.js +++ b/packages/@aws-cdk/aws-devopsguru/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-devopsguru/jest.config.js b/packages/@aws-cdk/aws-devopsguru/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-devopsguru/jest.config.js +++ b/packages/@aws-cdk/aws-devopsguru/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-devopsguru/package.json b/packages/@aws-cdk/aws-devopsguru/package.json index 9c9ff7fdb0228..0434c473a8862 100644 --- a/packages/@aws-cdk/aws-devopsguru/package.json +++ b/packages/@aws-cdk/aws-devopsguru/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::DevOpsGuru", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-directoryservice/.eslintrc.js b/packages/@aws-cdk/aws-directoryservice/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-directoryservice/.eslintrc.js +++ b/packages/@aws-cdk/aws-directoryservice/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-directoryservice/jest.config.js b/packages/@aws-cdk/aws-directoryservice/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-directoryservice/jest.config.js +++ b/packages/@aws-cdk/aws-directoryservice/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-directoryservice/package.json b/packages/@aws-cdk/aws-directoryservice/package.json index 1396430e3a34a..0f5d849fd4b1f 100644 --- a/packages/@aws-cdk/aws-directoryservice/package.json +++ b/packages/@aws-cdk/aws-directoryservice/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::DirectoryService", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-dlm/.eslintrc.js b/packages/@aws-cdk/aws-dlm/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-dlm/.eslintrc.js +++ b/packages/@aws-cdk/aws-dlm/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-dlm/jest.config.js b/packages/@aws-cdk/aws-dlm/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-dlm/jest.config.js +++ b/packages/@aws-cdk/aws-dlm/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-dlm/package.json b/packages/@aws-cdk/aws-dlm/package.json index 84fd44d939683..d8baae91ee532 100644 --- a/packages/@aws-cdk/aws-dlm/package.json +++ b/packages/@aws-cdk/aws-dlm/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::DLM", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -74,11 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-dms/.eslintrc.js b/packages/@aws-cdk/aws-dms/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-dms/.eslintrc.js +++ b/packages/@aws-cdk/aws-dms/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-dms/jest.config.js b/packages/@aws-cdk/aws-dms/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-dms/jest.config.js +++ b/packages/@aws-cdk/aws-dms/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-dms/package.json b/packages/@aws-cdk/aws-dms/package.json index d1ba735745e55..366911bc7129c 100644 --- a/packages/@aws-cdk/aws-dms/package.json +++ b/packages/@aws-cdk/aws-dms/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::DMS", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-docdb/.eslintrc.js b/packages/@aws-cdk/aws-docdb/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-docdb/.eslintrc.js +++ b/packages/@aws-cdk/aws-docdb/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-docdb/jest.config.js b/packages/@aws-cdk/aws-docdb/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-docdb/jest.config.js +++ b/packages/@aws-cdk/aws-docdb/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-docdb/package.json b/packages/@aws-cdk/aws-docdb/package.json index 472f2a229215c..cc8a7bb9802a3 100644 --- a/packages/@aws-cdk/aws-docdb/package.json +++ b/packages/@aws-cdk/aws-docdb/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::DocDB", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,24 +74,24 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { - "@aws-cdk/aws-efs": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/aws-efs": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "peerDependencies": { - "@aws-cdk/aws-efs": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/aws-efs": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-dynamodb-global/.eslintrc.js b/packages/@aws-cdk/aws-dynamodb-global/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/.eslintrc.js +++ b/packages/@aws-cdk/aws-dynamodb-global/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-dynamodb-global/jest.config.js b/packages/@aws-cdk/aws-dynamodb-global/jest.config.js index f5d5c4c8ad18f..34818e1593f6b 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/jest.config.js +++ b/packages/@aws-cdk/aws-dynamodb-global/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); -module.exports = baseConfig; \ No newline at end of file +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-dynamodb-global/lambda-packages/aws-global-table-coordinator/package.json b/packages/@aws-cdk/aws-dynamodb-global/lambda-packages/aws-global-table-coordinator/package.json index 130fed06d99c7..3893d9f854cee 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/lambda-packages/aws-global-table-coordinator/package.json +++ b/packages/@aws-cdk/aws-dynamodb-global/lambda-packages/aws-global-table-coordinator/package.json @@ -1,5 +1,5 @@ { - "name": "aws-global-lambda-coordinator", + "name": "@aws-cdk/aws-global-lambda-coordinator", "private": true, "version": "0.0.0", "description": "This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project.", @@ -30,15 +30,15 @@ "license": "Apache-2.0", "devDependencies": { "aws-sdk": "^2.596.0", - "aws-sdk-mock": "^5.2.1", - "eslint": "^7.31.0", + "aws-sdk-mock": "^5.4.0", + "eslint": "^7.32.0", "eslint-config-standard": "^14.1.1", - "eslint-plugin-import": "^2.23.4", + "eslint-plugin-import": "^2.24.2", "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^4.3.1", "eslint-plugin-standard": "^4.1.0", "jest": "^26.6.3", "lambda-tester": "^3.6.0", - "nock": "^13.1.1" + "nock": "^13.1.3" } } diff --git a/packages/@aws-cdk/aws-dynamodb-global/package.json b/packages/@aws-cdk/aws-dynamodb-global/package.json index 4f55047bb9b95..4c0f401086469 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/package.json +++ b/packages/@aws-cdk/aws-dynamodb-global/package.json @@ -41,9 +41,6 @@ }, "projectReferences": true }, - "cdk-build": { - "jest": true - }, "keywords": [ "aws", "cdk", @@ -59,12 +56,12 @@ "constructs": "^3.3.69" }, "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "peerDependencies": { "@aws-cdk/aws-dynamodb": "0.0.0", diff --git a/packages/@aws-cdk/aws-dynamodb/.eslintrc.js b/packages/@aws-cdk/aws-dynamodb/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-dynamodb/.eslintrc.js +++ b/packages/@aws-cdk/aws-dynamodb/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-dynamodb/jest.config.js b/packages/@aws-cdk/aws-dynamodb/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-dynamodb/jest.config.js +++ b/packages/@aws-cdk/aws-dynamodb/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-dynamodb/package.json b/packages/@aws-cdk/aws-dynamodb/package.json index e6d4627e3455e..71428a04816cf 100644 --- a/packages/@aws-cdk/aws-dynamodb/package.json +++ b/packages/@aws-cdk/aws-dynamodb/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::DynamoDB", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,19 +72,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/aws-lambda": "^8.10.79", + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/aws-lambda": "^8.10.83", "@types/jest": "^26.0.24", "@types/sinon": "^9.0.11", "aws-sdk": "^2.848.0", - "aws-sdk-mock": "^5.2.1", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", + "aws-sdk-mock": "^5.4.0", "jest": "^26.6.3", - "pkglint": "0.0.0", "sinon": "^9.2.4", - "ts-jest": "^26.5.6", - "@aws-cdk/assert-internal": "0.0.0" + "ts-jest": "^26.5.6" }, "dependencies": { "@aws-cdk/aws-applicationautoscaling": "0.0.0", diff --git a/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts b/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts index 9ca717c46b8da..56ab48f19f501 100644 --- a/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts +++ b/packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts @@ -6,7 +6,7 @@ import * as kinesis from '@aws-cdk/aws-kinesis'; import * as kms from '@aws-cdk/aws-kms'; import { App, Aws, CfnDeletionPolicy, ConstructNode, Duration, PhysicalName, RemovalPolicy, Resource, Stack, Tags } from '@aws-cdk/core'; import * as cr from '@aws-cdk/custom-resources'; -import { testLegacyBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testLegacyBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import { Construct } from 'constructs'; import { Attribute, diff --git a/packages/@aws-cdk/aws-ec2/.eslintrc.js b/packages/@aws-cdk/aws-ec2/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-ec2/.eslintrc.js +++ b/packages/@aws-cdk/aws-ec2/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ec2/jest.config.js b/packages/@aws-cdk/aws-ec2/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-ec2/jest.config.js +++ b/packages/@aws-cdk/aws-ec2/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ec2/lib/cfn-init.ts b/packages/@aws-cdk/aws-ec2/lib/cfn-init.ts index 78b3345743347..860e37001dd68 100644 --- a/packages/@aws-cdk/aws-ec2/lib/cfn-init.ts +++ b/packages/@aws-cdk/aws-ec2/lib/cfn-init.ts @@ -125,14 +125,19 @@ export class CloudFormationInit { // To identify the resources that have the metadata and where the signal // needs to be sent, we need { region, stackName, logicalId } let resourceLocator = `--region ${Aws.REGION} --stack ${Aws.STACK_NAME} --resource ${attachedResource.logicalId}`; + const signalResource = attachOptions.signalResource?.logicalId ?? attachedResource.logicalId; + let notifyResourceLocator = `--region ${Aws.REGION} --stack ${Aws.STACK_NAME} --resource ${signalResource}`; // If specified in attachOptions, include arguments in cfn-init/cfn-signal commands if (attachOptions.includeUrl) { resourceLocator = `${resourceLocator} --url https://cloudformation.${Aws.REGION}.${Aws.URL_SUFFIX}`; + notifyResourceLocator = `${notifyResourceLocator} --url https://cloudformation.${Aws.REGION}.${Aws.URL_SUFFIX}`; } if (attachOptions.includeRole) { - resourceLocator = `${resourceLocator} --role ${attachOptions.instanceRole}`; + resourceLocator = `${resourceLocator} --role ${attachOptions.instanceRole.roleName}`; + notifyResourceLocator = `${notifyResourceLocator} --role ${attachOptions.instanceRole.roleName}`; } + const configSets = (attachOptions.configSets ?? ['default']).join(','); const printLog = attachOptions.printLog ?? true; @@ -143,22 +148,26 @@ export class CloudFormationInit { if (attachOptions.platform === OperatingSystemType.WINDOWS) { const errCode = attachOptions.ignoreFailures ? '0' : '$LASTEXITCODE'; - attachOptions.userData.addCommands(...[ - `cfn-init.exe -v ${resourceLocator} -c ${configSets}`, - `cfn-signal.exe -e ${errCode} ${resourceLocator}`, - ...printLog ? ['type C:\\cfn\\log\\cfn-init.log'] : [], - ]); + attachOptions.userData.addCommands( + ...[ + `cfn-init.exe -v ${resourceLocator} -c ${configSets}`, + `cfn-signal.exe -e ${errCode} ${notifyResourceLocator}`, + ...(printLog ? ['type C:\\cfn\\log\\cfn-init.log'] : []), + ], + ); } else { const errCode = attachOptions.ignoreFailures ? '0' : '$?'; - attachOptions.userData.addCommands(...[ - // Run a subshell without 'errexit', so we can signal using the exit code of cfn-init - '(', - ' set +e', - ` /opt/aws/bin/cfn-init -v ${resourceLocator} -c ${configSets}`, - ` /opt/aws/bin/cfn-signal -e ${errCode} ${resourceLocator}`, - ...printLog ? [' cat /var/log/cfn-init.log >&2'] : [], - ')', - ]); + attachOptions.userData.addCommands( + ...[ + // Run a subshell without 'errexit', so we can signal using the exit code of cfn-init + '(', + ' set +e', + ` /opt/aws/bin/cfn-init -v ${resourceLocator} -c ${configSets}`, + ` /opt/aws/bin/cfn-signal -e ${errCode} ${notifyResourceLocator}`, + ...(printLog ? [' cat /var/log/cfn-init.log >&2'] : []), + ')', + ], + ); } } @@ -428,4 +437,13 @@ export interface AttachInitOptions { * @default false */ readonly ignoreFailures?: boolean; + + /** + * When provided, signals this resource instead of the attached resource + * + * You can use this to support signaling LaunchTemplate while attaching AutoScalingGroup + * + * @default - if this property is undefined cfn-signal signals the attached resource + */ + readonly signalResource?: CfnResource; } diff --git a/packages/@aws-cdk/aws-ec2/lib/security-group.ts b/packages/@aws-cdk/aws-ec2/lib/security-group.ts index 90613e3904475..2c01da7aef943 100644 --- a/packages/@aws-cdk/aws-ec2/lib/security-group.ts +++ b/packages/@aws-cdk/aws-ec2/lib/security-group.ts @@ -382,6 +382,7 @@ export class SecurityGroup extends SecurityGroupBase { * An attribute that represents the security group name. * * @attribute + * @deprecated returns the security group ID, rather than the name. */ public readonly securityGroupName: string; diff --git a/packages/@aws-cdk/aws-ec2/package.json b/packages/@aws-cdk/aws-ec2/package.json index 6bb38a38ece94..1124e2d561741 100644 --- a/packages/@aws-cdk/aws-ec2/package.json +++ b/packages/@aws-cdk/aws-ec2/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::EC2", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -73,16 +72,16 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/aws-lambda": "^8.10.79", - "@types/jest": "^26.0.24", - "@aws-cdk/cx-api": "0.0.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/cx-api": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/aws-lambda": "^8.10.83", + "@types/jest": "^26.0.24", + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", @@ -107,9 +106,9 @@ "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", + "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/region-info": "0.0.0", "constructs": "^3.3.69" }, diff --git a/packages/@aws-cdk/aws-ec2/test/cfn-init.test.ts b/packages/@aws-cdk/aws-ec2/test/cfn-init.test.ts index e2539b71ac223..37d4fe2d72d28 100644 --- a/packages/@aws-cdk/aws-ec2/test/cfn-init.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/cfn-init.test.ts @@ -14,6 +14,7 @@ let stack: Stack; let instanceRole: iam.Role; let resource: CfnResource; let linuxUserData: ec2.UserData; +let signalResource: CfnResource; function resetState() { resetStateWithSynthesizer(); @@ -31,6 +32,9 @@ function resetStateWithSynthesizer(customSynthesizer?: IStackSynthesizer) { resource = new CfnResource(stack, 'Resource', { type: 'CDK::Test::Resource', }); + signalResource = new CfnResource(stack, 'SignalResource', { + type: 'CDK::Test::Resource', + }); linuxUserData = ec2.UserData.forLinux(); }; @@ -135,11 +139,7 @@ describe('userdata', () => { ); }); - test('linux userdata contains right commands', () => { - // WHEN - simpleInit.attach(resource, linuxOptions()); - - // THEN + function linuxUserDataTest(signalLogicalId: string) { const lines = linuxUserData.render().split('\n'); expectLine(lines, cmdArg('cfn-init', `--region ${Aws.REGION}`)); expectLine(lines, cmdArg('cfn-init', `--stack ${Aws.STACK_NAME}`)); @@ -147,10 +147,46 @@ describe('userdata', () => { expectLine(lines, cmdArg('cfn-init', '-c default')); expectLine(lines, cmdArg('cfn-signal', `--region ${Aws.REGION}`)); expectLine(lines, cmdArg('cfn-signal', `--stack ${Aws.STACK_NAME}`)); - expectLine(lines, cmdArg('cfn-signal', `--resource ${resource.logicalId}`)); + expectLine(lines, cmdArg('cfn-signal', `--resource ${signalLogicalId}`)); expectLine(lines, cmdArg('cfn-signal', '-e $?')); expectLine(lines, cmdArg('cat', 'cfn-init.log')); expectLine(lines, /fingerprint/); + } + + function windowsUserDataTest( + windowsUserData: ec2.UserData, + signalLogicalId: string, + ) { + const lines = windowsUserData.render().split('\n'); + expectLine(lines, cmdArg('cfn-init', `--region ${Aws.REGION}`)); + expectLine(lines, cmdArg('cfn-init', `--stack ${Aws.STACK_NAME}`)); + expectLine(lines, cmdArg('cfn-init', `--resource ${resource.logicalId}`)); + expectLine(lines, cmdArg('cfn-init', '-c default')); + expectLine(lines, cmdArg('cfn-signal', `--region ${Aws.REGION}`)); + expectLine(lines, cmdArg('cfn-signal', `--stack ${Aws.STACK_NAME}`)); + expectLine(lines, cmdArg('cfn-signal', `--resource ${signalLogicalId}`)); + expectLine(lines, cmdArg('cfn-signal', '-e $LASTEXITCODE')); + expectLine(lines, cmdArg('type', 'cfn-init.log')); + expectLine(lines, /fingerprint/); + } + + test('linux userdata contains right commands', () => { + // WHEN + simpleInit.attach(resource, linuxOptions()); + + // THEN + linuxUserDataTest(resource.logicalId); + }); + + test('linux userdata contains right commands with different signal resource', () => { + // WHEN + simpleInit.attach(resource, { + ...linuxOptions(), + signalResource, + }); + + // THEN + linuxUserDataTest(signalResource.logicalId); }); test('linux userdata contains right commands when url and role included', () => { @@ -168,13 +204,13 @@ describe('userdata', () => { expectLine(lines, cmdArg('cfn-init', `--region ${Aws.REGION}`)); expectLine(lines, cmdArg('cfn-init', `--stack ${Aws.STACK_NAME}`)); expectLine(lines, cmdArg('cfn-init', `--resource ${resource.logicalId}`)); - expectLine(lines, cmdArg('cfn-init', `--role ${instanceRole}`)); + expectLine(lines, cmdArg('cfn-init', `--role ${instanceRole.roleName}`)); expectLine(lines, cmdArg('cfn-init', `--url https://cloudformation.${Aws.REGION}.${Aws.URL_SUFFIX}`)); expectLine(lines, cmdArg('cfn-init', '-c default')); expectLine(lines, cmdArg('cfn-signal', `--region ${Aws.REGION}`)); expectLine(lines, cmdArg('cfn-signal', `--stack ${Aws.STACK_NAME}`)); expectLine(lines, cmdArg('cfn-signal', `--resource ${resource.logicalId}`)); - expectLine(lines, cmdArg('cfn-init', `--role ${instanceRole}`)); + expectLine(lines, cmdArg('cfn-init', `--role ${instanceRole.roleName}`)); expectLine(lines, cmdArg('cfn-init', `--url https://cloudformation.${Aws.REGION}.${Aws.URL_SUFFIX}`)); expectLine(lines, cmdArg('cfn-signal', '-e $?')); expectLine(lines, cmdArg('cat', 'cfn-init.log')); @@ -192,17 +228,22 @@ describe('userdata', () => { }); // THEN - const lines = windowsUserData.render().split('\n'); - expectLine(lines, cmdArg('cfn-init', `--region ${Aws.REGION}`)); - expectLine(lines, cmdArg('cfn-init', `--stack ${Aws.STACK_NAME}`)); - expectLine(lines, cmdArg('cfn-init', `--resource ${resource.logicalId}`)); - expectLine(lines, cmdArg('cfn-init', '-c default')); - expectLine(lines, cmdArg('cfn-signal', `--region ${Aws.REGION}`)); - expectLine(lines, cmdArg('cfn-signal', `--stack ${Aws.STACK_NAME}`)); - expectLine(lines, cmdArg('cfn-signal', `--resource ${resource.logicalId}`)); - expectLine(lines, cmdArg('cfn-signal', '-e $LASTEXITCODE')); - expectLine(lines, cmdArg('type', 'cfn-init.log')); - expectLine(lines, /fingerprint/); + windowsUserDataTest(windowsUserData, resource.logicalId); + }); + + test('Windows userdata contains right commands with different signal resource', () => { + // WHEN + const windowsUserData = ec2.UserData.forWindows(); + + simpleInit.attach(resource, { + platform: ec2.OperatingSystemType.WINDOWS, + instanceRole, + userData: windowsUserData, + signalResource, + }); + + // THEN + windowsUserDataTest(windowsUserData, signalResource.logicalId); }); test('ignoreFailures disables result code reporting', () => { diff --git a/packages/@aws-cdk/aws-ec2/test/volume.test.ts b/packages/@aws-cdk/aws-ec2/test/volume.test.ts index d33acadc3f8dc..4ac7874c701d2 100644 --- a/packages/@aws-cdk/aws-ec2/test/volume.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/volume.test.ts @@ -10,7 +10,7 @@ import { import * as kms from '@aws-cdk/aws-kms'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior, testLegacyBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior, testLegacyBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import { AmazonLinuxGeneration, EbsDeviceVolumeType, diff --git a/packages/@aws-cdk/aws-ecr-assets/.eslintrc.js b/packages/@aws-cdk/aws-ecr-assets/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-ecr-assets/.eslintrc.js +++ b/packages/@aws-cdk/aws-ecr-assets/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ecr-assets/README.md b/packages/@aws-cdk/aws-ecr-assets/README.md index f5993097418ac..8221fe8091d14 100644 --- a/packages/@aws-cdk/aws-ecr-assets/README.md +++ b/packages/@aws-cdk/aws-ecr-assets/README.md @@ -14,8 +14,8 @@ This module allows bundling Docker images as assets. ## Images from Dockerfile Images are built from a local Docker context directory (with a `Dockerfile`), -uploaded to ECR by the CDK toolkit and/or your app's CI-CD pipeline, and can be -naturally referenced in your CDK app. +uploaded to Amazon Elastic Container Registry (ECR) by the CDK toolkit +and/or your app's CI/CD pipeline, and can be naturally referenced in your CDK app. ```ts import { DockerImageAsset } from '@aws-cdk/aws-ecr-assets'; @@ -28,7 +28,7 @@ const asset = new DockerImageAsset(this, 'MyBuildImage', { The directory `my-image` must include a `Dockerfile`. This will instruct the toolkit to build a Docker image from `my-image`, push it -to an AWS ECR repository and wire the name of the repository as CloudFormation +to an Amazon ECR repository and wire the name of the repository as CloudFormation parameters to your stack. By default, all files in the given directory will be copied into the docker @@ -85,7 +85,7 @@ const asset = new TarballImageAsset(this, 'MyBuildImage', { ``` This will instruct the toolkit to add the tarball as a file asset. During deployment it will load the container image -from `local-image.tar`, push it to an AWS ECR repository and wire the name of the repository as CloudFormation parameters +from `local-image.tar`, push it to an Amazon ECR repository and wire the name of the repository as CloudFormation parameters to your stack. ## Publishing images to ECR repositories diff --git a/packages/@aws-cdk/aws-ecr-assets/jest.config.js b/packages/@aws-cdk/aws-ecr-assets/jest.config.js index 12d0151b1bb3b..45db604d94785 100644 --- a/packages/@aws-cdk/aws-ecr-assets/jest.config.js +++ b/packages/@aws-cdk/aws-ecr-assets/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/aws-ecr-assets/package.json b/packages/@aws-cdk/aws-ecr-assets/package.json index 44f7a2d4ffa7c..b6b407041eda6 100644 --- a/packages/@aws-cdk/aws-ecr-assets/package.json +++ b/packages/@aws-cdk/aws-ecr-assets/package.json @@ -65,32 +65,32 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cloud-assembly-schema": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", "@types/proxyquire": "^1.3.28", "aws-cdk": "0.0.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0", - "proxyquire": "^2.1.3", - "@aws-cdk/cloud-assembly-schema": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "proxyquire": "^2.1.3" }, "dependencies": { + "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-ecr": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", - "@aws-cdk/assets": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "minimatch": "^3.0.4", - "constructs": "^3.3.69" + "constructs": "^3.3.69", + "minimatch": "^3.0.4" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { + "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-ecr": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", - "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", @@ -111,7 +111,6 @@ "announce": false }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-ecr-assets/test/image-asset.test.ts b/packages/@aws-cdk/aws-ecr-assets/test/image-asset.test.ts index e156209458878..667a2ba9d0145 100644 --- a/packages/@aws-cdk/aws-ecr-assets/test/image-asset.test.ts +++ b/packages/@aws-cdk/aws-ecr-assets/test/image-asset.test.ts @@ -5,7 +5,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import { App, DefaultStackSynthesizer, IgnoreMode, Lazy, LegacyStackSynthesizer, Stack, Stage } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import { DockerImageAsset } from '../lib'; /* eslint-disable quote-props */ diff --git a/packages/@aws-cdk/aws-ecr-assets/test/tarball-asset.test.ts b/packages/@aws-cdk/aws-ecr-assets/test/tarball-asset.test.ts index 20d7517e23915..77e22f20dca9d 100644 --- a/packages/@aws-cdk/aws-ecr-assets/test/tarball-asset.test.ts +++ b/packages/@aws-cdk/aws-ecr-assets/test/tarball-asset.test.ts @@ -5,7 +5,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as cxschema from '@aws-cdk/cloud-assembly-schema'; import { App, Stack } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import { TarballImageAsset } from '../lib'; /* eslint-disable quote-props */ diff --git a/packages/@aws-cdk/aws-ecr/.eslintrc.js b/packages/@aws-cdk/aws-ecr/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-ecr/.eslintrc.js +++ b/packages/@aws-cdk/aws-ecr/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ecr/jest.config.js b/packages/@aws-cdk/aws-ecr/jest.config.js index 07a010c639ba8..f4f042f9d2c29 100644 --- a/packages/@aws-cdk/aws-ecr/jest.config.js +++ b/packages/@aws-cdk/aws-ecr/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/aws-ecr/package.json b/packages/@aws-cdk/aws-ecr/package.json index d2eecfc93b1ba..1884a03470d31 100644 --- a/packages/@aws-cdk/aws-ecr/package.json +++ b/packages/@aws-cdk/aws-ecr/package.json @@ -57,8 +57,7 @@ "cloudformation": "AWS::ECR", "env": { "AWSLINT_BASE_CONSTRUCT": true - }, - "jest": true + } }, "nyc": { "lines": 78, @@ -78,11 +77,11 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert-internal": "0.0.0", - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-events": "0.0.0", diff --git a/packages/@aws-cdk/aws-ecs-patterns/.eslintrc.js b/packages/@aws-cdk/aws-ecs-patterns/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/.eslintrc.js +++ b/packages/@aws-cdk/aws-ecs-patterns/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ecs-patterns/.gitignore b/packages/@aws-cdk/aws-ecs-patterns/.gitignore index dcc1dc41e477f..17a41566f0002 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/.gitignore +++ b/packages/@aws-cdk/aws-ecs-patterns/.gitignore @@ -15,4 +15,5 @@ nyc.config.js *.snk !.eslintrc.js -junit.xml \ No newline at end of file +junit.xml +!jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs-patterns/.npmignore b/packages/@aws-cdk/aws-ecs-patterns/.npmignore index 9a032ae80868c..e8acf10a468a1 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/.npmignore +++ b/packages/@aws-cdk/aws-ecs-patterns/.npmignore @@ -24,4 +24,5 @@ tsconfig.json **/cdk.out junit.xml test/ -!*.lit.ts \ No newline at end of file +!*.lit.ts +jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs-patterns/jest.config.js b/packages/@aws-cdk/aws-ecs-patterns/jest.config.js new file mode 100644 index 0000000000000..34818e1593f6b --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ecs-patterns/package.json b/packages/@aws-cdk/aws-ecs-patterns/package.json index c9d3b46b8f8b2..4e776d3b82cce 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/package.json +++ b/packages/@aws-cdk/aws-ecs-patterns/package.json @@ -65,14 +65,13 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/nodeunit": "^0.0.32", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "nodeunit": "^0.11.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-applicationautoscaling": "0.0.0", diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s-v2.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s-v2.test.ts new file mode 100644 index 0000000000000..575ab92b40cfb --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s-v2.test.ts @@ -0,0 +1,1481 @@ +import { SynthUtils } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +import { Certificate } from '@aws-cdk/aws-certificatemanager'; +import { InstanceType, Vpc } from '@aws-cdk/aws-ec2'; +import { AwsLogDriver, Cluster, ContainerImage, Ec2TaskDefinition, PropagatedTagSource, Protocol } from '@aws-cdk/aws-ecs'; +import { ApplicationProtocol, SslPolicy } from '@aws-cdk/aws-elasticloadbalancingv2'; +import { CompositePrincipal, Role, ServicePrincipal } from '@aws-cdk/aws-iam'; +import { PublicHostedZone } from '@aws-cdk/aws-route53'; +import { NamespaceType } from '@aws-cdk/aws-servicediscovery'; +import { Duration, Stack } from '@aws-cdk/core'; +import { ApplicationMultipleTargetGroupsEc2Service, NetworkMultipleTargetGroupsEc2Service } from '../../lib'; + +describe('When Application Load Balancer', () => { + test('test ECS ALB construct with default settings', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + // WHEN + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + }); + + // THEN - stack contains a load balancer, a service, and a target group. + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); + + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 1, + LaunchType: 'EC2', + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Image: 'test', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ServiceTaskDefwebLogGroup2A898F61', + }, + 'awslogs-stream-prefix': 'Service', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Memory: 1024, + Name: 'web', + PortMappings: [ + { + ContainerPort: 80, + HostPort: 0, + Protocol: 'tcp', + }, + ], + }, + ], + NetworkMode: 'bridge', + RequiresCompatibilities: [ + 'EC2', + ], + }); + }); + + test('test ECS ALB construct with all settings', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); + + // WHEN + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + containerName: 'myContainer', + containerPorts: [80, 90], + enableLogging: false, + environment: { + TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', + TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', + }, + logDriver: new AwsLogDriver({ + streamPrefix: 'TestStream', + }), + family: 'Ec2TaskDef', + executionRole: new Role(stack, 'ExecutionRole', { + path: '/', + assumedBy: new CompositePrincipal( + new ServicePrincipal('ecs.amazonaws.com'), + new ServicePrincipal('ecs-tasks.amazonaws.com'), + ), + }), + taskRole: new Role(stack, 'TaskRole', { + assumedBy: new ServicePrincipal('ecs-tasks.amazonaws.com'), + }), + dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, + }, + cpu: 256, + desiredCount: 3, + enableECSManagedTags: true, + healthCheckGracePeriod: Duration.millis(2000), + loadBalancers: [ + { + name: 'lb', + domainName: 'api.example.com', + domainZone: zone, + publicLoadBalancer: false, + listeners: [ + { + name: 'listener', + protocol: ApplicationProtocol.HTTPS, + certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), + sslPolicy: SslPolicy.TLS12_EXT, + }, + ], + }, + ], + propagateTags: PropagatedTagSource.SERVICE, + memoryReservationMiB: 1024, + serviceName: 'myService', + targetGroups: [ + { + containerPort: 80, + listener: 'listener', + }, + { + containerPort: 90, + listener: 'listener', + pathPattern: 'a/b/c', + priority: 10, + protocol: Protocol.TCP, + }, + ], + }); + + // THEN + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 3, + LaunchType: 'EC2', + EnableECSManagedTags: true, + HealthCheckGracePeriodSeconds: 2, + LoadBalancers: [ + { + ContainerName: 'myContainer', + ContainerPort: 80, + TargetGroupArn: { + Ref: 'ServicelblistenerECSTargetGroupmyContainer80GroupAD83584A', + }, + }, + { + ContainerName: 'myContainer', + ContainerPort: 90, + TargetGroupArn: { + Ref: 'ServicelblistenerECSTargetGroupmyContainer90GroupF5A6D3A0', + }, + }, + ], + PropagateTags: 'SERVICE', + ServiceName: 'myService', + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Cpu: 256, + Environment: [ + { + Name: 'TEST_ENVIRONMENT_VARIABLE1', + Value: 'test environment variable 1 value', + }, + { + Name: 'TEST_ENVIRONMENT_VARIABLE2', + Value: 'test environment variable 2 value', + }, + ], + Essential: true, + Image: 'test', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ServiceTaskDefmyContainerLogGroup0A87368B', + }, + 'awslogs-stream-prefix': 'TestStream', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Memory: 1024, + MemoryReservation: 1024, + Name: 'myContainer', + PortMappings: [ + { + ContainerPort: 80, + HostPort: 0, + Protocol: 'tcp', + }, + { + ContainerPort: 90, + HostPort: 0, + Protocol: 'tcp', + }, + ], + DockerLabels: { + label1: 'labelValue1', + label2: 'labelValue2', + }, + }, + ], + ExecutionRoleArn: { + 'Fn::GetAtt': [ + 'ExecutionRole605A040B', + 'Arn', + ], + }, + Family: 'ServiceTaskDef79D79521', + NetworkMode: 'bridge', + RequiresCompatibilities: [ + 'EC2', + ], + TaskRoleArn: { + 'Fn::GetAtt': [ + 'TaskRole30FC0FBB', + 'Arn', + ], + }, + }); + + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { + Port: 443, + Protocol: 'HTTPS', + Certificates: [{ + CertificateArn: 'helloworld', + }], + SslPolicy: SslPolicy.TLS12_EXT, + }); + }); + + test('set vpc instead of cluster', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + + // WHEN + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + vpc, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + }); + + // THEN - stack does not contain a LaunchConfiguration + const template = SynthUtils.synthesize(stack, { skipValidation: true }); + expect(template).not.toHaveResource('AWS::AutoScaling::LaunchConfiguration'); + expect(() => SynthUtils.synthesize(stack)).toThrow(); + }); + + test('able to pass pre-defined task definition', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + const taskDefinition = new Ec2TaskDefinition(stack, 'Ec2TaskDef'); + const container = taskDefinition.addContainer('web', { + image: ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + memoryLimitMiB: 512, + }); + container.addPortMappings({ + containerPort: 80, + }); + + // WHEN + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskDefinition, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Essential: true, + Image: 'amazon/amazon-ecs-sample', + Memory: 512, + Name: 'web', + PortMappings: [ + { + ContainerPort: 80, + HostPort: 0, + Protocol: 'tcp', + }, + ], + }, + ], + Family: 'Ec2TaskDef', + NetworkMode: 'bridge', + RequiresCompatibilities: [ + 'EC2', + ], + }); + }); + + test('able to output correct load balancer DNS and URLs for each protocol type', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); + + // WHEN + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + loadBalancers: [ + { + name: 'lb1', + domainName: 'api.example.com', + domainZone: zone, + listeners: [ + { + name: 'listener1', + protocol: ApplicationProtocol.HTTPS, + certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), + }, + { + name: 'listener2', + protocol: ApplicationProtocol.HTTP, + }, + ], + }, + { + name: 'lb3', + listeners: [ + { + name: 'listener3', + protocol: ApplicationProtocol.HTTP, + }, + ], + }, + ], + targetGroups: [ + { + containerPort: 80, + listener: 'listener1', + }, + { + containerPort: 90, + listener: 'listener2', + }, + { + containerPort: 70, + listener: 'listener3', + }, + ], + }); + + // THEN + const template = SynthUtils.synthesize(stack).template.Outputs; + expect(template).toEqual({ + ServiceLoadBalancerDNSlb175E78BFE: { + Value: { + 'Fn::GetAtt': [ + 'Servicelb152C7F4F9', + 'DNSName', + ], + }, + }, + ServiceServiceURLlb1https5C0C4079: { + Value: { + 'Fn::Join': [ + '', + [ + 'https://', + { + Ref: 'ServiceDNSlb12BA1FAD3', + }, + ], + ], + }, + }, + ServiceServiceURLlb1http65F0546A: { + Value: { + 'Fn::Join': [ + '', + [ + 'http://', + { + Ref: 'ServiceDNSlb12BA1FAD3', + }, + ], + ], + }, + }, + ServiceLoadBalancerDNSlb32F273F27: { + Value: { + 'Fn::GetAtt': [ + 'Servicelb3A583D5E7', + 'DNSName', + ], + }, + }, + ServiceServiceURLlb3http40F9CADC: { + Value: { + 'Fn::Join': [ + '', + [ + 'http://', + { + 'Fn::GetAtt': [ + 'Servicelb3A583D5E7', + 'DNSName', + ], + }, + ], + ], + }, + }, + }); + }); + + test('errors if no essential container in pre-defined task definition', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + const taskDefinition = new Ec2TaskDefinition(stack, 'Ec2TaskDef'); + + // THEN + expect(() => { + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskDefinition, + }); + }).toThrow(/At least one essential container must be specified/); + }); + + test('set default load balancer, listener, target group correctly', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); + + // WHEN + const ecsService = new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + vpc, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + loadBalancers: [ + { + name: 'lb1', + listeners: [ + { + name: 'listener1', + }, + ], + }, + { + name: 'lb2', + domainName: 'api.example.com', + domainZone: zone, + listeners: [ + { + name: 'listener2', + }, + { + name: 'listener3', + protocol: ApplicationProtocol.HTTPS, + certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), + }, + ], + }, + ], + targetGroups: [ + { + containerPort: 80, + }, + { + containerPort: 90, + }, + ], + }); + + // THEN + expect(ecsService.loadBalancer.node.id).toEqual('lb1'); + expect(ecsService.listener.node.id).toEqual('listener1'); + expect(ecsService.targetGroup.node.id).toEqual('ECSTargetGroupweb80Group'); + }); + + test('setting vpc and cluster throws error', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + + // WHEN + expect(() => new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + vpc, + taskImageOptions: { + image: ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + })).toThrow(/You can only specify either vpc or cluster. Alternatively, you can leave both blank/); + }); + + test('creates AWS Cloud Map service for Private DNS namespace', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'MyVpc', {}); + const cluster = new Cluster(stack, 'EcsCluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + // WHEN + cluster.addDefaultCloudMapNamespace({ + name: 'foo.com', + type: NamespaceType.DNS_PRIVATE, + }); + + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('hello'), + }, + cloudMapOptions: { + name: 'myApp', + }, + memoryLimitMiB: 512, + }); + + // THEN + expect(stack).toHaveResource('AWS::ECS::Service', { + ServiceRegistries: [ + { + ContainerName: 'web', + ContainerPort: 80, + RegistryArn: { + 'Fn::GetAtt': [ + 'ServiceCloudmapServiceDE76B29D', + 'Arn', + ], + }, + }, + ], + }); + + expect(stack).toHaveResource('AWS::ServiceDiscovery::Service', { + DnsConfig: { + DnsRecords: [ + { + TTL: 60, + Type: 'SRV', + }, + ], + NamespaceId: { + 'Fn::GetAtt': [ + 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', + 'Id', + ], + }, + RoutingPolicy: 'MULTIVALUE', + }, + HealthCheckCustomConfig: { + FailureThreshold: 1, + }, + Name: 'myApp', + NamespaceId: { + 'Fn::GetAtt': [ + 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', + 'Id', + ], + }, + }); + }); + + test('errors when setting both taskDefinition and taskImageOptions', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + const taskDefinition = new Ec2TaskDefinition(stack, 'Ec2TaskDef'); + taskDefinition.addContainer('test', { + image: ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + memoryLimitMiB: 512, + }); + + // THEN + expect(() => { + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + taskDefinition, + }); + }).toThrow(/You must specify only one of TaskDefinition or TaskImageOptions./); + }); + + test('errors when setting neither taskDefinition nor taskImageOptions', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + // THEN + expect(() => { + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + }); + }).toThrow(/You must specify one of: taskDefinition or image/); + }); + + test('errors when setting domainName but not domainZone', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + // THEN + expect(() => { + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + loadBalancers: [ + { + name: 'lb1', + domainName: 'api.example.com', + listeners: [ + { + name: 'listener1', + }, + ], + }, + ], + }); + }).toThrow(/A Route53 hosted domain zone name is required to configure the specified domain name/); + }); + + test('errors when loadBalancers is empty', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + loadBalancers: [], + }); + }).toThrow(/At least one load balancer must be specified/); + }); + + test('errors when targetGroups is empty', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + targetGroups: [], + }); + }).toThrow(/At least one target group should be specified/); + }); + + test('errors when no listener specified', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + loadBalancers: [ + { + name: 'lb', + listeners: [], + }, + ], + }); + }).toThrow(/At least one listener must be specified/); + }); + + test('errors when setting both HTTP protocol and certificate', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + loadBalancers: [ + { + name: 'lb', + listeners: [ + { + name: 'listener', + protocol: ApplicationProtocol.HTTP, + certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), + }, + ], + }, + ], + }); + }).toThrow(/The HTTPS protocol must be used when a certificate is given/); + }); + + test('errors when setting HTTPS protocol but not domain name', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + loadBalancers: [ + { + name: 'lb', + listeners: [ + { + name: 'listener', + protocol: ApplicationProtocol.HTTPS, + }, + ], + }, + ], + }); + }).toThrow(/A domain name and zone is required when using the HTTPS protocol/); + }); + + test('errors when listener is not defined but used in creating target groups', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + loadBalancers: [ + { + name: 'lb', + listeners: [ + { + name: 'listener1', + }, + ], + }, + ], + targetGroups: [ + { + containerPort: 80, + listener: 'listener2', + }, + ], + }); + }).toThrow(/Listener listener2 is not defined. Did you define listener with name listener2?/); + }); + + test('errors if desiredTaskCount is 0', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + // THEN + expect(() => + new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + desiredCount: 0, + })).toThrow(/You must specify a desiredCount greater than 0/); + }); +}); + +describe('When Network Load Balancer', () => { + test('test ECS NLB construct with default settings', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + // WHEN + new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 256, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + }); + + // THEN - stack contains a load balancer and a service + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); + + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 1, + LaunchType: 'EC2', + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Essential: true, + Image: 'test', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ServiceTaskDefwebLogGroup2A898F61', + }, + 'awslogs-stream-prefix': 'Service', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Memory: 256, + Name: 'web', + PortMappings: [ + { + ContainerPort: 80, + HostPort: 0, + Protocol: 'tcp', + }, + ], + }, + ], + ExecutionRoleArn: { + 'Fn::GetAtt': [ + 'ServiceTaskDefExecutionRole919F7BE3', + 'Arn', + ], + }, + Family: 'ServiceTaskDef79D79521', + NetworkMode: 'bridge', + RequiresCompatibilities: [ + 'EC2', + ], + TaskRoleArn: { + 'Fn::GetAtt': [ + 'ServiceTaskDefTaskRole0CFE2F57', + 'Arn', + ], + }, + }); + }); + + test('test ECS NLB construct with all settings', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); + + // WHEN + new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 256, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + containerName: 'myContainer', + containerPorts: [80, 90], + enableLogging: false, + environment: { + TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', + TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', + }, + logDriver: new AwsLogDriver({ + streamPrefix: 'TestStream', + }), + family: 'Ec2TaskDef', + executionRole: new Role(stack, 'ExecutionRole', { + path: '/', + assumedBy: new CompositePrincipal( + new ServicePrincipal('ecs.amazonaws.com'), + new ServicePrincipal('ecs-tasks.amazonaws.com'), + ), + }), + taskRole: new Role(stack, 'TaskRole', { + assumedBy: new ServicePrincipal('ecs-tasks.amazonaws.com'), + }), + dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, + }, + cpu: 256, + desiredCount: 3, + enableECSManagedTags: true, + healthCheckGracePeriod: Duration.millis(2000), + loadBalancers: [ + { + name: 'lb1', + domainName: 'api.example.com', + domainZone: zone, + publicLoadBalancer: false, + listeners: [ + { + name: 'listener1', + }, + ], + }, + { + name: 'lb2', + listeners: [ + { + name: 'listener2', + port: 81, + }, + ], + }, + ], + propagateTags: PropagatedTagSource.SERVICE, + memoryReservationMiB: 256, + serviceName: 'myService', + targetGroups: [ + { + containerPort: 80, + listener: 'listener1', + }, + { + containerPort: 90, + listener: 'listener2', + }, + ], + }); + + // THEN + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 3, + EnableECSManagedTags: true, + HealthCheckGracePeriodSeconds: 2, + LaunchType: 'EC2', + LoadBalancers: [ + { + ContainerName: 'myContainer', + ContainerPort: 80, + TargetGroupArn: { + Ref: 'Servicelb1listener1ECSTargetGroupmyContainer80Group43098F8B', + }, + }, + { + ContainerName: 'myContainer', + ContainerPort: 90, + TargetGroupArn: { + Ref: 'Servicelb2listener2ECSTargetGroupmyContainer90GroupDEB417E4', + }, + }, + ], + PropagateTags: 'SERVICE', + SchedulingStrategy: 'REPLICA', + ServiceName: 'myService', + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Cpu: 256, + Environment: [ + { + Name: 'TEST_ENVIRONMENT_VARIABLE1', + Value: 'test environment variable 1 value', + }, + { + Name: 'TEST_ENVIRONMENT_VARIABLE2', + Value: 'test environment variable 2 value', + }, + ], + Essential: true, + Image: 'test', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ServiceTaskDefmyContainerLogGroup0A87368B', + }, + 'awslogs-stream-prefix': 'TestStream', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Memory: 256, + MemoryReservation: 256, + Name: 'myContainer', + PortMappings: [ + { + ContainerPort: 80, + HostPort: 0, + Protocol: 'tcp', + }, + { + ContainerPort: 90, + HostPort: 0, + Protocol: 'tcp', + }, + ], + DockerLabels: { + label1: 'labelValue1', + label2: 'labelValue2', + }, + }, + ], + ExecutionRoleArn: { + 'Fn::GetAtt': [ + 'ExecutionRole605A040B', + 'Arn', + ], + }, + Family: 'ServiceTaskDef79D79521', + NetworkMode: 'bridge', + RequiresCompatibilities: [ + 'EC2', + ], + TaskRoleArn: { + 'Fn::GetAtt': [ + 'TaskRole30FC0FBB', + 'Arn', + ], + }, + }); + }); + + test('set vpc instead of cluster', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + + // WHEN + new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + vpc, + memoryLimitMiB: 256, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + }); + + // THEN - stack does not contain a LaunchConfiguration + const template = SynthUtils.synthesize(stack, { skipValidation: true }); + expect(template).not.toHaveResource('AWS::AutoScaling::LaunchConfiguration'); + expect(() => SynthUtils.synthesize(stack)).toThrow(); + }); + + test('able to pass pre-defined task definition', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + const taskDefinition = new Ec2TaskDefinition(stack, 'Ec2TaskDef'); + const container = taskDefinition.addContainer('web', { + image: ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + memoryLimitMiB: 512, + }); + container.addPortMappings({ + containerPort: 80, + }); + + // WHEN + new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskDefinition, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Essential: true, + Image: 'amazon/amazon-ecs-sample', + Memory: 512, + Name: 'web', + PortMappings: [ + { + ContainerPort: 80, + HostPort: 0, + Protocol: 'tcp', + }, + ], + }, + ], + Family: 'Ec2TaskDef', + NetworkMode: 'bridge', + RequiresCompatibilities: [ + 'EC2', + ], + }); + }); + + test('errors if no essential container in pre-defined task definition', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + const taskDefinition = new Ec2TaskDefinition(stack, 'Ec2TaskDef'); + + // THEN + expect(() => { + new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskDefinition, + }); + }).toThrow(/At least one essential container must be specified/); + }); + + test('set default load balancer, listener, target group correctly', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); + + // WHEN + const ecsService = new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + vpc, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + loadBalancers: [ + { + name: 'lb1', + listeners: [ + { + name: 'listener1', + }, + ], + }, + { + name: 'lb2', + domainName: 'api.example.com', + domainZone: zone, + listeners: [ + { + name: 'listener2', + }, + { + name: 'listener3', + }, + ], + }, + ], + targetGroups: [ + { + containerPort: 80, + }, + { + containerPort: 90, + }, + ], + }); + + // THEN + expect(ecsService.loadBalancer.node.id).toEqual('lb1'); + expect(ecsService.listener.node.id).toEqual('listener1'); + expect(ecsService.targetGroup.node.id).toEqual('ECSTargetGroupweb80Group'); + }); + + test('setting vpc and cluster throws error', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + + // WHEN + expect(() => new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + vpc, + taskImageOptions: { + image: ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + })).toThrow(/You can only specify either vpc or cluster. Alternatively, you can leave both blank/); + }); + + test('creates AWS Cloud Map service for Private DNS namespace', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'MyVpc', {}); + const cluster = new Cluster(stack, 'EcsCluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + // WHEN + cluster.addDefaultCloudMapNamespace({ + name: 'foo.com', + type: NamespaceType.DNS_PRIVATE, + }); + + new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('hello'), + }, + cloudMapOptions: { + name: 'myApp', + }, + memoryLimitMiB: 512, + }); + + // THEN + expect(stack).toHaveResource('AWS::ECS::Service', { + ServiceRegistries: [ + { + ContainerName: 'web', + ContainerPort: 80, + RegistryArn: { + 'Fn::GetAtt': [ + 'ServiceCloudmapServiceDE76B29D', + 'Arn', + ], + }, + }, + ], + }); + + expect(stack).toHaveResource('AWS::ServiceDiscovery::Service', { + DnsConfig: { + DnsRecords: [ + { + TTL: 60, + Type: 'SRV', + }, + ], + NamespaceId: { + 'Fn::GetAtt': [ + 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', + 'Id', + ], + }, + RoutingPolicy: 'MULTIVALUE', + }, + HealthCheckCustomConfig: { + FailureThreshold: 1, + }, + Name: 'myApp', + NamespaceId: { + 'Fn::GetAtt': [ + 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', + 'Id', + ], + }, + }); + }); + + test('errors when setting both taskDefinition and taskImageOptions', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + const taskDefinition = new Ec2TaskDefinition(stack, 'Ec2TaskDef'); + taskDefinition.addContainer('test', { + image: ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + memoryLimitMiB: 512, + }); + + // THEN + expect(() => { + new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + taskDefinition, + }); + }).toThrow(/You must specify only one of TaskDefinition or TaskImageOptions./); + }); + + test('errors when setting neither taskDefinition nor taskImageOptions', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + // THEN + expect(() => { + new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + }); + }).toThrow(/You must specify one of: taskDefinition or image/); + }); + + test('errors when setting domainName but not domainZone', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + // THEN + expect(() => { + new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + loadBalancers: [ + { + name: 'lb1', + domainName: 'api.example.com', + listeners: [{ + name: 'listener1', + }], + }, + ], + }); + }).toThrow(/A Route53 hosted domain zone name is required to configure the specified domain name/); + }); + + test('errors when loadBalancers is empty', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + loadBalancers: [], + }); + }).toThrow(/At least one load balancer must be specified/); + }); + + test('errors when targetGroups is empty', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + targetGroups: [], + }); + }).toThrow(/At least one target group should be specified/); + }); + + test('errors when no listener specified', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + loadBalancers: [ + { + name: 'lb', + listeners: [], + }, + ], + }); + }).toThrow(/At least one listener must be specified/); + }); + + test('errors when listener is not defined but used in creating target groups', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + loadBalancers: [ + { + name: 'lb', + listeners: [ + { + name: 'listener1', + }, + ], + }, + ], + targetGroups: [ + { + containerPort: 80, + listener: 'listener2', + }, + ], + }); + }).toThrow(/Listener listener2 is not defined. Did you define listener with name listener2?/); + }); + + test('errors if desiredTaskCount is 0', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); + + // THEN + expect(() => + new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ContainerImage.fromRegistry('test'), + }, + desiredCount: 0, + })).toThrow(/You must specify a desiredCount greater than 0/); + }); +}); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s.test.ts new file mode 100644 index 0000000000000..6248c9c4d14dd --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s.test.ts @@ -0,0 +1,1338 @@ +import { ABSENT, arrayWith, objectLike, SynthUtils } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +import { Certificate } from '@aws-cdk/aws-certificatemanager'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as ecs from '@aws-cdk/aws-ecs'; +import { ApplicationLoadBalancer, ApplicationProtocol, ApplicationProtocolVersion, NetworkLoadBalancer, SslPolicy } from '@aws-cdk/aws-elasticloadbalancingv2'; +import { PublicHostedZone } from '@aws-cdk/aws-route53'; +import * as cloudmap from '@aws-cdk/aws-servicediscovery'; +import * as cdk from '@aws-cdk/core'; +import * as cxapi from '@aws-cdk/cx-api'; +import * as ecsPatterns from '../../lib'; + +test('test ECS loadbalanced construct', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + environment: { + TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', + TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', + }, + dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, + }, + desiredCount: 2, + }); + + // THEN - stack contains a load balancer and a service + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); + + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 2, + LaunchType: 'EC2', + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Environment: [ + { + Name: 'TEST_ENVIRONMENT_VARIABLE1', + Value: 'test environment variable 1 value', + }, + { + Name: 'TEST_ENVIRONMENT_VARIABLE2', + Value: 'test environment variable 2 value', + }, + ], + Memory: 1024, + DockerLabels: { + label1: 'labelValue1', + label2: 'labelValue2', + }, + }, + ], + }); +}); + +test('ApplicationLoadBalancedEc2Service desiredCount can be undefined when feature flag is set', () => { + // GIVEN + const stack = new cdk.Stack(); + stack.node.setContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT, true); + + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + }); + + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: ABSENT, + }); +}); + +test('ApplicationLoadBalancedFargateService desiredCount can be undefined when feature flag is set', () => { + // GIVEN + const stack = new cdk.Stack(); + stack.node.setContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT, true); + + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + }); + + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: ABSENT, + }); +}); + +test('NetworkLoadBalancedEc2Service desiredCount can be undefined when feature flag is set', () => { + // GIVEN + const stack = new cdk.Stack(); + stack.node.setContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT, true); + + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + }); + + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: ABSENT, + }); +}); + +test('NetworkLoadBalancedFargateService desiredCount can be undefined when feature flag is set', () => { + // GIVEN + const stack = new cdk.Stack(); + stack.node.setContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT, true); + + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + }); + + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: ABSENT, + }); +}); + +test('set vpc instead of cluster', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { + vpc, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + environment: { + TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', + TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', + }, + }, + desiredCount: 2, + }); + + // THEN - stack does not contain a LaunchConfiguration\ + const template = SynthUtils.synthesize(stack, { skipValidation: true }); + expect(template).not.toHaveResource('AWS::AutoScaling::LaunchConfiguration'); + expect(() => SynthUtils.synthesize(stack)).toThrow(); +}); + +test('setting vpc and cluster throws error', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + expect(() => new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { + cluster, + vpc, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + })).toThrow(); +}); + +test('test ECS loadbalanced construct with memoryReservationMiB', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryReservationMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + }); + + // THEN - stack contains a load balancer and a service + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + MemoryReservation: 1024, + }, + ], + }); +}); + +test('creates AWS Cloud Map service for Private DNS namespace with application load balanced ec2 service', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'MyVpc', {}); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + cluster.addDefaultCloudMapNamespace({ + name: 'foo.com', + type: cloudmap.NamespaceType.DNS_PRIVATE, + }); + + new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { + cluster, + taskImageOptions: { + containerPort: 8000, + image: ecs.ContainerImage.fromRegistry('hello'), + }, + cloudMapOptions: { + name: 'myApp', + }, + memoryLimitMiB: 512, + }); + + // THEN + expect(stack).toHaveResource('AWS::ECS::Service', { + ServiceRegistries: [ + { + ContainerName: 'web', + ContainerPort: 8000, + RegistryArn: { + 'Fn::GetAtt': [ + 'ServiceCloudmapServiceDE76B29D', + 'Arn', + ], + }, + }, + ], + }); + + expect(stack).toHaveResource('AWS::ServiceDiscovery::Service', { + DnsConfig: { + DnsRecords: [ + { + TTL: 60, + Type: 'SRV', + }, + ], + NamespaceId: { + 'Fn::GetAtt': [ + 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', + 'Id', + ], + }, + RoutingPolicy: 'MULTIVALUE', + }, + HealthCheckCustomConfig: { + FailureThreshold: 1, + }, + Name: 'myApp', + NamespaceId: { + 'Fn::GetAtt': [ + 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', + 'Id', + ], + }, + }); +}); + +test('creates AWS Cloud Map service for Private DNS namespace with network load balanced fargate service', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'MyVpc', {}); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + cluster.addDefaultCloudMapNamespace({ + name: 'foo.com', + type: cloudmap.NamespaceType.DNS_PRIVATE, + }); + + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + containerPort: 8000, + image: ecs.ContainerImage.fromRegistry('hello'), + }, + cloudMapOptions: { + name: 'myApp', + }, + memoryLimitMiB: 512, + }); + + // THEN + expect(stack).toHaveResource('AWS::ECS::Service', { + ServiceRegistries: [ + { + RegistryArn: { + 'Fn::GetAtt': [ + 'ServiceCloudmapServiceDE76B29D', + 'Arn', + ], + }, + }, + ], + }); + + expect(stack).toHaveResource('AWS::ServiceDiscovery::Service', { + DnsConfig: { + DnsRecords: [ + { + TTL: 60, + Type: 'A', + }, + ], + NamespaceId: { + 'Fn::GetAtt': [ + 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', + 'Id', + ], + }, + RoutingPolicy: 'MULTIVALUE', + }, + HealthCheckCustomConfig: { + FailureThreshold: 1, + }, + Name: 'myApp', + NamespaceId: { + 'Fn::GetAtt': [ + 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', + 'Id', + ], + }, + }); +}); + +test('test Fargate loadbalanced construct', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + environment: { + TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', + TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', + }, + dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, + }, + desiredCount: 2, + }); + + // THEN - stack contains a load balancer and a service + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Environment: [ + { + Name: 'TEST_ENVIRONMENT_VARIABLE1', + Value: 'test environment variable 1 value', + }, + { + Name: 'TEST_ENVIRONMENT_VARIABLE2', + Value: 'test environment variable 2 value', + }, + ], + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { Ref: 'ServiceTaskDefwebLogGroup2A898F61' }, + 'awslogs-stream-prefix': 'Service', + 'awslogs-region': { Ref: 'AWS::Region' }, + }, + }, + DockerLabels: { + label1: 'labelValue1', + label2: 'labelValue2', + }, + }, + ], + }); + + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 2, + LaunchType: 'FARGATE', + }); + + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Port: 80, + Protocol: 'HTTP', + }); +}); + +test('test Fargate loadbalanced construct opting out of log driver creation', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + enableLogging: false, + environment: { + TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', + TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', + }, + }, + desiredCount: 2, + }); + + // THEN - stack contains a load balancer and a service + expect(stack).not.toHaveResource('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Environment: [ + { + Name: 'TEST_ENVIRONMENT_VARIABLE1', + Value: 'test environment variable 1 value', + }, + { + Name: 'TEST_ENVIRONMENT_VARIABLE2', + Value: 'test environment variable 2 value', + }, + ], + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { Ref: 'ServiceTaskDefwebLogGroup2A898F61' }, + 'awslogs-stream-prefix': 'Service', + 'awslogs-region': { Ref: 'AWS::Region' }, + }, + }, + }, + ], + }); +}); + +test('test Fargate loadbalanced construct with TLS', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + domainName: 'api.example.com', + domainZone: zone, + certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), + sslPolicy: SslPolicy.TLS12_EXT, + }); + + // THEN - stack contains a load balancer and a service + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); + + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Port: 443, + Protocol: 'HTTPS', + Certificates: [{ + CertificateArn: 'helloworld', + }], + SslPolicy: SslPolicy.TLS12_EXT, + }); + + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { + Port: 80, + Protocol: 'HTTP', + TargetType: 'ip', + VpcId: { + Ref: 'VPCB9E5F0B4', + }, + }); + + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 1, + LaunchType: 'FARGATE', + }); + + expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Name: 'api.example.com.', + HostedZoneId: { + Ref: 'HostedZoneDB99F866', + }, + Type: 'A', + AliasTarget: { + HostedZoneId: { 'Fn::GetAtt': ['ServiceLBE9A1ADBC', 'CanonicalHostedZoneID'] }, + DNSName: { 'Fn::Join': ['', ['dualstack.', { 'Fn::GetAtt': ['ServiceLBE9A1ADBC', 'DNSName'] }]] }, + }, + }); +}); + +test('test Fargateloadbalanced construct with TLS and default certificate', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + domainName: 'api.example.com', + domainZone: zone, + protocol: ApplicationProtocol.HTTPS, + }); + + // THEN - stack contains a load balancer, a service, and a certificate + expect(stack).toHaveResource('AWS::CertificateManager::Certificate', { + DomainName: 'api.example.com', + DomainValidationOptions: [ + { + DomainName: 'api.example.com', + HostedZoneId: { + Ref: 'HostedZoneDB99F866', + }, + }, + ], + ValidationMethod: 'DNS', + }); + + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); + + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::Listener', { + Port: 443, + Protocol: 'HTTPS', + Certificates: [{ + CertificateArn: { + Ref: 'ServiceCertificateA7C65FE6', + }, + }], + }); + + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 1, + LaunchType: 'FARGATE', + }); + + expect(stack).toHaveResource('AWS::Route53::RecordSet', { + Name: 'api.example.com.', + HostedZoneId: { + Ref: 'HostedZoneDB99F866', + }, + Type: 'A', + AliasTarget: { + HostedZoneId: { 'Fn::GetAtt': ['ServiceLBE9A1ADBC', 'CanonicalHostedZoneID'] }, + DNSName: { 'Fn::Join': ['', ['dualstack.', { 'Fn::GetAtt': ['ServiceLBE9A1ADBC', 'DNSName'] }]] }, + }, + }); +}); + +test('errors when setting domainName but not domainZone', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + domainName: 'api.example.com', + }); + }).toThrow(); +}); + +test('errors when setting both HTTP protocol and certificate', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + protocol: ApplicationProtocol.HTTP, + certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), + }); + }).toThrow(); +}); + +test('errors when setting both HTTP protocol and redirectHTTP', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + protocol: ApplicationProtocol.HTTP, + redirectHTTP: true, + }); + }).toThrow(); +}); + +test('does not throw errors when not setting HTTPS protocol but certificate for redirectHTTP', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); + + // THEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + domainName: 'api.example.com', + domainZone: zone, + redirectHTTP: true, + certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), + }); +}); + +test('errors when setting HTTPS protocol but not domain name', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + protocol: ApplicationProtocol.HTTPS, + }); + }).toThrow(); +}); + +test('test Fargate loadbalanced construct with optional log driver input', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + enableLogging: false, + environment: { + TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', + TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', + }, + logDriver: new ecs.AwsLogDriver({ + streamPrefix: 'TestStream', + }), + }, + desiredCount: 2, + }); + + // THEN - stack contains a load balancer and a service + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Environment: [ + { + Name: 'TEST_ENVIRONMENT_VARIABLE1', + Value: 'test environment variable 1 value', + }, + { + Name: 'TEST_ENVIRONMENT_VARIABLE2', + Value: 'test environment variable 2 value', + }, + ], + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { Ref: 'ServiceTaskDefwebLogGroup2A898F61' }, + 'awslogs-stream-prefix': 'TestStream', + 'awslogs-region': { Ref: 'AWS::Region' }, + }, + }, + }, + ], + }); +}); + +test('test Fargate loadbalanced construct with logging enabled', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + enableLogging: true, + environment: { + TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', + TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', + }, + }, + desiredCount: 2, + }); + + // THEN - stack contains a load balancer and a service + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Environment: [ + { + Name: 'TEST_ENVIRONMENT_VARIABLE1', + Value: 'test environment variable 1 value', + }, + { + Name: 'TEST_ENVIRONMENT_VARIABLE2', + Value: 'test environment variable 2 value', + }, + ], + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { Ref: 'ServiceTaskDefwebLogGroup2A898F61' }, + 'awslogs-stream-prefix': 'Service', + 'awslogs-region': { Ref: 'AWS::Region' }, + }, + }, + }, + ], + }); +}); + +test('test Fargate loadbalanced construct with both image and taskDefinition provided', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef'); + taskDefinition.addContainer('web', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + memoryLimitMiB: 512, + }); + + // WHEN + expect(() => new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + enableLogging: true, + environment: { + TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', + TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', + }, + }, + desiredCount: 2, + taskDefinition, + })).toThrow(); +}); + +test('test Fargate application loadbalanced construct with taskDefinition provided', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); + const container = taskDefinition.addContainer('passedTaskDef', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + memoryLimitMiB: 512, + }); + container.addPortMappings({ + containerPort: 80, + }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskDefinition, + desiredCount: 2, + memoryLimitMiB: 1024, + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Image: 'amazon/amazon-ecs-sample', + Memory: 512, + Name: 'passedTaskDef', + PortMappings: [ + { + ContainerPort: 80, + Protocol: 'tcp', + }, + ], + }, + ], + }); +}); + +test('ALB - throws if desiredTaskCount is 0', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // THEN + expect(() => + new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + desiredCount: 0, + }), + ).toThrow(/You must specify a desiredCount greater than 0/); +}); + +test('NLB - throws if desiredTaskCount is 0', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // THEN + expect(() => + new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + desiredCount: 0, + }), + ).toThrow(/You must specify a desiredCount greater than 0/); +}); + +test('ALBFargate - having *HealthyPercent properties', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'ALB123Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + }, + minHealthyPercent: 100, + maxHealthyPercent: 200, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + DeploymentConfiguration: { + MinimumHealthyPercent: 100, + MaximumPercent: 200, + }, + }); +}); + +test('NLBFargate - having *HealthyPercent properties', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + }, + desiredCount: 1, + minHealthyPercent: 100, + maxHealthyPercent: 200, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + DeploymentConfiguration: { + MinimumHealthyPercent: 100, + MaximumPercent: 200, + }, + }); +}); + +test('ALB - having *HealthyPercent properties', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + }, + desiredCount: 1, + minHealthyPercent: 100, + maxHealthyPercent: 200, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + DeploymentConfiguration: { + MinimumHealthyPercent: 100, + MaximumPercent: 200, + }, + }); +}); + +test('ALB - includes provided protocol version properties', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + }, + desiredCount: 1, + domainName: 'api.example.com', + domainZone: zone, + protocol: ApplicationProtocol.HTTPS, + protocolVersion: ApplicationProtocolVersion.GRPC, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup', { + ProtocolVersion: 'GRPC', + }); +}); + +test('NLB - having *HealthyPercent properties', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + }, + desiredCount: 1, + minHealthyPercent: 100, + maxHealthyPercent: 200, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + DeploymentConfiguration: { + MinimumHealthyPercent: 100, + MaximumPercent: 200, + }, + }); +}); + +test('ALB - having deployment controller', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + }, + deploymentController: { + type: ecs.DeploymentControllerType.CODE_DEPLOY, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + DeploymentController: { + Type: 'CODE_DEPLOY', + }, + }); +}); + +test('NLB - having deployment controller', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + }, + deploymentController: { + type: ecs.DeploymentControllerType.CODE_DEPLOY, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + DeploymentController: { + Type: 'CODE_DEPLOY', + }, + }); +}); + +test('ALB with circuit breaker', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + }, + circuitBreaker: { rollback: true }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + DeploymentConfiguration: { + DeploymentCircuitBreaker: { + Enable: true, + Rollback: true, + }, + }, + DeploymentController: { + Type: 'ECS', + }, + }); +}); + +test('NLB with circuit breaker', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + }, + circuitBreaker: { rollback: true }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + DeploymentConfiguration: { + DeploymentCircuitBreaker: { + Enable: true, + Rollback: true, + }, + }, + DeploymentController: { + Type: 'ECS', + }, + }); +}); + +test('NetworkLoadbalancedEC2Service accepts previously created load balancer', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc, clusterName: 'MyCluster' }); + cluster.addCapacity('Capacity', { instanceType: new ec2.InstanceType('t2.micro') }); + const nlb = new NetworkLoadBalancer(stack, 'NLB', { vpc }); + const taskDef = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); + const container = taskDef.addContainer('Container', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + memoryLimitMiB: 1024, + }); + container.addPortMappings({ containerPort: 80 }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { + cluster, + loadBalancer: nlb, + taskDefinition: taskDef, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + LaunchType: 'EC2', + }); + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Type: 'network', + }); +}); + +test('NetworkLoadBalancedEC2Service accepts imported load balancer', () => { + // GIVEN + const stack = new cdk.Stack(); + const nlbArn = 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188'; + const vpc = new ec2.Vpc(stack, 'Vpc'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc, clusterName: 'MyCluster' }); + cluster.addCapacity('Capacity', { instanceType: new ec2.InstanceType('t2.micro') }); + const nlb = NetworkLoadBalancer.fromNetworkLoadBalancerAttributes(stack, 'NLB', { + loadBalancerArn: nlbArn, + vpc, + }); + const taskDef = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); + const container = taskDef.addContainer('Container', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + memoryLimitMiB: 1024, + }); + container.addPortMappings({ + containerPort: 80, + }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { + cluster, + loadBalancer: nlb, + desiredCount: 1, + taskDefinition: taskDef, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + LaunchType: 'EC2', + LoadBalancers: [{ ContainerName: 'Container', ContainerPort: 80 }], + }); + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup'); + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { + LoadBalancerArn: nlb.loadBalancerArn, + Port: 80, + }); +}); + +test('ApplicationLoadBalancedEC2Service accepts previously created load balancer', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc, clusterName: 'MyCluster' }); + cluster.addCapacity('Capacity', { instanceType: new ec2.InstanceType('t2.micro') }); + const sg = new ec2.SecurityGroup(stack, 'SG', { vpc }); + const alb = new ApplicationLoadBalancer(stack, 'NLB', { + vpc, + securityGroup: sg, + }); + const taskDef = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); + const container = taskDef.addContainer('Container', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + memoryLimitMiB: 1024, + }); + container.addPortMappings({ containerPort: 80 }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { + cluster, + loadBalancer: alb, + taskDefinition: taskDef, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + LaunchType: 'EC2', + }); + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Type: 'application', + }); +}); + +test('ApplicationLoadBalancedEC2Service accepts imported load balancer', () => { + // GIVEN + const stack = new cdk.Stack(); + const albArn = 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188'; + const vpc = new ec2.Vpc(stack, 'Vpc'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc, clusterName: 'MyCluster' }); + cluster.addCapacity('Capacity', { instanceType: new ec2.InstanceType('t2.micro') }); + const sg = new ec2.SecurityGroup(stack, 'SG', { vpc }); + const alb = ApplicationLoadBalancer.fromApplicationLoadBalancerAttributes(stack, 'ALB', { + loadBalancerArn: albArn, + vpc, + securityGroupId: sg.securityGroupId, + loadBalancerDnsName: 'MyName', + }); + const taskDef = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); + const container = taskDef.addContainer('Container', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + memoryLimitMiB: 1024, + }); + container.addPortMappings({ + containerPort: 80, + }); + // WHEN + new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { + cluster, + loadBalancer: alb, + taskDefinition: taskDef, + }); + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + LaunchType: 'EC2', + LoadBalancers: [{ ContainerName: 'Container', ContainerPort: 80 }], + }); + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup'); + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { + LoadBalancerArn: alb.loadBalancerArn, + Port: 80, + }); +}); + +test('test ECS loadbalanced construct default/open security group', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryReservationMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + }); + + // THEN - Stack contains no ingress security group rules + expect(stack).toHaveResourceLike('AWS::EC2::SecurityGroup', { + SecurityGroupIngress: [{ + CidrIp: '0.0.0.0/0', + FromPort: 80, + IpProtocol: 'tcp', + ToPort: 80, + }], + }); +}); + +test('test ECS loadbalanced construct closed security group', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { + cluster, + memoryReservationMiB: 1024, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + domainName: 'api.example.com', + domainZone: zone, + certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), + openListener: false, + redirectHTTP: true, + }); + + // THEN - Stack contains no ingress security group rules + expect(stack).not.toHaveResourceLike('AWS::EC2::SecurityGroup', { + SecurityGroupIngress: arrayWith(objectLike({})), + }); +}); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/queue-processing-ecs-service.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/queue-processing-ecs-service.test.ts new file mode 100644 index 0000000000000..60e6a7d0f6969 --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/queue-processing-ecs-service.test.ts @@ -0,0 +1,379 @@ +import { ABSENT } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +import * as autoscaling from '@aws-cdk/aws-autoscaling'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as ecs from '@aws-cdk/aws-ecs'; +import * as sqs from '@aws-cdk/aws-sqs'; +import * as cdk from '@aws-cdk/core'; +import * as cxapi from '@aws-cdk/cx-api'; +import * as ecsPatterns from '../../lib'; + +test('test ECS queue worker service construct - with only required props', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + }); + + // THEN - QueueWorker is of EC2 launch type, an SQS queue is created and all default properties are set. + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 1, + LaunchType: 'EC2', + }); + + expect(stack).toHaveResource('AWS::SQS::Queue', { + RedrivePolicy: { + deadLetterTargetArn: { + 'Fn::GetAtt': [ + 'ServiceEcsProcessingDeadLetterQueue4A89196E', + 'Arn', + ], + }, + maxReceiveCount: 3, + }, + }); + + expect(stack).toHaveResource('AWS::SQS::Queue', { + MessageRetentionPeriod: 1209600, + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Environment: [ + { + Name: 'QUEUE_NAME', + Value: { + 'Fn::GetAtt': [ + 'ServiceEcsProcessingQueueC266885C', + 'QueueName', + ], + }, + }, + ], + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupD52338D1', + }, + 'awslogs-stream-prefix': 'Service', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Essential: true, + Image: 'test', + Memory: 512, + }, + ], + Family: 'ServiceQueueProcessingTaskDef83DB34F1', + }); +}); + +test('test ECS queue worker service construct - with remove default desiredCount feature flag', () => { + // GIVEN + const stack = new cdk.Stack(); + stack.node.setContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT, true); + + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + }); + + // THEN - QueueWorker is of EC2 launch type, and desiredCount is not defined on the Ec2Service. + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: ABSENT, + LaunchType: 'EC2', + }); +}); + +test('test ECS queue worker service construct - with optional props for queues', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + maxReceiveCount: 42, + retentionPeriod: cdk.Duration.days(7), + visibilityTimeout: cdk.Duration.minutes(5), + }); + + // THEN - QueueWorker is of EC2 launch type, an SQS queue is created and all default properties are set. + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 1, + LaunchType: 'EC2', + }); + + expect(stack).toHaveResource('AWS::SQS::Queue', { + RedrivePolicy: { + deadLetterTargetArn: { + 'Fn::GetAtt': [ + 'ServiceEcsProcessingDeadLetterQueue4A89196E', + 'Arn', + ], + }, + maxReceiveCount: 42, + }, + VisibilityTimeout: 300, + }); + + expect(stack).toHaveResource('AWS::SQS::Queue', { + MessageRetentionPeriod: 604800, + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Environment: [ + { + Name: 'QUEUE_NAME', + Value: { + 'Fn::GetAtt': [ + 'ServiceEcsProcessingQueueC266885C', + 'QueueName', + ], + }, + }, + ], + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupD52338D1', + }, + 'awslogs-stream-prefix': 'Service', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Essential: true, + Image: 'test', + Memory: 512, + }, + ], + Family: 'ServiceQueueProcessingTaskDef83DB34F1', + }); +}); + +test('test ECS queue worker service construct - with optional props', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + const queue = new sqs.Queue(stack, 'ecs-test-queue', { + queueName: 'ecs-test-sqs-queue', + }); + + // WHEN + new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 1024, + image: ecs.ContainerImage.fromRegistry('test'), + command: ['-c', '4', 'amazon.com'], + enableLogging: false, + desiredTaskCount: 2, + environment: { + TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', + TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', + }, + queue, + maxScalingCapacity: 5, + minHealthyPercent: 60, + maxHealthyPercent: 150, + serviceName: 'ecs-test-service', + family: 'ecs-task-family', + circuitBreaker: { rollback: true }, + gpuCount: 256, + }); + + // THEN - QueueWorker is of EC2 launch type, an SQS queue is created and all optional properties are set. + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 2, + DeploymentConfiguration: { + MinimumHealthyPercent: 60, + MaximumPercent: 150, + DeploymentCircuitBreaker: { + Enable: true, + Rollback: true, + }, + }, + LaunchType: 'EC2', + ServiceName: 'ecs-test-service', + DeploymentController: { + Type: 'ECS', + }, + }); + + expect(stack).toHaveResource('AWS::SQS::Queue', { + QueueName: 'ecs-test-sqs-queue', + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Command: [ + '-c', + '4', + 'amazon.com', + ], + Environment: [ + { + Name: 'TEST_ENVIRONMENT_VARIABLE1', + Value: 'test environment variable 1 value', + }, + { + Name: 'TEST_ENVIRONMENT_VARIABLE2', + Value: 'test environment variable 2 value', + }, + { + Name: 'QUEUE_NAME', + Value: { + 'Fn::GetAtt': [ + 'ecstestqueueD1FDA34B', + 'QueueName', + ], + }, + }, + ], + Image: 'test', + Memory: 1024, + ResourceRequirements: [ + { + Type: 'GPU', + Value: '256', + }, + ], + }, + ], + Family: 'ecs-task-family', + }); +}); + +test('can set desiredTaskCount to 0', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { + cluster, + desiredTaskCount: 0, + maxScalingCapacity: 2, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + }); + + // THEN - QueueWorker is of EC2 launch type, an SQS queue is created and all default properties are set. + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 0, + LaunchType: 'EC2', + }); +}); + +test('throws if desiredTaskCount and maxScalingCapacity are 0', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // THEN + expect(() => + new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { + cluster, + desiredTaskCount: 0, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + }), + ).toThrow(/maxScalingCapacity must be set and greater than 0 if desiredCount is 0/); +}); + +test('can set custom containerName', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { + cluster, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + containerName: 'my-container', + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Name: 'my-container', + }, + ], + }); +}); + +test('can set capacity provider strategies', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + const autoScalingGroup = new autoscaling.AutoScalingGroup(stack, 'asg', { + vpc, + instanceType: new ec2.InstanceType('bogus'), + machineImage: ecs.EcsOptimizedImage.amazonLinux2(), + }); + const capacityProvider = new ecs.AsgCapacityProvider(stack, 'provider', { + autoScalingGroup, + }); + cluster.addAsgCapacityProvider(capacityProvider); + + // WHEN + new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { + cluster, + image: ecs.ContainerImage.fromRegistry('test'), + memoryLimitMiB: 512, + capacityProviderStrategies: [ + { + capacityProvider: capacityProvider.capacityProviderName, + }, + ], + }); + + // THEN + expect(stack).toHaveResource('AWS::ECS::Service', { + LaunchType: ABSENT, + CapacityProviderStrategy: [ + { + CapacityProvider: { + Ref: 'providerD3FF4D3A', + }, + }, + ], + }); +}); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/scheduled-ecs-task.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/scheduled-ecs-task.test.ts new file mode 100644 index 0000000000000..745d6a17460bc --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/scheduled-ecs-task.test.ts @@ -0,0 +1,325 @@ +import '@aws-cdk/assert-internal/jest'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as ecs from '@aws-cdk/aws-ecs'; +import * as events from '@aws-cdk/aws-events'; +import * as cdk from '@aws-cdk/core'; +import { ScheduledEc2Task } from '../../lib'; + +test('Can create a scheduled Ec2 Task - with only required props', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { + instanceType: new ec2.InstanceType('t2.micro'), + }); + + new ScheduledEc2Task(stack, 'ScheduledEc2Task', { + cluster, + scheduledEc2TaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + memoryLimitMiB: 512, + }, + schedule: events.Schedule.expression('rate(1 minute)'), + }); + + // THEN + expect(stack).toHaveResource('AWS::Events::Rule', { + State: 'ENABLED', + Targets: [ + { + Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, + EcsParameters: { + TaskCount: 1, + TaskDefinitionArn: { Ref: 'ScheduledEc2TaskScheduledTaskDef56328BA4' }, + }, + Id: 'Target0', + Input: '{}', + RoleArn: { 'Fn::GetAtt': ['ScheduledEc2TaskScheduledTaskDefEventsRole64113C5F', 'Arn'] }, + }, + ], + }); + + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Essential: true, + Image: 'henk', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ScheduledEc2TaskScheduledTaskDefScheduledContainerLogGroupA85E11E6', + }, + 'awslogs-stream-prefix': 'ScheduledEc2Task', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Memory: 512, + Name: 'ScheduledContainer', + }, + ], + }); +}); + +test('Can create a scheduled Ec2 Task - with optional props', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + + cluster.addCapacity('DefaultAutoScalingGroup', { + instanceType: new ec2.InstanceType('t2.micro'), + }); + + new ScheduledEc2Task(stack, 'ScheduledEc2Task', { + cluster, + enabled: false, + scheduledEc2TaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + memoryLimitMiB: 512, + cpu: 2, + environment: { TRIGGER: 'CloudWatch Events' }, + }, + desiredTaskCount: 2, + schedule: events.Schedule.expression('rate(1 minute)'), + ruleName: 'sample-scheduled-task-rule', + }); + + // THEN + expect(stack).toHaveResource('AWS::Events::Rule', { + Name: 'sample-scheduled-task-rule', + State: 'DISABLED', + Targets: [ + { + Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, + EcsParameters: { + TaskCount: 2, + TaskDefinitionArn: { Ref: 'ScheduledEc2TaskScheduledTaskDef56328BA4' }, + }, + Id: 'Target0', + Input: '{}', + RoleArn: { 'Fn::GetAtt': ['ScheduledEc2TaskScheduledTaskDefEventsRole64113C5F', 'Arn'] }, + }, + ], + }); + + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Cpu: 2, + Environment: [ + { + Name: 'TRIGGER', + Value: 'CloudWatch Events', + }, + ], + Essential: true, + Image: 'henk', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ScheduledEc2TaskScheduledTaskDefScheduledContainerLogGroupA85E11E6', + }, + 'awslogs-stream-prefix': 'ScheduledEc2Task', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Memory: 512, + Name: 'ScheduledContainer', + }, + ], + }); +}); + +test('Scheduled ECS Task - with securityGroups defined', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', { + networkMode: ecs.NetworkMode.AWS_VPC, + }); + const sg = new ec2.SecurityGroup(stack, 'MySG', { vpc }); + + new ScheduledEc2Task(stack, 'ScheduledEc2Task', { + cluster, + scheduledEc2TaskDefinitionOptions: { + taskDefinition, + }, + schedule: events.Schedule.expression('rate(1 minute)'), + securityGroups: [sg], + }); + + // THEN + expect(stack).toHaveResource('AWS::Events::Rule', { + Targets: [ + { + Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, + EcsParameters: { + LaunchType: 'EC2', + NetworkConfiguration: { + AwsVpcConfiguration: { + AssignPublicIp: 'DISABLED', + SecurityGroups: [{ + 'Fn::GetAtt': [ + 'MySG94FE69A8', + 'GroupId', + ], + }], + Subnets: [ + { + Ref: 'VpcPrivateSubnet1Subnet536B997A', + }, + ], + }, + }, + TaskCount: 1, + TaskDefinitionArn: { Ref: 'Ec2TaskDef0226F28C' }, + }, + Id: 'Target0', + Input: '{}', + RoleArn: { 'Fn::GetAtt': ['Ec2TaskDefEventsRoleA0756175', 'Arn'] }, + }, + ], + }); +}); + +test('Scheduled Ec2 Task - with MemoryReservation defined', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { + instanceType: new ec2.InstanceType('t2.micro'), + }); + + new ScheduledEc2Task(stack, 'ScheduledEc2Task', { + cluster, + scheduledEc2TaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + memoryReservationMiB: 512, + }, + schedule: events.Schedule.expression('rate(1 minute)'), + }); + + // THEN + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Essential: true, + Image: 'henk', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ScheduledEc2TaskScheduledTaskDefScheduledContainerLogGroupA85E11E6', + }, + 'awslogs-stream-prefix': 'ScheduledEc2Task', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + MemoryReservation: 512, + Name: 'ScheduledContainer', + }, + ], + }); +}); + +test('Scheduled Ec2 Task - with Command defined', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { + instanceType: new ec2.InstanceType('t2.micro'), + }); + + new ScheduledEc2Task(stack, 'ScheduledEc2Task', { + cluster, + scheduledEc2TaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + memoryReservationMiB: 512, + command: ['-c', '4', 'amazon.com'], + }, + schedule: events.Schedule.expression('rate(1 minute)'), + }); + + // THEN + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Command: [ + '-c', + '4', + 'amazon.com', + ], + Essential: true, + Image: 'henk', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ScheduledEc2TaskScheduledTaskDefScheduledContainerLogGroupA85E11E6', + }, + 'awslogs-stream-prefix': 'ScheduledEc2Task', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + MemoryReservation: 512, + Name: 'ScheduledContainer', + }, + ], + }); +}); + +test('throws if desiredTaskCount is 0', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { + instanceType: new ec2.InstanceType('t2.micro'), + }); + + // THEN + expect(() => + new ScheduledEc2Task(stack, 'ScheduledEc2Task', { + cluster, + scheduledEc2TaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + memoryLimitMiB: 512, + }, + schedule: events.Schedule.expression('rate(1 minute)'), + desiredTaskCount: 0, + }), + ).toThrow(/You must specify a desiredTaskCount greater than 0/); +}); + +test('Scheduled Ec2 Task - exposes ECS Task', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + + const scheduledEc2Task = new ScheduledEc2Task(stack, 'ScheduledEc2Task', { + cluster, + scheduledEc2TaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + memoryLimitMiB: 512, + }, + schedule: events.Schedule.expression('rate(1 minute)'), + }); + + // THEN + expect(scheduledEc2Task.task).toBeDefined(); +}); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s-v2.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s-v2.ts deleted file mode 100644 index 5c3c5889c62b6..0000000000000 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s-v2.ts +++ /dev/null @@ -1,1555 +0,0 @@ -import { expect, haveResource, haveResourceLike, SynthUtils } from '@aws-cdk/assert-internal'; -import { Certificate } from '@aws-cdk/aws-certificatemanager'; -import { InstanceType, Vpc } from '@aws-cdk/aws-ec2'; -import { AwsLogDriver, Cluster, ContainerImage, Ec2TaskDefinition, PropagatedTagSource, Protocol } from '@aws-cdk/aws-ecs'; -import { ApplicationProtocol, SslPolicy } from '@aws-cdk/aws-elasticloadbalancingv2'; -import { CompositePrincipal, Role, ServicePrincipal } from '@aws-cdk/aws-iam'; -import { PublicHostedZone } from '@aws-cdk/aws-route53'; -import { NamespaceType } from '@aws-cdk/aws-servicediscovery'; -import { Duration, Stack } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; -import { ApplicationMultipleTargetGroupsEc2Service, NetworkMultipleTargetGroupsEc2Service } from '../../lib'; - -export = { - 'When Application Load Balancer': { - 'test ECS ALB construct with default settings'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - // WHEN - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - }); - - // THEN - stack contains a load balancer, a service, and a target group. - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::LoadBalancer')); - - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 1, - LaunchType: 'EC2', - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Image: 'test', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ServiceTaskDefwebLogGroup2A898F61', - }, - 'awslogs-stream-prefix': 'Service', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Memory: 1024, - Name: 'web', - PortMappings: [ - { - ContainerPort: 80, - HostPort: 0, - Protocol: 'tcp', - }, - ], - }, - ], - NetworkMode: 'bridge', - RequiresCompatibilities: [ - 'EC2', - ], - })); - - test.done(); - }, - - 'test ECS ALB construct with all settings'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); - - // WHEN - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - containerName: 'myContainer', - containerPorts: [80, 90], - enableLogging: false, - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - logDriver: new AwsLogDriver({ - streamPrefix: 'TestStream', - }), - family: 'Ec2TaskDef', - executionRole: new Role(stack, 'ExecutionRole', { - path: '/', - assumedBy: new CompositePrincipal( - new ServicePrincipal('ecs.amazonaws.com'), - new ServicePrincipal('ecs-tasks.amazonaws.com'), - ), - }), - taskRole: new Role(stack, 'TaskRole', { - assumedBy: new ServicePrincipal('ecs-tasks.amazonaws.com'), - }), - dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, - }, - cpu: 256, - desiredCount: 3, - enableECSManagedTags: true, - healthCheckGracePeriod: Duration.millis(2000), - loadBalancers: [ - { - name: 'lb', - domainName: 'api.example.com', - domainZone: zone, - publicLoadBalancer: false, - listeners: [ - { - name: 'listener', - protocol: ApplicationProtocol.HTTPS, - certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), - sslPolicy: SslPolicy.TLS12_EXT, - }, - ], - }, - ], - propagateTags: PropagatedTagSource.SERVICE, - memoryReservationMiB: 1024, - serviceName: 'myService', - targetGroups: [ - { - containerPort: 80, - listener: 'listener', - }, - { - containerPort: 90, - listener: 'listener', - pathPattern: 'a/b/c', - priority: 10, - protocol: Protocol.TCP, - }, - ], - }); - - // THEN - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 3, - LaunchType: 'EC2', - EnableECSManagedTags: true, - HealthCheckGracePeriodSeconds: 2, - LoadBalancers: [ - { - ContainerName: 'myContainer', - ContainerPort: 80, - TargetGroupArn: { - Ref: 'ServicelblistenerECSTargetGroupmyContainer80GroupAD83584A', - }, - }, - { - ContainerName: 'myContainer', - ContainerPort: 90, - TargetGroupArn: { - Ref: 'ServicelblistenerECSTargetGroupmyContainer90GroupF5A6D3A0', - }, - }, - ], - PropagateTags: 'SERVICE', - ServiceName: 'myService', - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Cpu: 256, - Environment: [ - { - Name: 'TEST_ENVIRONMENT_VARIABLE1', - Value: 'test environment variable 1 value', - }, - { - Name: 'TEST_ENVIRONMENT_VARIABLE2', - Value: 'test environment variable 2 value', - }, - ], - Essential: true, - Image: 'test', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ServiceTaskDefmyContainerLogGroup0A87368B', - }, - 'awslogs-stream-prefix': 'TestStream', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Memory: 1024, - MemoryReservation: 1024, - Name: 'myContainer', - PortMappings: [ - { - ContainerPort: 80, - HostPort: 0, - Protocol: 'tcp', - }, - { - ContainerPort: 90, - HostPort: 0, - Protocol: 'tcp', - }, - ], - DockerLabels: { - label1: 'labelValue1', - label2: 'labelValue2', - }, - }, - ], - ExecutionRoleArn: { - 'Fn::GetAtt': [ - 'ExecutionRole605A040B', - 'Arn', - ], - }, - Family: 'ServiceTaskDef79D79521', - NetworkMode: 'bridge', - RequiresCompatibilities: [ - 'EC2', - ], - TaskRoleArn: { - 'Fn::GetAtt': [ - 'TaskRole30FC0FBB', - 'Arn', - ], - }, - })); - - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { - Port: 443, - Protocol: 'HTTPS', - Certificates: [{ - CertificateArn: 'helloworld', - }], - SslPolicy: SslPolicy.TLS12_EXT, - })); - - test.done(); - }, - - 'set vpc instead of cluster'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - - // WHEN - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - vpc, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - }); - - // THEN - stack does not contain a LaunchConfiguration - expect(stack, true).notTo(haveResource('AWS::AutoScaling::LaunchConfiguration')); - - test.throws(() => expect(stack)); - - test.done(); - }, - - 'able to pass pre-defined task definition'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - const taskDefinition = new Ec2TaskDefinition(stack, 'Ec2TaskDef'); - const container = taskDefinition.addContainer('web', { - image: ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - memoryLimitMiB: 512, - }); - container.addPortMappings({ - containerPort: 80, - }); - - // WHEN - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskDefinition, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Essential: true, - Image: 'amazon/amazon-ecs-sample', - Memory: 512, - Name: 'web', - PortMappings: [ - { - ContainerPort: 80, - HostPort: 0, - Protocol: 'tcp', - }, - ], - }, - ], - Family: 'Ec2TaskDef', - NetworkMode: 'bridge', - RequiresCompatibilities: [ - 'EC2', - ], - })); - - test.done(); - }, - - 'able to output correct load balancer DNS and URLs for each protocol type'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); - - // WHEN - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - loadBalancers: [ - { - name: 'lb1', - domainName: 'api.example.com', - domainZone: zone, - listeners: [ - { - name: 'listener1', - protocol: ApplicationProtocol.HTTPS, - certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), - }, - { - name: 'listener2', - protocol: ApplicationProtocol.HTTP, - }, - ], - }, - { - name: 'lb3', - listeners: [ - { - name: 'listener3', - protocol: ApplicationProtocol.HTTP, - }, - ], - }, - ], - targetGroups: [ - { - containerPort: 80, - listener: 'listener1', - }, - { - containerPort: 90, - listener: 'listener2', - }, - { - containerPort: 70, - listener: 'listener3', - }, - ], - }); - - // THEN - const template = SynthUtils.synthesize(stack).template.Outputs; - test.deepEqual(template, { - ServiceLoadBalancerDNSlb175E78BFE: { - Value: { - 'Fn::GetAtt': [ - 'Servicelb152C7F4F9', - 'DNSName', - ], - }, - }, - ServiceServiceURLlb1https5C0C4079: { - Value: { - 'Fn::Join': [ - '', - [ - 'https://', - { - Ref: 'ServiceDNSlb12BA1FAD3', - }, - ], - ], - }, - }, - ServiceServiceURLlb1http65F0546A: { - Value: { - 'Fn::Join': [ - '', - [ - 'http://', - { - Ref: 'ServiceDNSlb12BA1FAD3', - }, - ], - ], - }, - }, - ServiceLoadBalancerDNSlb32F273F27: { - Value: { - 'Fn::GetAtt': [ - 'Servicelb3A583D5E7', - 'DNSName', - ], - }, - }, - ServiceServiceURLlb3http40F9CADC: { - Value: { - 'Fn::Join': [ - '', - [ - 'http://', - { - 'Fn::GetAtt': [ - 'Servicelb3A583D5E7', - 'DNSName', - ], - }, - ], - ], - }, - }, - }); - - test.done(); - }, - - 'errors if no essential container in pre-defined task definition'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - const taskDefinition = new Ec2TaskDefinition(stack, 'Ec2TaskDef'); - - // THEN - test.throws(() => { - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskDefinition, - }); - }, /At least one essential container must be specified/); - - test.done(); - }, - - 'set default load balancer, listener, target group correctly'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); - - // WHEN - const ecsService = new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - vpc, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - loadBalancers: [ - { - name: 'lb1', - listeners: [ - { - name: 'listener1', - }, - ], - }, - { - name: 'lb2', - domainName: 'api.example.com', - domainZone: zone, - listeners: [ - { - name: 'listener2', - }, - { - name: 'listener3', - protocol: ApplicationProtocol.HTTPS, - certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), - }, - ], - }, - ], - targetGroups: [ - { - containerPort: 80, - }, - { - containerPort: 90, - }, - ], - }); - - // THEN - test.equal(ecsService.loadBalancer.node.id, 'lb1'); - test.equal(ecsService.listener.node.id, 'listener1'); - test.equal(ecsService.targetGroup.node.id, 'ECSTargetGroupweb80Group'); - - test.done(); - }, - - 'setting vpc and cluster throws error'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - - // WHEN - test.throws(() => new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - vpc, - taskImageOptions: { - image: ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - }), /You can only specify either vpc or cluster. Alternatively, you can leave both blank/); - - test.done(); - }, - - 'creates AWS Cloud Map service for Private DNS namespace'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'MyVpc', {}); - const cluster = new Cluster(stack, 'EcsCluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - // WHEN - cluster.addDefaultCloudMapNamespace({ - name: 'foo.com', - type: NamespaceType.DNS_PRIVATE, - }); - - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('hello'), - }, - cloudMapOptions: { - name: 'myApp', - }, - memoryLimitMiB: 512, - }); - - // THEN - expect(stack).to(haveResource('AWS::ECS::Service', { - ServiceRegistries: [ - { - ContainerName: 'web', - ContainerPort: 80, - RegistryArn: { - 'Fn::GetAtt': [ - 'ServiceCloudmapServiceDE76B29D', - 'Arn', - ], - }, - }, - ], - })); - - expect(stack).to(haveResource('AWS::ServiceDiscovery::Service', { - DnsConfig: { - DnsRecords: [ - { - TTL: 60, - Type: 'SRV', - }, - ], - NamespaceId: { - 'Fn::GetAtt': [ - 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', - 'Id', - ], - }, - RoutingPolicy: 'MULTIVALUE', - }, - HealthCheckCustomConfig: { - FailureThreshold: 1, - }, - Name: 'myApp', - NamespaceId: { - 'Fn::GetAtt': [ - 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', - 'Id', - ], - }, - })); - - test.done(); - }, - - 'errors when setting both taskDefinition and taskImageOptions'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - const taskDefinition = new Ec2TaskDefinition(stack, 'Ec2TaskDef'); - taskDefinition.addContainer('test', { - image: ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - memoryLimitMiB: 512, - }); - - // THEN - test.throws(() => { - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - taskDefinition, - }); - }, /You must specify only one of TaskDefinition or TaskImageOptions./); - - test.done(); - }, - - 'errors when setting neither taskDefinition nor taskImageOptions'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - // THEN - test.throws(() => { - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - }); - }, /You must specify one of: taskDefinition or image/); - - test.done(); - }, - - 'errors when setting domainName but not domainZone'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - // THEN - test.throws(() => { - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - loadBalancers: [ - { - name: 'lb1', - domainName: 'api.example.com', - listeners: [ - { - name: 'listener1', - }, - ], - }, - ], - }); - }, /A Route53 hosted domain zone name is required to configure the specified domain name/); - - test.done(); - }, - - 'errors when loadBalancers is empty'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - loadBalancers: [], - }); - }, /At least one load balancer must be specified/); - - test.done(); - }, - - 'errors when targetGroups is empty'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - targetGroups: [], - }); - }, /At least one target group should be specified/); - - test.done(); - }, - - 'errors when no listener specified'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - loadBalancers: [ - { - name: 'lb', - listeners: [], - }, - ], - }); - }, /At least one listener must be specified/); - - test.done(); - }, - - 'errors when setting both HTTP protocol and certificate'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - loadBalancers: [ - { - name: 'lb', - listeners: [ - { - name: 'listener', - protocol: ApplicationProtocol.HTTP, - certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), - }, - ], - }, - ], - }); - }, /The HTTPS protocol must be used when a certificate is given/); - - test.done(); - }, - - 'errors when setting HTTPS protocol but not domain name'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - loadBalancers: [ - { - name: 'lb', - listeners: [ - { - name: 'listener', - protocol: ApplicationProtocol.HTTPS, - }, - ], - }, - ], - }); - }, /A domain name and zone is required when using the HTTPS protocol/); - - test.done(); - }, - - 'errors when listener is not defined but used in creating target groups'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - loadBalancers: [ - { - name: 'lb', - listeners: [ - { - name: 'listener1', - }, - ], - }, - ], - targetGroups: [ - { - containerPort: 80, - listener: 'listener2', - }, - ], - }); - }, /Listener listener2 is not defined. Did you define listener with name listener2?/); - - test.done(); - }, - - 'errors if desiredTaskCount is 0'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - // THEN - test.throws(() => - new ApplicationMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - desiredCount: 0, - }) - , /You must specify a desiredCount greater than 0/); - - test.done(); - }, - }, - - 'When Network Load Balancer': { - 'test ECS NLB construct with default settings'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - // WHEN - new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 256, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - }); - - // THEN - stack contains a load balancer and a service - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::LoadBalancer')); - - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 1, - LaunchType: 'EC2', - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Essential: true, - Image: 'test', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ServiceTaskDefwebLogGroup2A898F61', - }, - 'awslogs-stream-prefix': 'Service', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Memory: 256, - Name: 'web', - PortMappings: [ - { - ContainerPort: 80, - HostPort: 0, - Protocol: 'tcp', - }, - ], - }, - ], - ExecutionRoleArn: { - 'Fn::GetAtt': [ - 'ServiceTaskDefExecutionRole919F7BE3', - 'Arn', - ], - }, - Family: 'ServiceTaskDef79D79521', - NetworkMode: 'bridge', - RequiresCompatibilities: [ - 'EC2', - ], - TaskRoleArn: { - 'Fn::GetAtt': [ - 'ServiceTaskDefTaskRole0CFE2F57', - 'Arn', - ], - }, - })); - - test.done(); - }, - - 'test ECS NLB construct with all settings'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); - - // WHEN - new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 256, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - containerName: 'myContainer', - containerPorts: [80, 90], - enableLogging: false, - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - logDriver: new AwsLogDriver({ - streamPrefix: 'TestStream', - }), - family: 'Ec2TaskDef', - executionRole: new Role(stack, 'ExecutionRole', { - path: '/', - assumedBy: new CompositePrincipal( - new ServicePrincipal('ecs.amazonaws.com'), - new ServicePrincipal('ecs-tasks.amazonaws.com'), - ), - }), - taskRole: new Role(stack, 'TaskRole', { - assumedBy: new ServicePrincipal('ecs-tasks.amazonaws.com'), - }), - dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, - }, - cpu: 256, - desiredCount: 3, - enableECSManagedTags: true, - healthCheckGracePeriod: Duration.millis(2000), - loadBalancers: [ - { - name: 'lb1', - domainName: 'api.example.com', - domainZone: zone, - publicLoadBalancer: false, - listeners: [ - { - name: 'listener1', - }, - ], - }, - { - name: 'lb2', - listeners: [ - { - name: 'listener2', - port: 81, - }, - ], - }, - ], - propagateTags: PropagatedTagSource.SERVICE, - memoryReservationMiB: 256, - serviceName: 'myService', - targetGroups: [ - { - containerPort: 80, - listener: 'listener1', - }, - { - containerPort: 90, - listener: 'listener2', - }, - ], - }); - - // THEN - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 3, - EnableECSManagedTags: true, - HealthCheckGracePeriodSeconds: 2, - LaunchType: 'EC2', - LoadBalancers: [ - { - ContainerName: 'myContainer', - ContainerPort: 80, - TargetGroupArn: { - Ref: 'Servicelb1listener1ECSTargetGroupmyContainer80Group43098F8B', - }, - }, - { - ContainerName: 'myContainer', - ContainerPort: 90, - TargetGroupArn: { - Ref: 'Servicelb2listener2ECSTargetGroupmyContainer90GroupDEB417E4', - }, - }, - ], - PropagateTags: 'SERVICE', - SchedulingStrategy: 'REPLICA', - ServiceName: 'myService', - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Cpu: 256, - Environment: [ - { - Name: 'TEST_ENVIRONMENT_VARIABLE1', - Value: 'test environment variable 1 value', - }, - { - Name: 'TEST_ENVIRONMENT_VARIABLE2', - Value: 'test environment variable 2 value', - }, - ], - Essential: true, - Image: 'test', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ServiceTaskDefmyContainerLogGroup0A87368B', - }, - 'awslogs-stream-prefix': 'TestStream', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Memory: 256, - MemoryReservation: 256, - Name: 'myContainer', - PortMappings: [ - { - ContainerPort: 80, - HostPort: 0, - Protocol: 'tcp', - }, - { - ContainerPort: 90, - HostPort: 0, - Protocol: 'tcp', - }, - ], - DockerLabels: { - label1: 'labelValue1', - label2: 'labelValue2', - }, - }, - ], - ExecutionRoleArn: { - 'Fn::GetAtt': [ - 'ExecutionRole605A040B', - 'Arn', - ], - }, - Family: 'ServiceTaskDef79D79521', - NetworkMode: 'bridge', - RequiresCompatibilities: [ - 'EC2', - ], - TaskRoleArn: { - 'Fn::GetAtt': [ - 'TaskRole30FC0FBB', - 'Arn', - ], - }, - })); - - test.done(); - }, - - 'set vpc instead of cluster'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - - // WHEN - new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - vpc, - memoryLimitMiB: 256, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - }); - - // THEN - stack does not contain a LaunchConfiguration - expect(stack, true).notTo(haveResource('AWS::AutoScaling::LaunchConfiguration')); - - test.throws(() => expect(stack)); - - test.done(); - }, - - 'able to pass pre-defined task definition'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - const taskDefinition = new Ec2TaskDefinition(stack, 'Ec2TaskDef'); - const container = taskDefinition.addContainer('web', { - image: ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - memoryLimitMiB: 512, - }); - container.addPortMappings({ - containerPort: 80, - }); - - // WHEN - new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskDefinition, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Essential: true, - Image: 'amazon/amazon-ecs-sample', - Memory: 512, - Name: 'web', - PortMappings: [ - { - ContainerPort: 80, - HostPort: 0, - Protocol: 'tcp', - }, - ], - }, - ], - Family: 'Ec2TaskDef', - NetworkMode: 'bridge', - RequiresCompatibilities: [ - 'EC2', - ], - })); - - test.done(); - }, - - 'errors if no essential container in pre-defined task definition'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - const taskDefinition = new Ec2TaskDefinition(stack, 'Ec2TaskDef'); - - // THEN - test.throws(() => { - new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskDefinition, - }); - }, /At least one essential container must be specified/); - - test.done(); - }, - - 'set default load balancer, listener, target group correctly'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); - - // WHEN - const ecsService = new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - vpc, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - loadBalancers: [ - { - name: 'lb1', - listeners: [ - { - name: 'listener1', - }, - ], - }, - { - name: 'lb2', - domainName: 'api.example.com', - domainZone: zone, - listeners: [ - { - name: 'listener2', - }, - { - name: 'listener3', - }, - ], - }, - ], - targetGroups: [ - { - containerPort: 80, - }, - { - containerPort: 90, - }, - ], - }); - - // THEN - test.equal(ecsService.loadBalancer.node.id, 'lb1'); - test.equal(ecsService.listener.node.id, 'listener1'); - test.equal(ecsService.targetGroup.node.id, 'ECSTargetGroupweb80Group'); - - test.done(); - }, - - 'setting vpc and cluster throws error'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - - // WHEN - test.throws(() => new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - vpc, - taskImageOptions: { - image: ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - }), /You can only specify either vpc or cluster. Alternatively, you can leave both blank/); - - test.done(); - }, - - 'creates AWS Cloud Map service for Private DNS namespace'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'MyVpc', {}); - const cluster = new Cluster(stack, 'EcsCluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - // WHEN - cluster.addDefaultCloudMapNamespace({ - name: 'foo.com', - type: NamespaceType.DNS_PRIVATE, - }); - - new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('hello'), - }, - cloudMapOptions: { - name: 'myApp', - }, - memoryLimitMiB: 512, - }); - - // THEN - expect(stack).to(haveResource('AWS::ECS::Service', { - ServiceRegistries: [ - { - ContainerName: 'web', - ContainerPort: 80, - RegistryArn: { - 'Fn::GetAtt': [ - 'ServiceCloudmapServiceDE76B29D', - 'Arn', - ], - }, - }, - ], - })); - - expect(stack).to(haveResource('AWS::ServiceDiscovery::Service', { - DnsConfig: { - DnsRecords: [ - { - TTL: 60, - Type: 'SRV', - }, - ], - NamespaceId: { - 'Fn::GetAtt': [ - 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', - 'Id', - ], - }, - RoutingPolicy: 'MULTIVALUE', - }, - HealthCheckCustomConfig: { - FailureThreshold: 1, - }, - Name: 'myApp', - NamespaceId: { - 'Fn::GetAtt': [ - 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', - 'Id', - ], - }, - })); - - test.done(); - }, - - 'errors when setting both taskDefinition and taskImageOptions'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - const taskDefinition = new Ec2TaskDefinition(stack, 'Ec2TaskDef'); - taskDefinition.addContainer('test', { - image: ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - memoryLimitMiB: 512, - }); - - // THEN - test.throws(() => { - new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - taskDefinition, - }); - }, /You must specify only one of TaskDefinition or TaskImageOptions./); - - test.done(); - }, - - 'errors when setting neither taskDefinition nor taskImageOptions'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - // THEN - test.throws(() => { - new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - }); - }, /You must specify one of: taskDefinition or image/); - - test.done(); - }, - - 'errors when setting domainName but not domainZone'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - // THEN - test.throws(() => { - new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - loadBalancers: [ - { - name: 'lb1', - domainName: 'api.example.com', - listeners: [{ - name: 'listener1', - }], - }, - ], - }); - }, /A Route53 hosted domain zone name is required to configure the specified domain name/); - - test.done(); - }, - - 'errors when loadBalancers is empty'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - loadBalancers: [], - }); - }, /At least one load balancer must be specified/); - - test.done(); - }, - - 'errors when targetGroups is empty'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - targetGroups: [], - }); - }, /At least one target group should be specified/); - - test.done(); - }, - - 'errors when no listener specified'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - loadBalancers: [ - { - name: 'lb', - listeners: [], - }, - ], - }); - }, /At least one listener must be specified/); - - test.done(); - }, - - 'errors when listener is not defined but used in creating target groups'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - loadBalancers: [ - { - name: 'lb', - listeners: [ - { - name: 'listener1', - }, - ], - }, - ], - targetGroups: [ - { - containerPort: 80, - listener: 'listener2', - }, - ], - }); - }, /Listener listener2 is not defined. Did you define listener with name listener2?/); - - test.done(); - }, - - 'errors if desiredTaskCount is 0'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new InstanceType('t2.micro') }); - - // THEN - test.throws(() => - new NetworkMultipleTargetGroupsEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ContainerImage.fromRegistry('test'), - }, - desiredCount: 0, - }) - , /You must specify a desiredCount greater than 0/); - - test.done(); - }, - }, -}; diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s.ts deleted file mode 100644 index 8e2f527fbe509..0000000000000 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s.ts +++ /dev/null @@ -1,1416 +0,0 @@ -import { ABSENT, arrayWith, expect, haveResource, haveResourceLike, objectLike } from '@aws-cdk/assert-internal'; -import { Certificate } from '@aws-cdk/aws-certificatemanager'; -import * as ec2 from '@aws-cdk/aws-ec2'; -import * as ecs from '@aws-cdk/aws-ecs'; -import { ApplicationLoadBalancer, ApplicationProtocol, ApplicationProtocolVersion, NetworkLoadBalancer, SslPolicy } from '@aws-cdk/aws-elasticloadbalancingv2'; -import { PublicHostedZone } from '@aws-cdk/aws-route53'; -import * as cloudmap from '@aws-cdk/aws-servicediscovery'; -import * as cdk from '@aws-cdk/core'; -import * as cxapi from '@aws-cdk/cx-api'; -import { Test } from 'nodeunit'; -import * as ecsPatterns from '../../lib'; - -export = { - 'test ECS loadbalanced construct'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, - }, - desiredCount: 2, - }); - - // THEN - stack contains a load balancer and a service - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::LoadBalancer')); - - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 2, - LaunchType: 'EC2', - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Environment: [ - { - Name: 'TEST_ENVIRONMENT_VARIABLE1', - Value: 'test environment variable 1 value', - }, - { - Name: 'TEST_ENVIRONMENT_VARIABLE2', - Value: 'test environment variable 2 value', - }, - ], - Memory: 1024, - DockerLabels: { - label1: 'labelValue1', - label2: 'labelValue2', - }, - }, - ], - })); - - test.done(); - }, - - 'ApplicationLoadBalancedEc2Service desiredCount can be undefined when feature flag is set'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - stack.node.setContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT, true); - - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - }); - - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: ABSENT, - })); - - test.done(); - }, - - 'ApplicationLoadBalancedFargateService desiredCount can be undefined when feature flag is set'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - stack.node.setContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT, true); - - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - }); - - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: ABSENT, - })); - - test.done(); - }, - - 'NetworkLoadBalancedEc2Service desiredCount can be undefined when feature flag is set'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - stack.node.setContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT, true); - - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - }); - - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: ABSENT, - })); - - test.done(); - }, - - 'NetworkLoadBalancedFargateService desiredCount can be undefined when feature flag is set'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - stack.node.setContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT, true); - - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - }); - - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: ABSENT, - })); - - test.done(); - }, - - 'set vpc instead of cluster'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { - vpc, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - }, - desiredCount: 2, - }); - - // THEN - stack does not contain a LaunchConfiguration - expect(stack, true).notTo(haveResource('AWS::AutoScaling::LaunchConfiguration')); - - test.throws(() => expect(stack)); - - test.done(); - }, - - 'setting vpc and cluster throws error'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - test.throws(() => new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { - cluster, - vpc, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - })); - - test.done(); - }, - - 'test ECS loadbalanced construct with memoryReservationMiB'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { - cluster, - memoryReservationMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - }); - - // THEN - stack contains a load balancer and a service - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::LoadBalancer')); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - MemoryReservation: 1024, - }, - ], - })); - - test.done(); - }, - - 'creates AWS Cloud Map service for Private DNS namespace with application load balanced ec2 service'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'MyVpc', {}); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - cluster.addDefaultCloudMapNamespace({ - name: 'foo.com', - type: cloudmap.NamespaceType.DNS_PRIVATE, - }); - - new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { - cluster, - taskImageOptions: { - containerPort: 8000, - image: ecs.ContainerImage.fromRegistry('hello'), - }, - cloudMapOptions: { - name: 'myApp', - }, - memoryLimitMiB: 512, - }); - - // THEN - expect(stack).to(haveResource('AWS::ECS::Service', { - ServiceRegistries: [ - { - ContainerName: 'web', - ContainerPort: 8000, - RegistryArn: { - 'Fn::GetAtt': [ - 'ServiceCloudmapServiceDE76B29D', - 'Arn', - ], - }, - }, - ], - })); - - expect(stack).to(haveResource('AWS::ServiceDiscovery::Service', { - DnsConfig: { - DnsRecords: [ - { - TTL: 60, - Type: 'SRV', - }, - ], - NamespaceId: { - 'Fn::GetAtt': [ - 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', - 'Id', - ], - }, - RoutingPolicy: 'MULTIVALUE', - }, - HealthCheckCustomConfig: { - FailureThreshold: 1, - }, - Name: 'myApp', - NamespaceId: { - 'Fn::GetAtt': [ - 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', - 'Id', - ], - }, - })); - - test.done(); - }, - - 'creates AWS Cloud Map service for Private DNS namespace with network load balanced fargate service'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'MyVpc', {}); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - cluster.addDefaultCloudMapNamespace({ - name: 'foo.com', - type: cloudmap.NamespaceType.DNS_PRIVATE, - }); - - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - containerPort: 8000, - image: ecs.ContainerImage.fromRegistry('hello'), - }, - cloudMapOptions: { - name: 'myApp', - }, - memoryLimitMiB: 512, - }); - - // THEN - expect(stack).to(haveResource('AWS::ECS::Service', { - ServiceRegistries: [ - { - RegistryArn: { - 'Fn::GetAtt': [ - 'ServiceCloudmapServiceDE76B29D', - 'Arn', - ], - }, - }, - ], - })); - - expect(stack).to(haveResource('AWS::ServiceDiscovery::Service', { - DnsConfig: { - DnsRecords: [ - { - TTL: 60, - Type: 'A', - }, - ], - NamespaceId: { - 'Fn::GetAtt': [ - 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', - 'Id', - ], - }, - RoutingPolicy: 'MULTIVALUE', - }, - HealthCheckCustomConfig: { - FailureThreshold: 1, - }, - Name: 'myApp', - NamespaceId: { - 'Fn::GetAtt': [ - 'EcsClusterDefaultServiceDiscoveryNamespaceB0971B2F', - 'Id', - ], - }, - })); - - test.done(); - }, - - 'test Fargate loadbalanced construct'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, - }, - desiredCount: 2, - }); - - // THEN - stack contains a load balancer and a service - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::LoadBalancer')); - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Environment: [ - { - Name: 'TEST_ENVIRONMENT_VARIABLE1', - Value: 'test environment variable 1 value', - }, - { - Name: 'TEST_ENVIRONMENT_VARIABLE2', - Value: 'test environment variable 2 value', - }, - ], - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { Ref: 'ServiceTaskDefwebLogGroup2A898F61' }, - 'awslogs-stream-prefix': 'Service', - 'awslogs-region': { Ref: 'AWS::Region' }, - }, - }, - DockerLabels: { - label1: 'labelValue1', - label2: 'labelValue2', - }, - }, - ], - })); - - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 2, - LaunchType: 'FARGATE', - })); - - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::Listener', { - Port: 80, - Protocol: 'HTTP', - })); - - test.done(); - }, - - 'test Fargate loadbalanced construct opting out of log driver creation'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - enableLogging: false, - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - }, - desiredCount: 2, - }); - - // THEN - stack contains a load balancer and a service - expect(stack).notTo(haveResource('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Environment: [ - { - Name: 'TEST_ENVIRONMENT_VARIABLE1', - Value: 'test environment variable 1 value', - }, - { - Name: 'TEST_ENVIRONMENT_VARIABLE2', - Value: 'test environment variable 2 value', - }, - ], - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { Ref: 'ServiceTaskDefwebLogGroup2A898F61' }, - 'awslogs-stream-prefix': 'Service', - 'awslogs-region': { Ref: 'AWS::Region' }, - }, - }, - }, - ], - })); - - test.done(); - }, - - 'test Fargate loadbalanced construct with TLS'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - domainName: 'api.example.com', - domainZone: zone, - certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), - sslPolicy: SslPolicy.TLS12_EXT, - }); - - // THEN - stack contains a load balancer and a service - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::LoadBalancer')); - - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::Listener', { - Port: 443, - Protocol: 'HTTPS', - Certificates: [{ - CertificateArn: 'helloworld', - }], - SslPolicy: SslPolicy.TLS12_EXT, - })); - - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::TargetGroup', { - Port: 80, - Protocol: 'HTTP', - TargetType: 'ip', - VpcId: { - Ref: 'VPCB9E5F0B4', - }, - })); - - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 1, - LaunchType: 'FARGATE', - })); - - expect(stack).to(haveResource('AWS::Route53::RecordSet', { - Name: 'api.example.com.', - HostedZoneId: { - Ref: 'HostedZoneDB99F866', - }, - Type: 'A', - AliasTarget: { - HostedZoneId: { 'Fn::GetAtt': ['ServiceLBE9A1ADBC', 'CanonicalHostedZoneID'] }, - DNSName: { 'Fn::Join': ['', ['dualstack.', { 'Fn::GetAtt': ['ServiceLBE9A1ADBC', 'DNSName'] }]] }, - }, - })); - - test.done(); - }, - - 'test Fargateloadbalanced construct with TLS and default certificate'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - domainName: 'api.example.com', - domainZone: zone, - protocol: ApplicationProtocol.HTTPS, - }); - - // THEN - stack contains a load balancer, a service, and a certificate - expect(stack).to(haveResource('AWS::CertificateManager::Certificate', { - DomainName: 'api.example.com', - DomainValidationOptions: [ - { - DomainName: 'api.example.com', - HostedZoneId: { - Ref: 'HostedZoneDB99F866', - }, - }, - ], - ValidationMethod: 'DNS', - })); - - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::LoadBalancer')); - - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::Listener', { - Port: 443, - Protocol: 'HTTPS', - Certificates: [{ - CertificateArn: { - Ref: 'ServiceCertificateA7C65FE6', - }, - }], - })); - - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 1, - LaunchType: 'FARGATE', - })); - - expect(stack).to(haveResource('AWS::Route53::RecordSet', { - Name: 'api.example.com.', - HostedZoneId: { - Ref: 'HostedZoneDB99F866', - }, - Type: 'A', - AliasTarget: { - HostedZoneId: { 'Fn::GetAtt': ['ServiceLBE9A1ADBC', 'CanonicalHostedZoneID'] }, - DNSName: { 'Fn::Join': ['', ['dualstack.', { 'Fn::GetAtt': ['ServiceLBE9A1ADBC', 'DNSName'] }]] }, - }, - })); - - test.done(); - }, - - 'errors when setting domainName but not domainZone'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - domainName: 'api.example.com', - }); - }); - - test.done(); - }, - - 'errors when setting both HTTP protocol and certificate'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - protocol: ApplicationProtocol.HTTP, - certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), - }); - }); - - test.done(); - }, - - 'errors when setting both HTTP protocol and redirectHTTP'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - protocol: ApplicationProtocol.HTTP, - redirectHTTP: true, - }); - }); - - test.done(); - }, - - 'does not throw errors when not setting HTTPS protocol but certificate for redirectHTTP'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); - - // THEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - domainName: 'api.example.com', - domainZone: zone, - redirectHTTP: true, - certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), - }); - - test.done(); - }, - - 'errors when setting HTTPS protocol but not domain name'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - protocol: ApplicationProtocol.HTTPS, - }); - }); - - test.done(); - }, - - 'test Fargate loadbalanced construct with optional log driver input'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - enableLogging: false, - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - logDriver: new ecs.AwsLogDriver({ - streamPrefix: 'TestStream', - }), - }, - desiredCount: 2, - }); - - // THEN - stack contains a load balancer and a service - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Environment: [ - { - Name: 'TEST_ENVIRONMENT_VARIABLE1', - Value: 'test environment variable 1 value', - }, - { - Name: 'TEST_ENVIRONMENT_VARIABLE2', - Value: 'test environment variable 2 value', - }, - ], - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { Ref: 'ServiceTaskDefwebLogGroup2A898F61' }, - 'awslogs-stream-prefix': 'TestStream', - 'awslogs-region': { Ref: 'AWS::Region' }, - }, - }, - }, - ], - })); - - test.done(); - }, - - 'test Fargate loadbalanced construct with logging enabled'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - enableLogging: true, - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - }, - desiredCount: 2, - }); - - // THEN - stack contains a load balancer and a service - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Environment: [ - { - Name: 'TEST_ENVIRONMENT_VARIABLE1', - Value: 'test environment variable 1 value', - }, - { - Name: 'TEST_ENVIRONMENT_VARIABLE2', - Value: 'test environment variable 2 value', - }, - ], - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { Ref: 'ServiceTaskDefwebLogGroup2A898F61' }, - 'awslogs-stream-prefix': 'Service', - 'awslogs-region': { Ref: 'AWS::Region' }, - }, - }, - }, - ], - })); - - test.done(); - }, - - 'test Fargate loadbalanced construct with both image and taskDefinition provided'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef'); - taskDefinition.addContainer('web', { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - memoryLimitMiB: 512, - }); - - // WHEN - test.throws(() => new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - enableLogging: true, - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - }, - desiredCount: 2, - taskDefinition, - })); - - test.done(); - }, - - 'test Fargate application loadbalanced construct with taskDefinition provided'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); - const container = taskDefinition.addContainer('passedTaskDef', { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - memoryLimitMiB: 512, - }); - container.addPortMappings({ - containerPort: 80, - }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskDefinition, - desiredCount: 2, - memoryLimitMiB: 1024, - }); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Image: 'amazon/amazon-ecs-sample', - Memory: 512, - Name: 'passedTaskDef', - PortMappings: [ - { - ContainerPort: 80, - Protocol: 'tcp', - }, - ], - }, - ], - })); - - test.done(); - }, - - 'ALB - throws if desiredTaskCount is 0'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // THEN - test.throws(() => - new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - desiredCount: 0, - }) - , /You must specify a desiredCount greater than 0/); - - test.done(); - }, - - 'NLB - throws if desiredTaskCount is 0'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // THEN - test.throws(() => - new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - desiredCount: 0, - }) - , /You must specify a desiredCount greater than 0/); - - test.done(); - }, - 'ALBFargate - having *HealthyPercent properties'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'ALB123Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - }, - minHealthyPercent: 100, - maxHealthyPercent: 200, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - DeploymentConfiguration: { - MinimumHealthyPercent: 100, - MaximumPercent: 200, - }, - })); - - test.done(); - }, - - 'NLBFargate - having *HealthyPercent properties'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - }, - desiredCount: 1, - minHealthyPercent: 100, - maxHealthyPercent: 200, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - DeploymentConfiguration: { - MinimumHealthyPercent: 100, - MaximumPercent: 200, - }, - })); - - test.done(); - }, - - 'ALB - having *HealthyPercent properties'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - }, - desiredCount: 1, - minHealthyPercent: 100, - maxHealthyPercent: 200, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - DeploymentConfiguration: { - MinimumHealthyPercent: 100, - MaximumPercent: 200, - }, - })); - - test.done(); - }, - - 'ALB - includes provided protocol version properties'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - }, - desiredCount: 1, - domainName: 'api.example.com', - domainZone: zone, - protocol: ApplicationProtocol.HTTPS, - protocolVersion: ApplicationProtocolVersion.GRPC, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup', { - ProtocolVersion: 'GRPC', - })); - - test.done(); - }, - - 'NLB - having *HealthyPercent properties'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - }, - desiredCount: 1, - minHealthyPercent: 100, - maxHealthyPercent: 200, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - DeploymentConfiguration: { - MinimumHealthyPercent: 100, - MaximumPercent: 200, - }, - })); - - test.done(); - }, - - 'ALB - having deployment controller'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - }, - deploymentController: { - type: ecs.DeploymentControllerType.CODE_DEPLOY, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - DeploymentController: { - Type: 'CODE_DEPLOY', - }, - })); - - test.done(); - }, - - 'NLB - having deployment controller'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - }, - deploymentController: { - type: ecs.DeploymentControllerType.CODE_DEPLOY, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - DeploymentController: { - Type: 'CODE_DEPLOY', - }, - })); - - test.done(); - }, - - 'ALB with circuit breaker'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - }, - circuitBreaker: { rollback: true }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - DeploymentConfiguration: { - DeploymentCircuitBreaker: { - Enable: true, - Rollback: true, - }, - }, - DeploymentController: { - Type: 'ECS', - }, - })); - - test.done(); - }, - - 'NLB with circuit breaker'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - }, - circuitBreaker: { rollback: true }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - DeploymentConfiguration: { - DeploymentCircuitBreaker: { - Enable: true, - Rollback: true, - }, - }, - DeploymentController: { - Type: 'ECS', - }, - })); - - test.done(); - }, - - 'NetworkLoadbalancedEC2Service accepts previously created load balancer'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc, clusterName: 'MyCluster' }); - cluster.addCapacity('Capacity', { instanceType: new ec2.InstanceType('t2.micro') }); - const nlb = new NetworkLoadBalancer(stack, 'NLB', { vpc }); - const taskDef = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); - const container = taskDef.addContainer('Container', { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - memoryLimitMiB: 1024, - }); - container.addPortMappings({ containerPort: 80 }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { - cluster, - loadBalancer: nlb, - taskDefinition: taskDef, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - LaunchType: 'EC2', - })); - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::LoadBalancer', { - Type: 'network', - })); - test.done(); - }, - - 'NetworkLoadBalancedEC2Service accepts imported load balancer'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const nlbArn = 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188'; - const vpc = new ec2.Vpc(stack, 'Vpc'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc, clusterName: 'MyCluster' }); - cluster.addCapacity('Capacity', { instanceType: new ec2.InstanceType('t2.micro') }); - const nlb = NetworkLoadBalancer.fromNetworkLoadBalancerAttributes(stack, 'NLB', { - loadBalancerArn: nlbArn, - vpc, - }); - const taskDef = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); - const container = taskDef.addContainer('Container', { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - memoryLimitMiB: 1024, - }); - container.addPortMappings({ - containerPort: 80, - }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', { - cluster, - loadBalancer: nlb, - desiredCount: 1, - taskDefinition: taskDef, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - LaunchType: 'EC2', - LoadBalancers: [{ ContainerName: 'Container', ContainerPort: 80 }], - })); - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup')); - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { - LoadBalancerArn: nlb.loadBalancerArn, - Port: 80, - })); - test.done(); - }, - - 'ApplicationLoadBalancedEC2Service accepts previously created load balancer'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc, clusterName: 'MyCluster' }); - cluster.addCapacity('Capacity', { instanceType: new ec2.InstanceType('t2.micro') }); - const sg = new ec2.SecurityGroup(stack, 'SG', { vpc }); - const alb = new ApplicationLoadBalancer(stack, 'NLB', { - vpc, - securityGroup: sg, - }); - const taskDef = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); - const container = taskDef.addContainer('Container', { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - memoryLimitMiB: 1024, - }); - container.addPortMappings({ containerPort: 80 }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { - cluster, - loadBalancer: alb, - taskDefinition: taskDef, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - LaunchType: 'EC2', - })); - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::LoadBalancer', { - Type: 'application', - })); - test.done(); - }, - - 'ApplicationLoadBalancedEC2Service accepts imported load balancer'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const albArn = 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188'; - const vpc = new ec2.Vpc(stack, 'Vpc'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc, clusterName: 'MyCluster' }); - cluster.addCapacity('Capacity', { instanceType: new ec2.InstanceType('t2.micro') }); - const sg = new ec2.SecurityGroup(stack, 'SG', { vpc }); - const alb = ApplicationLoadBalancer.fromApplicationLoadBalancerAttributes(stack, 'ALB', { - loadBalancerArn: albArn, - vpc, - securityGroupId: sg.securityGroupId, - loadBalancerDnsName: 'MyName', - }); - const taskDef = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); - const container = taskDef.addContainer('Container', { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - memoryLimitMiB: 1024, - }); - container.addPortMappings({ - containerPort: 80, - }); - // WHEN - new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { - cluster, - loadBalancer: alb, - taskDefinition: taskDef, - }); - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - LaunchType: 'EC2', - LoadBalancers: [{ ContainerName: 'Container', ContainerPort: 80 }], - })); - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup')); - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { - LoadBalancerArn: alb.loadBalancerArn, - Port: 80, - })); - - test.done(); - }, - - 'test ECS loadbalanced construct default/open security group'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { - cluster, - memoryReservationMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - }); - - // THEN - Stack contains no ingress security group rules - expect(stack).to(haveResourceLike('AWS::EC2::SecurityGroup', { - SecurityGroupIngress: [{ - CidrIp: '0.0.0.0/0', - FromPort: 80, - IpProtocol: 'tcp', - ToPort: 80, - }], - })); - - test.done(); - }, - - 'test ECS loadbalanced construct closed security group'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'example.com' }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', { - cluster, - memoryReservationMiB: 1024, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - domainName: 'api.example.com', - domainZone: zone, - certificate: Certificate.fromCertificateArn(stack, 'Cert', 'helloworld'), - openListener: false, - redirectHTTP: true, - }); - - // THEN - Stack contains no ingress security group rules - expect(stack).notTo(haveResourceLike('AWS::EC2::SecurityGroup', { - SecurityGroupIngress: arrayWith(objectLike({})), - })); - - test.done(); - }, -}; diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.queue-processing-ecs-service.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.queue-processing-ecs-service.ts deleted file mode 100644 index 97bdb47c7b5b3..0000000000000 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.queue-processing-ecs-service.ts +++ /dev/null @@ -1,399 +0,0 @@ -import { ABSENT, expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; -import * as autoscaling from '@aws-cdk/aws-autoscaling'; -import * as ec2 from '@aws-cdk/aws-ec2'; -import * as ecs from '@aws-cdk/aws-ecs'; -import * as sqs from '@aws-cdk/aws-sqs'; -import * as cdk from '@aws-cdk/core'; -import * as cxapi from '@aws-cdk/cx-api'; -import { Test } from 'nodeunit'; -import * as ecsPatterns from '../../lib'; - -export = { - 'test ECS queue worker service construct - with only required props'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 512, - image: ecs.ContainerImage.fromRegistry('test'), - }); - - // THEN - QueueWorker is of EC2 launch type, an SQS queue is created and all default properties are set. - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 1, - LaunchType: 'EC2', - })); - - expect(stack).to(haveResource('AWS::SQS::Queue', { - RedrivePolicy: { - deadLetterTargetArn: { - 'Fn::GetAtt': [ - 'ServiceEcsProcessingDeadLetterQueue4A89196E', - 'Arn', - ], - }, - maxReceiveCount: 3, - }, - })); - - expect(stack).to(haveResource('AWS::SQS::Queue', { - MessageRetentionPeriod: 1209600, - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Environment: [ - { - Name: 'QUEUE_NAME', - Value: { - 'Fn::GetAtt': [ - 'ServiceEcsProcessingQueueC266885C', - 'QueueName', - ], - }, - }, - ], - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupD52338D1', - }, - 'awslogs-stream-prefix': 'Service', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Essential: true, - Image: 'test', - Memory: 512, - }, - ], - Family: 'ServiceQueueProcessingTaskDef83DB34F1', - })); - - test.done(); - }, - - 'test ECS queue worker service construct - with remove default desiredCount feature flag'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - stack.node.setContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT, true); - - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 512, - image: ecs.ContainerImage.fromRegistry('test'), - }); - - // THEN - QueueWorker is of EC2 launch type, and desiredCount is not defined on the Ec2Service. - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: ABSENT, - LaunchType: 'EC2', - })); - - test.done(); - }, - - 'test ECS queue worker service construct - with optional props for queues'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 512, - image: ecs.ContainerImage.fromRegistry('test'), - maxReceiveCount: 42, - retentionPeriod: cdk.Duration.days(7), - visibilityTimeout: cdk.Duration.minutes(5), - }); - - // THEN - QueueWorker is of EC2 launch type, an SQS queue is created and all default properties are set. - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 1, - LaunchType: 'EC2', - })); - - expect(stack).to(haveResource('AWS::SQS::Queue', { - RedrivePolicy: { - deadLetterTargetArn: { - 'Fn::GetAtt': [ - 'ServiceEcsProcessingDeadLetterQueue4A89196E', - 'Arn', - ], - }, - maxReceiveCount: 42, - }, - VisibilityTimeout: 300, - })); - - expect(stack).to(haveResource('AWS::SQS::Queue', { - MessageRetentionPeriod: 604800, - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Environment: [ - { - Name: 'QUEUE_NAME', - Value: { - 'Fn::GetAtt': [ - 'ServiceEcsProcessingQueueC266885C', - 'QueueName', - ], - }, - }, - ], - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupD52338D1', - }, - 'awslogs-stream-prefix': 'Service', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Essential: true, - Image: 'test', - Memory: 512, - }, - ], - Family: 'ServiceQueueProcessingTaskDef83DB34F1', - })); - - test.done(); - }, - - 'test ECS queue worker service construct - with optional props'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - const queue = new sqs.Queue(stack, 'ecs-test-queue', { - queueName: 'ecs-test-sqs-queue', - }); - - // WHEN - new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 1024, - image: ecs.ContainerImage.fromRegistry('test'), - command: ['-c', '4', 'amazon.com'], - enableLogging: false, - desiredTaskCount: 2, - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - queue, - maxScalingCapacity: 5, - minHealthyPercent: 60, - maxHealthyPercent: 150, - serviceName: 'ecs-test-service', - family: 'ecs-task-family', - circuitBreaker: { rollback: true }, - gpuCount: 256, - }); - - // THEN - QueueWorker is of EC2 launch type, an SQS queue is created and all optional properties are set. - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 2, - DeploymentConfiguration: { - MinimumHealthyPercent: 60, - MaximumPercent: 150, - DeploymentCircuitBreaker: { - Enable: true, - Rollback: true, - }, - }, - LaunchType: 'EC2', - ServiceName: 'ecs-test-service', - DeploymentController: { - Type: 'ECS', - }, - })); - - expect(stack).to(haveResource('AWS::SQS::Queue', { - QueueName: 'ecs-test-sqs-queue', - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Command: [ - '-c', - '4', - 'amazon.com', - ], - Environment: [ - { - Name: 'TEST_ENVIRONMENT_VARIABLE1', - Value: 'test environment variable 1 value', - }, - { - Name: 'TEST_ENVIRONMENT_VARIABLE2', - Value: 'test environment variable 2 value', - }, - { - Name: 'QUEUE_NAME', - Value: { - 'Fn::GetAtt': [ - 'ecstestqueueD1FDA34B', - 'QueueName', - ], - }, - }, - ], - Image: 'test', - Memory: 1024, - ResourceRequirements: [ - { - Type: 'GPU', - Value: '256', - }, - ], - }, - ], - Family: 'ecs-task-family', - })); - - test.done(); - }, - - 'can set desiredTaskCount to 0'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { - cluster, - desiredTaskCount: 0, - maxScalingCapacity: 2, - memoryLimitMiB: 512, - image: ecs.ContainerImage.fromRegistry('test'), - }); - - // THEN - QueueWorker is of EC2 launch type, an SQS queue is created and all default properties are set. - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 0, - LaunchType: 'EC2', - })); - - test.done(); - }, - - 'throws if desiredTaskCount and maxScalingCapacity are 0'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // THEN - test.throws(() => - new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { - cluster, - desiredTaskCount: 0, - memoryLimitMiB: 512, - image: ecs.ContainerImage.fromRegistry('test'), - }) - , /maxScalingCapacity must be set and greater than 0 if desiredCount is 0/); - - test.done(); - }, - - 'can set custom containerName'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { - cluster, - memoryLimitMiB: 512, - image: ecs.ContainerImage.fromRegistry('test'), - containerName: 'my-container', - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Name: 'my-container', - }, - ], - })); - - test.done(); - }, - - 'can set capacity provider strategies'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - const autoScalingGroup = new autoscaling.AutoScalingGroup(stack, 'asg', { - vpc, - instanceType: new ec2.InstanceType('bogus'), - machineImage: ecs.EcsOptimizedImage.amazonLinux2(), - }); - const capacityProvider = new ecs.AsgCapacityProvider(stack, 'provider', { - autoScalingGroup, - }); - cluster.addAsgCapacityProvider(capacityProvider); - - // WHEN - new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { - cluster, - image: ecs.ContainerImage.fromRegistry('test'), - memoryLimitMiB: 512, - capacityProviderStrategies: [ - { - capacityProvider: capacityProvider.capacityProviderName, - }, - ], - }); - - // THEN - expect(stack).to( - haveResource('AWS::ECS::Service', { - LaunchType: ABSENT, - CapacityProviderStrategy: [ - { - CapacityProvider: { - Ref: 'providerD3FF4D3A', - }, - }, - ], - }), - ); - - test.done(); - }, -}; diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.scheduled-ecs-task.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.scheduled-ecs-task.ts deleted file mode 100644 index 712c83ab83b93..0000000000000 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.scheduled-ecs-task.ts +++ /dev/null @@ -1,341 +0,0 @@ -import { expect, haveResource } from '@aws-cdk/assert-internal'; -import * as ec2 from '@aws-cdk/aws-ec2'; -import * as ecs from '@aws-cdk/aws-ecs'; -import * as events from '@aws-cdk/aws-events'; -import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; -import { ScheduledEc2Task } from '../../lib'; - -export = { - 'Can create a scheduled Ec2 Task - with only required props'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { - instanceType: new ec2.InstanceType('t2.micro'), - }); - - new ScheduledEc2Task(stack, 'ScheduledEc2Task', { - cluster, - scheduledEc2TaskImageOptions: { - image: ecs.ContainerImage.fromRegistry('henk'), - memoryLimitMiB: 512, - }, - schedule: events.Schedule.expression('rate(1 minute)'), - }); - - // THEN - expect(stack).to(haveResource('AWS::Events::Rule', { - State: 'ENABLED', - Targets: [ - { - Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, - EcsParameters: { - TaskCount: 1, - TaskDefinitionArn: { Ref: 'ScheduledEc2TaskScheduledTaskDef56328BA4' }, - }, - Id: 'Target0', - Input: '{}', - RoleArn: { 'Fn::GetAtt': ['ScheduledEc2TaskScheduledTaskDefEventsRole64113C5F', 'Arn'] }, - }, - ], - })); - - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Essential: true, - Image: 'henk', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ScheduledEc2TaskScheduledTaskDefScheduledContainerLogGroupA85E11E6', - }, - 'awslogs-stream-prefix': 'ScheduledEc2Task', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Memory: 512, - Name: 'ScheduledContainer', - }, - ], - })); - - test.done(); - }, - - 'Can create a scheduled Ec2 Task - with optional props'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - - cluster.addCapacity('DefaultAutoScalingGroup', { - instanceType: new ec2.InstanceType('t2.micro'), - }); - - new ScheduledEc2Task(stack, 'ScheduledEc2Task', { - cluster, - enabled: false, - scheduledEc2TaskImageOptions: { - image: ecs.ContainerImage.fromRegistry('henk'), - memoryLimitMiB: 512, - cpu: 2, - environment: { TRIGGER: 'CloudWatch Events' }, - }, - desiredTaskCount: 2, - schedule: events.Schedule.expression('rate(1 minute)'), - ruleName: 'sample-scheduled-task-rule', - }); - - // THEN - expect(stack).to(haveResource('AWS::Events::Rule', { - Name: 'sample-scheduled-task-rule', - State: 'DISABLED', - Targets: [ - { - Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, - EcsParameters: { - TaskCount: 2, - TaskDefinitionArn: { Ref: 'ScheduledEc2TaskScheduledTaskDef56328BA4' }, - }, - Id: 'Target0', - Input: '{}', - RoleArn: { 'Fn::GetAtt': ['ScheduledEc2TaskScheduledTaskDefEventsRole64113C5F', 'Arn'] }, - }, - ], - })); - - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Cpu: 2, - Environment: [ - { - Name: 'TRIGGER', - Value: 'CloudWatch Events', - }, - ], - Essential: true, - Image: 'henk', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ScheduledEc2TaskScheduledTaskDefScheduledContainerLogGroupA85E11E6', - }, - 'awslogs-stream-prefix': 'ScheduledEc2Task', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Memory: 512, - Name: 'ScheduledContainer', - }, - ], - })); - - test.done(); - }, - 'Scheduled ECS Task - with securityGroups defined'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', { - networkMode: ecs.NetworkMode.AWS_VPC, - }); - const sg = new ec2.SecurityGroup(stack, 'MySG', { vpc }); - - new ScheduledEc2Task(stack, 'ScheduledEc2Task', { - cluster, - scheduledEc2TaskDefinitionOptions: { - taskDefinition, - }, - schedule: events.Schedule.expression('rate(1 minute)'), - securityGroups: [sg], - }); - - // THEN - expect(stack).to(haveResource('AWS::Events::Rule', { - Targets: [ - { - Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, - EcsParameters: { - LaunchType: 'EC2', - NetworkConfiguration: { - AwsVpcConfiguration: { - AssignPublicIp: 'DISABLED', - SecurityGroups: [{ - 'Fn::GetAtt': [ - 'MySG94FE69A8', - 'GroupId', - ], - }], - Subnets: [ - { - Ref: 'VpcPrivateSubnet1Subnet536B997A', - }, - ], - }, - }, - TaskCount: 1, - TaskDefinitionArn: { Ref: 'Ec2TaskDef0226F28C' }, - }, - Id: 'Target0', - Input: '{}', - RoleArn: { 'Fn::GetAtt': ['Ec2TaskDefEventsRoleA0756175', 'Arn'] }, - }, - ], - })); - - test.done(); - }, - - 'Scheduled Ec2 Task - with MemoryReservation defined'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { - instanceType: new ec2.InstanceType('t2.micro'), - }); - - new ScheduledEc2Task(stack, 'ScheduledEc2Task', { - cluster, - scheduledEc2TaskImageOptions: { - image: ecs.ContainerImage.fromRegistry('henk'), - memoryReservationMiB: 512, - }, - schedule: events.Schedule.expression('rate(1 minute)'), - }); - - // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Essential: true, - Image: 'henk', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ScheduledEc2TaskScheduledTaskDefScheduledContainerLogGroupA85E11E6', - }, - 'awslogs-stream-prefix': 'ScheduledEc2Task', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - MemoryReservation: 512, - Name: 'ScheduledContainer', - }, - ], - })); - - test.done(); - }, - - 'Scheduled Ec2 Task - with Command defined'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { - instanceType: new ec2.InstanceType('t2.micro'), - }); - - new ScheduledEc2Task(stack, 'ScheduledEc2Task', { - cluster, - scheduledEc2TaskImageOptions: { - image: ecs.ContainerImage.fromRegistry('henk'), - memoryReservationMiB: 512, - command: ['-c', '4', 'amazon.com'], - }, - schedule: events.Schedule.expression('rate(1 minute)'), - }); - - // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Command: [ - '-c', - '4', - 'amazon.com', - ], - Essential: true, - Image: 'henk', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ScheduledEc2TaskScheduledTaskDefScheduledContainerLogGroupA85E11E6', - }, - 'awslogs-stream-prefix': 'ScheduledEc2Task', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - MemoryReservation: 512, - Name: 'ScheduledContainer', - }, - ], - })); - - test.done(); - }, - - 'throws if desiredTaskCount is 0'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { - instanceType: new ec2.InstanceType('t2.micro'), - }); - - // THEN - test.throws(() => - new ScheduledEc2Task(stack, 'ScheduledEc2Task', { - cluster, - scheduledEc2TaskImageOptions: { - image: ecs.ContainerImage.fromRegistry('henk'), - memoryLimitMiB: 512, - }, - schedule: events.Schedule.expression('rate(1 minute)'), - desiredTaskCount: 0, - }), - /You must specify a desiredTaskCount greater than 0/); - - test.done(); - }, - - 'Scheduled Ec2 Task - exposes ECS Task'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - - const scheduledEc2Task = new ScheduledEc2Task(stack, 'ScheduledEc2Task', { - cluster, - scheduledEc2TaskImageOptions: { - image: ecs.ContainerImage.fromRegistry('henk'), - memoryLimitMiB: 512, - }, - schedule: events.Schedule.expression('rate(1 minute)'), - }); - - // THEN - test.notEqual(scheduledEc2Task.task, undefined); - - test.done(); - }, -}; diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/load-balanced-fargate-service-v2.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/load-balanced-fargate-service-v2.test.ts new file mode 100644 index 0000000000000..902d5412ee8bf --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/load-balanced-fargate-service-v2.test.ts @@ -0,0 +1,664 @@ +import '@aws-cdk/assert-internal/jest'; +import { Vpc } from '@aws-cdk/aws-ec2'; +import * as ecs from '@aws-cdk/aws-ecs'; +import { CompositePrincipal, Role, ServicePrincipal } from '@aws-cdk/aws-iam'; +import { Duration, Stack } from '@aws-cdk/core'; +import { ApplicationMultipleTargetGroupsFargateService, NetworkMultipleTargetGroupsFargateService, ApplicationLoadBalancedFargateService } from '../../lib'; + +describe('When Application Load Balancer', () => { + test('test Fargate loadbalanced construct with default settings', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ApplicationMultipleTargetGroupsFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + }); + + // THEN - stack contains a load balancer and a service + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); + + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 1, + LaunchType: 'FARGATE', + LoadBalancers: [ + { + ContainerName: 'web', + ContainerPort: 80, + TargetGroupArn: { + Ref: 'ServiceLBPublicListenerECSGroup0CC8688C', + }, + }, + ], + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Image: 'test', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ServiceTaskDefwebLogGroup2A898F61', + }, + 'awslogs-stream-prefix': 'Service', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Name: 'web', + PortMappings: [ + { + ContainerPort: 80, + Protocol: 'tcp', + }, + ], + }, + ], + Cpu: '256', + ExecutionRoleArn: { + 'Fn::GetAtt': [ + 'ServiceTaskDefExecutionRole919F7BE3', + 'Arn', + ], + }, + Family: 'ServiceTaskDef79D79521', + Memory: '512', + NetworkMode: 'awsvpc', + RequiresCompatibilities: [ + 'FARGATE', + ], + }); + }); + + test('test Fargate loadbalanced construct with all settings', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ApplicationMultipleTargetGroupsFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + containerName: 'hello', + containerPorts: [80, 90], + enableLogging: false, + environment: { + TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', + TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', + }, + logDriver: new ecs.AwsLogDriver({ + streamPrefix: 'TestStream', + }), + family: 'Ec2TaskDef', + executionRole: new Role(stack, 'ExecutionRole', { + path: '/', + assumedBy: new CompositePrincipal( + new ServicePrincipal('ecs.amazonaws.com'), + new ServicePrincipal('ecs-tasks.amazonaws.com'), + ), + }), + taskRole: new Role(stack, 'TaskRole', { + assumedBy: new ServicePrincipal('ecs-tasks.amazonaws.com'), + }), + dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, + }, + cpu: 256, + assignPublicIp: true, + memoryLimitMiB: 512, + desiredCount: 3, + enableECSManagedTags: true, + healthCheckGracePeriod: Duration.millis(2000), + platformVersion: ecs.FargatePlatformVersion.VERSION1_4, + propagateTags: ecs.PropagatedTagSource.SERVICE, + serviceName: 'myService', + targetGroups: [ + { + containerPort: 80, + }, + { + containerPort: 90, + pathPattern: 'a/b/c', + priority: 10, + protocol: ecs.Protocol.TCP, + }, + ], + }); + + // THEN - stack contains a load balancer and a service + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 3, + EnableECSManagedTags: true, + HealthCheckGracePeriodSeconds: 2, + LaunchType: 'FARGATE', + LoadBalancers: [ + { + ContainerName: 'hello', + ContainerPort: 80, + TargetGroupArn: { + Ref: 'ServiceLBPublicListenerECSTargetGrouphello80Group233A4D54', + }, + }, + { + ContainerName: 'hello', + ContainerPort: 90, + TargetGroupArn: { + Ref: 'ServiceLBPublicListenerECSTargetGrouphello90GroupE58E4EAB', + }, + }, + ], + NetworkConfiguration: { + AwsvpcConfiguration: { + AssignPublicIp: 'ENABLED', + SecurityGroups: [ + { + 'Fn::GetAtt': [ + 'ServiceSecurityGroupEEA09B68', + 'GroupId', + ], + }, + ], + Subnets: [ + { + Ref: 'VPCPublicSubnet1SubnetB4246D30', + }, + { + Ref: 'VPCPublicSubnet2Subnet74179F39', + }, + ], + }, + }, + PlatformVersion: ecs.FargatePlatformVersion.VERSION1_4, + PropagateTags: 'SERVICE', + ServiceName: 'myService', + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Environment: [ + { + Name: 'TEST_ENVIRONMENT_VARIABLE1', + Value: 'test environment variable 1 value', + }, + { + Name: 'TEST_ENVIRONMENT_VARIABLE2', + Value: 'test environment variable 2 value', + }, + ], + Essential: true, + Image: 'test', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ServiceTaskDefhelloLogGroup44519781', + }, + 'awslogs-stream-prefix': 'TestStream', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Name: 'hello', + PortMappings: [ + { + ContainerPort: 80, + Protocol: 'tcp', + }, + { + ContainerPort: 90, + Protocol: 'tcp', + }, + ], + DockerLabels: { + label1: 'labelValue1', + label2: 'labelValue2', + }, + }, + ], + Cpu: '256', + ExecutionRoleArn: { + 'Fn::GetAtt': [ + 'ExecutionRole605A040B', + 'Arn', + ], + }, + Family: 'Ec2TaskDef', + Memory: '512', + NetworkMode: 'awsvpc', + RequiresCompatibilities: [ + 'FARGATE', + ], + TaskRoleArn: { + 'Fn::GetAtt': [ + 'TaskRole30FC0FBB', + 'Arn', + ], + }, + }); + }); + + test('errors if no essential container in pre-defined task definition', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); + + // THEN + expect(() => { + new ApplicationMultipleTargetGroupsFargateService(stack, 'Service', { + cluster, + taskDefinition, + }); + }).toThrow(/At least one essential container must be specified/); + }); + + test('errors when setting both taskDefinition and taskImageOptions', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'Ec2TaskDef'); + + // THEN + expect(() => { + new ApplicationMultipleTargetGroupsFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + taskDefinition, + }); + }).toThrow(/You must specify only one of TaskDefinition or TaskImageOptions./); + }); + + test('errors when setting neither taskDefinition nor taskImageOptions', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new ApplicationMultipleTargetGroupsFargateService(stack, 'Service', { + cluster, + }); + }).toThrow(/You must specify one of: taskDefinition or image/); + }); + + test('test Fargate loadbalancer construct with application load balancer name set', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + loadBalancerName: 'alb-test-load-balancer', + }); + + // THEN - stack contains a load balancer and a service + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Name: 'alb-test-load-balancer', + }); + + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 1, + LaunchType: 'FARGATE', + LoadBalancers: [ + { + ContainerName: 'web', + ContainerPort: 80, + TargetGroupArn: { + Ref: 'ServiceLBPublicListenerECSGroup0CC8688C', + }, + }, + ], + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Image: 'test', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ServiceTaskDefwebLogGroup2A898F61', + }, + 'awslogs-stream-prefix': 'Service', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Name: 'web', + PortMappings: [ + { + ContainerPort: 80, + Protocol: 'tcp', + }, + ], + }, + ], + Cpu: '256', + ExecutionRoleArn: { + 'Fn::GetAtt': [ + 'ServiceTaskDefExecutionRole919F7BE3', + 'Arn', + ], + }, + Family: 'ServiceTaskDef79D79521', + Memory: '512', + NetworkMode: 'awsvpc', + RequiresCompatibilities: [ + 'FARGATE', + ], + }); + }); +}); + +describe('When Network Load Balancer', () => { + test('test Fargate loadbalanced construct with default settings', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new NetworkMultipleTargetGroupsFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + }); + + // THEN - stack contains a load balancer and a service + expect(stack).toHaveResource('AWS::ElasticLoadBalancingV2::LoadBalancer'); + + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 1, + LaunchType: 'FARGATE', + LoadBalancers: [ + { + ContainerName: 'web', + ContainerPort: 80, + TargetGroupArn: { + Ref: 'ServiceLBPublicListenerECSGroup0CC8688C', + }, + }, + ], + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Image: 'test', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ServiceTaskDefwebLogGroup2A898F61', + }, + 'awslogs-stream-prefix': 'Service', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Name: 'web', + PortMappings: [ + { + ContainerPort: 80, + Protocol: 'tcp', + }, + ], + }, + ], + Cpu: '256', + ExecutionRoleArn: { + 'Fn::GetAtt': [ + 'ServiceTaskDefExecutionRole919F7BE3', + 'Arn', + ], + }, + Family: 'ServiceTaskDef79D79521', + Memory: '512', + NetworkMode: 'awsvpc', + RequiresCompatibilities: [ + 'FARGATE', + ], + }); + }); + + test('test Fargate loadbalanced construct with all settings', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new NetworkMultipleTargetGroupsFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + containerName: 'hello', + containerPorts: [80, 90], + enableLogging: false, + environment: { + TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', + TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', + }, + logDriver: new ecs.AwsLogDriver({ + streamPrefix: 'TestStream', + }), + family: 'Ec2TaskDef', + executionRole: new Role(stack, 'ExecutionRole', { + path: '/', + assumedBy: new CompositePrincipal( + new ServicePrincipal('ecs.amazonaws.com'), + new ServicePrincipal('ecs-tasks.amazonaws.com'), + ), + }), + taskRole: new Role(stack, 'TaskRole', { + assumedBy: new ServicePrincipal('ecs-tasks.amazonaws.com'), + }), + dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, + }, + cpu: 256, + assignPublicIp: true, + memoryLimitMiB: 512, + desiredCount: 3, + enableECSManagedTags: true, + healthCheckGracePeriod: Duration.millis(2000), + propagateTags: ecs.PropagatedTagSource.SERVICE, + serviceName: 'myService', + targetGroups: [ + { + containerPort: 80, + }, + { + containerPort: 90, + }, + ], + }); + + // THEN - stack contains a load balancer and a service + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 3, + EnableECSManagedTags: true, + HealthCheckGracePeriodSeconds: 2, + LaunchType: 'FARGATE', + LoadBalancers: [ + { + ContainerName: 'hello', + ContainerPort: 80, + TargetGroupArn: { + Ref: 'ServiceLBPublicListenerECSTargetGrouphello80Group233A4D54', + }, + }, + { + ContainerName: 'hello', + ContainerPort: 90, + TargetGroupArn: { + Ref: 'ServiceLBPublicListenerECSTargetGrouphello90GroupE58E4EAB', + }, + }, + ], + NetworkConfiguration: { + AwsvpcConfiguration: { + AssignPublicIp: 'ENABLED', + SecurityGroups: [ + { + 'Fn::GetAtt': [ + 'ServiceSecurityGroupEEA09B68', + 'GroupId', + ], + }, + ], + Subnets: [ + { + Ref: 'VPCPublicSubnet1SubnetB4246D30', + }, + { + Ref: 'VPCPublicSubnet2Subnet74179F39', + }, + ], + }, + }, + PropagateTags: 'SERVICE', + ServiceName: 'myService', + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Environment: [ + { + Name: 'TEST_ENVIRONMENT_VARIABLE1', + Value: 'test environment variable 1 value', + }, + { + Name: 'TEST_ENVIRONMENT_VARIABLE2', + Value: 'test environment variable 2 value', + }, + ], + Essential: true, + Image: 'test', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ServiceTaskDefhelloLogGroup44519781', + }, + 'awslogs-stream-prefix': 'TestStream', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Name: 'hello', + PortMappings: [ + { + ContainerPort: 80, + Protocol: 'tcp', + }, + { + ContainerPort: 90, + Protocol: 'tcp', + }, + ], + DockerLabels: { + label1: 'labelValue1', + label2: 'labelValue2', + }, + }, + ], + Cpu: '256', + ExecutionRoleArn: { + 'Fn::GetAtt': [ + 'ExecutionRole605A040B', + 'Arn', + ], + }, + Family: 'Ec2TaskDef', + Memory: '512', + NetworkMode: 'awsvpc', + RequiresCompatibilities: [ + 'FARGATE', + ], + TaskRoleArn: { + 'Fn::GetAtt': [ + 'TaskRole30FC0FBB', + 'Arn', + ], + }, + }); + }); + + test('errors if no essential container in pre-defined task definition', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); + + // THEN + expect(() => { + new NetworkMultipleTargetGroupsFargateService(stack, 'Service', { + cluster, + taskDefinition, + }); + }).toThrow(/At least one essential container must be specified/); + }); + + test('errors when setting both taskDefinition and taskImageOptions', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'Ec2TaskDef'); + + // THEN + expect(() => { + new NetworkMultipleTargetGroupsFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('test'), + }, + taskDefinition, + }); + }).toThrow(/You must specify only one of TaskDefinition or TaskImageOptions./); + }); + + test('errors when setting neither taskDefinition nor taskImageOptions', () => { + // GIVEN + const stack = new Stack(); + const vpc = new Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // THEN + expect(() => { + new NetworkMultipleTargetGroupsFargateService(stack, 'Service', { + cluster, + }); + }).toThrow(/You must specify one of: taskDefinition or image/); + }); +}); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/load-balanced-fargate-service.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/load-balanced-fargate-service.test.ts new file mode 100644 index 0000000000000..765d86788277e --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/load-balanced-fargate-service.test.ts @@ -0,0 +1,1028 @@ +import { SynthUtils } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +import { DnsValidatedCertificate } from '@aws-cdk/aws-certificatemanager'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as ecs from '@aws-cdk/aws-ecs'; +import { ApplicationLoadBalancer, ApplicationProtocol, NetworkLoadBalancer } from '@aws-cdk/aws-elasticloadbalancingv2'; +import * as iam from '@aws-cdk/aws-iam'; +import * as route53 from '@aws-cdk/aws-route53'; +import * as cdk from '@aws-cdk/core'; +import * as ecsPatterns from '../../lib'; + +test('setting loadBalancerType to Network creates an NLB Public', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Type: 'network', + Scheme: 'internet-facing', + }); +}); + +test('setting loadBalancerType to Network and publicLoadBalancer to false creates an NLB Private', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + publicLoadBalancer: false, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Type: 'network', + Scheme: 'internal', + }); +}); + +test('setting vpc and cluster throws error', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + expect(() => new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + cluster, + vpc, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + })).toThrow(); +}); + +test('setting executionRole updated taskDefinition with given execution role', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + const executionRole = new iam.Role(stack, 'ExecutionRole', { + path: '/', + assumedBy: new iam.CompositePrincipal( + new iam.ServicePrincipal('ecs.amazonaws.com'), + new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), + ), + }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + executionRole, + }, + }); + + // THEN + const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.ServiceTaskDef1922A00F; + expect(serviceTaskDefinition.Properties.ExecutionRoleArn).toEqual({ 'Fn::GetAtt': ['ExecutionRole605A040B', 'Arn'] }); +}); + +test('setting taskRole updated taskDefinition with given task role', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + const taskRole = new iam.Role(stack, 'taskRoleTest', { + path: '/', + assumedBy: new iam.CompositePrincipal( + new iam.ServicePrincipal('ecs.amazonaws.com'), + new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), + ), + }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + taskRole, + }, + }); + + // THEN + const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.ServiceTaskDef1922A00F; + expect(serviceTaskDefinition.Properties.TaskRoleArn).toEqual({ 'Fn::GetAtt': ['taskRoleTest9DA66B6E', 'Arn'] }); +}); + +test('setting containerName updates container name with given name', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + containerName: 'bob', + }, + }); + + // THEN + const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.ServiceTaskDef1922A00F; + expect(serviceTaskDefinition.Properties.ContainerDefinitions[0].Name).toEqual('bob'); +}); + +test('not setting containerName updates container name with default', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + }); + + // THEN + const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.ServiceTaskDef1922A00F; + expect(serviceTaskDefinition.Properties.ContainerDefinitions[0].Name).toEqual('web'); +}); + +test('setting servicename updates service name with given name', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + serviceName: 'bob', + }); + // THEN + const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.Service9571FDD8; + expect(serviceTaskDefinition.Properties.ServiceName).toEqual('bob'); +}); + +test('not setting servicename updates service name with default', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + }); + + // THEN + const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.Service9571FDD8; + expect(serviceTaskDefinition.Properties.ServiceName).toBeUndefined(); +}); + +test('setting healthCheckGracePeriod works', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + healthCheckGracePeriod: cdk.Duration.seconds(600), + }); + // THEN + const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.Service9571FDD8; + expect(serviceTaskDefinition.Properties.HealthCheckGracePeriodSeconds).toEqual(600); +}); + +test('selecting correct vpcSubnets', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { + maxAzs: 2, + subnetConfiguration: [ + { + subnetType: ec2.SubnetType.PUBLIC, + cidrMask: 20, + name: 'Public', + }, + { + subnetType: ec2.SubnetType.ISOLATED, + cidrMask: 20, + name: 'ISOLATED', + }, + ], + }); + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + vpc, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + taskSubnets: { + subnetType: ec2.SubnetType.ISOLATED, + }, + }); + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + NetworkConfiguration: { + AwsvpcConfiguration: { + Subnets: [ + { + Ref: 'VpcISOLATEDSubnet1Subnet80F07FA0', + }, + { + Ref: 'VpcISOLATEDSubnet2SubnetB0B548C3', + }, + ], + }, + }, + }); +}); + +test('target group uses HTTP/80 as default', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + }); + // THEN + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup', { + Port: 80, + Protocol: 'HTTP', + }); +}); + +test('target group uses HTTPS/443 when configured', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + targetProtocol: ApplicationProtocol.HTTPS, + }); + // THEN + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup', { + Port: 443, + Protocol: 'HTTPS', + }); +}); + +test('setting platform version', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + platformVersion: ecs.FargatePlatformVersion.VERSION1_4, + }); + // THEN + expect(stack).toHaveResource('AWS::ECS::Service', { + PlatformVersion: ecs.FargatePlatformVersion.VERSION1_4, + }); +}); + +test('test load balanced service with family defined', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + enableLogging: false, + environment: { + TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', + TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', + }, + family: 'fargate-task-family', + }, + desiredCount: 2, + memoryLimitMiB: 512, + serviceName: 'fargate-test-service', + }); + + // THEN + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 2, + LaunchType: 'FARGATE', + ServiceName: 'fargate-test-service', + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Environment: [ + { + Name: 'TEST_ENVIRONMENT_VARIABLE1', + Value: 'test environment variable 1 value', + }, + { + Name: 'TEST_ENVIRONMENT_VARIABLE2', + Value: 'test environment variable 2 value', + }, + ], + Image: '/aws/aws-example-app', + }, + ], + Family: 'fargate-task-family', + }); +}); + +test('setting ALB deployment controller', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + deploymentController: { + type: ecs.DeploymentControllerType.CODE_DEPLOY, + }, + }); + + // THEN + expect(stack).toHaveResource('AWS::ECS::Service', { + DeploymentController: { + Type: 'CODE_DEPLOY', + }, + }); +}); + +test('setting NLB deployment controller', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + deploymentController: { + type: ecs.DeploymentControllerType.CODE_DEPLOY, + }, + }); + + // THEN + expect(stack).toHaveResource('AWS::ECS::Service', { + DeploymentController: { + Type: 'CODE_DEPLOY', + }, + }); +}); + +test('setting ALB circuitBreaker works', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + circuitBreaker: { rollback: true }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + DeploymentConfiguration: { + DeploymentCircuitBreaker: { + Enable: true, + Rollback: true, + }, + }, + DeploymentController: { + Type: 'ECS', + }, + }); +}); + +test('setting NLB circuitBreaker works', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + }, + circuitBreaker: { rollback: true }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + DeploymentConfiguration: { + DeploymentCircuitBreaker: { + Enable: true, + Rollback: true, + }, + }, + DeploymentController: { + Type: 'ECS', + }, + }); +}); + +test('setting NLB special listener port to create the listener', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'FargateNlbService', { + cluster, + listenerPort: 2015, + taskImageOptions: { + containerPort: 2015, + image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { + DefaultActions: [ + { + Type: 'forward', + }, + ], + Port: 2015, + Protocol: 'TCP', + }); +}); + +test('setting ALB special listener port to create the listener', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { + cluster, + listenerPort: 2015, + taskImageOptions: { + containerPort: 2015, + image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { + DefaultActions: [ + { + Type: 'forward', + }, + ], + Port: 2015, + Protocol: 'HTTP', + }); +}); + +test('setting ALB HTTPS protocol to create the listener on 443', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { + cluster, + protocol: ApplicationProtocol.HTTPS, + domainName: 'domain.com', + domainZone: route53.HostedZone.fromHostedZoneAttributes(stack, 'HostedZone', { + hostedZoneId: 'fakeId', + zoneName: 'domain.com', + }), + taskImageOptions: { + containerPort: 2015, + image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { + DefaultActions: [ + { + Type: 'forward', + }, + ], + Port: 443, + Protocol: 'HTTPS', + }); +}); + +test('setting ALB HTTPS correctly sets the recordset name', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { + cluster, + protocol: ApplicationProtocol.HTTPS, + domainName: 'test.domain.com', + domainZone: route53.HostedZone.fromHostedZoneAttributes(stack, 'HostedZone', { + hostedZoneId: 'fakeId', + zoneName: 'domain.com.', + }), + taskImageOptions: { + containerPort: 2015, + image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::Route53::RecordSet', { + Name: 'test.domain.com.', + }); +}); + +test('setting ALB cname option correctly sets the recordset type', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { + cluster, + protocol: ApplicationProtocol.HTTPS, + domainName: 'test.domain.com', + domainZone: route53.HostedZone.fromHostedZoneAttributes(stack, 'HostedZone', { + hostedZoneId: 'fakeId', + zoneName: 'domain.com.', + }), + recordType: ecsPatterns.ApplicationLoadBalancedServiceRecordType.CNAME, + taskImageOptions: { + containerPort: 2015, + image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::Route53::RecordSet', { + Name: 'test.domain.com.', + Type: 'CNAME', + }); +}); + +test('setting ALB record type to NONE correctly omits the recordset', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { + cluster, + protocol: ApplicationProtocol.HTTPS, + domainName: 'test.domain.com', + domainZone: route53.HostedZone.fromHostedZoneAttributes(stack, 'HostedZone', { + hostedZoneId: 'fakeId', + zoneName: 'domain.com.', + }), + recordType: ecsPatterns.ApplicationLoadBalancedServiceRecordType.NONE, + taskImageOptions: { + containerPort: 2015, + image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), + }, + }); + + // THEN + expect(stack).not.toHaveResource('AWS::Route53::RecordSet'); +}); + + +test('setting NLB cname option correctly sets the recordset type', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'FargateNlbService', { + cluster, + domainName: 'test.domain.com', + domainZone: route53.HostedZone.fromHostedZoneAttributes(stack, 'HostedZone', { + hostedZoneId: 'fakeId', + zoneName: 'domain.com.', + }), + recordType: ecsPatterns.NetworkLoadBalancedServiceRecordType.CNAME, + taskImageOptions: { + containerPort: 2015, + image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::Route53::RecordSet', { + Name: 'test.domain.com.', + Type: 'CNAME', + }); +}); + +test('setting NLB record type to NONE correctly omits the recordset', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'FargateNlbService', { + cluster, + domainName: 'test.domain.com', + domainZone: route53.HostedZone.fromHostedZoneAttributes(stack, 'HostedZone', { + hostedZoneId: 'fakeId', + zoneName: 'domain.com.', + }), + recordType: ecsPatterns.NetworkLoadBalancedServiceRecordType.NONE, + taskImageOptions: { + containerPort: 2015, + image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), + }, + }); + + // THEN + expect(stack).not.toHaveResource('AWS::Route53::RecordSet'); +}); + +test('setting ALB HTTP protocol to create the listener on 80', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { + cluster, + protocol: ApplicationProtocol.HTTP, + taskImageOptions: { + containerPort: 2015, + image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { + DefaultActions: [ + { + Type: 'forward', + }, + ], + Port: 80, + Protocol: 'HTTP', + }); +}); + +test('setting ALB without any protocol or listenerPort to create the listener on 80', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { + cluster, + taskImageOptions: { + containerPort: 2015, + image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { + DefaultActions: [ + { + Type: 'forward', + }, + ], + Port: 80, + Protocol: 'HTTP', + }); +}); + +test('passing in existing network load balancer to NLB Fargate Service', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const nlb = new NetworkLoadBalancer(stack, 'NLB', { vpc }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + vpc, + loadBalancer: nlb, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + LaunchType: 'FARGATE', + }); + + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Type: 'network', + }); +}); + +test('passing in imported network load balancer and resources to NLB Fargate service', () => { + // GIVEN + const app = new cdk.App(); + const stack1 = new cdk.Stack(app, 'MyStack'); + const vpc1 = new ec2.Vpc(stack1, 'VPC'); + const cluster1 = new ecs.Cluster(stack1, 'Cluster', { vpc: vpc1 }); + const nlbArn = 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188'; + const stack2 = new cdk.Stack(stack1, 'Stack2'); + const cluster2 = ecs.Cluster.fromClusterAttributes(stack2, 'ImportedCluster', { + vpc: vpc1, + securityGroups: cluster1.connections.securityGroups, + clusterName: 'cluster-name', + }); + + // WHEN + const nlb2 = NetworkLoadBalancer.fromNetworkLoadBalancerAttributes(stack2, 'ImportedNLB', { + loadBalancerArn: nlbArn, + vpc: vpc1, + }); + const taskDef = new ecs.FargateTaskDefinition(stack2, 'TaskDef', { + cpu: 1024, + memoryLimitMiB: 1024, + }); + const container = taskDef.addContainer('myContainer', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + memoryLimitMiB: 1024, + }); + container.addPortMappings({ + containerPort: 80, + }); + + new ecsPatterns.NetworkLoadBalancedFargateService(stack2, 'FargateNLBService', { + cluster: cluster2, + loadBalancer: nlb2, + desiredCount: 1, + taskDefinition: taskDef, + }); + + // THEN + expect(stack2).toHaveResourceLike('AWS::ECS::Service', { + LaunchType: 'FARGATE', + LoadBalancers: [{ ContainerName: 'myContainer', ContainerPort: 80 }], + }); + + expect(stack2).toHaveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup'); + + expect(stack2).toHaveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { + LoadBalancerArn: nlb2.loadBalancerArn, + Port: 80, + }); +}); + +test('passing in previously created application load balancer to ALB Fargate Service', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc, clusterName: 'MyCluster' }); + const sg = new ec2.SecurityGroup(stack, 'SecurityGroup', { vpc }); + cluster.connections.addSecurityGroup(sg); + const alb = new ApplicationLoadBalancer(stack, 'ALB', { vpc, securityGroup: sg }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + loadBalancer: alb, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + LaunchType: 'FARGATE', + }); + + expect(stack).toHaveResourceLike('AWS::ElasticLoadBalancingV2::LoadBalancer', { + Type: 'application', + }); +}); + +test('passing in imported application load balancer and resources to ALB Fargate Service', () => { + // GIVEN + const stack1 = new cdk.Stack(); + const albArn = 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188'; + const vpc = new ec2.Vpc(stack1, 'Vpc'); + const cluster = new ecs.Cluster(stack1, 'Cluster', { vpc, clusterName: 'MyClusterName' }); + const sg = new ec2.SecurityGroup(stack1, 'SecurityGroup', { vpc }); + cluster.connections.addSecurityGroup(sg); + const alb = ApplicationLoadBalancer.fromApplicationLoadBalancerAttributes(stack1, 'ALB', { + loadBalancerArn: albArn, + vpc, + securityGroupId: sg.securityGroupId, + loadBalancerDnsName: 'MyDnsName', + }); + + // WHEN + const taskDef = new ecs.FargateTaskDefinition(stack1, 'TaskDef', { + cpu: 1024, + memoryLimitMiB: 1024, + }); + const container = taskDef.addContainer('Container', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + memoryLimitMiB: 1024, + }); + container.addPortMappings({ + containerPort: 80, + }); + + new ecsPatterns.ApplicationLoadBalancedFargateService(stack1, 'FargateALBService', { + cluster, + loadBalancer: alb, + desiredCount: 1, + taskDefinition: taskDef, + }); + + // THEN + expect(stack1).toHaveResourceLike('AWS::ECS::Service', { + LaunchType: 'FARGATE', + LoadBalancers: [{ ContainerName: 'Container', ContainerPort: 80 }], + }); + + expect(stack1).toHaveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup'); + + expect(stack1).toHaveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { + LoadBalancerArn: alb.loadBalancerArn, + Port: 80, + }); +}); + +test('passing in previously created security groups to ALB Fargate Service', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc, clusterName: 'MyCluster' }); + const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup', { + allowAllOutbound: false, + description: 'Example', + securityGroupName: 'Rolly', + vpc, + }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + }, + securityGroups: [securityGroup], + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::Service', { + LaunchType: 'FARGATE', + }); + + expect(stack).toHaveResource('AWS::EC2::SecurityGroup', { + GroupDescription: 'Example', + GroupName: 'Rolly', + SecurityGroupEgress: [ + { + CidrIp: '255.255.255.255/32', + Description: 'Disallow all traffic', + FromPort: 252, + IpProtocol: 'icmp', + ToPort: 86, + }, + ], + VpcId: { + Ref: 'Vpc8378EB38', + }, + }); +}); + +test('domainName and domainZone not required for HTTPS listener with provided cert', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + const exampleDotComZone = new route53.PublicHostedZone(stack, 'ExampleDotCom', { + zoneName: 'example.com', + }); + const certificate = new DnsValidatedCertificate(stack, 'Certificate', { + domainName: 'test.example.com', + hostedZone: exampleDotComZone, + }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { + cluster, + protocol: ApplicationProtocol.HTTPS, + + taskImageOptions: { + containerPort: 2015, + image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), + }, + certificate: certificate, + }); + + // THEN + expect(stack).not.toHaveResourceLike('AWS::Route53::RecordSet', { + Name: 'test.domain.com.', + }); +}); + +test('test ALB load balanced service with docker labels defined', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Image: '/aws/aws-example-app', + DockerLabels: { + label1: 'labelValue1', + label2: 'labelValue2', + }, + }, + ], + }); +}); + +test('test Network load balanced service with docker labels defined', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { + cluster, + taskImageOptions: { + image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), + dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, + }, + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Image: '/aws/aws-example-app', + DockerLabels: { + label1: 'labelValue1', + label2: 'labelValue2', + }, + }, + ], + }); +}); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/queue-processing-fargate-service.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/queue-processing-fargate-service.test.ts new file mode 100644 index 0000000000000..916bcb43cdf63 --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/queue-processing-fargate-service.test.ts @@ -0,0 +1,555 @@ +import { ABSENT } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as ecs from '@aws-cdk/aws-ecs'; +import * as sqs from '@aws-cdk/aws-sqs'; +import * as cdk from '@aws-cdk/core'; +import * as cxapi from '@aws-cdk/cx-api'; +import * as ecsPatterns from '../../lib'; + +test('test fargate queue worker service construct - with only required props', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { + cluster, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + }); + + // THEN - QueueWorker is of FARGATE launch type, an SQS queue is created and all default properties are set. + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 1, + LaunchType: 'FARGATE', + }); + + expect(stack).toHaveResource('AWS::SQS::Queue', { + RedrivePolicy: { + deadLetterTargetArn: { + 'Fn::GetAtt': [ + 'ServiceEcsProcessingDeadLetterQueue4A89196E', + 'Arn', + ], + }, + maxReceiveCount: 3, + }, + }); + + expect(stack).toHaveResource('AWS::SQS::Queue', { + MessageRetentionPeriod: 1209600, + }); + + expect(stack).toHaveResource('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: [ + 'sqs:ReceiveMessage', + 'sqs:ChangeMessageVisibility', + 'sqs:GetQueueUrl', + 'sqs:DeleteMessage', + 'sqs:GetQueueAttributes', + ], + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': [ + 'ServiceEcsProcessingQueueC266885C', + 'Arn', + ], + }, + }, + ], + Version: '2012-10-17', + }, + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Environment: [ + { + Name: 'QUEUE_NAME', + Value: { + 'Fn::GetAtt': [ + 'ServiceEcsProcessingQueueC266885C', + 'QueueName', + ], + }, + }, + ], + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupD52338D1', + }, + 'awslogs-stream-prefix': 'Service', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Image: 'test', + }, + ], + Family: 'ServiceQueueProcessingTaskDef83DB34F1', + }); +}); + +test('test fargate queue worker service construct - with remove default desiredCount feature flag', () => { + // GIVEN + const stack = new cdk.Stack(); + stack.node.setContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT, true); + + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + + // WHEN + new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { + cluster, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + }); + + // THEN - QueueWorker is of FARGATE launch type, and desiredCount is not defined on the FargateService. + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: ABSENT, + LaunchType: 'FARGATE', + }); +}); + +test('test fargate queue worker service construct - with optional props for queues', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { + cluster, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + maxReceiveCount: 42, + retentionPeriod: cdk.Duration.days(7), + visibilityTimeout: cdk.Duration.minutes(5), + }); + + // THEN - QueueWorker is of FARGATE launch type, an SQS queue is created and all default properties are set. + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 1, + LaunchType: 'FARGATE', + }); + + expect(stack).toHaveResource('AWS::SQS::Queue', { + RedrivePolicy: { + deadLetterTargetArn: { + 'Fn::GetAtt': [ + 'ServiceEcsProcessingDeadLetterQueue4A89196E', + 'Arn', + ], + }, + maxReceiveCount: 42, + }, + VisibilityTimeout: 300, + }); + + expect(stack).toHaveResource('AWS::SQS::Queue', { + MessageRetentionPeriod: 604800, + }); + + expect(stack).toHaveResource('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: [ + 'sqs:ReceiveMessage', + 'sqs:ChangeMessageVisibility', + 'sqs:GetQueueUrl', + 'sqs:DeleteMessage', + 'sqs:GetQueueAttributes', + ], + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': [ + 'ServiceEcsProcessingQueueC266885C', + 'Arn', + ], + }, + }, + ], + Version: '2012-10-17', + }, + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Environment: [ + { + Name: 'QUEUE_NAME', + Value: { + 'Fn::GetAtt': [ + 'ServiceEcsProcessingQueueC266885C', + 'QueueName', + ], + }, + }, + ], + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupD52338D1', + }, + 'awslogs-stream-prefix': 'Service', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Image: 'test', + }, + ], + Family: 'ServiceQueueProcessingTaskDef83DB34F1', + }); +}); + +test('test Fargate queue worker service construct - without desiredCount specified', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + const queue = new sqs.Queue(stack, 'fargate-test-queue', { + queueName: 'fargate-test-sqs-queue', + }); + + // WHEN + new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { + cluster, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + command: ['-c', '4', 'amazon.com'], + enableLogging: false, + environment: { + TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', + TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', + }, + queue, + maxScalingCapacity: 5, + minScalingCapacity: 2, + minHealthyPercent: 60, + maxHealthyPercent: 150, + serviceName: 'fargate-test-service', + family: 'fargate-task-family', + platformVersion: ecs.FargatePlatformVersion.VERSION1_4, + deploymentController: { + type: ecs.DeploymentControllerType.CODE_DEPLOY, + }, + }); + + // THEN - QueueWorker is of FARGATE launch type, an SQS queue is created and all optional properties are set. + expect(stack).toHaveResource('AWS::ECS::Service', { + DeploymentConfiguration: { + MinimumHealthyPercent: 60, + MaximumPercent: 150, + }, + LaunchType: 'FARGATE', + ServiceName: 'fargate-test-service', + PlatformVersion: ecs.FargatePlatformVersion.VERSION1_4, + DeploymentController: { + Type: 'CODE_DEPLOY', + }, + }); + + expect(stack).toHaveResource('AWS::ApplicationAutoScaling::ScalableTarget', { + MaxCapacity: 5, + MinCapacity: 2, + }); + + expect(stack).toHaveResource('AWS::SQS::Queue', { QueueName: 'fargate-test-sqs-queue' }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Command: [ + '-c', + '4', + 'amazon.com', + ], + Environment: [ + { + Name: 'TEST_ENVIRONMENT_VARIABLE1', + Value: 'test environment variable 1 value', + }, + { + Name: 'TEST_ENVIRONMENT_VARIABLE2', + Value: 'test environment variable 2 value', + }, + { + Name: 'QUEUE_NAME', + Value: { + 'Fn::GetAtt': [ + 'fargatetestqueue28B43841', + 'QueueName', + ], + }, + }, + ], + Image: 'test', + }, + ], + Family: 'fargate-task-family', + }); +}); + +test('test Fargate queue worker service construct - with optional props', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + const queue = new sqs.Queue(stack, 'fargate-test-queue', { + queueName: 'fargate-test-sqs-queue', + }); + + // WHEN + new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { + cluster, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + command: ['-c', '4', 'amazon.com'], + enableLogging: false, + desiredTaskCount: 2, + environment: { + TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', + TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', + }, + queue, + maxScalingCapacity: 5, + minHealthyPercent: 60, + maxHealthyPercent: 150, + serviceName: 'fargate-test-service', + family: 'fargate-task-family', + platformVersion: ecs.FargatePlatformVersion.VERSION1_4, + circuitBreaker: { rollback: true }, + }); + + // THEN - QueueWorker is of FARGATE launch type, an SQS queue is created and all optional properties are set. + expect(stack).toHaveResource('AWS::ECS::Service', { + DesiredCount: 2, + DeploymentConfiguration: { + MinimumHealthyPercent: 60, + MaximumPercent: 150, + DeploymentCircuitBreaker: { + Enable: true, + Rollback: true, + }, + }, + LaunchType: 'FARGATE', + ServiceName: 'fargate-test-service', + PlatformVersion: ecs.FargatePlatformVersion.VERSION1_4, + DeploymentController: { + Type: 'ECS', + }, + }); + + expect(stack).toHaveResource('AWS::SQS::Queue', { QueueName: 'fargate-test-sqs-queue' }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Command: [ + '-c', + '4', + 'amazon.com', + ], + Environment: [ + { + Name: 'TEST_ENVIRONMENT_VARIABLE1', + Value: 'test environment variable 1 value', + }, + { + Name: 'TEST_ENVIRONMENT_VARIABLE2', + Value: 'test environment variable 2 value', + }, + { + Name: 'QUEUE_NAME', + Value: { + 'Fn::GetAtt': [ + 'fargatetestqueue28B43841', + 'QueueName', + ], + }, + }, + ], + Image: 'test', + }, + ], + Family: 'fargate-task-family', + }); +}); + +test('can set custom containerName', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + + // WHEN + new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { + cluster, + containerName: 'my-container', + image: ecs.ContainerImage.fromRegistry('test'), + }); + + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Name: 'my-container', + }, + ], + }); +}); + +test('can set custom networking options', () => { + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC', { + subnetConfiguration: [ + { + cidrMask: 24, + name: 'Public', + subnetType: ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'Isolated', + subnetType: ec2.SubnetType.ISOLATED, + }, + ], + }); + const securityGroup = new ec2.SecurityGroup(stack, 'MyCustomSG', { + vpc, + }); + + // WHEN - SecurityGroups and taskSubnets selection is defined + new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { + vpc, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + securityGroups: [securityGroup], + taskSubnets: { subnetType: ec2.SubnetType.ISOLATED }, + }); + + // THEN - NetworkConfiguration is created with the specific security groups and selected subnets + expect(stack).toHaveResource('AWS::ECS::Service', { + LaunchType: 'FARGATE', + NetworkConfiguration: { + AwsvpcConfiguration: { + AssignPublicIp: 'DISABLED', + SecurityGroups: [ + { + 'Fn::GetAtt': [ + 'MyCustomSGDE27C661', + 'GroupId', + ], + }, + ], + Subnets: [ + { + Ref: 'VPCIsolatedSubnet1SubnetEBD00FC6', + }, + { + Ref: 'VPCIsolatedSubnet2Subnet4B1C8CAA', + }, + ], + }, + }, + }); +}); + +test('can set use public IP', () => { + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN - Assign Public IP is set to True + new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { + vpc, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + assignPublicIp: true, + }); + + // THEN - The Subnets defaults to Public and AssignPublicIp settings change to ENABLED + expect(stack).toHaveResource('AWS::ECS::Service', { + LaunchType: 'FARGATE', + NetworkConfiguration: { + AwsvpcConfiguration: { + AssignPublicIp: 'ENABLED', + SecurityGroups: [ + { + 'Fn::GetAtt': [ + 'ServiceQueueProcessingFargateServiceSecurityGroup6E981512', + 'GroupId', + ], + }, + ], + Subnets: [ + { + Ref: 'VPCPublicSubnet1SubnetB4246D30', + }, + { + Ref: 'VPCPublicSubnet2Subnet74179F39', + }, + ], + }, + }, + }); +}); + +test('can set capacity provider strategies', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'MyVpc', {}); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { + vpc, + }); + cluster.enableFargateCapacityProviders(); + + // WHEN + new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { + cluster, + image: ecs.ContainerImage.fromRegistry('test'), + capacityProviderStrategies: [ + { + capacityProvider: 'FARGATE_SPOT', + weight: 2, + }, + { + capacityProvider: 'FARGATE', + weight: 1, + }, + ], + }); + + // THEN + expect(stack).toHaveResource('AWS::ECS::Service', { + LaunchType: ABSENT, + CapacityProviderStrategy: [ + { + CapacityProvider: 'FARGATE_SPOT', + Weight: 2, + }, + { + CapacityProvider: 'FARGATE', + Weight: 1, + }, + ], + }); +}); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/scheduled-fargate-task.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/scheduled-fargate-task.test.ts new file mode 100644 index 0000000000000..5d37bba01af2f --- /dev/null +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/scheduled-fargate-task.test.ts @@ -0,0 +1,412 @@ +import '@aws-cdk/assert-internal/jest'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as ecs from '@aws-cdk/aws-ecs'; +import * as events from '@aws-cdk/aws-events'; +import * as cdk from '@aws-cdk/core'; +import { ScheduledFargateTask } from '../../lib'; + +test('Can create a scheduled Fargate Task - with only required props', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + + new ScheduledFargateTask(stack, 'ScheduledFargateTask', { + cluster, + scheduledFargateTaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + memoryLimitMiB: 512, + }, + schedule: events.Schedule.expression('rate(1 minute)'), + }); + + // THEN + expect(stack).toHaveResource('AWS::Events::Rule', { + State: 'ENABLED', + Targets: [ + { + Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, + EcsParameters: { + LaunchType: 'FARGATE', + NetworkConfiguration: { + AwsVpcConfiguration: { + AssignPublicIp: 'DISABLED', + SecurityGroups: [ + { + 'Fn::GetAtt': [ + 'ScheduledFargateTaskScheduledTaskDefSecurityGroupE075BC19', + 'GroupId', + ], + }, + ], + Subnets: [ + { + Ref: 'VpcPrivateSubnet1Subnet536B997A', + }, + ], + }, + }, + TaskCount: 1, + TaskDefinitionArn: { Ref: 'ScheduledFargateTaskScheduledTaskDef521FA675' }, + }, + Id: 'Target0', + Input: '{}', + RoleArn: { 'Fn::GetAtt': ['ScheduledFargateTaskScheduledTaskDefEventsRole6CE19522', 'Arn'] }, + }, + ], + }); + + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Essential: true, + Image: 'henk', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ScheduledFargateTaskScheduledTaskDefScheduledContainerLogGroup4134B16C', + }, + 'awslogs-stream-prefix': 'ScheduledFargateTask', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Name: 'ScheduledContainer', + }, + ], + }); +}); + +test('Can create a scheduled Fargate Task - with optional props', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + + new ScheduledFargateTask(stack, 'ScheduledFargateTask', { + cluster, + enabled: false, + scheduledFargateTaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + memoryLimitMiB: 512, + cpu: 2, + environment: { TRIGGER: 'CloudWatch Events' }, + }, + desiredTaskCount: 2, + schedule: events.Schedule.expression('rate(1 minute)'), + ruleName: 'sample-scheduled-task-rule', + }); + + // THEN + expect(stack).toHaveResource('AWS::Events::Rule', { + Name: 'sample-scheduled-task-rule', + State: 'DISABLED', + Targets: [ + { + Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, + EcsParameters: { + LaunchType: 'FARGATE', + NetworkConfiguration: { + AwsVpcConfiguration: { + AssignPublicIp: 'DISABLED', + SecurityGroups: [ + { + 'Fn::GetAtt': [ + 'ScheduledFargateTaskScheduledTaskDefSecurityGroupE075BC19', + 'GroupId', + ], + }, + ], + Subnets: [ + { + Ref: 'VpcPrivateSubnet1Subnet536B997A', + }, + ], + }, + }, + TaskCount: 2, + TaskDefinitionArn: { Ref: 'ScheduledFargateTaskScheduledTaskDef521FA675' }, + }, + Id: 'Target0', + Input: '{}', + RoleArn: { 'Fn::GetAtt': ['ScheduledFargateTaskScheduledTaskDefEventsRole6CE19522', 'Arn'] }, + }, + ], + }); + + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Environment: [ + { + Name: 'TRIGGER', + Value: 'CloudWatch Events', + }, + ], + Essential: true, + Image: 'henk', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ScheduledFargateTaskScheduledTaskDefScheduledContainerLogGroup4134B16C', + }, + 'awslogs-stream-prefix': 'ScheduledFargateTask', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Name: 'ScheduledContainer', + }, + ], + }); +}); + +test('Scheduled Fargate Task - with MemoryReservation defined', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + + new ScheduledFargateTask(stack, 'ScheduledFargateTask', { + cluster, + scheduledFargateTaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + }, + schedule: events.Schedule.expression('rate(1 minute)'), + }); + + // THEN + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Essential: true, + Image: 'henk', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ScheduledFargateTaskScheduledTaskDefScheduledContainerLogGroup4134B16C', + }, + 'awslogs-stream-prefix': 'ScheduledFargateTask', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Name: 'ScheduledContainer', + }, + ], + }); +}); + +test('Scheduled Fargate Task - with Command defined', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + + new ScheduledFargateTask(stack, 'ScheduledFargateTask', { + cluster, + scheduledFargateTaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + command: ['-c', '4', 'amazon.com'], + }, + schedule: events.Schedule.expression('rate(1 minute)'), + }); + + // THEN + expect(stack).toHaveResource('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Command: [ + '-c', + '4', + 'amazon.com', + ], + Essential: true, + Image: 'henk', + LogConfiguration: { + LogDriver: 'awslogs', + Options: { + 'awslogs-group': { + Ref: 'ScheduledFargateTaskScheduledTaskDefScheduledContainerLogGroup4134B16C', + }, + 'awslogs-stream-prefix': 'ScheduledFargateTask', + 'awslogs-region': { + Ref: 'AWS::Region', + }, + }, + }, + Name: 'ScheduledContainer', + }, + ], + }); +}); + +test('Scheduled Fargate Task - with subnetSelection defined', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { + maxAzs: 1, + subnetConfiguration: [ + { name: 'Public', cidrMask: 28, subnetType: ec2.SubnetType.PUBLIC }, + ], + }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + + new ScheduledFargateTask(stack, 'ScheduledFargateTask', { + cluster, + scheduledFargateTaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + }, + subnetSelection: { subnetType: ec2.SubnetType.PUBLIC }, + schedule: events.Schedule.expression('rate(1 minute)'), + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::Events::Rule', { + Targets: [ + { + EcsParameters: { + NetworkConfiguration: { + AwsVpcConfiguration: { + AssignPublicIp: 'ENABLED', + Subnets: [ + { + Ref: 'VpcPublicSubnet1Subnet5C2D37C4', + }, + ], + }, + }, + }, + }, + ], + }); +}); + +test('Scheduled Fargate Task - with platformVersion defined', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + + new ScheduledFargateTask(stack, 'ScheduledFargateTask', { + cluster, + scheduledFargateTaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + memoryLimitMiB: 512, + }, + schedule: events.Schedule.expression('rate(1 minute)'), + platformVersion: ecs.FargatePlatformVersion.VERSION1_4, + }); + + // THEN + expect(stack).toHaveResource('AWS::Events::Rule', { + Targets: [ + { + Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, + EcsParameters: { + LaunchType: 'FARGATE', + NetworkConfiguration: { + AwsVpcConfiguration: { + AssignPublicIp: 'DISABLED', + SecurityGroups: [ + { + 'Fn::GetAtt': [ + 'ScheduledFargateTaskScheduledTaskDefSecurityGroupE075BC19', + 'GroupId', + ], + }, + ], + Subnets: [ + { + Ref: 'VpcPrivateSubnet1Subnet536B997A', + }, + ], + }, + }, + PlatformVersion: '1.4.0', + TaskCount: 1, + TaskDefinitionArn: { Ref: 'ScheduledFargateTaskScheduledTaskDef521FA675' }, + }, + Id: 'Target0', + Input: '{}', + RoleArn: { 'Fn::GetAtt': ['ScheduledFargateTaskScheduledTaskDefEventsRole6CE19522', 'Arn'] }, + }, + ], + }); +}); + +test('Scheduled Fargate Task - with securityGroups defined', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + const sg = new ec2.SecurityGroup(stack, 'SG', { vpc }); + + new ScheduledFargateTask(stack, 'ScheduledFargateTask', { + cluster, + scheduledFargateTaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + memoryLimitMiB: 512, + }, + schedule: events.Schedule.expression('rate(1 minute)'), + securityGroups: [sg], + }); + + // THEN + expect(stack).toHaveResource('AWS::Events::Rule', { + Targets: [ + { + Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, + EcsParameters: { + LaunchType: 'FARGATE', + NetworkConfiguration: { + AwsVpcConfiguration: { + AssignPublicIp: 'DISABLED', + SecurityGroups: [{ + 'Fn::GetAtt': [ + 'SGADB53937', + 'GroupId', + ], + }], + Subnets: [ + { + Ref: 'VpcPrivateSubnet1Subnet536B997A', + }, + ], + }, + }, + TaskCount: 1, + TaskDefinitionArn: { Ref: 'ScheduledFargateTaskScheduledTaskDef521FA675' }, + }, + Id: 'Target0', + Input: '{}', + RoleArn: { 'Fn::GetAtt': ['ScheduledFargateTaskScheduledTaskDefEventsRole6CE19522', 'Arn'] }, + }, + ], + }); +}); + +test('Scheduled Fargate Task - exposes ECS Task', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + + const scheduledFargateTask = new ScheduledFargateTask(stack, 'ScheduledFargateTask', { + cluster, + scheduledFargateTaskImageOptions: { + image: ecs.ContainerImage.fromRegistry('henk'), + memoryLimitMiB: 512, + }, + schedule: events.Schedule.expression('rate(1 minute)'), + }); + + // THEN + expect(scheduledFargateTask.task).toBeDefined(); +}); diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service-v2.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service-v2.ts deleted file mode 100644 index cad68a5a270ae..0000000000000 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service-v2.ts +++ /dev/null @@ -1,689 +0,0 @@ -import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; -import { Vpc } from '@aws-cdk/aws-ec2'; -import * as ecs from '@aws-cdk/aws-ecs'; -import { CompositePrincipal, Role, ServicePrincipal } from '@aws-cdk/aws-iam'; -import { Duration, Stack } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; -import { ApplicationMultipleTargetGroupsFargateService, NetworkMultipleTargetGroupsFargateService, ApplicationLoadBalancedFargateService } from '../../lib'; - -export = { - 'When Application Load Balancer': { - 'test Fargate loadbalanced construct with default settings'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ApplicationMultipleTargetGroupsFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - }); - - // THEN - stack contains a load balancer and a service - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::LoadBalancer')); - - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 1, - LaunchType: 'FARGATE', - LoadBalancers: [ - { - ContainerName: 'web', - ContainerPort: 80, - TargetGroupArn: { - Ref: 'ServiceLBPublicListenerECSGroup0CC8688C', - }, - }, - ], - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Image: 'test', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ServiceTaskDefwebLogGroup2A898F61', - }, - 'awslogs-stream-prefix': 'Service', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Name: 'web', - PortMappings: [ - { - ContainerPort: 80, - Protocol: 'tcp', - }, - ], - }, - ], - Cpu: '256', - ExecutionRoleArn: { - 'Fn::GetAtt': [ - 'ServiceTaskDefExecutionRole919F7BE3', - 'Arn', - ], - }, - Family: 'ServiceTaskDef79D79521', - Memory: '512', - NetworkMode: 'awsvpc', - RequiresCompatibilities: [ - 'FARGATE', - ], - })); - - test.done(); - }, - - 'test Fargate loadbalanced construct with all settings'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ApplicationMultipleTargetGroupsFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - containerName: 'hello', - containerPorts: [80, 90], - enableLogging: false, - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - logDriver: new ecs.AwsLogDriver({ - streamPrefix: 'TestStream', - }), - family: 'Ec2TaskDef', - executionRole: new Role(stack, 'ExecutionRole', { - path: '/', - assumedBy: new CompositePrincipal( - new ServicePrincipal('ecs.amazonaws.com'), - new ServicePrincipal('ecs-tasks.amazonaws.com'), - ), - }), - taskRole: new Role(stack, 'TaskRole', { - assumedBy: new ServicePrincipal('ecs-tasks.amazonaws.com'), - }), - dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, - }, - cpu: 256, - assignPublicIp: true, - memoryLimitMiB: 512, - desiredCount: 3, - enableECSManagedTags: true, - healthCheckGracePeriod: Duration.millis(2000), - platformVersion: ecs.FargatePlatformVersion.VERSION1_4, - propagateTags: ecs.PropagatedTagSource.SERVICE, - serviceName: 'myService', - targetGroups: [ - { - containerPort: 80, - }, - { - containerPort: 90, - pathPattern: 'a/b/c', - priority: 10, - protocol: ecs.Protocol.TCP, - }, - ], - }); - - // THEN - stack contains a load balancer and a service - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 3, - EnableECSManagedTags: true, - HealthCheckGracePeriodSeconds: 2, - LaunchType: 'FARGATE', - LoadBalancers: [ - { - ContainerName: 'hello', - ContainerPort: 80, - TargetGroupArn: { - Ref: 'ServiceLBPublicListenerECSTargetGrouphello80Group233A4D54', - }, - }, - { - ContainerName: 'hello', - ContainerPort: 90, - TargetGroupArn: { - Ref: 'ServiceLBPublicListenerECSTargetGrouphello90GroupE58E4EAB', - }, - }, - ], - NetworkConfiguration: { - AwsvpcConfiguration: { - AssignPublicIp: 'ENABLED', - SecurityGroups: [ - { - 'Fn::GetAtt': [ - 'ServiceSecurityGroupEEA09B68', - 'GroupId', - ], - }, - ], - Subnets: [ - { - Ref: 'VPCPublicSubnet1SubnetB4246D30', - }, - { - Ref: 'VPCPublicSubnet2Subnet74179F39', - }, - ], - }, - }, - PlatformVersion: ecs.FargatePlatformVersion.VERSION1_4, - PropagateTags: 'SERVICE', - ServiceName: 'myService', - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Environment: [ - { - Name: 'TEST_ENVIRONMENT_VARIABLE1', - Value: 'test environment variable 1 value', - }, - { - Name: 'TEST_ENVIRONMENT_VARIABLE2', - Value: 'test environment variable 2 value', - }, - ], - Essential: true, - Image: 'test', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ServiceTaskDefhelloLogGroup44519781', - }, - 'awslogs-stream-prefix': 'TestStream', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Name: 'hello', - PortMappings: [ - { - ContainerPort: 80, - Protocol: 'tcp', - }, - { - ContainerPort: 90, - Protocol: 'tcp', - }, - ], - DockerLabels: { - label1: 'labelValue1', - label2: 'labelValue2', - }, - }, - ], - Cpu: '256', - ExecutionRoleArn: { - 'Fn::GetAtt': [ - 'ExecutionRole605A040B', - 'Arn', - ], - }, - Family: 'Ec2TaskDef', - Memory: '512', - NetworkMode: 'awsvpc', - RequiresCompatibilities: [ - 'FARGATE', - ], - TaskRoleArn: { - 'Fn::GetAtt': [ - 'TaskRole30FC0FBB', - 'Arn', - ], - }, - })); - - test.done(); - }, - - 'errors if no essential container in pre-defined task definition'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); - - // THEN - test.throws(() => { - new ApplicationMultipleTargetGroupsFargateService(stack, 'Service', { - cluster, - taskDefinition, - }); - }, /At least one essential container must be specified/); - - test.done(); - }, - - 'errors when setting both taskDefinition and taskImageOptions'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - const taskDefinition = new ecs.FargateTaskDefinition(stack, 'Ec2TaskDef'); - - // THEN - test.throws(() => { - new ApplicationMultipleTargetGroupsFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - taskDefinition, - }); - }, /You must specify only one of TaskDefinition or TaskImageOptions./); - - test.done(); - }, - - 'errors when setting neither taskDefinition nor taskImageOptions'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new ApplicationMultipleTargetGroupsFargateService(stack, 'Service', { - cluster, - }); - }, /You must specify one of: taskDefinition or image/); - - test.done(); - }, - - 'test Fargate loadbalancer construct with application load balancer name set'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - loadBalancerName: 'alb-test-load-balancer', - }); - - // THEN - stack contains a load balancer and a service - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::LoadBalancer', { - Name: 'alb-test-load-balancer', - })); - - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 1, - LaunchType: 'FARGATE', - LoadBalancers: [ - { - ContainerName: 'web', - ContainerPort: 80, - TargetGroupArn: { - Ref: 'ServiceLBPublicListenerECSGroup0CC8688C', - }, - }, - ], - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Image: 'test', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ServiceTaskDefwebLogGroup2A898F61', - }, - 'awslogs-stream-prefix': 'Service', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Name: 'web', - PortMappings: [ - { - ContainerPort: 80, - Protocol: 'tcp', - }, - ], - }, - ], - Cpu: '256', - ExecutionRoleArn: { - 'Fn::GetAtt': [ - 'ServiceTaskDefExecutionRole919F7BE3', - 'Arn', - ], - }, - Family: 'ServiceTaskDef79D79521', - Memory: '512', - NetworkMode: 'awsvpc', - RequiresCompatibilities: [ - 'FARGATE', - ], - })); - - test.done(); - }, - }, - - 'When Network Load Balancer': { - 'test Fargate loadbalanced construct with default settings'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new NetworkMultipleTargetGroupsFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - }); - - // THEN - stack contains a load balancer and a service - expect(stack).to(haveResource('AWS::ElasticLoadBalancingV2::LoadBalancer')); - - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 1, - LaunchType: 'FARGATE', - LoadBalancers: [ - { - ContainerName: 'web', - ContainerPort: 80, - TargetGroupArn: { - Ref: 'ServiceLBPublicListenerECSGroup0CC8688C', - }, - }, - ], - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Image: 'test', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ServiceTaskDefwebLogGroup2A898F61', - }, - 'awslogs-stream-prefix': 'Service', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Name: 'web', - PortMappings: [ - { - ContainerPort: 80, - Protocol: 'tcp', - }, - ], - }, - ], - Cpu: '256', - ExecutionRoleArn: { - 'Fn::GetAtt': [ - 'ServiceTaskDefExecutionRole919F7BE3', - 'Arn', - ], - }, - Family: 'ServiceTaskDef79D79521', - Memory: '512', - NetworkMode: 'awsvpc', - RequiresCompatibilities: [ - 'FARGATE', - ], - })); - - test.done(); - }, - - 'test Fargate loadbalanced construct with all settings'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new NetworkMultipleTargetGroupsFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - containerName: 'hello', - containerPorts: [80, 90], - enableLogging: false, - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - logDriver: new ecs.AwsLogDriver({ - streamPrefix: 'TestStream', - }), - family: 'Ec2TaskDef', - executionRole: new Role(stack, 'ExecutionRole', { - path: '/', - assumedBy: new CompositePrincipal( - new ServicePrincipal('ecs.amazonaws.com'), - new ServicePrincipal('ecs-tasks.amazonaws.com'), - ), - }), - taskRole: new Role(stack, 'TaskRole', { - assumedBy: new ServicePrincipal('ecs-tasks.amazonaws.com'), - }), - dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, - }, - cpu: 256, - assignPublicIp: true, - memoryLimitMiB: 512, - desiredCount: 3, - enableECSManagedTags: true, - healthCheckGracePeriod: Duration.millis(2000), - propagateTags: ecs.PropagatedTagSource.SERVICE, - serviceName: 'myService', - targetGroups: [ - { - containerPort: 80, - }, - { - containerPort: 90, - }, - ], - }); - - // THEN - stack contains a load balancer and a service - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 3, - EnableECSManagedTags: true, - HealthCheckGracePeriodSeconds: 2, - LaunchType: 'FARGATE', - LoadBalancers: [ - { - ContainerName: 'hello', - ContainerPort: 80, - TargetGroupArn: { - Ref: 'ServiceLBPublicListenerECSTargetGrouphello80Group233A4D54', - }, - }, - { - ContainerName: 'hello', - ContainerPort: 90, - TargetGroupArn: { - Ref: 'ServiceLBPublicListenerECSTargetGrouphello90GroupE58E4EAB', - }, - }, - ], - NetworkConfiguration: { - AwsvpcConfiguration: { - AssignPublicIp: 'ENABLED', - SecurityGroups: [ - { - 'Fn::GetAtt': [ - 'ServiceSecurityGroupEEA09B68', - 'GroupId', - ], - }, - ], - Subnets: [ - { - Ref: 'VPCPublicSubnet1SubnetB4246D30', - }, - { - Ref: 'VPCPublicSubnet2Subnet74179F39', - }, - ], - }, - }, - PropagateTags: 'SERVICE', - ServiceName: 'myService', - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Environment: [ - { - Name: 'TEST_ENVIRONMENT_VARIABLE1', - Value: 'test environment variable 1 value', - }, - { - Name: 'TEST_ENVIRONMENT_VARIABLE2', - Value: 'test environment variable 2 value', - }, - ], - Essential: true, - Image: 'test', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ServiceTaskDefhelloLogGroup44519781', - }, - 'awslogs-stream-prefix': 'TestStream', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Name: 'hello', - PortMappings: [ - { - ContainerPort: 80, - Protocol: 'tcp', - }, - { - ContainerPort: 90, - Protocol: 'tcp', - }, - ], - DockerLabels: { - label1: 'labelValue1', - label2: 'labelValue2', - }, - }, - ], - Cpu: '256', - ExecutionRoleArn: { - 'Fn::GetAtt': [ - 'ExecutionRole605A040B', - 'Arn', - ], - }, - Family: 'Ec2TaskDef', - Memory: '512', - NetworkMode: 'awsvpc', - RequiresCompatibilities: [ - 'FARGATE', - ], - TaskRoleArn: { - 'Fn::GetAtt': [ - 'TaskRole30FC0FBB', - 'Arn', - ], - }, - })); - - test.done(); - }, - - 'errors if no essential container in pre-defined task definition'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef'); - - // THEN - test.throws(() => { - new NetworkMultipleTargetGroupsFargateService(stack, 'Service', { - cluster, - taskDefinition, - }); - }, /At least one essential container must be specified/); - - test.done(); - }, - - 'errors when setting both taskDefinition and taskImageOptions'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - const taskDefinition = new ecs.FargateTaskDefinition(stack, 'Ec2TaskDef'); - - // THEN - test.throws(() => { - new NetworkMultipleTargetGroupsFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('test'), - }, - taskDefinition, - }); - }, /You must specify only one of TaskDefinition or TaskImageOptions./); - - test.done(); - }, - - 'errors when setting neither taskDefinition nor taskImageOptions'(test: Test) { - // GIVEN - const stack = new Stack(); - const vpc = new Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // THEN - test.throws(() => { - new NetworkMultipleTargetGroupsFargateService(stack, 'Service', { - cluster, - }); - }, /You must specify one of: taskDefinition or image/); - - test.done(); - }, - }, -}; diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service.ts deleted file mode 100644 index b0f8d0d573d7f..0000000000000 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.load-balanced-fargate-service.ts +++ /dev/null @@ -1,1076 +0,0 @@ -import { expect, haveResource, haveResourceLike, SynthUtils } from '@aws-cdk/assert-internal'; -import { DnsValidatedCertificate } from '@aws-cdk/aws-certificatemanager'; -import * as ec2 from '@aws-cdk/aws-ec2'; -import * as ecs from '@aws-cdk/aws-ecs'; -import { ApplicationLoadBalancer, ApplicationProtocol, NetworkLoadBalancer } from '@aws-cdk/aws-elasticloadbalancingv2'; -import * as iam from '@aws-cdk/aws-iam'; -import * as route53 from '@aws-cdk/aws-route53'; -import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; -import * as ecsPatterns from '../../lib'; - -export = { - 'setting loadBalancerType to Network creates an NLB Public'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::LoadBalancer', { - Type: 'network', - Scheme: 'internet-facing', - })); - - test.done(); - }, - - 'setting loadBalancerType to Network and publicLoadBalancer to false creates an NLB Private'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - publicLoadBalancer: false, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::LoadBalancer', { - Type: 'network', - Scheme: 'internal', - })); - - test.done(); - }, - - 'setting vpc and cluster throws error'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - test.throws(() => new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - cluster, - vpc, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - })); - - test.done(); - }, - - 'setting executionRole updated taskDefinition with given execution role'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - const executionRole = new iam.Role(stack, 'ExecutionRole', { - path: '/', - assumedBy: new iam.CompositePrincipal( - new iam.ServicePrincipal('ecs.amazonaws.com'), - new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), - ), - }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - executionRole, - }, - }); - - // THEN - const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.ServiceTaskDef1922A00F; - test.deepEqual(serviceTaskDefinition.Properties.ExecutionRoleArn, { 'Fn::GetAtt': ['ExecutionRole605A040B', 'Arn'] }); - test.done(); - }, - - 'setting taskRole updated taskDefinition with given task role'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - const taskRole = new iam.Role(stack, 'taskRoleTest', { - path: '/', - assumedBy: new iam.CompositePrincipal( - new iam.ServicePrincipal('ecs.amazonaws.com'), - new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), - ), - }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - taskRole, - }, - }); - - // THEN - const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.ServiceTaskDef1922A00F; - test.deepEqual(serviceTaskDefinition.Properties.TaskRoleArn, { 'Fn::GetAtt': ['taskRoleTest9DA66B6E', 'Arn'] }); - test.done(); - }, - - 'setting containerName updates container name with given name'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - containerName: 'bob', - }, - }); - - // THEN - const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.ServiceTaskDef1922A00F; - test.deepEqual(serviceTaskDefinition.Properties.ContainerDefinitions[0].Name, 'bob'); - test.done(); - }, - - 'not setting containerName updates container name with default'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - }); - - // THEN - const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.ServiceTaskDef1922A00F; - test.deepEqual(serviceTaskDefinition.Properties.ContainerDefinitions[0].Name, 'web'); - test.done(); - }, - - 'setting servicename updates service name with given name'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - serviceName: 'bob', - }); - // THEN - const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.Service9571FDD8; - test.deepEqual(serviceTaskDefinition.Properties.ServiceName, 'bob'); - test.done(); - }, - - 'not setting servicename updates service name with default'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - }); - - // THEN - const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.Service9571FDD8; - test.equal(serviceTaskDefinition.Properties.ServiceName, undefined); - test.done(); - }, - - 'setting healthCheckGracePeriod works'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - healthCheckGracePeriod: cdk.Duration.seconds(600), - }); - // THEN - const serviceTaskDefinition = SynthUtils.synthesize(stack).template.Resources.Service9571FDD8; - test.deepEqual(serviceTaskDefinition.Properties.HealthCheckGracePeriodSeconds, 600); - test.done(); - }, - - 'selecting correct vpcSubnets'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { - maxAzs: 2, - subnetConfiguration: [ - { - subnetType: ec2.SubnetType.PUBLIC, - cidrMask: 20, - name: 'Public', - }, - { - subnetType: ec2.SubnetType.ISOLATED, - cidrMask: 20, - name: 'ISOLATED', - }, - ], - }); - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - vpc, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - taskSubnets: { - subnetType: ec2.SubnetType.ISOLATED, - }, - }); - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - NetworkConfiguration: { - AwsvpcConfiguration: { - Subnets: [ - { - Ref: 'VpcISOLATEDSubnet1Subnet80F07FA0', - }, - { - Ref: 'VpcISOLATEDSubnet2SubnetB0B548C3', - }, - ], - }, - }, - })); - test.done(); - }, - - 'target group uses HTTP/80 as default'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - }); - // THEN - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup', { - Port: 80, - Protocol: 'HTTP', - })); - test.done(); - }, - - 'target group uses HTTPS/443 when configured'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - targetProtocol: ApplicationProtocol.HTTPS, - }); - // THEN - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup', { - Port: 443, - Protocol: 'HTTPS', - })); - test.done(); - }, - - 'setting platform version'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - platformVersion: ecs.FargatePlatformVersion.VERSION1_4, - }); - // THEN - expect(stack).to(haveResource('AWS::ECS::Service', { - PlatformVersion: ecs.FargatePlatformVersion.VERSION1_4, - })); - test.done(); - }, - - 'test load balanced service with family defined'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - enableLogging: false, - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - family: 'fargate-task-family', - }, - desiredCount: 2, - memoryLimitMiB: 512, - serviceName: 'fargate-test-service', - }); - - // THEN - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 2, - LaunchType: 'FARGATE', - ServiceName: 'fargate-test-service', - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Environment: [ - { - Name: 'TEST_ENVIRONMENT_VARIABLE1', - Value: 'test environment variable 1 value', - }, - { - Name: 'TEST_ENVIRONMENT_VARIABLE2', - Value: 'test environment variable 2 value', - }, - ], - Image: '/aws/aws-example-app', - }, - ], - Family: 'fargate-task-family', - })); - - test.done(); - }, - - 'setting ALB deployment controller'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - deploymentController: { - type: ecs.DeploymentControllerType.CODE_DEPLOY, - }, - }); - // THEN - expect(stack).to(haveResource('AWS::ECS::Service', { - DeploymentController: { - Type: 'CODE_DEPLOY', - }, - })); - test.done(); - }, - - 'setting NLB deployment controller'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - deploymentController: { - type: ecs.DeploymentControllerType.CODE_DEPLOY, - }, - }); - // THEN - expect(stack).to(haveResource('AWS::ECS::Service', { - DeploymentController: { - Type: 'CODE_DEPLOY', - }, - })); - test.done(); - }, - - 'setting ALB circuitBreaker works'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - circuitBreaker: { rollback: true }, - }); - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - DeploymentConfiguration: { - DeploymentCircuitBreaker: { - Enable: true, - Rollback: true, - }, - }, - DeploymentController: { - Type: 'ECS', - }, - })); - test.done(); - }, - - 'setting NLB circuitBreaker works'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - }, - circuitBreaker: { rollback: true }, - }); - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - DeploymentConfiguration: { - DeploymentCircuitBreaker: { - Enable: true, - Rollback: true, - }, - }, - DeploymentController: { - Type: 'ECS', - }, - })); - test.done(); - }, - - 'setting NLB special listener port to create the listener'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'FargateNlbService', { - cluster, - listenerPort: 2015, - taskImageOptions: { - containerPort: 2015, - image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { - DefaultActions: [ - { - Type: 'forward', - }, - ], - Port: 2015, - Protocol: 'TCP', - })); - - test.done(); - }, - - 'setting ALB special listener port to create the listener'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { - cluster, - listenerPort: 2015, - taskImageOptions: { - containerPort: 2015, - image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { - DefaultActions: [ - { - Type: 'forward', - }, - ], - Port: 2015, - Protocol: 'HTTP', - })); - - test.done(); - }, - - 'setting ALB HTTPS protocol to create the listener on 443'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { - cluster, - protocol: ApplicationProtocol.HTTPS, - domainName: 'domain.com', - domainZone: route53.HostedZone.fromHostedZoneAttributes(stack, 'HostedZone', { - hostedZoneId: 'fakeId', - zoneName: 'domain.com', - }), - taskImageOptions: { - containerPort: 2015, - image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { - DefaultActions: [ - { - Type: 'forward', - }, - ], - Port: 443, - Protocol: 'HTTPS', - })); - - test.done(); - }, - - 'setting ALB HTTPS correctly sets the recordset name'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { - cluster, - protocol: ApplicationProtocol.HTTPS, - domainName: 'test.domain.com', - domainZone: route53.HostedZone.fromHostedZoneAttributes(stack, 'HostedZone', { - hostedZoneId: 'fakeId', - zoneName: 'domain.com.', - }), - taskImageOptions: { - containerPort: 2015, - image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::Route53::RecordSet', { - Name: 'test.domain.com.', - })); - - test.done(); - }, - - 'setting ALB cname option correctly sets the recordset type'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { - cluster, - protocol: ApplicationProtocol.HTTPS, - domainName: 'test.domain.com', - domainZone: route53.HostedZone.fromHostedZoneAttributes(stack, 'HostedZone', { - hostedZoneId: 'fakeId', - zoneName: 'domain.com.', - }), - recordType: ecsPatterns.ApplicationLoadBalancedServiceRecordType.CNAME, - taskImageOptions: { - containerPort: 2015, - image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::Route53::RecordSet', { - Name: 'test.domain.com.', - Type: 'CNAME', - })); - - test.done(); - }, - - 'setting ALB record type to NONE correctly omits the recordset'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { - cluster, - protocol: ApplicationProtocol.HTTPS, - domainName: 'test.domain.com', - domainZone: route53.HostedZone.fromHostedZoneAttributes(stack, 'HostedZone', { - hostedZoneId: 'fakeId', - zoneName: 'domain.com.', - }), - recordType: ecsPatterns.ApplicationLoadBalancedServiceRecordType.NONE, - taskImageOptions: { - containerPort: 2015, - image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), - }, - }); - - // THEN - expect(stack).notTo(haveResource('AWS::Route53::RecordSet')); - - test.done(); - }, - - - 'setting NLB cname option correctly sets the recordset type'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'FargateNlbService', { - cluster, - domainName: 'test.domain.com', - domainZone: route53.HostedZone.fromHostedZoneAttributes(stack, 'HostedZone', { - hostedZoneId: 'fakeId', - zoneName: 'domain.com.', - }), - recordType: ecsPatterns.NetworkLoadBalancedServiceRecordType.CNAME, - taskImageOptions: { - containerPort: 2015, - image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::Route53::RecordSet', { - Name: 'test.domain.com.', - Type: 'CNAME', - })); - - test.done(); - }, - - 'setting NLB record type to NONE correctly omits the recordset'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'FargateNlbService', { - cluster, - domainName: 'test.domain.com', - domainZone: route53.HostedZone.fromHostedZoneAttributes(stack, 'HostedZone', { - hostedZoneId: 'fakeId', - zoneName: 'domain.com.', - }), - recordType: ecsPatterns.NetworkLoadBalancedServiceRecordType.NONE, - taskImageOptions: { - containerPort: 2015, - image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), - }, - }); - - // THEN - expect(stack).notTo(haveResource('AWS::Route53::RecordSet')); - - test.done(); - }, - - 'setting ALB HTTP protocol to create the listener on 80'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { - cluster, - protocol: ApplicationProtocol.HTTP, - taskImageOptions: { - containerPort: 2015, - image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { - DefaultActions: [ - { - Type: 'forward', - }, - ], - Port: 80, - Protocol: 'HTTP', - })); - - test.done(); - }, - - 'setting ALB without any protocol or listenerPort to create the listener on 80'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { - cluster, - taskImageOptions: { - containerPort: 2015, - image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { - DefaultActions: [ - { - Type: 'forward', - }, - ], - Port: 80, - Protocol: 'HTTP', - })); - - test.done(); - }, - - 'passing in existing network load balancer to NLB Fargate Service'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const nlb = new NetworkLoadBalancer(stack, 'NLB', { vpc }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - vpc, - loadBalancer: nlb, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - LaunchType: 'FARGATE', - })); - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::LoadBalancer', { - Type: 'network', - })); - test.done(); - }, - - 'passing in imported network load balancer and resources to NLB Fargate service'(test: Test) { - // GIVEN - const app = new cdk.App(); - const stack1 = new cdk.Stack(app, 'MyStack'); - const vpc1 = new ec2.Vpc(stack1, 'VPC'); - const cluster1 = new ecs.Cluster(stack1, 'Cluster', { vpc: vpc1 }); - const nlbArn = 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188'; - const stack2 = new cdk.Stack(stack1, 'Stack2'); - const cluster2 = ecs.Cluster.fromClusterAttributes(stack2, 'ImportedCluster', { - vpc: vpc1, - securityGroups: cluster1.connections.securityGroups, - clusterName: 'cluster-name', - }); - - // WHEN - const nlb2 = NetworkLoadBalancer.fromNetworkLoadBalancerAttributes(stack2, 'ImportedNLB', { - loadBalancerArn: nlbArn, - vpc: vpc1, - }); - const taskDef = new ecs.FargateTaskDefinition(stack2, 'TaskDef', { - cpu: 1024, - memoryLimitMiB: 1024, - }); - const container = taskDef.addContainer('myContainer', { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - memoryLimitMiB: 1024, - }); - container.addPortMappings({ - containerPort: 80, - }); - - new ecsPatterns.NetworkLoadBalancedFargateService(stack2, 'FargateNLBService', { - cluster: cluster2, - loadBalancer: nlb2, - desiredCount: 1, - taskDefinition: taskDef, - }); - - // THEN - expect(stack2).to(haveResourceLike('AWS::ECS::Service', { - LaunchType: 'FARGATE', - LoadBalancers: [{ ContainerName: 'myContainer', ContainerPort: 80 }], - })); - expect(stack2).to(haveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup')); - expect(stack2).to(haveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { - LoadBalancerArn: nlb2.loadBalancerArn, - Port: 80, - })); - - test.done(); - }, - - 'passing in previously created application load balancer to ALB Fargate Service'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc, clusterName: 'MyCluster' }); - const sg = new ec2.SecurityGroup(stack, 'SecurityGroup', { vpc }); - cluster.connections.addSecurityGroup(sg); - const alb = new ApplicationLoadBalancer(stack, 'ALB', { vpc, securityGroup: sg }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - loadBalancer: alb, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - LaunchType: 'FARGATE', - })); - expect(stack).to(haveResourceLike('AWS::ElasticLoadBalancingV2::LoadBalancer', { - Type: 'application', - })); - test.done(); - }, - - 'passing in imported application load balancer and resources to ALB Fargate Service'(test: Test) { - // GIVEN - const stack1 = new cdk.Stack(); - const albArn = 'arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188'; - const vpc = new ec2.Vpc(stack1, 'Vpc'); - const cluster = new ecs.Cluster(stack1, 'Cluster', { vpc, clusterName: 'MyClusterName' }); - const sg = new ec2.SecurityGroup(stack1, 'SecurityGroup', { vpc }); - cluster.connections.addSecurityGroup(sg); - const alb = ApplicationLoadBalancer.fromApplicationLoadBalancerAttributes(stack1, 'ALB', { - loadBalancerArn: albArn, - vpc, - securityGroupId: sg.securityGroupId, - loadBalancerDnsName: 'MyDnsName', - }); - - // WHEN - const taskDef = new ecs.FargateTaskDefinition(stack1, 'TaskDef', { - cpu: 1024, - memoryLimitMiB: 1024, - }); - const container = taskDef.addContainer('Container', { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - memoryLimitMiB: 1024, - }); - container.addPortMappings({ - containerPort: 80, - }); - - new ecsPatterns.ApplicationLoadBalancedFargateService(stack1, 'FargateALBService', { - cluster, - loadBalancer: alb, - desiredCount: 1, - taskDefinition: taskDef, - }); - - // THEN - expect(stack1).to(haveResourceLike('AWS::ECS::Service', { - LaunchType: 'FARGATE', - LoadBalancers: [{ ContainerName: 'Container', ContainerPort: 80 }], - })); - expect(stack1).to(haveResourceLike('AWS::ElasticLoadBalancingV2::TargetGroup')); - expect(stack1).to(haveResourceLike('AWS::ElasticLoadBalancingV2::Listener', { - LoadBalancerArn: alb.loadBalancerArn, - Port: 80, - })); - - test.done(); - }, - - 'passing in previously created security groups to ALB Fargate Service'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc, clusterName: 'MyCluster' }); - const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup', { - allowAllOutbound: false, - description: 'Example', - securityGroupName: 'Rolly', - vpc, - }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), - }, - securityGroups: [securityGroup], - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::Service', { - LaunchType: 'FARGATE', - })); - expect(stack).to(haveResource('AWS::EC2::SecurityGroup', { - GroupDescription: 'Example', - GroupName: 'Rolly', - SecurityGroupEgress: [ - { - CidrIp: '255.255.255.255/32', - Description: 'Disallow all traffic', - FromPort: 252, - IpProtocol: 'icmp', - ToPort: 86, - }, - ], - VpcId: { - Ref: 'Vpc8378EB38', - }, - })); - test.done(); - }, - - 'domainName and domainZone not required for HTTPS listener with provided cert'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - const exampleDotComZone = new route53.PublicHostedZone(stack, 'ExampleDotCom', { - zoneName: 'example.com', - }); - const certificate = new DnsValidatedCertificate(stack, 'Certificate', { - domainName: 'test.example.com', - hostedZone: exampleDotComZone, - }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'FargateAlbService', { - cluster, - protocol: ApplicationProtocol.HTTPS, - - taskImageOptions: { - containerPort: 2015, - image: ecs.ContainerImage.fromRegistry('abiosoft/caddy'), - }, - certificate: certificate, - }); - - // THEN - expect(stack).notTo(haveResourceLike('AWS::Route53::RecordSet', { - Name: 'test.domain.com.', - })); - - test.done(); - - }, - - 'test ALB load balanced service with docker labels defined'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Image: '/aws/aws-example-app', - DockerLabels: { - label1: 'labelValue1', - label2: 'labelValue2', - }, - }, - ], - })); - - test.done(); - }, - - 'test Network load balanced service with docker labels defined'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', { - cluster, - taskImageOptions: { - image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'), - dockerLabels: { label1: 'labelValue1', label2: 'labelValue2' }, - }, - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Image: '/aws/aws-example-app', - DockerLabels: { - label1: 'labelValue1', - label2: 'labelValue2', - }, - }, - ], - })); - - test.done(); - }, -}; diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts deleted file mode 100644 index 6b5a05ccaaf7b..0000000000000 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts +++ /dev/null @@ -1,577 +0,0 @@ -import { ABSENT, expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; -import * as ec2 from '@aws-cdk/aws-ec2'; -import * as ecs from '@aws-cdk/aws-ecs'; -import * as sqs from '@aws-cdk/aws-sqs'; -import * as cdk from '@aws-cdk/core'; -import * as cxapi from '@aws-cdk/cx-api'; -import { Test } from 'nodeunit'; -import * as ecsPatterns from '../../lib'; - -export = { - 'test fargate queue worker service construct - with only required props'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { - cluster, - memoryLimitMiB: 512, - image: ecs.ContainerImage.fromRegistry('test'), - }); - - // THEN - QueueWorker is of FARGATE launch type, an SQS queue is created and all default properties are set. - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 1, - LaunchType: 'FARGATE', - })); - - expect(stack).to(haveResource('AWS::SQS::Queue', { - RedrivePolicy: { - deadLetterTargetArn: { - 'Fn::GetAtt': [ - 'ServiceEcsProcessingDeadLetterQueue4A89196E', - 'Arn', - ], - }, - maxReceiveCount: 3, - }, - })); - - expect(stack).to(haveResource('AWS::SQS::Queue', { - MessageRetentionPeriod: 1209600, - })); - - expect(stack).to(haveResource('AWS::IAM::Policy', { - PolicyDocument: { - Statement: [ - { - Action: [ - 'sqs:ReceiveMessage', - 'sqs:ChangeMessageVisibility', - 'sqs:GetQueueUrl', - 'sqs:DeleteMessage', - 'sqs:GetQueueAttributes', - ], - Effect: 'Allow', - Resource: { - 'Fn::GetAtt': [ - 'ServiceEcsProcessingQueueC266885C', - 'Arn', - ], - }, - }, - ], - Version: '2012-10-17', - }, - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Environment: [ - { - Name: 'QUEUE_NAME', - Value: { - 'Fn::GetAtt': [ - 'ServiceEcsProcessingQueueC266885C', - 'QueueName', - ], - }, - }, - ], - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupD52338D1', - }, - 'awslogs-stream-prefix': 'Service', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Image: 'test', - }, - ], - Family: 'ServiceQueueProcessingTaskDef83DB34F1', - })); - - test.done(); - }, - - 'test fargate queue worker service construct - with remove default desiredCount feature flag'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - stack.node.setContext(cxapi.ECS_REMOVE_DEFAULT_DESIRED_COUNT, true); - - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - - // WHEN - new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { - cluster, - memoryLimitMiB: 512, - image: ecs.ContainerImage.fromRegistry('test'), - }); - - // THEN - QueueWorker is of FARGATE launch type, and desiredCount is not defined on the FargateService. - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: ABSENT, - LaunchType: 'FARGATE', - })); - - test.done(); - }, - - 'test fargate queue worker service construct - with optional props for queues'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { - cluster, - memoryLimitMiB: 512, - image: ecs.ContainerImage.fromRegistry('test'), - maxReceiveCount: 42, - retentionPeriod: cdk.Duration.days(7), - visibilityTimeout: cdk.Duration.minutes(5), - }); - - // THEN - QueueWorker is of FARGATE launch type, an SQS queue is created and all default properties are set. - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 1, - LaunchType: 'FARGATE', - })); - - expect(stack).to(haveResource('AWS::SQS::Queue', { - RedrivePolicy: { - deadLetterTargetArn: { - 'Fn::GetAtt': [ - 'ServiceEcsProcessingDeadLetterQueue4A89196E', - 'Arn', - ], - }, - maxReceiveCount: 42, - }, - VisibilityTimeout: 300, - })); - - expect(stack).to(haveResource('AWS::SQS::Queue', { - MessageRetentionPeriod: 604800, - })); - - expect(stack).to(haveResource('AWS::IAM::Policy', { - PolicyDocument: { - Statement: [ - { - Action: [ - 'sqs:ReceiveMessage', - 'sqs:ChangeMessageVisibility', - 'sqs:GetQueueUrl', - 'sqs:DeleteMessage', - 'sqs:GetQueueAttributes', - ], - Effect: 'Allow', - Resource: { - 'Fn::GetAtt': [ - 'ServiceEcsProcessingQueueC266885C', - 'Arn', - ], - }, - }, - ], - Version: '2012-10-17', - }, - })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Environment: [ - { - Name: 'QUEUE_NAME', - Value: { - 'Fn::GetAtt': [ - 'ServiceEcsProcessingQueueC266885C', - 'QueueName', - ], - }, - }, - ], - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ServiceQueueProcessingTaskDefQueueProcessingContainerLogGroupD52338D1', - }, - 'awslogs-stream-prefix': 'Service', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Image: 'test', - }, - ], - Family: 'ServiceQueueProcessingTaskDef83DB34F1', - })); - - test.done(); - }, - - 'test Fargate queue worker service construct - without desiredCount specified'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - const queue = new sqs.Queue(stack, 'fargate-test-queue', { - queueName: 'fargate-test-sqs-queue', - }); - - // WHEN - new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { - cluster, - memoryLimitMiB: 512, - image: ecs.ContainerImage.fromRegistry('test'), - command: ['-c', '4', 'amazon.com'], - enableLogging: false, - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - queue, - maxScalingCapacity: 5, - minScalingCapacity: 2, - minHealthyPercent: 60, - maxHealthyPercent: 150, - serviceName: 'fargate-test-service', - family: 'fargate-task-family', - platformVersion: ecs.FargatePlatformVersion.VERSION1_4, - deploymentController: { - type: ecs.DeploymentControllerType.CODE_DEPLOY, - }, - }); - - // THEN - QueueWorker is of FARGATE launch type, an SQS queue is created and all optional properties are set. - expect(stack).to(haveResource('AWS::ECS::Service', { - DeploymentConfiguration: { - MinimumHealthyPercent: 60, - MaximumPercent: 150, - }, - LaunchType: 'FARGATE', - ServiceName: 'fargate-test-service', - PlatformVersion: ecs.FargatePlatformVersion.VERSION1_4, - DeploymentController: { - Type: 'CODE_DEPLOY', - }, - })); - - expect(stack).to(haveResource('AWS::ApplicationAutoScaling::ScalableTarget', { - MaxCapacity: 5, - MinCapacity: 2, - })); - - expect(stack).to(haveResource('AWS::SQS::Queue', { QueueName: 'fargate-test-sqs-queue' })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Command: [ - '-c', - '4', - 'amazon.com', - ], - Environment: [ - { - Name: 'TEST_ENVIRONMENT_VARIABLE1', - Value: 'test environment variable 1 value', - }, - { - Name: 'TEST_ENVIRONMENT_VARIABLE2', - Value: 'test environment variable 2 value', - }, - { - Name: 'QUEUE_NAME', - Value: { - 'Fn::GetAtt': [ - 'fargatetestqueue28B43841', - 'QueueName', - ], - }, - }, - ], - Image: 'test', - }, - ], - Family: 'fargate-task-family', - })); - - test.done(); - }, - - 'test Fargate queue worker service construct - with optional props'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - const queue = new sqs.Queue(stack, 'fargate-test-queue', { - queueName: 'fargate-test-sqs-queue', - }); - - // WHEN - new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { - cluster, - memoryLimitMiB: 512, - image: ecs.ContainerImage.fromRegistry('test'), - command: ['-c', '4', 'amazon.com'], - enableLogging: false, - desiredTaskCount: 2, - environment: { - TEST_ENVIRONMENT_VARIABLE1: 'test environment variable 1 value', - TEST_ENVIRONMENT_VARIABLE2: 'test environment variable 2 value', - }, - queue, - maxScalingCapacity: 5, - minHealthyPercent: 60, - maxHealthyPercent: 150, - serviceName: 'fargate-test-service', - family: 'fargate-task-family', - platformVersion: ecs.FargatePlatformVersion.VERSION1_4, - circuitBreaker: { rollback: true }, - }); - - // THEN - QueueWorker is of FARGATE launch type, an SQS queue is created and all optional properties are set. - expect(stack).to(haveResource('AWS::ECS::Service', { - DesiredCount: 2, - DeploymentConfiguration: { - MinimumHealthyPercent: 60, - MaximumPercent: 150, - DeploymentCircuitBreaker: { - Enable: true, - Rollback: true, - }, - }, - LaunchType: 'FARGATE', - ServiceName: 'fargate-test-service', - PlatformVersion: ecs.FargatePlatformVersion.VERSION1_4, - DeploymentController: { - Type: 'ECS', - }, - })); - - expect(stack).to(haveResource('AWS::SQS::Queue', { QueueName: 'fargate-test-sqs-queue' })); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Command: [ - '-c', - '4', - 'amazon.com', - ], - Environment: [ - { - Name: 'TEST_ENVIRONMENT_VARIABLE1', - Value: 'test environment variable 1 value', - }, - { - Name: 'TEST_ENVIRONMENT_VARIABLE2', - Value: 'test environment variable 2 value', - }, - { - Name: 'QUEUE_NAME', - Value: { - 'Fn::GetAtt': [ - 'fargatetestqueue28B43841', - 'QueueName', - ], - }, - }, - ], - Image: 'test', - }, - ], - Family: 'fargate-task-family', - })); - - test.done(); - }, - - 'can set custom containerName'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - const cluster = new ecs.Cluster(stack, 'Cluster', { vpc }); - cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); - - // WHEN - new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { - cluster, - containerName: 'my-container', - image: ecs.ContainerImage.fromRegistry('test'), - }); - - expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Name: 'my-container', - }, - ], - })); - - test.done(); - }, - - 'can set custom networking options'(test: Test) { - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC', { - subnetConfiguration: [ - { - cidrMask: 24, - name: 'Public', - subnetType: ec2.SubnetType.PUBLIC, - }, - { - cidrMask: 24, - name: 'Isolated', - subnetType: ec2.SubnetType.ISOLATED, - }, - ], - }); - const securityGroup = new ec2.SecurityGroup(stack, 'MyCustomSG', { - vpc, - }); - - // WHEN - SecurityGroups and taskSubnets selection is defined - new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { - vpc, - memoryLimitMiB: 512, - image: ecs.ContainerImage.fromRegistry('test'), - securityGroups: [securityGroup], - taskSubnets: { subnetType: ec2.SubnetType.ISOLATED }, - }); - - // THEN - NetworkConfiguration is created with the specific security groups and selected subnets - expect(stack).to(haveResource('AWS::ECS::Service', { - LaunchType: 'FARGATE', - NetworkConfiguration: { - AwsvpcConfiguration: { - AssignPublicIp: 'DISABLED', - SecurityGroups: [ - { - 'Fn::GetAtt': [ - 'MyCustomSGDE27C661', - 'GroupId', - ], - }, - ], - Subnets: [ - { - Ref: 'VPCIsolatedSubnet1SubnetEBD00FC6', - }, - { - Ref: 'VPCIsolatedSubnet2Subnet4B1C8CAA', - }, - ], - }, - }, - })); - - test.done(); - }, - - 'can set use public IP'(test: Test) { - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'VPC'); - - // WHEN - Assign Public IP is set to True - new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { - vpc, - memoryLimitMiB: 512, - image: ecs.ContainerImage.fromRegistry('test'), - assignPublicIp: true, - }); - - // THEN - The Subnets defaults to Public and AssignPublicIp settings change to ENABLED - expect(stack).to(haveResource('AWS::ECS::Service', { - LaunchType: 'FARGATE', - NetworkConfiguration: { - AwsvpcConfiguration: { - AssignPublicIp: 'ENABLED', - SecurityGroups: [ - { - 'Fn::GetAtt': [ - 'ServiceQueueProcessingFargateServiceSecurityGroup6E981512', - 'GroupId', - ], - }, - ], - Subnets: [ - { - Ref: 'VPCPublicSubnet1SubnetB4246D30', - }, - { - Ref: 'VPCPublicSubnet2Subnet74179F39', - }, - ], - }, - }, - })); - - test.done(); - }, - - 'can set capacity provider strategies'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'MyVpc', {}); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { - vpc, - }); - cluster.enableFargateCapacityProviders(); - - // WHEN - new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { - cluster, - image: ecs.ContainerImage.fromRegistry('test'), - capacityProviderStrategies: [ - { - capacityProvider: 'FARGATE_SPOT', - weight: 2, - }, - { - capacityProvider: 'FARGATE', - weight: 1, - }, - ], - }); - - // THEN - expect(stack).to( - haveResource('AWS::ECS::Service', { - LaunchType: ABSENT, - CapacityProviderStrategy: [ - { - CapacityProvider: 'FARGATE_SPOT', - Weight: 2, - }, - { - CapacityProvider: 'FARGATE', - Weight: 1, - }, - ], - }), - ); - - test.done(); - }, -}; diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.scheduled-fargate-task.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.scheduled-fargate-task.ts deleted file mode 100644 index 497e885460f26..0000000000000 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.scheduled-fargate-task.ts +++ /dev/null @@ -1,430 +0,0 @@ -import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; -import * as ec2 from '@aws-cdk/aws-ec2'; -import * as ecs from '@aws-cdk/aws-ecs'; -import * as events from '@aws-cdk/aws-events'; -import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; -import { ScheduledFargateTask } from '../../lib'; - -export = { - 'Can create a scheduled Fargate Task - with only required props'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - - new ScheduledFargateTask(stack, 'ScheduledFargateTask', { - cluster, - scheduledFargateTaskImageOptions: { - image: ecs.ContainerImage.fromRegistry('henk'), - memoryLimitMiB: 512, - }, - schedule: events.Schedule.expression('rate(1 minute)'), - }); - - // THEN - expect(stack).to(haveResource('AWS::Events::Rule', { - State: 'ENABLED', - Targets: [ - { - Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, - EcsParameters: { - LaunchType: 'FARGATE', - NetworkConfiguration: { - AwsVpcConfiguration: { - AssignPublicIp: 'DISABLED', - SecurityGroups: [ - { - 'Fn::GetAtt': [ - 'ScheduledFargateTaskScheduledTaskDefSecurityGroupE075BC19', - 'GroupId', - ], - }, - ], - Subnets: [ - { - Ref: 'VpcPrivateSubnet1Subnet536B997A', - }, - ], - }, - }, - TaskCount: 1, - TaskDefinitionArn: { Ref: 'ScheduledFargateTaskScheduledTaskDef521FA675' }, - }, - Id: 'Target0', - Input: '{}', - RoleArn: { 'Fn::GetAtt': ['ScheduledFargateTaskScheduledTaskDefEventsRole6CE19522', 'Arn'] }, - }, - ], - })); - - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Essential: true, - Image: 'henk', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ScheduledFargateTaskScheduledTaskDefScheduledContainerLogGroup4134B16C', - }, - 'awslogs-stream-prefix': 'ScheduledFargateTask', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Name: 'ScheduledContainer', - }, - ], - })); - - test.done(); - }, - - 'Can create a scheduled Fargate Task - with optional props'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - - new ScheduledFargateTask(stack, 'ScheduledFargateTask', { - cluster, - enabled: false, - scheduledFargateTaskImageOptions: { - image: ecs.ContainerImage.fromRegistry('henk'), - memoryLimitMiB: 512, - cpu: 2, - environment: { TRIGGER: 'CloudWatch Events' }, - }, - desiredTaskCount: 2, - schedule: events.Schedule.expression('rate(1 minute)'), - ruleName: 'sample-scheduled-task-rule', - }); - - // THEN - expect(stack).to(haveResource('AWS::Events::Rule', { - Name: 'sample-scheduled-task-rule', - State: 'DISABLED', - Targets: [ - { - Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, - EcsParameters: { - LaunchType: 'FARGATE', - NetworkConfiguration: { - AwsVpcConfiguration: { - AssignPublicIp: 'DISABLED', - SecurityGroups: [ - { - 'Fn::GetAtt': [ - 'ScheduledFargateTaskScheduledTaskDefSecurityGroupE075BC19', - 'GroupId', - ], - }, - ], - Subnets: [ - { - Ref: 'VpcPrivateSubnet1Subnet536B997A', - }, - ], - }, - }, - TaskCount: 2, - TaskDefinitionArn: { Ref: 'ScheduledFargateTaskScheduledTaskDef521FA675' }, - }, - Id: 'Target0', - Input: '{}', - RoleArn: { 'Fn::GetAtt': ['ScheduledFargateTaskScheduledTaskDefEventsRole6CE19522', 'Arn'] }, - }, - ], - })); - - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Environment: [ - { - Name: 'TRIGGER', - Value: 'CloudWatch Events', - }, - ], - Essential: true, - Image: 'henk', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ScheduledFargateTaskScheduledTaskDefScheduledContainerLogGroup4134B16C', - }, - 'awslogs-stream-prefix': 'ScheduledFargateTask', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Name: 'ScheduledContainer', - }, - ], - })); - - test.done(); - }, - - 'Scheduled Fargate Task - with MemoryReservation defined'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - - new ScheduledFargateTask(stack, 'ScheduledFargateTask', { - cluster, - scheduledFargateTaskImageOptions: { - image: ecs.ContainerImage.fromRegistry('henk'), - }, - schedule: events.Schedule.expression('rate(1 minute)'), - }); - - // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Essential: true, - Image: 'henk', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ScheduledFargateTaskScheduledTaskDefScheduledContainerLogGroup4134B16C', - }, - 'awslogs-stream-prefix': 'ScheduledFargateTask', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Name: 'ScheduledContainer', - }, - ], - })); - - test.done(); - }, - - 'Scheduled Fargate Task - with Command defined'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - - new ScheduledFargateTask(stack, 'ScheduledFargateTask', { - cluster, - scheduledFargateTaskImageOptions: { - image: ecs.ContainerImage.fromRegistry('henk'), - command: ['-c', '4', 'amazon.com'], - }, - schedule: events.Schedule.expression('rate(1 minute)'), - }); - - // THEN - expect(stack).to(haveResource('AWS::ECS::TaskDefinition', { - ContainerDefinitions: [ - { - Command: [ - '-c', - '4', - 'amazon.com', - ], - Essential: true, - Image: 'henk', - LogConfiguration: { - LogDriver: 'awslogs', - Options: { - 'awslogs-group': { - Ref: 'ScheduledFargateTaskScheduledTaskDefScheduledContainerLogGroup4134B16C', - }, - 'awslogs-stream-prefix': 'ScheduledFargateTask', - 'awslogs-region': { - Ref: 'AWS::Region', - }, - }, - }, - Name: 'ScheduledContainer', - }, - ], - })); - - test.done(); - }, - - 'Scheduled Fargate Task - with subnetSelection defined'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { - maxAzs: 1, - subnetConfiguration: [ - { name: 'Public', cidrMask: 28, subnetType: ec2.SubnetType.PUBLIC }, - ], - }); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - - new ScheduledFargateTask(stack, 'ScheduledFargateTask', { - cluster, - scheduledFargateTaskImageOptions: { - image: ecs.ContainerImage.fromRegistry('henk'), - }, - subnetSelection: { subnetType: ec2.SubnetType.PUBLIC }, - schedule: events.Schedule.expression('rate(1 minute)'), - }); - - // THEN - expect(stack).to(haveResourceLike('AWS::Events::Rule', { - Targets: [ - { - EcsParameters: { - NetworkConfiguration: { - AwsVpcConfiguration: { - AssignPublicIp: 'ENABLED', - Subnets: [ - { - Ref: 'VpcPublicSubnet1Subnet5C2D37C4', - }, - ], - }, - }, - }, - }, - ], - })); - - test.done(); - }, - - 'Scheduled Fargate Task - with platformVersion defined'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - - new ScheduledFargateTask(stack, 'ScheduledFargateTask', { - cluster, - scheduledFargateTaskImageOptions: { - image: ecs.ContainerImage.fromRegistry('henk'), - memoryLimitMiB: 512, - }, - schedule: events.Schedule.expression('rate(1 minute)'), - platformVersion: ecs.FargatePlatformVersion.VERSION1_4, - }); - - // THEN - expect(stack).to(haveResource('AWS::Events::Rule', { - Targets: [ - { - Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, - EcsParameters: { - LaunchType: 'FARGATE', - NetworkConfiguration: { - AwsVpcConfiguration: { - AssignPublicIp: 'DISABLED', - SecurityGroups: [ - { - 'Fn::GetAtt': [ - 'ScheduledFargateTaskScheduledTaskDefSecurityGroupE075BC19', - 'GroupId', - ], - }, - ], - Subnets: [ - { - Ref: 'VpcPrivateSubnet1Subnet536B997A', - }, - ], - }, - }, - PlatformVersion: '1.4.0', - TaskCount: 1, - TaskDefinitionArn: { Ref: 'ScheduledFargateTaskScheduledTaskDef521FA675' }, - }, - Id: 'Target0', - Input: '{}', - RoleArn: { 'Fn::GetAtt': ['ScheduledFargateTaskScheduledTaskDefEventsRole6CE19522', 'Arn'] }, - }, - ], - })); - - test.done(); - }, - 'Scheduled Fargate Task - with securityGroups defined'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - const sg = new ec2.SecurityGroup(stack, 'SG', { vpc }); - - new ScheduledFargateTask(stack, 'ScheduledFargateTask', { - cluster, - scheduledFargateTaskImageOptions: { - image: ecs.ContainerImage.fromRegistry('henk'), - memoryLimitMiB: 512, - }, - schedule: events.Schedule.expression('rate(1 minute)'), - securityGroups: [sg], - }); - - // THEN - expect(stack).to(haveResource('AWS::Events::Rule', { - Targets: [ - { - Arn: { 'Fn::GetAtt': ['EcsCluster97242B84', 'Arn'] }, - EcsParameters: { - LaunchType: 'FARGATE', - NetworkConfiguration: { - AwsVpcConfiguration: { - AssignPublicIp: 'DISABLED', - SecurityGroups: [{ - 'Fn::GetAtt': [ - 'SGADB53937', - 'GroupId', - ], - }], - Subnets: [ - { - Ref: 'VpcPrivateSubnet1Subnet536B997A', - }, - ], - }, - }, - TaskCount: 1, - TaskDefinitionArn: { Ref: 'ScheduledFargateTaskScheduledTaskDef521FA675' }, - }, - Id: 'Target0', - Input: '{}', - RoleArn: { 'Fn::GetAtt': ['ScheduledFargateTaskScheduledTaskDefEventsRole6CE19522', 'Arn'] }, - }, - ], - })); - - test.done(); - }, - - 'Scheduled Fargate Task - exposes ECS Task'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc', { maxAzs: 1 }); - const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); - - const scheduledFargateTask = new ScheduledFargateTask(stack, 'ScheduledFargateTask', { - cluster, - scheduledFargateTaskImageOptions: { - image: ecs.ContainerImage.fromRegistry('henk'), - memoryLimitMiB: 512, - }, - schedule: events.Schedule.expression('rate(1 minute)'), - }); - - // THEN - test.notEqual(scheduledFargateTask.task, undefined); - - test.done(); - }, -}; diff --git a/packages/@aws-cdk/aws-ecs/.eslintrc.js b/packages/@aws-cdk/aws-ecs/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-ecs/.eslintrc.js +++ b/packages/@aws-cdk/aws-ecs/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ecs/jest.config.js b/packages/@aws-cdk/aws-ecs/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-ecs/jest.config.js +++ b/packages/@aws-cdk/aws-ecs/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ecs/package.json b/packages/@aws-cdk/aws-ecs/package.json index f050efe94d045..d1839630a6eff 100644 --- a/packages/@aws-cdk/aws-ecs/package.json +++ b/packages/@aws-cdk/aws-ecs/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::ECS", - "jest": "true", "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,18 +72,17 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-s3-deployment": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "@types/nodeunit": "^0.0.32", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", "@types/proxyquire": "^1.3.28", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0", - "proxyquire": "^2.1.3", - "@aws-cdk/assert-internal": "0.0.0" + "proxyquire": "^2.1.3" }, "dependencies": { "@aws-cdk/aws-applicationautoscaling": "0.0.0", @@ -132,6 +130,8 @@ "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-route53": "0.0.0", "@aws-cdk/aws-route53-targets": "0.0.0", + "@aws-cdk/aws-s3": "0.0.0", + "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/aws-servicediscovery": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", @@ -139,8 +139,6 @@ "@aws-cdk/aws-ssm": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "@aws-cdk/aws-s3": "0.0.0", - "@aws-cdk/aws-s3-assets": "0.0.0", "constructs": "^3.3.69" }, "engines": { diff --git a/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts b/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts index b5c60ae1c5c0c..524551aba1286 100644 --- a/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts @@ -7,7 +7,7 @@ import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; import * as ssm from '@aws-cdk/aws-ssm'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as ecs from '../lib'; describe('container definition', () => { diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts b/packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts index 793dff5c3b97b..4f80d48118bc6 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts @@ -7,7 +7,7 @@ import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; import * as ssm from '@aws-cdk/aws-ssm'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as ecs from '../../lib'; describe('ec2 task definition', () => { diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/integ.environment-file.expected.json b/packages/@aws-cdk/aws-ecs/test/ec2/integ.environment-file.expected.json index b26608d3626bf..eee0801d80061 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/integ.environment-file.expected.json +++ b/packages/@aws-cdk/aws-ecs/test/ec2/integ.environment-file.expected.json @@ -1267,7 +1267,7 @@ "Ref": "EnvFileDeploymentAwsCliLayerA8FC897D" } ], - "Runtime": "python3.6", + "Runtime": "python3.7", "Timeout": 900 }, "DependsOn": [ diff --git a/packages/@aws-cdk/aws-efs/.eslintrc.js b/packages/@aws-cdk/aws-efs/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-efs/.eslintrc.js +++ b/packages/@aws-cdk/aws-efs/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-efs/jest.config.js b/packages/@aws-cdk/aws-efs/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-efs/jest.config.js +++ b/packages/@aws-cdk/aws-efs/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-efs/package.json b/packages/@aws-cdk/aws-efs/package.json index d6dbf8bce203b..e97a3d99e8fd6 100644 --- a/packages/@aws-cdk/aws-efs/package.json +++ b/packages/@aws-cdk/aws-efs/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::EFS", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,12 +72,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", @@ -91,12 +90,12 @@ }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { - "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", - "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", + "@aws-cdk/core": "0.0.0", + "@aws-cdk/cx-api": "0.0.0", "constructs": "^3.3.69" }, "engines": { diff --git a/packages/@aws-cdk/aws-efs/test/efs-file-system.test.ts b/packages/@aws-cdk/aws-efs/test/efs-file-system.test.ts index 60a0133e63ca2..5e098503de2eb 100644 --- a/packages/@aws-cdk/aws-efs/test/efs-file-system.test.ts +++ b/packages/@aws-cdk/aws-efs/test/efs-file-system.test.ts @@ -4,7 +4,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import { App, RemovalPolicy, Size, Stack, Tags } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior, testLegacyBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior, testLegacyBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import { FileSystem, LifecyclePolicy, PerformanceMode, ThroughputMode } from '../lib'; let stack = new Stack(); diff --git a/packages/@aws-cdk/aws-eks-legacy/.eslintrc.js b/packages/@aws-cdk/aws-eks-legacy/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-eks-legacy/.eslintrc.js +++ b/packages/@aws-cdk/aws-eks-legacy/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-eks-legacy/jest.config.js b/packages/@aws-cdk/aws-eks-legacy/jest.config.js index cd664e1d069e5..34818e1593f6b 100644 --- a/packages/@aws-cdk/aws-eks-legacy/jest.config.js +++ b/packages/@aws-cdk/aws-eks-legacy/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-eks-legacy/package.json b/packages/@aws-cdk/aws-eks-legacy/package.json index 1494c1d93020f..66251dac2e6ee 100644 --- a/packages/@aws-cdk/aws-eks-legacy/package.json +++ b/packages/@aws-cdk/aws-eks-legacy/package.json @@ -55,8 +55,7 @@ "build+test+extract": "yarn build+test && yarn rosetta:extract" }, "cdk-build": { - "cloudformation": "AWS::EKS", - "jest": true + "cloudformation": "AWS::EKS" }, "keywords": [ "aws", @@ -71,13 +70,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-autoscaling": "0.0.0", diff --git a/packages/@aws-cdk/aws-eks/.eslintrc.js b/packages/@aws-cdk/aws-eks/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-eks/.eslintrc.js +++ b/packages/@aws-cdk/aws-eks/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-eks/.npmignore b/packages/@aws-cdk/aws-eks/.npmignore index e8acf10a468a1..8f3952dca3211 100644 --- a/packages/@aws-cdk/aws-eks/.npmignore +++ b/packages/@aws-cdk/aws-eks/.npmignore @@ -25,4 +25,7 @@ tsconfig.json junit.xml test/ !*.lit.ts -jest.config.js \ No newline at end of file +jest.config.js + +# Don't include lambda node_modules. These are installed at build time. +lib/cluster-resource-handler/node_modules diff --git a/packages/@aws-cdk/aws-eks/README.md b/packages/@aws-cdk/aws-eks/README.md index 1437446e6640a..3b04f5d9e7f61 100644 --- a/packages/@aws-cdk/aws-eks/README.md +++ b/packages/@aws-cdk/aws-eks/README.md @@ -372,6 +372,18 @@ const asg = new ec2.AutoScalingGroup(...); cluster.connectAutoScalingGroupCapacity(asg); ``` +To connect a self-managed node group to an imported cluster, use the `cluster.connectAutoScalingGroupCapacity()` method: + +```ts +const importedCluster = eks.Cluster.fromClusterAttributes(stack, 'ImportedCluster', { + clusterName: cluster.clusterName, + clusterSecurityGroupId: cluster.clusterSecurityGroupId, +}); + +const asg = new ec2.AutoScalingGroup(...); +importedCluster.connectAutoScalingGroupCapacity(asg); +``` + In both cases, the [cluster security group](https://docs.aws.amazon.com/eks/latest/userguide/sec-group-reqs.html#cluster-sg) will be automatically attached to the auto-scaling group, allowing for traffic to flow freely between managed and self-managed nodes. diff --git a/packages/@aws-cdk/aws-eks/jest.config.js b/packages/@aws-cdk/aws-eks/jest.config.js index cd664e1d069e5..34818e1593f6b 100644 --- a/packages/@aws-cdk/aws-eks/jest.config.js +++ b/packages/@aws-cdk/aws-eks/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/cluster.ts b/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/cluster.ts index 4dc909113ac91..61a33ddb3ab05 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/cluster.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/cluster.ts @@ -1,5 +1,6 @@ /* eslint-disable no-console */ +// eslint-disable-next-line import/no-extraneous-dependencies import { IsCompleteResponse, OnEventResponse } from '@aws-cdk/custom-resources/lib/provider-framework/types'; // eslint-disable-next-line import/no-extraneous-dependencies import * as aws from 'aws-sdk'; @@ -23,7 +24,7 @@ export class ClusterResourceHandler extends ResourceHandler { super(eks, event); this.newProps = parseProps(this.event.ResourceProperties); - this.oldProps = event.RequestType === 'Update' ? parseProps(event.OldResourceProperties) : { }; + this.oldProps = event.RequestType === 'Update' ? parseProps(event.OldResourceProperties) : {}; } // ------ @@ -271,16 +272,16 @@ export class ClusterResourceHandler extends ResourceHandler { function parseProps(props: any): aws.EKS.CreateClusterRequest { - const parsed = props?.Config ?? { }; + const parsed = props?.Config ?? {}; // this is weird but these boolean properties are passed by CFN as a string, and we need them to be booleanic for the SDK. // Otherwise it fails with 'Unexpected Parameter: params.resourcesVpcConfig.endpointPrivateAccess is expected to be a boolean' - if (typeof(parsed.resourcesVpcConfig?.endpointPrivateAccess) === 'string') { + if (typeof (parsed.resourcesVpcConfig?.endpointPrivateAccess) === 'string') { parsed.resourcesVpcConfig.endpointPrivateAccess = parsed.resourcesVpcConfig.endpointPrivateAccess === 'true'; } - if (typeof(parsed.resourcesVpcConfig?.endpointPublicAccess) === 'string') { + if (typeof (parsed.resourcesVpcConfig?.endpointPublicAccess) === 'string') { parsed.resourcesVpcConfig.endpointPublicAccess = parsed.resourcesVpcConfig.endpointPublicAccess === 'true'; } @@ -303,13 +304,13 @@ function analyzeUpdate(oldProps: Partial, newProps console.log('old props: ', JSON.stringify(oldProps)); console.log('new props: ', JSON.stringify(newProps)); - const newVpcProps = newProps.resourcesVpcConfig || { }; - const oldVpcProps = oldProps.resourcesVpcConfig || { }; + const newVpcProps = newProps.resourcesVpcConfig || {}; + const oldVpcProps = oldProps.resourcesVpcConfig || {}; const oldPublicAccessCidrs = new Set(oldVpcProps.publicAccessCidrs ?? []); const newPublicAccessCidrs = new Set(newVpcProps.publicAccessCidrs ?? []); - const newEnc = newProps.encryptionConfig || { }; - const oldEnc = oldProps.encryptionConfig || { }; + const newEnc = newProps.encryptionConfig || {}; + const oldEnc = oldProps.encryptionConfig || {}; return { replaceName: newProps.name !== oldProps.name, @@ -329,4 +330,4 @@ function analyzeUpdate(oldProps: Partial, newProps function setsEqual(first: Set, second: Set) { return first.size === second.size || [...first].every((e: string) => second.has(e)); -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/common.ts b/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/common.ts index 7383689e4a95a..1adb2eb328564 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/common.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/common.ts @@ -1,3 +1,4 @@ +// eslint-disable-next-line import/no-extraneous-dependencies import { IsCompleteResponse, OnEventResponse } from '@aws-cdk/custom-resources/lib/provider-framework/types'; // eslint-disable-next-line import/no-extraneous-dependencies @@ -37,6 +38,16 @@ export abstract class ResourceHandler { RoleArn: roleToAssume, RoleSessionName: `AWSCDK.EKSCluster.${this.requestType}.${this.requestId}`, }); + + const proxyAddress = this.httpProxyFromEnvironment(); + if (proxyAddress) { + this.log(`Using proxy server: ${proxyAddress}`); + // eslint-disable-next-line @typescript-eslint/no-require-imports, import/no-extraneous-dependencies + const ProxyAgent: any = require('proxy-agent'); + aws.config.update({ + httpOptions: { agent: new ProxyAgent(proxyAddress) }, + }); + } } public onEvent() { @@ -64,6 +75,16 @@ export abstract class ResourceHandler { console.log(JSON.stringify(x, undefined, 2)); } + private httpProxyFromEnvironment(): string | undefined { + if (process.env.http_proxy) { + return process.env.http_proxy; + } + if (process.env.HTTP_PROXY) { + return process.env.HTTP_PROXY; + } + return undefined; + } + protected abstract async onCreate(): Promise; protected abstract async onDelete(): Promise; protected abstract async onUpdate(): Promise<(OnEventResponse & EksUpdateId) | void>; diff --git a/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/index.ts b/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/index.ts index d1be0c12e1e38..e7fc357846259 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/index.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster-resource-handler/index.ts @@ -1,5 +1,5 @@ /* eslint-disable no-console */ - +// eslint-disable-next-line import/no-extraneous-dependencies import { IsCompleteResponse } from '@aws-cdk/custom-resources/lib/provider-framework/types'; // eslint-disable-next-line import/no-extraneous-dependencies import * as aws from 'aws-sdk'; @@ -57,4 +57,4 @@ function createResourceHandler(event: AWSLambda.CloudFormationCustomResourceEven default: throw new Error(`Unsupported resource type "${event.ResourceType}`); } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-eks/lib/cluster-resource-provider.ts b/packages/@aws-cdk/aws-eks/lib/cluster-resource-provider.ts index 12839a3ee6044..f425b0a1eaba6 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster-resource-provider.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster-resource-provider.ts @@ -4,6 +4,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as lambda from '@aws-cdk/aws-lambda'; import { Duration, NestedStack, Stack } from '@aws-cdk/core'; import * as cr from '@aws-cdk/custom-resources'; +import { NodeProxyAgentLayer } from '@aws-cdk/lambda-layer-node-proxy-agent'; import { Construct } from 'constructs'; // v2 - keep this import as a separate section to reduce merge conflict when forward merging with the v2 branch. @@ -33,6 +34,13 @@ export interface ClusterResourceProviderProps { * Environment to add to the handler. */ readonly environment?: { [key: string]: string }; + + /** + * An AWS Lambda layer that includes the NPM dependency `proxy-agent`. + * + * If not defined, a default layer will be used. + */ + readonly onEventLayer?: lambda.ILayerVersion; } /** @@ -69,6 +77,14 @@ export class ClusterResourceProvider extends NestedStack { vpcSubnets: props.subnets ? { subnets: props.subnets } : undefined, }); + // Allow user to customize the layer + if (!props.onEventLayer) { + // `NodeProxyAgentLayer` provides `proxy-agent` which is needed to configure `aws-sdk-js` with a user provided proxy. + onEvent.addLayers(new NodeProxyAgentLayer(this, 'NodeProxyAgentLayer')); + } else { + onEvent.addLayers(props.onEventLayer); + } + const isComplete = new lambda.Function(this, 'IsCompleteHandler', { code: lambda.Code.fromAsset(HANDLER_DIR), description: 'isComplete handler for EKS cluster resource provider', @@ -96,4 +112,4 @@ export class ClusterResourceProvider extends NestedStack { * The custom resource service token for this provider. */ public get serviceToken() { return this.provider.serviceToken; } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts b/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts index e134601aef73d..662f4e345a24c 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts @@ -1,6 +1,7 @@ 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 lambda from '@aws-cdk/aws-lambda'; import { ArnComponents, CustomResource, Token, Stack, Lazy } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { CLUSTER_RESOURCE_TYPE } from './cluster-resource-handler/consts'; @@ -24,6 +25,7 @@ export interface ClusterResourceProps { readonly environment?: { [key: string]: string }; readonly subnets?: ec2.ISubnet[]; readonly secretsEncryptionKey?: kms.IKey; + readonly onEventLayer?: lambda.ILayerVersion; } /** @@ -62,6 +64,7 @@ export class ClusterResource extends CoreConstruct { subnets: props.subnets, vpc: props.vpc, environment: props.environment, + onEventLayer: props.onEventLayer, }); const resource = new CustomResource(this, 'Resource', { diff --git a/packages/@aws-cdk/aws-eks/lib/cluster.ts b/packages/@aws-cdk/aws-eks/lib/cluster.ts index 009a79ecdb8ce..2db0438537f97 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster.ts @@ -129,6 +129,13 @@ export interface ICluster extends IResource, ec2.IConnectable { */ readonly kubectlMemory?: Size; + /** + * An AWS Lambda layer that includes the NPM dependency `proxy-agent`. + * + * If not defined, a default layer will be used. + */ + readonly onEventLayer?: lambda.ILayerVersion; + /** * Indicates whether Kubernetes resources can be automatically pruned. When * this is enabled (default), prune labels will be allocated and injected to @@ -174,6 +181,27 @@ export interface ICluster extends IResource, ec2.IConnectable { */ addCdk8sChart(id: string, chart: Construct): KubernetesManifest; + /** + * Connect capacity in the form of an existing AutoScalingGroup to the EKS cluster. + * + * The AutoScalingGroup must be running an EKS-optimized AMI containing the + * /etc/eks/bootstrap.sh script. This method will configure Security Groups, + * add the right policies to the instance role, apply the right tags, and add + * the required user data to the instance's launch configuration. + * + * Spot instances will be labeled `lifecycle=Ec2Spot` and tainted with `PreferNoSchedule`. + * If kubectl is enabled, the + * [spot interrupt handler](https://github.com/awslabs/ec2-spot-labs/tree/master/ec2-spot-eks-solution/spot-termination-handler) + * daemon will be installed on all spot instances to handle + * [EC2 Spot Instance Termination Notices](https://aws.amazon.com/blogs/aws/new-ec2-spot-instance-termination-notices/). + * + * Prefer to use `addAutoScalingGroupCapacity` if possible. + * + * @see https://docs.aws.amazon.com/eks/latest/userguide/launch-workers.html + * @param autoScalingGroup [disable-awslint:ref-via-interface] + * @param options options for adding auto scaling groups, like customizing the bootstrap script + */ + connectAutoScalingGroupCapacity(autoScalingGroup: autoscaling.AutoScalingGroup, options: AutoScalingGroupOptions): void; } /** @@ -281,6 +309,18 @@ export interface ClusterAttributes { */ readonly kubectlMemory?: Size; + /** + * An AWS Lambda Layer which includes the NPM dependency `proxy-agent`. This layer + * is used by the onEvent handler to route AWS SDK requests through a proxy. + * + * The handler expects the layer to include the following node_modules: + * + * proxy-agent + * + * @default - a layer bundled with this module. + */ + readonly onEventLayer?: lambda.ILayerVersion; + /** * Indicates whether Kubernetes resources added through `addManifest()` can be * automatically pruned. When this is enabled (default), prune labels will be @@ -450,6 +490,30 @@ export interface ClusterOptions extends CommonClusterOptions { */ readonly kubectlMemory?: Size; + /** + * An AWS Lambda Layer which includes the NPM dependency `proxy-agent`. + * + * By default, the provider will use the layer included in the + * "aws-lambda-layer-node-proxy-agent" SAR application which is available in all + * commercial regions. + * + * To deploy the layer locally, visit + * https://github.com/aws-samples/aws-lambda-layer-node-proxy-agent/blob/master/cdk/README.md + * for instructions on how to prepare the .zip file and then define it in your + * app as follows: + * + * ```ts + * const layer = new lambda.LayerVersion(this, 'node-proxy-agent-layer', { + * code: lambda.Code.fromAsset(`${__dirname}/layer.zip`)), + * compatibleRuntimes: [lambda.Runtime.NODEJS_14_X] + * }) + * ``` + * + * @default - the layer provided by the `aws-lambda-layer-node-proxy-agent` SAR app. + * @see https://github.com/aws-samples/aws-lambda-layer-node-proxy-agent + */ + readonly onEventLayer?: lambda.ILayerVersion; + /** * Indicates whether Kubernetes resources added through `addManifest()` can be * automatically pruned. When this is enabled (default), prune labels will be @@ -678,6 +742,16 @@ abstract class ClusterBase extends Resource implements ICluster { public abstract readonly kubectlMemory?: Size; public abstract readonly prune: boolean; public abstract readonly openIdConnectProvider: iam.IOpenIdConnectProvider; + public abstract readonly awsAuth: AwsAuth; + + private _spotInterruptHandler?: HelmChart; + + /** + * Manages the aws-auth config map. + * + * @internal + */ + protected _awsAuth?: AwsAuth; /** * Defines a Kubernetes resource in this cluster. @@ -728,6 +802,124 @@ abstract class ClusterBase extends Resource implements ICluster { cluster: this, }); } + + /** + * Installs the AWS spot instance interrupt handler on the cluster if it's not + * already added. + */ + private addSpotInterruptHandler() { + if (!this._spotInterruptHandler) { + this._spotInterruptHandler = this.addHelmChart('spot-interrupt-handler', { + chart: 'aws-node-termination-handler', + version: '0.13.2', + repository: 'https://aws.github.io/eks-charts', + namespace: 'kube-system', + values: { + nodeSelector: { + lifecycle: LifecycleLabel.SPOT, + }, + }, + }); + } + + return this._spotInterruptHandler; + } + + /** + * Connect capacity in the form of an existing AutoScalingGroup to the EKS cluster. + * + * The AutoScalingGroup must be running an EKS-optimized AMI containing the + * /etc/eks/bootstrap.sh script. This method will configure Security Groups, + * add the right policies to the instance role, apply the right tags, and add + * the required user data to the instance's launch configuration. + * + * Spot instances will be labeled `lifecycle=Ec2Spot` and tainted with `PreferNoSchedule`. + * If kubectl is enabled, the + * [spot interrupt handler](https://github.com/awslabs/ec2-spot-labs/tree/master/ec2-spot-eks-solution/spot-termination-handler) + * daemon will be installed on all spot instances to handle + * [EC2 Spot Instance Termination Notices](https://aws.amazon.com/blogs/aws/new-ec2-spot-instance-termination-notices/). + * + * Prefer to use `addAutoScalingGroupCapacity` if possible. + * + * @see https://docs.aws.amazon.com/eks/latest/userguide/launch-workers.html + * @param autoScalingGroup [disable-awslint:ref-via-interface] + * @param options options for adding auto scaling groups, like customizing the bootstrap script + */ + public connectAutoScalingGroupCapacity(autoScalingGroup: autoscaling.AutoScalingGroup, options: AutoScalingGroupOptions) { + // self rules + autoScalingGroup.connections.allowInternally(ec2.Port.allTraffic()); + + // Cluster to:nodes rules + autoScalingGroup.connections.allowFrom(this, ec2.Port.tcp(443)); + autoScalingGroup.connections.allowFrom(this, ec2.Port.tcpRange(1025, 65535)); + + // Allow HTTPS from Nodes to Cluster + autoScalingGroup.connections.allowTo(this, ec2.Port.tcp(443)); + + // Allow all node outbound traffic + autoScalingGroup.connections.allowToAnyIpv4(ec2.Port.allTcp()); + autoScalingGroup.connections.allowToAnyIpv4(ec2.Port.allUdp()); + autoScalingGroup.connections.allowToAnyIpv4(ec2.Port.allIcmp()); + + // allow traffic to/from managed node groups (eks attaches this security group to the managed nodes) + autoScalingGroup.addSecurityGroup(this.clusterSecurityGroup); + + const bootstrapEnabled = options.bootstrapEnabled ?? true; + if (options.bootstrapOptions && !bootstrapEnabled) { + throw new Error('Cannot specify "bootstrapOptions" if "bootstrapEnabled" is false'); + } + + if (bootstrapEnabled) { + const userData = options.machineImageType === MachineImageType.BOTTLEROCKET ? + renderBottlerocketUserData(this) : + renderAmazonLinuxUserData(this, autoScalingGroup, options.bootstrapOptions); + autoScalingGroup.addUserData(...userData); + } + + autoScalingGroup.role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonEKSWorkerNodePolicy')); + autoScalingGroup.role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonEKS_CNI_Policy')); + autoScalingGroup.role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonEC2ContainerRegistryReadOnly')); + + // EKS Required Tags + // https://docs.aws.amazon.com/eks/latest/userguide/worker.html + Tags.of(autoScalingGroup).add(`kubernetes.io/cluster/${this.clusterName}`, 'owned', { + applyToLaunchedInstances: true, + // exclude security groups to avoid multiple "owned" security groups. + // (the cluster security group already has this tag) + excludeResourceTypes: ['AWS::EC2::SecurityGroup'], + }); + + // do not attempt to map the role if `kubectl` is not enabled for this + // cluster or if `mapRole` is set to false. By default this should happen. + let mapRole = options.mapRole ?? true; + if (mapRole && !(this instanceof Cluster)) { + // do the mapping... + Annotations.of(autoScalingGroup).addWarning('Auto-mapping aws-auth role for imported cluster is not supported, please map role manually'); + mapRole = false; + } + if (mapRole) { + // see https://docs.aws.amazon.com/en_us/eks/latest/userguide/add-user-role.html + this.awsAuth.addRoleMapping(autoScalingGroup.role, { + username: 'system:node:{{EC2PrivateDNSName}}', + groups: [ + 'system:bootstrappers', + 'system:nodes', + ], + }); + } else { + // since we are not mapping the instance role to RBAC, synthesize an + // output so it can be pasted into `aws-auth-cm.yaml` + new CfnOutput(autoScalingGroup, 'InstanceRoleARN', { + value: autoScalingGroup.role.roleArn, + }); + } + + const addSpotInterruptHandler = options.spotInterruptHandler ?? true; + // if this is an ASG with spot instances, install the spot interrupt handler (only if kubectl is enabled). + if (autoScalingGroup.spotPrice && addSpotInterruptHandler) { + this.addSpotInterruptHandler(); + } + } } /** @@ -898,6 +1090,12 @@ export class Cluster extends ClusterBase { */ public readonly kubectlMemory?: Size; + /** + * The AWS Lambda layer that contains the NPM dependency `proxy-agent`. If + * undefined, a SAR app that contains this layer will be used. + */ + public readonly onEventLayer?: lambda.ILayerVersion; + /** * Determines if Kubernetes resources can be pruned automatically. */ @@ -910,13 +1108,6 @@ export class Cluster extends ClusterBase { */ private readonly _clusterResource: ClusterResource; - /** - * Manages the aws-auth config map. - */ - private _awsAuth?: AwsAuth; - - private _spotInterruptHandler?: HelmChart; - private _neuronDevicePlugin?: KubernetesManifest; private readonly endpointAccess: EndpointAccess; @@ -988,6 +1179,7 @@ export class Cluster extends ClusterBase { this.endpointAccess = props.endpointAccess ?? EndpointAccess.PUBLIC_AND_PRIVATE; this.kubectlEnvironment = props.kubectlEnvironment; this.kubectlLayer = props.kubectlLayer; + this.onEventLayer = props.onEventLayer; this.kubectlMemory = props.kubectlMemory; const privateSubents = this.selectPrivateSubnets().slice(0, 16); @@ -1037,6 +1229,7 @@ export class Cluster extends ClusterBase { secretsEncryptionKey: props.secretsEncryptionKey, vpc: this.vpc, subnets: placeClusterHandlerInVpc ? privateSubents : undefined, + onEventLayer: this.onEventLayer, }); if (this.endpointAccess._config.privateAccess && privateSubents.length !== 0) { @@ -1227,97 +1420,6 @@ export class Cluster extends ClusterBase { }); } - /** - * Connect capacity in the form of an existing AutoScalingGroup to the EKS cluster. - * - * The AutoScalingGroup must be running an EKS-optimized AMI containing the - * /etc/eks/bootstrap.sh script. This method will configure Security Groups, - * add the right policies to the instance role, apply the right tags, and add - * the required user data to the instance's launch configuration. - * - * Spot instances will be labeled `lifecycle=Ec2Spot` and tainted with `PreferNoSchedule`. - * If kubectl is enabled, the - * [spot interrupt handler](https://github.com/awslabs/ec2-spot-labs/tree/master/ec2-spot-eks-solution/spot-termination-handler) - * daemon will be installed on all spot instances to handle - * [EC2 Spot Instance Termination Notices](https://aws.amazon.com/blogs/aws/new-ec2-spot-instance-termination-notices/). - * - * Prefer to use `addAutoScalingGroupCapacity` if possible. - * - * @see https://docs.aws.amazon.com/eks/latest/userguide/launch-workers.html - * @param autoScalingGroup [disable-awslint:ref-via-interface] - * @param options options for adding auto scaling groups, like customizing the bootstrap script - */ - public connectAutoScalingGroupCapacity(autoScalingGroup: autoscaling.AutoScalingGroup, options: AutoScalingGroupOptions) { - // self rules - autoScalingGroup.connections.allowInternally(ec2.Port.allTraffic()); - - // Cluster to:nodes rules - autoScalingGroup.connections.allowFrom(this, ec2.Port.tcp(443)); - autoScalingGroup.connections.allowFrom(this, ec2.Port.tcpRange(1025, 65535)); - - // Allow HTTPS from Nodes to Cluster - autoScalingGroup.connections.allowTo(this, ec2.Port.tcp(443)); - - // Allow all node outbound traffic - autoScalingGroup.connections.allowToAnyIpv4(ec2.Port.allTcp()); - autoScalingGroup.connections.allowToAnyIpv4(ec2.Port.allUdp()); - autoScalingGroup.connections.allowToAnyIpv4(ec2.Port.allIcmp()); - - // allow traffic to/from managed node groups (eks attaches this security group to the managed nodes) - autoScalingGroup.addSecurityGroup(this.clusterSecurityGroup); - - const bootstrapEnabled = options.bootstrapEnabled ?? true; - if (options.bootstrapOptions && !bootstrapEnabled) { - throw new Error('Cannot specify "bootstrapOptions" if "bootstrapEnabled" is false'); - } - - if (bootstrapEnabled) { - const userData = options.machineImageType === MachineImageType.BOTTLEROCKET ? - renderBottlerocketUserData(this) : - renderAmazonLinuxUserData(this, autoScalingGroup, options.bootstrapOptions); - autoScalingGroup.addUserData(...userData); - } - - autoScalingGroup.role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonEKSWorkerNodePolicy')); - autoScalingGroup.role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonEKS_CNI_Policy')); - autoScalingGroup.role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonEC2ContainerRegistryReadOnly')); - - // EKS Required Tags - // https://docs.aws.amazon.com/eks/latest/userguide/worker.html - Tags.of(autoScalingGroup).add(`kubernetes.io/cluster/${this.clusterName}`, 'owned', { - applyToLaunchedInstances: true, - // exclude security groups to avoid multiple "owned" security groups. - // (the cluster security group already has this tag) - excludeResourceTypes: ['AWS::EC2::SecurityGroup'], - }); - - // do not attempt to map the role if `kubectl` is not enabled for this - // cluster or if `mapRole` is set to false. By default this should happen. - const mapRole = options.mapRole ?? true; - if (mapRole) { - // see https://docs.aws.amazon.com/en_us/eks/latest/userguide/add-user-role.html - this.awsAuth.addRoleMapping(autoScalingGroup.role, { - username: 'system:node:{{EC2PrivateDNSName}}', - groups: [ - 'system:bootstrappers', - 'system:nodes', - ], - }); - } else { - // since we are not mapping the instance role to RBAC, synthesize an - // output so it can be pasted into `aws-auth-cm.yaml` - new CfnOutput(autoScalingGroup, 'InstanceRoleARN', { - value: autoScalingGroup.role.roleArn, - }); - } - - const addSpotInterruptHandler = options.spotInterruptHandler ?? true; - // if this is an ASG with spot instances, install the spot interrupt handler (only if kubectl is enabled). - if (autoScalingGroup.spotPrice && addSpotInterruptHandler) { - this.addSpotInterruptHandler(); - } - } - /** * Lazily creates the AwsAuth resource, which manages AWS authentication mapping. */ @@ -1458,28 +1560,6 @@ export class Cluster extends ClusterBase { return privateSubnets; } - /** - * Installs the AWS spot instance interrupt handler on the cluster if it's not - * already added. - */ - private addSpotInterruptHandler() { - if (!this._spotInterruptHandler) { - this._spotInterruptHandler = this.addHelmChart('spot-interrupt-handler', { - chart: 'aws-node-termination-handler', - version: '0.13.2', - repository: 'https://aws.github.io/eks-charts', - namespace: 'kube-system', - values: { - nodeSelector: { - lifecycle: LifecycleLabel.SPOT, - }, - }, - }); - } - - return this._spotInterruptHandler; - } - /** * Installs the Neuron device plugin on the cluster if it's not * already added. @@ -1735,6 +1815,7 @@ class ImportedCluster extends ClusterBase { public readonly kubectlSecurityGroup?: ec2.ISecurityGroup | undefined; public readonly kubectlPrivateSubnets?: ec2.ISubnet[] | undefined; public readonly kubectlLayer?: lambda.ILayerVersion; + public readonly onEventLayer?: lambda.ILayerVersion; public readonly kubectlMemory?: Size; public readonly prune: boolean; @@ -1752,6 +1833,7 @@ class ImportedCluster extends ClusterBase { this.kubectlEnvironment = props.kubectlEnvironment; this.kubectlPrivateSubnets = props.kubectlPrivateSubnetIds ? props.kubectlPrivateSubnetIds.map((subnetid, index) => ec2.Subnet.fromSubnetId(this, `KubectlSubnet${index}`, subnetid)) : undefined; this.kubectlLayer = props.kubectlLayer; + this.onEventLayer = props.onEventLayer; this.kubectlMemory = props.kubectlMemory; this.prune = props.prune ?? true; @@ -1815,6 +1897,10 @@ class ImportedCluster extends ClusterBase { } return this.props.openIdConnectProvider; } + + public get awsAuth(): AwsAuth { + throw new Error('"awsAuth" is not supported on imported clusters'); + } } /** diff --git a/packages/@aws-cdk/aws-eks/lib/fargate-profile.ts b/packages/@aws-cdk/aws-eks/lib/fargate-profile.ts index 4ce6f094909bd..8d5b0301ff24b 100644 --- a/packages/@aws-cdk/aws-eks/lib/fargate-profile.ts +++ b/packages/@aws-cdk/aws-eks/lib/fargate-profile.ts @@ -1,6 +1,6 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; -import { CustomResource, ITaggable, Lazy, TagManager, TagType } from '@aws-cdk/core'; +import { Annotations, CustomResource, ITaggable, Lazy, TagManager, TagType } from '@aws-cdk/core'; import { Construct } from 'constructs'; import { Cluster } from './cluster'; import { FARGATE_PROFILE_RESOURCE_TYPE } from './cluster-resource-handler/consts'; @@ -46,7 +46,7 @@ export interface FargateProfileOptions { * By default, all private subnets are selected. You can customize this using * `subnetSelection`. * - * @default - all private subnets used by theEKS cluster + * @default - all private subnets used by the EKS cluster */ readonly vpc?: ec2.IVpc; @@ -55,6 +55,8 @@ export interface FargateProfileOptions { * on Fargate are not assigned public IP addresses, so only private subnets * (with no direct route to an Internet Gateway) are allowed. * + * You must specify the VPC to customize the subnet selection + * * @default - all private subnets of the VPC are selected. */ readonly subnetSelection?: ec2.SubnetSelection; @@ -147,6 +149,7 @@ export class FargateProfile extends CoreConstruct implements ITaggable { const provider = ClusterResourceProvider.getOrCreate(this, { adminRole: props.cluster.adminRole, + onEventLayer: props.cluster.onEventLayer, }); this.podExecutionRole = props.podExecutionRole ?? new iam.Role(this, 'PodExecutionRole', { @@ -156,6 +159,10 @@ export class FargateProfile extends CoreConstruct implements ITaggable { this.podExecutionRole.grantPassRole(props.cluster.adminRole); + if (props.subnetSelection && !props.vpc) { + Annotations.of(this).addWarning('Vpc must be defined to use a custom subnet selection. All private subnets belonging to the EKS cluster will be used by default'); + } + let subnets: string[] | undefined; if (props.vpc) { const selection: ec2.SubnetSelection = props.subnetSelection ?? { subnetType: ec2.SubnetType.PRIVATE }; diff --git a/packages/@aws-cdk/aws-eks/lib/user-data.ts b/packages/@aws-cdk/aws-eks/lib/user-data.ts index 8add0f7cb5bbc..f14c254b1f24f 100644 --- a/packages/@aws-cdk/aws-eks/lib/user-data.ts +++ b/packages/@aws-cdk/aws-eks/lib/user-data.ts @@ -1,9 +1,9 @@ import * as autoscaling from '@aws-cdk/aws-autoscaling'; import { Stack } from '@aws-cdk/core'; -import { BootstrapOptions, ICluster, Cluster } from './cluster'; +import { BootstrapOptions, ICluster } from './cluster'; // eslint-disable-next-line max-len -export function renderAmazonLinuxUserData(cluster: Cluster, autoScalingGroup: autoscaling.AutoScalingGroup, options: BootstrapOptions = {}): string[] { +export function renderAmazonLinuxUserData(cluster: ICluster, autoScalingGroup: autoscaling.AutoScalingGroup, options: BootstrapOptions = {}): string[] { const stack = Stack.of(autoScalingGroup); @@ -13,8 +13,21 @@ export function renderAmazonLinuxUserData(cluster: Cluster, autoScalingGroup: au const extraArgs = new Array(); - extraArgs.push(`--apiserver-endpoint '${cluster.clusterEndpoint}'`); - extraArgs.push(`--b64-cluster-ca '${cluster.clusterCertificateAuthorityData}'`); + try { + const clusterEndpoint = cluster.clusterEndpoint; + const clusterCertificateAuthorityData = + cluster.clusterCertificateAuthorityData; + extraArgs.push(`--apiserver-endpoint '${clusterEndpoint}'`); + extraArgs.push(`--b64-cluster-ca '${clusterCertificateAuthorityData}'`); + } catch (e) { + /** + * Errors are ignored here. + * apiserver-endpoint and b64-cluster-ca arguments are added in #12659 to make nodes join the cluster faster. + * As these are not necessary arguments, we don't need to pass these arguments when they don't exist. + * + * @see https://github.com/aws/aws-cdk/pull/12659 + */ + } extraArgs.push(`--use-max-pods ${options.useMaxPods ?? true}`); diff --git a/packages/@aws-cdk/aws-eks/package.json b/packages/@aws-cdk/aws-eks/package.json index 6e2d193036981..00be1a03620c4 100644 --- a/packages/@aws-cdk/aws-eks/package.json +++ b/packages/@aws-cdk/aws-eks/package.json @@ -57,8 +57,7 @@ "cloudformation": "AWS::EKS", "env": { "AWSLINT_BASE_CONSTRUCT": true - }, - "jest": true + } }, "keywords": [ "aws", @@ -73,20 +72,20 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/aws-lambda": "^8.10.79", - "@types/sinon": "^9.0.11", + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/aws-lambda": "^8.10.83", "@types/jest": "^26.0.24", + "@types/sinon": "^9.0.11", "@types/yaml": "1.9.6", "aws-sdk": "^2.848.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "sinon": "^9.2.4", - "cdk8s-plus": "^0.33.0", "cdk8s": "^0.33.0", - "@aws-cdk/assert-internal": "0.0.0" + "cdk8s-plus": "^0.33.0", + "jest": "^26.6.3", + "sinon": "^9.2.4" }, "dependencies": { "@aws-cdk/aws-autoscaling": "0.0.0", @@ -94,11 +93,13 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/aws-lambda-nodejs": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", "@aws-cdk/lambda-layer-awscli": "0.0.0", "@aws-cdk/lambda-layer-kubectl": "0.0.0", + "@aws-cdk/lambda-layer-node-proxy-agent": "0.0.0", "constructs": "^3.3.69", "yaml": "1.10.2" }, @@ -112,12 +113,14 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/aws-lambda-nodejs": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", - "constructs": "^3.3.69", "@aws-cdk/lambda-layer-awscli": "0.0.0", - "@aws-cdk/lambda-layer-kubectl": "0.0.0" + "@aws-cdk/lambda-layer-kubectl": "0.0.0", + "@aws-cdk/lambda-layer-node-proxy-agent": "0.0.0", + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-eks/test/cluster.test.ts b/packages/@aws-cdk/aws-eks/test/cluster.test.ts index f68a2738dbb40..14e2bfad0746b 100644 --- a/packages/@aws-cdk/aws-eks/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-eks/test/cluster.test.ts @@ -36,8 +36,6 @@ describe('cluster', () => { const template = SynthUtils.toCloudFormation(nested); expect(template.Resources.OnEventHandler42BEBAE0.Properties.Environment).toEqual({ Variables: { foo: 'bar' } }); - - }); test('throws when trying to place cluster handlers in a vpc with no private subnets', () => { @@ -220,8 +218,38 @@ describe('cluster', () => { expect(template.Resources.ClusterselfmanagedInstanceSecurityGroup64468C3A.Properties.Tags).toEqual([ { Key: 'Name', Value: 'Stack/Cluster/self-managed' }, ]); + }); + test('connect autoscaling group with imported cluster', () => { + // GIVEN + const { stack, vpc } = testFixture(); + const cluster = new eks.Cluster(stack, 'Cluster', { + vpc, + defaultCapacity: 0, + version: CLUSTER_VERSION, + prune: false, + }); + + const importedCluster = eks.Cluster.fromClusterAttributes(stack, 'ImportedCluster', { + clusterName: cluster.clusterName, + clusterSecurityGroupId: cluster.clusterSecurityGroupId, + }); + + const selfManaged = new asg.AutoScalingGroup(stack, 'self-managed', { + instanceType: new ec2.InstanceType('t2.medium'), + vpc: vpc, + machineImage: new ec2.AmazonLinuxImage(), + }); + + // WHEN + importedCluster.connectAutoScalingGroupCapacity(selfManaged, {}); + + const template = SynthUtils.toCloudFormation(stack); + expect(template.Resources.selfmanagedLaunchConfigD41289EB.Properties.SecurityGroups).toEqual([ + { 'Fn::GetAtt': ['selfmanagedInstanceSecurityGroupEA6D80C9', 'GroupId'] }, + { 'Fn::GetAtt': ['Cluster9EE0221C', 'ClusterSecurityGroupId'] }, + ]); }); test('cluster security group is attached when connecting self-managed nodes', () => { @@ -651,7 +679,7 @@ describe('cluster', () => { const { stack } = testFixtureNoVpc(); // WHEN - new eks.Cluster(stack, 'cluster', { version: CLUSTER_VERSION, prune: false }) ; + new eks.Cluster(stack, 'cluster', { version: CLUSTER_VERSION, prune: false }); // THEN expect(stack).toHaveResource('AWS::EC2::VPC'); @@ -2469,7 +2497,7 @@ describe('cluster', () => { version: CLUSTER_VERSION, prune: false, endpointAccess: - eks.EndpointAccess.PRIVATE, + eks.EndpointAccess.PRIVATE, vpcSubnets: [{ subnets: [ec2.PrivateSubnet.fromSubnetAttributes(stack, 'Private1', { subnetId: 'subnet1', @@ -2568,14 +2596,14 @@ describe('cluster', () => { const subnetConfiguration: ec2.SubnetConfiguration[] = []; for (let i = 0; i < 20; i++) { - subnetConfiguration.push( { + subnetConfiguration.push({ subnetType: ec2.SubnetType.PRIVATE, name: `Private${i}`, }, ); } - subnetConfiguration.push( { + subnetConfiguration.push({ subnetType: ec2.SubnetType.PUBLIC, name: 'Public1', }); @@ -2619,14 +2647,14 @@ describe('cluster', () => { const subnetConfiguration: ec2.SubnetConfiguration[] = []; for (let i = 0; i < 20; i++) { - subnetConfiguration.push( { + subnetConfiguration.push({ subnetType: ec2.SubnetType.PRIVATE, name: `Private${i}`, }, ); } - subnetConfiguration.push( { + subnetConfiguration.push({ subnetType: ec2.SubnetType.PUBLIC, name: 'Public1', }); diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.expected.json b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.expected.json index cdb744ed6be0e..02d74f9efcf49 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-handlers-vpc.expected.json @@ -84,9 +84,7 @@ "Ref": "EksAllHandlersInVpcStackDefaultVpcIGW916D42F1" } }, - "DependsOn": [ - "EksAllHandlersInVpcStackDefaultVpcVPCGW5DC3BDB4" - ] + "DependsOn": ["EksAllHandlersInVpcStackDefaultVpcVPCGW5DC3BDB4"] }, "EksAllHandlersInVpcStackDefaultVpcPublicSubnet1EIP9380B54C": { "Type": "AWS::EC2::EIP", @@ -197,9 +195,7 @@ "Ref": "EksAllHandlersInVpcStackDefaultVpcIGW916D42F1" } }, - "DependsOn": [ - "EksAllHandlersInVpcStackDefaultVpcVPCGW5DC3BDB4" - ] + "DependsOn": ["EksAllHandlersInVpcStackDefaultVpcVPCGW5DC3BDB4"] }, "EksAllHandlersInVpcStackDefaultVpcPublicSubnet2EIP9186922F": { "Type": "AWS::EC2::EIP", @@ -310,9 +306,7 @@ "Ref": "EksAllHandlersInVpcStackDefaultVpcIGW916D42F1" } }, - "DependsOn": [ - "EksAllHandlersInVpcStackDefaultVpcVPCGW5DC3BDB4" - ] + "DependsOn": ["EksAllHandlersInVpcStackDefaultVpcVPCGW5DC3BDB4"] }, "EksAllHandlersInVpcStackDefaultVpcPublicSubnet3EIPBF5ED908": { "Type": "AWS::EC2::EIP", @@ -705,10 +699,7 @@ "Action": "iam:PassRole", "Effect": "Allow", "Resource": { - "Fn::GetAtt": [ - "EksAllHandlersInVpcStackRoleC36F09F0", - "Arn" - ] + "Fn::GetAtt": ["EksAllHandlersInVpcStackRoleC36F09F0", "Arn"] } }, { @@ -724,9 +715,7 @@ "eks:UntagResource" ], "Effect": "Allow", - "Resource": [ - "*" - ] + "Resource": ["*"] }, { "Action": [ @@ -737,10 +726,7 @@ "Resource": "*" }, { - "Action": [ - "iam:GetRole", - "iam:listAttachedRolePolicies" - ], + "Action": ["iam:GetRole", "iam:listAttachedRolePolicies"], "Effect": "Allow", "Resource": "*" }, @@ -820,10 +806,7 @@ "Config": { "version": "1.21", "roleArn": { - "Fn::GetAtt": [ - "EksAllHandlersInVpcStackRoleC36F09F0", - "Arn" - ] + "Fn::GetAtt": ["EksAllHandlersInVpcStackRoleC36F09F0", "Arn"] }, "resourcesVpcConfig": { "subnetIds": [ @@ -859,10 +842,7 @@ } }, "AssumeRoleArn": { - "Fn::GetAtt": [ - "EksAllHandlersInVpcStackCreationRole0BAA4CDC", - "Arn" - ] + "Fn::GetAtt": ["EksAllHandlersInVpcStackCreationRole0BAA4CDC", "Arn"] }, "AttributesRevision": 2 }, @@ -988,17 +968,12 @@ "Ref": "EksAllHandlersInVpcStack9ED695D7" }, "RoleArn": { - "Fn::GetAtt": [ - "EksAllHandlersInVpcStackCreationRole0BAA4CDC", - "Arn" - ] + "Fn::GetAtt": ["EksAllHandlersInVpcStackCreationRole0BAA4CDC", "Arn"] }, "PruneLabel": "aws.cdk.eks/prune-c8fa2698c0d935568a51a7732ad19350286b302ae8", "Overwrite": true }, - "DependsOn": [ - "EksAllHandlersInVpcStackKubectlReadyBarrier8687350F" - ], + "DependsOn": ["EksAllHandlersInVpcStackKubectlReadyBarrier8687350F"], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, @@ -1092,9 +1067,7 @@ ], "AmiType": "AL2_x86_64", "ForceUpdateEnabled": true, - "InstanceTypes": [ - "m5.large" - ], + "InstanceTypes": ["m5.large"], "ScalingConfig": { "DesiredSize": 2, "MaxSize": 2, @@ -1115,7 +1088,7 @@ }, "/", { - "Ref": "AssetParameters7b7589d8284d359f531f595891e11720582fb63d0f0051cb08b5bfbcd6d60f60S3BucketE63A0899" + "Ref": "AssetParametersaaf0702521101dbd9f595a941bc4553dc343cd8e278677ab192eee285c3cb5f7S3Bucket995BE909" }, "/", { @@ -1125,7 +1098,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters7b7589d8284d359f531f595891e11720582fb63d0f0051cb08b5bfbcd6d60f60S3VersionKey91A6BB03" + "Ref": "AssetParametersaaf0702521101dbd9f595a941bc4553dc343cd8e278677ab192eee285c3cb5f7S3VersionKeyFC082341" } ] } @@ -1138,7 +1111,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters7b7589d8284d359f531f595891e11720582fb63d0f0051cb08b5bfbcd6d60f60S3VersionKey91A6BB03" + "Ref": "AssetParametersaaf0702521101dbd9f595a941bc4553dc343cd8e278677ab192eee285c3cb5f7S3VersionKeyFC082341" } ] } @@ -1157,11 +1130,11 @@ "referencetoawscdkekshandlersinvpctestEksAllHandlersInVpcStackDefaultVpcE40EA7ACRef": { "Ref": "EksAllHandlersInVpcStackDefaultVpcBE11D4AE" }, - "referencetoawscdkekshandlersinvpctestAssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket020723FERef": { - "Ref": "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket14D204F9" + "referencetoawscdkekshandlersinvpctestAssetParametersf9e3ed49f5734f267f6dfffed3c6038e2d31d096ca7e70ce257b16aa613a3ffcS3Bucket2733AD2BRef": { + "Ref": "AssetParametersf9e3ed49f5734f267f6dfffed3c6038e2d31d096ca7e70ce257b16aa613a3ffcS3Bucket85C441D9" }, - "referencetoawscdkekshandlersinvpctestAssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyEC505E3ARef": { - "Ref": "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyDE8A2F1F" + "referencetoawscdkekshandlersinvpctestAssetParametersf9e3ed49f5734f267f6dfffed3c6038e2d31d096ca7e70ce257b16aa613a3ffcS3VersionKey97FD1B55Ref": { + "Ref": "AssetParametersf9e3ed49f5734f267f6dfffed3c6038e2d31d096ca7e70ce257b16aa613a3ffcS3VersionKeyABBEC6F6" }, "referencetoawscdkekshandlersinvpctestEksAllHandlersInVpcStackDefaultVpcPrivateSubnet1Subnet9479BAA8Ref": { "Ref": "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet1SubnetE2B86978" @@ -1172,6 +1145,12 @@ "referencetoawscdkekshandlersinvpctestEksAllHandlersInVpcStackDefaultVpcPrivateSubnet3Subnet1B127970Ref": { "Ref": "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet3SubnetA75A8BA9" }, + "referencetoawscdkekshandlersinvpctestAssetParameters80bcd5b0641df4315e277c71a1069094a5d7c76f9e2565c46b68a990c522eaefS3Bucket99F890C4Ref": { + "Ref": "AssetParameters80bcd5b0641df4315e277c71a1069094a5d7c76f9e2565c46b68a990c522eaefS3Bucket208EDB42" + }, + "referencetoawscdkekshandlersinvpctestAssetParameters80bcd5b0641df4315e277c71a1069094a5d7c76f9e2565c46b68a990c522eaefS3VersionKey12E014F2Ref": { + "Ref": "AssetParameters80bcd5b0641df4315e277c71a1069094a5d7c76f9e2565c46b68a990c522eaefS3VersionKey08C22772" + }, "referencetoawscdkekshandlersinvpctestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket9D7E9998Ref": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" }, @@ -1196,7 +1175,7 @@ }, "/", { - "Ref": "AssetParametersa894c8b40c44a95ab449d327b83cd64ab07c12c1d95cbe2852f2e36a1780ef30S3Bucket3108034A" + "Ref": "AssetParametersabc0a1f8e9cd253f3d630dc9e75261dfb185a252be4394b39e92e90423a7aae8S3Bucket6909A78C" }, "/", { @@ -1206,7 +1185,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersa894c8b40c44a95ab449d327b83cd64ab07c12c1d95cbe2852f2e36a1780ef30S3VersionKey72F9CB08" + "Ref": "AssetParametersabc0a1f8e9cd253f3d630dc9e75261dfb185a252be4394b39e92e90423a7aae8S3VersionKeyF89BBD63" } ] } @@ -1219,7 +1198,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersa894c8b40c44a95ab449d327b83cd64ab07c12c1d95cbe2852f2e36a1780ef30S3VersionKey72F9CB08" + "Ref": "AssetParametersabc0a1f8e9cd253f3d630dc9e75261dfb185a252be4394b39e92e90423a7aae8S3VersionKeyF89BBD63" } ] } @@ -1230,10 +1209,7 @@ }, "Parameters": { "referencetoawscdkekshandlersinvpctestEksAllHandlersInVpcStack429D29C0Arn": { - "Fn::GetAtt": [ - "EksAllHandlersInVpcStack9ED695D7", - "Arn" - ] + "Fn::GetAtt": ["EksAllHandlersInVpcStack9ED695D7", "Arn"] }, "referencetoawscdkekshandlersinvpctestEksAllHandlersInVpcStackCreationRoleADAAC7FDArn": { "Fn::GetAtt": [ @@ -1241,11 +1217,11 @@ "Arn" ] }, - "referencetoawscdkekshandlersinvpctestAssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3BucketF3527C76Ref": { - "Ref": "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3Bucket008DBB35" + "referencetoawscdkekshandlersinvpctestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3Bucket4673F14ERef": { + "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9" }, - "referencetoawscdkekshandlersinvpctestAssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKeyE9C79D35Ref": { - "Ref": "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey97C3E1A0" + "referencetoawscdkekshandlersinvpctestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKey61C348A6Ref": { + "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421" }, "referencetoawscdkekshandlersinvpctestEksAllHandlersInVpcStackDefaultVpcPrivateSubnet1Subnet9479BAA8Ref": { "Ref": "EksAllHandlersInVpcStackDefaultVpcPrivateSubnet1SubnetE2B86978" @@ -1268,11 +1244,11 @@ "referencetoawscdkekshandlersinvpctestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyF4C27F59Ref": { "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" }, - "referencetoawscdkekshandlersinvpctestAssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3Bucket74F7CECDRef": { - "Ref": "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3BucketD4F52C82" + "referencetoawscdkekshandlersinvpctestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3Bucket95C9D5A0Ref": { + "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998" }, - "referencetoawscdkekshandlersinvpctestAssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3VersionKeyE5A09AFARef": { - "Ref": "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3VersionKey9D243E8D" + "referencetoawscdkekshandlersinvpctestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKey2505ECB3Ref": { + "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565" }, "referencetoawscdkekshandlersinvpctestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket9D7E9998Ref": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" @@ -1329,17 +1305,29 @@ } }, "Parameters": { - "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket14D204F9": { + "AssetParametersf9e3ed49f5734f267f6dfffed3c6038e2d31d096ca7e70ce257b16aa613a3ffcS3Bucket85C441D9": { + "Type": "String", + "Description": "S3 bucket for asset \"f9e3ed49f5734f267f6dfffed3c6038e2d31d096ca7e70ce257b16aa613a3ffc\"" + }, + "AssetParametersf9e3ed49f5734f267f6dfffed3c6038e2d31d096ca7e70ce257b16aa613a3ffcS3VersionKeyABBEC6F6": { + "Type": "String", + "Description": "S3 key for asset version \"f9e3ed49f5734f267f6dfffed3c6038e2d31d096ca7e70ce257b16aa613a3ffc\"" + }, + "AssetParametersf9e3ed49f5734f267f6dfffed3c6038e2d31d096ca7e70ce257b16aa613a3ffcArtifactHashC6D6393C": { + "Type": "String", + "Description": "Artifact hash for asset \"f9e3ed49f5734f267f6dfffed3c6038e2d31d096ca7e70ce257b16aa613a3ffc\"" + }, + "AssetParameters80bcd5b0641df4315e277c71a1069094a5d7c76f9e2565c46b68a990c522eaefS3Bucket208EDB42": { "Type": "String", - "Description": "S3 bucket for asset \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + "Description": "S3 bucket for asset \"80bcd5b0641df4315e277c71a1069094a5d7c76f9e2565c46b68a990c522eaef\"" }, - "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyDE8A2F1F": { + "AssetParameters80bcd5b0641df4315e277c71a1069094a5d7c76f9e2565c46b68a990c522eaefS3VersionKey08C22772": { "Type": "String", - "Description": "S3 key for asset version \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + "Description": "S3 key for asset version \"80bcd5b0641df4315e277c71a1069094a5d7c76f9e2565c46b68a990c522eaef\"" }, - "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaArtifactHash54822A43": { + "AssetParameters80bcd5b0641df4315e277c71a1069094a5d7c76f9e2565c46b68a990c522eaefArtifactHash861FF133": { "Type": "String", - "Description": "Artifact hash for asset \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + "Description": "Artifact hash for asset \"80bcd5b0641df4315e277c71a1069094a5d7c76f9e2565c46b68a990c522eaef\"" }, "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { "Type": "String", @@ -1353,17 +1341,17 @@ "Type": "String", "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" }, - "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3Bucket008DBB35": { + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9": { "Type": "String", - "Description": "S3 bucket for asset \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + "Description": "S3 bucket for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" }, - "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey97C3E1A0": { + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421": { "Type": "String", - "Description": "S3 key for asset version \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + "Description": "S3 key for asset version \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" }, - "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757ArtifactHashF584A7D8": { + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10ArtifactHash528547CD": { "Type": "String", - "Description": "Artifact hash for asset \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + "Description": "Artifact hash for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" }, "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { "Type": "String", @@ -1377,41 +1365,41 @@ "Type": "String", "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" }, - "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3BucketD4F52C82": { + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998": { "Type": "String", - "Description": "S3 bucket for asset \"cd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793\"" + "Description": "S3 bucket for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3VersionKey9D243E8D": { + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565": { "Type": "String", - "Description": "S3 key for asset version \"cd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793\"" + "Description": "S3 key for asset version \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793ArtifactHash42EBA5B2": { + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eArtifactHash4654D012": { "Type": "String", - "Description": "Artifact hash for asset \"cd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793\"" + "Description": "Artifact hash for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParameters7b7589d8284d359f531f595891e11720582fb63d0f0051cb08b5bfbcd6d60f60S3BucketE63A0899": { + "AssetParametersaaf0702521101dbd9f595a941bc4553dc343cd8e278677ab192eee285c3cb5f7S3Bucket995BE909": { "Type": "String", - "Description": "S3 bucket for asset \"7b7589d8284d359f531f595891e11720582fb63d0f0051cb08b5bfbcd6d60f60\"" + "Description": "S3 bucket for asset \"aaf0702521101dbd9f595a941bc4553dc343cd8e278677ab192eee285c3cb5f7\"" }, - "AssetParameters7b7589d8284d359f531f595891e11720582fb63d0f0051cb08b5bfbcd6d60f60S3VersionKey91A6BB03": { + "AssetParametersaaf0702521101dbd9f595a941bc4553dc343cd8e278677ab192eee285c3cb5f7S3VersionKeyFC082341": { "Type": "String", - "Description": "S3 key for asset version \"7b7589d8284d359f531f595891e11720582fb63d0f0051cb08b5bfbcd6d60f60\"" + "Description": "S3 key for asset version \"aaf0702521101dbd9f595a941bc4553dc343cd8e278677ab192eee285c3cb5f7\"" }, - "AssetParameters7b7589d8284d359f531f595891e11720582fb63d0f0051cb08b5bfbcd6d60f60ArtifactHashEB6B332A": { + "AssetParametersaaf0702521101dbd9f595a941bc4553dc343cd8e278677ab192eee285c3cb5f7ArtifactHashABA2E5E1": { "Type": "String", - "Description": "Artifact hash for asset \"7b7589d8284d359f531f595891e11720582fb63d0f0051cb08b5bfbcd6d60f60\"" + "Description": "Artifact hash for asset \"aaf0702521101dbd9f595a941bc4553dc343cd8e278677ab192eee285c3cb5f7\"" }, - "AssetParametersa894c8b40c44a95ab449d327b83cd64ab07c12c1d95cbe2852f2e36a1780ef30S3Bucket3108034A": { + "AssetParametersabc0a1f8e9cd253f3d630dc9e75261dfb185a252be4394b39e92e90423a7aae8S3Bucket6909A78C": { "Type": "String", - "Description": "S3 bucket for asset \"a894c8b40c44a95ab449d327b83cd64ab07c12c1d95cbe2852f2e36a1780ef30\"" + "Description": "S3 bucket for asset \"abc0a1f8e9cd253f3d630dc9e75261dfb185a252be4394b39e92e90423a7aae8\"" }, - "AssetParametersa894c8b40c44a95ab449d327b83cd64ab07c12c1d95cbe2852f2e36a1780ef30S3VersionKey72F9CB08": { + "AssetParametersabc0a1f8e9cd253f3d630dc9e75261dfb185a252be4394b39e92e90423a7aae8S3VersionKeyF89BBD63": { "Type": "String", - "Description": "S3 key for asset version \"a894c8b40c44a95ab449d327b83cd64ab07c12c1d95cbe2852f2e36a1780ef30\"" + "Description": "S3 key for asset version \"abc0a1f8e9cd253f3d630dc9e75261dfb185a252be4394b39e92e90423a7aae8\"" }, - "AssetParametersa894c8b40c44a95ab449d327b83cd64ab07c12c1d95cbe2852f2e36a1780ef30ArtifactHash95BE80EE": { + "AssetParametersabc0a1f8e9cd253f3d630dc9e75261dfb185a252be4394b39e92e90423a7aae8ArtifactHashFAE25270": { "Type": "String", - "Description": "Artifact hash for asset \"a894c8b40c44a95ab449d327b83cd64ab07c12c1d95cbe2852f2e36a1780ef30\"" + "Description": "Artifact hash for asset \"abc0a1f8e9cd253f3d630dc9e75261dfb185a252be4394b39e92e90423a7aae8\"" } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.expected.json b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.expected.json index 1f5d852a6ec76..e9c0e267b04f5 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster-private-endpoint.expected.json @@ -112,9 +112,7 @@ "Ref": "VpcIGWD7BA715C" } }, - "DependsOn": [ - "VpcVPCGWBF912B6E" - ] + "DependsOn": ["VpcVPCGWBF912B6E"] }, "VpcPublicSubnet1EIPD7E02669": { "Type": "AWS::EC2::EIP", @@ -139,10 +137,7 @@ "Ref": "VpcPublicSubnet1Subnet5C2D37C4" }, "AllocationId": { - "Fn::GetAtt": [ - "VpcPublicSubnet1EIPD7E02669", - "AllocationId" - ] + "Fn::GetAtt": ["VpcPublicSubnet1EIPD7E02669", "AllocationId"] }, "Tags": [ { @@ -225,9 +220,7 @@ "Ref": "VpcIGWD7BA715C" } }, - "DependsOn": [ - "VpcVPCGWBF912B6E" - ] + "DependsOn": ["VpcVPCGWBF912B6E"] }, "VpcPublicSubnet3SubnetBE12F0B6": { "Type": "AWS::EC2::Subnet", @@ -298,9 +291,7 @@ "Ref": "VpcIGWD7BA715C" } }, - "DependsOn": [ - "VpcVPCGWBF912B6E" - ] + "DependsOn": ["VpcVPCGWBF912B6E"] }, "VpcPrivateSubnet1Subnet536B997A": { "Type": "AWS::EC2::Subnet", @@ -649,10 +640,7 @@ "Action": "iam:PassRole", "Effect": "Allow", "Resource": { - "Fn::GetAtt": [ - "ClusterRoleFA261979", - "Arn" - ] + "Fn::GetAtt": ["ClusterRoleFA261979", "Arn"] } }, { @@ -668,9 +656,7 @@ "eks:UntagResource" ], "Effect": "Allow", - "Resource": [ - "*" - ] + "Resource": ["*"] }, { "Action": [ @@ -681,10 +667,7 @@ "Resource": "*" }, { - "Action": [ - "iam:GetRole", - "iam:listAttachedRolePolicies" - ], + "Action": ["iam:GetRole", "iam:listAttachedRolePolicies"], "Effect": "Allow", "Resource": "*" }, @@ -760,10 +743,7 @@ "Config": { "version": "1.21", "roleArn": { - "Fn::GetAtt": [ - "ClusterRoleFA261979", - "Arn" - ] + "Fn::GetAtt": ["ClusterRoleFA261979", "Arn"] }, "resourcesVpcConfig": { "subnetIds": [ @@ -799,10 +779,7 @@ } }, "AssumeRoleArn": { - "Fn::GetAtt": [ - "ClusterCreationRole360249B6", - "Arn" - ] + "Fn::GetAtt": ["ClusterCreationRole360249B6", "Arn"] }, "AttributesRevision": 2 }, @@ -869,17 +846,11 @@ [ "[{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"aws-auth\",\"namespace\":\"kube-system\"},\"data\":{\"mapRoles\":\"[{\\\"rolearn\\\":\\\"", { - "Fn::GetAtt": [ - "AdminRole38563C57", - "Arn" - ] + "Fn::GetAtt": ["AdminRole38563C57", "Arn"] }, "\\\",\\\"username\\\":\\\"", { - "Fn::GetAtt": [ - "AdminRole38563C57", - "Arn" - ] + "Fn::GetAtt": ["AdminRole38563C57", "Arn"] }, "\\\",\\\"groups\\\":[\\\"system:masters\\\"]},{\\\"rolearn\\\":\\\"", { @@ -896,16 +867,11 @@ "Ref": "Cluster9EE0221C" }, "RoleArn": { - "Fn::GetAtt": [ - "ClusterCreationRole360249B6", - "Arn" - ] + "Fn::GetAtt": ["ClusterCreationRole360249B6", "Arn"] }, "Overwrite": true }, - "DependsOn": [ - "ClusterKubectlReadyBarrier200052AF" - ], + "DependsOn": ["ClusterKubectlReadyBarrier200052AF"], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, @@ -999,9 +965,7 @@ ], "AmiType": "AL2_x86_64", "ForceUpdateEnabled": true, - "InstanceTypes": [ - "m5.large" - ], + "InstanceTypes": ["m5.large"], "ScalingConfig": { "DesiredSize": 2, "MaxSize": 2, @@ -1023,15 +987,10 @@ "Ref": "Cluster9EE0221C" }, "RoleArn": { - "Fn::GetAtt": [ - "ClusterCreationRole360249B6", - "Arn" - ] + "Fn::GetAtt": ["ClusterCreationRole360249B6", "Arn"] } }, - "DependsOn": [ - "ClusterKubectlReadyBarrier200052AF" - ], + "DependsOn": ["ClusterKubectlReadyBarrier200052AF"], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, @@ -1048,7 +1007,7 @@ }, "/", { - "Ref": "AssetParametersf2b553bd53fbb997e6f23206daa298a3f8bfa7c9805c8c7c99155b4acc2d0cd6S3BucketFA2AD206" + "Ref": "AssetParameters2b4b27a5dbac433df377885ab4121999042fe5e0b5ba995556de20f74c03b85eS3Bucket880F308A" }, "/", { @@ -1058,7 +1017,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersf2b553bd53fbb997e6f23206daa298a3f8bfa7c9805c8c7c99155b4acc2d0cd6S3VersionKeyD5C722C7" + "Ref": "AssetParameters2b4b27a5dbac433df377885ab4121999042fe5e0b5ba995556de20f74c03b85eS3VersionKey67C8FBE4" } ] } @@ -1071,7 +1030,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersf2b553bd53fbb997e6f23206daa298a3f8bfa7c9805c8c7c99155b4acc2d0cd6S3VersionKeyD5C722C7" + "Ref": "AssetParameters2b4b27a5dbac433df377885ab4121999042fe5e0b5ba995556de20f74c03b85eS3VersionKey67C8FBE4" } ] } @@ -1082,16 +1041,19 @@ }, "Parameters": { "referencetoawscdkeksclusterprivateendpointtestClusterCreationRole990BAAEAArn": { - "Fn::GetAtt": [ - "ClusterCreationRole360249B6", - "Arn" - ] + "Fn::GetAtt": ["ClusterCreationRole360249B6", "Arn"] }, - "referencetoawscdkeksclusterprivateendpointtestAssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket0D497746Ref": { - "Ref": "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket14D204F9" + "referencetoawscdkeksclusterprivateendpointtestAssetParametersf9e3ed49f5734f267f6dfffed3c6038e2d31d096ca7e70ce257b16aa613a3ffcS3BucketE0A870AERef": { + "Ref": "AssetParametersf9e3ed49f5734f267f6dfffed3c6038e2d31d096ca7e70ce257b16aa613a3ffcS3Bucket85C441D9" }, - "referencetoawscdkeksclusterprivateendpointtestAssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyC516A514Ref": { - "Ref": "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyDE8A2F1F" + "referencetoawscdkeksclusterprivateendpointtestAssetParametersf9e3ed49f5734f267f6dfffed3c6038e2d31d096ca7e70ce257b16aa613a3ffcS3VersionKey087D1457Ref": { + "Ref": "AssetParametersf9e3ed49f5734f267f6dfffed3c6038e2d31d096ca7e70ce257b16aa613a3ffcS3VersionKeyABBEC6F6" + }, + "referencetoawscdkeksclusterprivateendpointtestAssetParameters80bcd5b0641df4315e277c71a1069094a5d7c76f9e2565c46b68a990c522eaefS3Bucket3935A25BRef": { + "Ref": "AssetParameters80bcd5b0641df4315e277c71a1069094a5d7c76f9e2565c46b68a990c522eaefS3Bucket208EDB42" + }, + "referencetoawscdkeksclusterprivateendpointtestAssetParameters80bcd5b0641df4315e277c71a1069094a5d7c76f9e2565c46b68a990c522eaefS3VersionKeyAEEB2678Ref": { + "Ref": "AssetParameters80bcd5b0641df4315e277c71a1069094a5d7c76f9e2565c46b68a990c522eaefS3VersionKey08C22772" }, "referencetoawscdkeksclusterprivateendpointtestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket7DDAFC04Ref": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" @@ -1117,7 +1079,7 @@ }, "/", { - "Ref": "AssetParametersdfe35aaa6ae98d71e5f9b7ada4fe74c141cb56fbf3fba2bef43a5e4f26ad0ea6S3Bucket1FD74644" + "Ref": "AssetParameters15015fc8ee187f2f31b7de5655eca3d8eff4e1c48e7c7243f61841f14cf5d6f5S3BucketEFCDE17E" }, "/", { @@ -1127,7 +1089,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdfe35aaa6ae98d71e5f9b7ada4fe74c141cb56fbf3fba2bef43a5e4f26ad0ea6S3VersionKey618B12D4" + "Ref": "AssetParameters15015fc8ee187f2f31b7de5655eca3d8eff4e1c48e7c7243f61841f14cf5d6f5S3VersionKey45DCD631" } ] } @@ -1140,7 +1102,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersdfe35aaa6ae98d71e5f9b7ada4fe74c141cb56fbf3fba2bef43a5e4f26ad0ea6S3VersionKey618B12D4" + "Ref": "AssetParameters15015fc8ee187f2f31b7de5655eca3d8eff4e1c48e7c7243f61841f14cf5d6f5S3VersionKey45DCD631" } ] } @@ -1151,22 +1113,16 @@ }, "Parameters": { "referencetoawscdkeksclusterprivateendpointtestClusterF4CF4FE8Arn": { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "Arn" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "Arn"] }, "referencetoawscdkeksclusterprivateendpointtestClusterCreationRole990BAAEAArn": { - "Fn::GetAtt": [ - "ClusterCreationRole360249B6", - "Arn" - ] + "Fn::GetAtt": ["ClusterCreationRole360249B6", "Arn"] }, - "referencetoawscdkeksclusterprivateendpointtestAssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3BucketD11B5EC1Ref": { - "Ref": "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3Bucket008DBB35" + "referencetoawscdkeksclusterprivateendpointtestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3Bucket5F23B36DRef": { + "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9" }, - "referencetoawscdkeksclusterprivateendpointtestAssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey8375F1D2Ref": { - "Ref": "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey97C3E1A0" + "referencetoawscdkeksclusterprivateendpointtestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKey658F22A4Ref": { + "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421" }, "referencetoawscdkeksclusterprivateendpointtestVpcPrivateSubnet1Subnet94DAD769Ref": { "Ref": "VpcPrivateSubnet1Subnet536B997A" @@ -1178,10 +1134,7 @@ "Ref": "VpcPrivateSubnet3SubnetF258B56E" }, "referencetoawscdkeksclusterprivateendpointtestClusterF4CF4FE8ClusterSecurityGroupId": { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "ClusterSecurityGroupId" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "ClusterSecurityGroupId"] }, "referencetoawscdkeksclusterprivateendpointtestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketFD6C4D26Ref": { "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7" @@ -1189,11 +1142,11 @@ "referencetoawscdkeksclusterprivateendpointtestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKey69E4725CRef": { "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" }, - "referencetoawscdkeksclusterprivateendpointtestAssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3Bucket0DEFF6BBRef": { - "Ref": "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3BucketD4F52C82" + "referencetoawscdkeksclusterprivateendpointtestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3Bucket99203424Ref": { + "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998" }, - "referencetoawscdkeksclusterprivateendpointtestAssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3VersionKeyE878793ARef": { - "Ref": "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3VersionKey9D243E8D" + "referencetoawscdkeksclusterprivateendpointtestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKey74D35E51Ref": { + "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565" }, "referencetoawscdkeksclusterprivateendpointtestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket7DDAFC04Ref": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" @@ -1219,10 +1172,7 @@ }, " --region test-region --role-arn ", { - "Fn::GetAtt": [ - "AdminRole38563C57", - "Arn" - ] + "Fn::GetAtt": ["AdminRole38563C57", "Arn"] } ] ] @@ -1239,10 +1189,7 @@ }, " --region test-region --role-arn ", { - "Fn::GetAtt": [ - "AdminRole38563C57", - "Arn" - ] + "Fn::GetAtt": ["AdminRole38563C57", "Arn"] } ] ] @@ -1250,17 +1197,29 @@ } }, "Parameters": { - "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket14D204F9": { + "AssetParametersf9e3ed49f5734f267f6dfffed3c6038e2d31d096ca7e70ce257b16aa613a3ffcS3Bucket85C441D9": { + "Type": "String", + "Description": "S3 bucket for asset \"f9e3ed49f5734f267f6dfffed3c6038e2d31d096ca7e70ce257b16aa613a3ffc\"" + }, + "AssetParametersf9e3ed49f5734f267f6dfffed3c6038e2d31d096ca7e70ce257b16aa613a3ffcS3VersionKeyABBEC6F6": { + "Type": "String", + "Description": "S3 key for asset version \"f9e3ed49f5734f267f6dfffed3c6038e2d31d096ca7e70ce257b16aa613a3ffc\"" + }, + "AssetParametersf9e3ed49f5734f267f6dfffed3c6038e2d31d096ca7e70ce257b16aa613a3ffcArtifactHashC6D6393C": { + "Type": "String", + "Description": "Artifact hash for asset \"f9e3ed49f5734f267f6dfffed3c6038e2d31d096ca7e70ce257b16aa613a3ffc\"" + }, + "AssetParameters80bcd5b0641df4315e277c71a1069094a5d7c76f9e2565c46b68a990c522eaefS3Bucket208EDB42": { "Type": "String", - "Description": "S3 bucket for asset \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + "Description": "S3 bucket for asset \"80bcd5b0641df4315e277c71a1069094a5d7c76f9e2565c46b68a990c522eaef\"" }, - "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyDE8A2F1F": { + "AssetParameters80bcd5b0641df4315e277c71a1069094a5d7c76f9e2565c46b68a990c522eaefS3VersionKey08C22772": { "Type": "String", - "Description": "S3 key for asset version \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + "Description": "S3 key for asset version \"80bcd5b0641df4315e277c71a1069094a5d7c76f9e2565c46b68a990c522eaef\"" }, - "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaArtifactHash54822A43": { + "AssetParameters80bcd5b0641df4315e277c71a1069094a5d7c76f9e2565c46b68a990c522eaefArtifactHash861FF133": { "Type": "String", - "Description": "Artifact hash for asset \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + "Description": "Artifact hash for asset \"80bcd5b0641df4315e277c71a1069094a5d7c76f9e2565c46b68a990c522eaef\"" }, "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { "Type": "String", @@ -1274,17 +1233,17 @@ "Type": "String", "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" }, - "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3Bucket008DBB35": { + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9": { "Type": "String", - "Description": "S3 bucket for asset \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + "Description": "S3 bucket for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" }, - "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey97C3E1A0": { + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421": { "Type": "String", - "Description": "S3 key for asset version \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + "Description": "S3 key for asset version \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" }, - "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757ArtifactHashF584A7D8": { + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10ArtifactHash528547CD": { "Type": "String", - "Description": "Artifact hash for asset \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + "Description": "Artifact hash for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" }, "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { "Type": "String", @@ -1298,41 +1257,41 @@ "Type": "String", "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" }, - "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3BucketD4F52C82": { + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998": { "Type": "String", - "Description": "S3 bucket for asset \"cd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793\"" + "Description": "S3 bucket for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3VersionKey9D243E8D": { + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565": { "Type": "String", - "Description": "S3 key for asset version \"cd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793\"" + "Description": "S3 key for asset version \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793ArtifactHash42EBA5B2": { + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eArtifactHash4654D012": { "Type": "String", - "Description": "Artifact hash for asset \"cd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793\"" + "Description": "Artifact hash for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParametersf2b553bd53fbb997e6f23206daa298a3f8bfa7c9805c8c7c99155b4acc2d0cd6S3BucketFA2AD206": { + "AssetParameters2b4b27a5dbac433df377885ab4121999042fe5e0b5ba995556de20f74c03b85eS3Bucket880F308A": { "Type": "String", - "Description": "S3 bucket for asset \"f2b553bd53fbb997e6f23206daa298a3f8bfa7c9805c8c7c99155b4acc2d0cd6\"" + "Description": "S3 bucket for asset \"2b4b27a5dbac433df377885ab4121999042fe5e0b5ba995556de20f74c03b85e\"" }, - "AssetParametersf2b553bd53fbb997e6f23206daa298a3f8bfa7c9805c8c7c99155b4acc2d0cd6S3VersionKeyD5C722C7": { + "AssetParameters2b4b27a5dbac433df377885ab4121999042fe5e0b5ba995556de20f74c03b85eS3VersionKey67C8FBE4": { "Type": "String", - "Description": "S3 key for asset version \"f2b553bd53fbb997e6f23206daa298a3f8bfa7c9805c8c7c99155b4acc2d0cd6\"" + "Description": "S3 key for asset version \"2b4b27a5dbac433df377885ab4121999042fe5e0b5ba995556de20f74c03b85e\"" }, - "AssetParametersf2b553bd53fbb997e6f23206daa298a3f8bfa7c9805c8c7c99155b4acc2d0cd6ArtifactHashD053AD55": { + "AssetParameters2b4b27a5dbac433df377885ab4121999042fe5e0b5ba995556de20f74c03b85eArtifactHash5B39BCF8": { "Type": "String", - "Description": "Artifact hash for asset \"f2b553bd53fbb997e6f23206daa298a3f8bfa7c9805c8c7c99155b4acc2d0cd6\"" + "Description": "Artifact hash for asset \"2b4b27a5dbac433df377885ab4121999042fe5e0b5ba995556de20f74c03b85e\"" }, - "AssetParametersdfe35aaa6ae98d71e5f9b7ada4fe74c141cb56fbf3fba2bef43a5e4f26ad0ea6S3Bucket1FD74644": { + "AssetParameters15015fc8ee187f2f31b7de5655eca3d8eff4e1c48e7c7243f61841f14cf5d6f5S3BucketEFCDE17E": { "Type": "String", - "Description": "S3 bucket for asset \"dfe35aaa6ae98d71e5f9b7ada4fe74c141cb56fbf3fba2bef43a5e4f26ad0ea6\"" + "Description": "S3 bucket for asset \"15015fc8ee187f2f31b7de5655eca3d8eff4e1c48e7c7243f61841f14cf5d6f5\"" }, - "AssetParametersdfe35aaa6ae98d71e5f9b7ada4fe74c141cb56fbf3fba2bef43a5e4f26ad0ea6S3VersionKey618B12D4": { + "AssetParameters15015fc8ee187f2f31b7de5655eca3d8eff4e1c48e7c7243f61841f14cf5d6f5S3VersionKey45DCD631": { "Type": "String", - "Description": "S3 key for asset version \"dfe35aaa6ae98d71e5f9b7ada4fe74c141cb56fbf3fba2bef43a5e4f26ad0ea6\"" + "Description": "S3 key for asset version \"15015fc8ee187f2f31b7de5655eca3d8eff4e1c48e7c7243f61841f14cf5d6f5\"" }, - "AssetParametersdfe35aaa6ae98d71e5f9b7ada4fe74c141cb56fbf3fba2bef43a5e4f26ad0ea6ArtifactHash378913E5": { + "AssetParameters15015fc8ee187f2f31b7de5655eca3d8eff4e1c48e7c7243f61841f14cf5d6f5ArtifactHash155A4596": { "Type": "String", - "Description": "Artifact hash for asset \"dfe35aaa6ae98d71e5f9b7ada4fe74c141cb56fbf3fba2bef43a5e4f26ad0ea6\"" + "Description": "Artifact hash for asset \"15015fc8ee187f2f31b7de5655eca3d8eff4e1c48e7c7243f61841f14cf5d6f5\"" } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json index 1509f2e16bcf6..252abae7c493c 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json @@ -143,9 +143,7 @@ "Ref": "VpcIGWD7BA715C" } }, - "DependsOn": [ - "VpcVPCGWBF912B6E" - ] + "DependsOn": ["VpcVPCGWBF912B6E"] }, "VpcPublicSubnet1EIPD7E02669": { "Type": "AWS::EC2::EIP", @@ -170,10 +168,7 @@ "Ref": "VpcPublicSubnet1Subnet5C2D37C4" }, "AllocationId": { - "Fn::GetAtt": [ - "VpcPublicSubnet1EIPD7E02669", - "AllocationId" - ] + "Fn::GetAtt": ["VpcPublicSubnet1EIPD7E02669", "AllocationId"] }, "Tags": [ { @@ -256,9 +251,7 @@ "Ref": "VpcIGWD7BA715C" } }, - "DependsOn": [ - "VpcVPCGWBF912B6E" - ] + "DependsOn": ["VpcVPCGWBF912B6E"] }, "VpcPublicSubnet3SubnetBE12F0B6": { "Type": "AWS::EC2::Subnet", @@ -329,9 +322,7 @@ "Ref": "VpcIGWD7BA715C" } }, - "DependsOn": [ - "VpcVPCGWBF912B6E" - ] + "DependsOn": ["VpcVPCGWBF912B6E"] }, "VpcPrivateSubnet1Subnet536B997A": { "Type": "AWS::EC2::Subnet", @@ -619,16 +610,10 @@ "Description": "from awscdkeksclustertestClusterNodesInstanceSecurityGroupD0B64C54:443", "FromPort": 443, "GroupId": { - "Fn::GetAtt": [ - "ClusterControlPlaneSecurityGroupD274242C", - "GroupId" - ] + "Fn::GetAtt": ["ClusterControlPlaneSecurityGroupD274242C", "GroupId"] }, "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "ClusterNodesInstanceSecurityGroup899246BD", - "GroupId" - ] + "Fn::GetAtt": ["ClusterNodesInstanceSecurityGroup899246BD", "GroupId"] }, "ToPort": 443 } @@ -640,10 +625,7 @@ "Description": "from awscdkeksclustertestClusterNodesArmInstanceSecurityGroup52C45858:443", "FromPort": 443, "GroupId": { - "Fn::GetAtt": [ - "ClusterControlPlaneSecurityGroupD274242C", - "GroupId" - ] + "Fn::GetAtt": ["ClusterControlPlaneSecurityGroupD274242C", "GroupId"] }, "SourceSecurityGroupId": { "Fn::GetAtt": [ @@ -661,10 +643,7 @@ "Description": "from awscdkeksclustertestClusterBottlerocketNodesInstanceSecurityGroup83FE7914:443", "FromPort": 443, "GroupId": { - "Fn::GetAtt": [ - "ClusterControlPlaneSecurityGroupD274242C", - "GroupId" - ] + "Fn::GetAtt": ["ClusterControlPlaneSecurityGroupD274242C", "GroupId"] }, "SourceSecurityGroupId": { "Fn::GetAtt": [ @@ -682,16 +661,10 @@ "Description": "from awscdkeksclustertestClusterspotInstanceSecurityGroupF50F5D47:443", "FromPort": 443, "GroupId": { - "Fn::GetAtt": [ - "ClusterControlPlaneSecurityGroupD274242C", - "GroupId" - ] + "Fn::GetAtt": ["ClusterControlPlaneSecurityGroupD274242C", "GroupId"] }, "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "ClusterspotInstanceSecurityGroup01F7B1CE", - "GroupId" - ] + "Fn::GetAtt": ["ClusterspotInstanceSecurityGroup01F7B1CE", "GroupId"] }, "ToPort": 443 } @@ -703,10 +676,7 @@ "Description": "from awscdkeksclustertestClusterInferenceInstancesInstanceSecurityGroup42C57C51:443", "FromPort": 443, "GroupId": { - "Fn::GetAtt": [ - "ClusterControlPlaneSecurityGroupD274242C", - "GroupId" - ] + "Fn::GetAtt": ["ClusterControlPlaneSecurityGroupD274242C", "GroupId"] }, "SourceSecurityGroupId": { "Fn::GetAtt": [ @@ -785,10 +755,7 @@ "Action": "iam:PassRole", "Effect": "Allow", "Resource": { - "Fn::GetAtt": [ - "ClusterRoleFA261979", - "Arn" - ] + "Fn::GetAtt": ["ClusterRoleFA261979", "Arn"] } }, { @@ -804,9 +771,7 @@ "eks:UntagResource" ], "Effect": "Allow", - "Resource": [ - "*" - ] + "Resource": ["*"] }, { "Action": [ @@ -817,10 +782,7 @@ "Resource": "*" }, { - "Action": [ - "iam:GetRole", - "iam:listAttachedRolePolicies" - ], + "Action": ["iam:GetRole", "iam:listAttachedRolePolicies"], "Effect": "Allow", "Resource": "*" }, @@ -851,10 +813,7 @@ ], "Effect": "Allow", "Resource": { - "Fn::GetAtt": [ - "SecretsKey317DCF94", - "Arn" - ] + "Fn::GetAtt": ["SecretsKey317DCF94", "Arn"] } }, { @@ -921,24 +880,16 @@ "Config": { "version": "1.21", "roleArn": { - "Fn::GetAtt": [ - "ClusterRoleFA261979", - "Arn" - ] + "Fn::GetAtt": ["ClusterRoleFA261979", "Arn"] }, "encryptionConfig": [ { "provider": { "keyArn": { - "Fn::GetAtt": [ - "SecretsKey317DCF94", - "Arn" - ] + "Fn::GetAtt": ["SecretsKey317DCF94", "Arn"] } }, - "resources": [ - "secrets" - ] + "resources": ["secrets"] } ], "resourcesVpcConfig": { @@ -975,10 +926,7 @@ } }, "AssumeRoleArn": { - "Fn::GetAtt": [ - "ClusterCreationRole360249B6", - "Arn" - ] + "Fn::GetAtt": ["ClusterCreationRole360249B6", "Arn"] }, "AttributesRevision": 2 }, @@ -1039,16 +987,10 @@ "Description": "from awscdkeksclustertestClusterNodesInstanceSecurityGroupD0B64C54:443", "FromPort": 443, "GroupId": { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "ClusterSecurityGroupId" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "ClusterSecurityGroupId"] }, "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "ClusterNodesInstanceSecurityGroup899246BD", - "GroupId" - ] + "Fn::GetAtt": ["ClusterNodesInstanceSecurityGroup899246BD", "GroupId"] }, "ToPort": 443 } @@ -1060,10 +1002,7 @@ "Description": "from awscdkeksclustertestClusterNodesArmInstanceSecurityGroup52C45858:443", "FromPort": 443, "GroupId": { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "ClusterSecurityGroupId" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "ClusterSecurityGroupId"] }, "SourceSecurityGroupId": { "Fn::GetAtt": [ @@ -1081,10 +1020,7 @@ "Description": "from awscdkeksclustertestClusterBottlerocketNodesInstanceSecurityGroup83FE7914:443", "FromPort": 443, "GroupId": { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "ClusterSecurityGroupId" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "ClusterSecurityGroupId"] }, "SourceSecurityGroupId": { "Fn::GetAtt": [ @@ -1102,16 +1038,10 @@ "Description": "from awscdkeksclustertestClusterspotInstanceSecurityGroupF50F5D47:443", "FromPort": 443, "GroupId": { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "ClusterSecurityGroupId" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "ClusterSecurityGroupId"] }, "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "ClusterspotInstanceSecurityGroup01F7B1CE", - "GroupId" - ] + "Fn::GetAtt": ["ClusterspotInstanceSecurityGroup01F7B1CE", "GroupId"] }, "ToPort": 443 } @@ -1123,10 +1053,7 @@ "Description": "from awscdkeksclustertestClusterInferenceInstancesInstanceSecurityGroup42C57C51:443", "FromPort": 443, "GroupId": { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "ClusterSecurityGroupId" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "ClusterSecurityGroupId"] }, "SourceSecurityGroupId": { "Fn::GetAtt": [ @@ -1152,17 +1079,11 @@ [ "[{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"aws-auth\",\"namespace\":\"kube-system\",\"labels\":{\"aws.cdk.eks/prune-c842be348c45337cd97b8759de76d5a68b4910d487\":\"\"}},\"data\":{\"mapRoles\":\"[{\\\"rolearn\\\":\\\"", { - "Fn::GetAtt": [ - "AdminRole38563C57", - "Arn" - ] + "Fn::GetAtt": ["AdminRole38563C57", "Arn"] }, "\\\",\\\"username\\\":\\\"", { - "Fn::GetAtt": [ - "AdminRole38563C57", - "Arn" - ] + "Fn::GetAtt": ["AdminRole38563C57", "Arn"] }, "\\\",\\\"groups\\\":[\\\"system:masters\\\"]},{\\\"rolearn\\\":\\\"", { @@ -1180,17 +1101,11 @@ }, "\\\",\\\"username\\\":\\\"system:node:{{SessionName}}\\\",\\\"groups\\\":[\\\"system:bootstrappers\\\",\\\"system:nodes\\\",\\\"system:node-proxier\\\"]},{\\\"rolearn\\\":\\\"", { - "Fn::GetAtt": [ - "ClusterNodesInstanceRoleC3C01328", - "Arn" - ] + "Fn::GetAtt": ["ClusterNodesInstanceRoleC3C01328", "Arn"] }, "\\\",\\\"username\\\":\\\"system:node:{{EC2PrivateDNSName}}\\\",\\\"groups\\\":[\\\"system:bootstrappers\\\",\\\"system:nodes\\\"]},{\\\"rolearn\\\":\\\"", { - "Fn::GetAtt": [ - "ClusterNodesArmInstanceRoleB93D3298", - "Arn" - ] + "Fn::GetAtt": ["ClusterNodesArmInstanceRoleB93D3298", "Arn"] }, "\\\",\\\"username\\\":\\\"system:node:{{EC2PrivateDNSName}}\\\",\\\"groups\\\":[\\\"system:bootstrappers\\\",\\\"system:nodes\\\"]},{\\\"rolearn\\\":\\\"", { @@ -1201,10 +1116,7 @@ }, "\\\",\\\"username\\\":\\\"system:node:{{EC2PrivateDNSName}}\\\",\\\"groups\\\":[\\\"system:bootstrappers\\\",\\\"system:nodes\\\"]},{\\\"rolearn\\\":\\\"", { - "Fn::GetAtt": [ - "ClusterspotInstanceRole39043830", - "Arn" - ] + "Fn::GetAtt": ["ClusterspotInstanceRole39043830", "Arn"] }, "\\\",\\\"username\\\":\\\"system:node:{{EC2PrivateDNSName}}\\\",\\\"groups\\\":[\\\"system:bootstrappers\\\",\\\"system:nodes\\\"]},{\\\"rolearn\\\":\\\"", { @@ -1249,17 +1161,12 @@ "Ref": "Cluster9EE0221C" }, "RoleArn": { - "Fn::GetAtt": [ - "ClusterCreationRole360249B6", - "Arn" - ] + "Fn::GetAtt": ["ClusterCreationRole360249B6", "Arn"] }, "PruneLabel": "aws.cdk.eks/prune-c842be348c45337cd97b8759de76d5a68b4910d487", "Overwrite": true }, - "DependsOn": [ - "ClusterKubectlReadyBarrier200052AF" - ], + "DependsOn": ["ClusterKubectlReadyBarrier200052AF"], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, @@ -1353,9 +1260,7 @@ ], "AmiType": "AL2_x86_64", "ForceUpdateEnabled": true, - "InstanceTypes": [ - "m5.large" - ], + "InstanceTypes": ["m5.large"], "ScalingConfig": { "DesiredSize": 2, "MaxSize": 2, @@ -1404,10 +1309,7 @@ ] }, "AssumeRoleArn": { - "Fn::GetAtt": [ - "ClusterCreationRole360249B6", - "Arn" - ] + "Fn::GetAtt": ["ClusterCreationRole360249B6", "Arn"] }, "Config": { "clusterName": { @@ -1457,16 +1359,10 @@ "IpProtocol": "-1", "Description": "from awscdkeksclustertestClusterNodesInstanceSecurityGroupD0B64C54:ALL TRAFFIC", "GroupId": { - "Fn::GetAtt": [ - "ClusterNodesInstanceSecurityGroup899246BD", - "GroupId" - ] + "Fn::GetAtt": ["ClusterNodesInstanceSecurityGroup899246BD", "GroupId"] }, "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "ClusterNodesInstanceSecurityGroup899246BD", - "GroupId" - ] + "Fn::GetAtt": ["ClusterNodesInstanceSecurityGroup899246BD", "GroupId"] } } }, @@ -1477,16 +1373,10 @@ "Description": "from awscdkeksclustertestClusterClusterSecurityGroupF7265A32:443", "FromPort": 443, "GroupId": { - "Fn::GetAtt": [ - "ClusterNodesInstanceSecurityGroup899246BD", - "GroupId" - ] + "Fn::GetAtt": ["ClusterNodesInstanceSecurityGroup899246BD", "GroupId"] }, "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "ClusterSecurityGroupId" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "ClusterSecurityGroupId"] }, "ToPort": 443 } @@ -1498,16 +1388,10 @@ "Description": "from awscdkeksclustertestClusterControlPlaneSecurityGroup2F130134:443", "FromPort": 443, "GroupId": { - "Fn::GetAtt": [ - "ClusterNodesInstanceSecurityGroup899246BD", - "GroupId" - ] + "Fn::GetAtt": ["ClusterNodesInstanceSecurityGroup899246BD", "GroupId"] }, "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "ClusterControlPlaneSecurityGroupD274242C", - "GroupId" - ] + "Fn::GetAtt": ["ClusterControlPlaneSecurityGroupD274242C", "GroupId"] }, "ToPort": 443 } @@ -1519,16 +1403,10 @@ "Description": "from awscdkeksclustertestClusterClusterSecurityGroupF7265A32:1025-65535", "FromPort": 1025, "GroupId": { - "Fn::GetAtt": [ - "ClusterNodesInstanceSecurityGroup899246BD", - "GroupId" - ] + "Fn::GetAtt": ["ClusterNodesInstanceSecurityGroup899246BD", "GroupId"] }, "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "ClusterSecurityGroupId" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "ClusterSecurityGroupId"] }, "ToPort": 65535 } @@ -1540,16 +1418,10 @@ "Description": "from awscdkeksclustertestClusterControlPlaneSecurityGroup2F130134:1025-65535", "FromPort": 1025, "GroupId": { - "Fn::GetAtt": [ - "ClusterNodesInstanceSecurityGroup899246BD", - "GroupId" - ] + "Fn::GetAtt": ["ClusterNodesInstanceSecurityGroup899246BD", "GroupId"] }, "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "ClusterControlPlaneSecurityGroupD274242C", - "GroupId" - ] + "Fn::GetAtt": ["ClusterControlPlaneSecurityGroupD274242C", "GroupId"] }, "ToPort": 65535 } @@ -1667,10 +1539,7 @@ ] }, { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "ClusterSecurityGroupId" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "ClusterSecurityGroupId"] } ], "UserData": { @@ -1684,17 +1553,11 @@ }, " --kubelet-extra-args \"--node-labels lifecycle=OnDemand\" --apiserver-endpoint '", { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "Endpoint" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "Endpoint"] }, "' --b64-cluster-ca '", { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "CertificateAuthorityData" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "CertificateAuthorityData"] }, "' --use-max-pods true\n/opt/aws/bin/cfn-signal --exit-code $? --stack aws-cdk-eks-cluster-test --resource ClusterNodesASGF172BD19 --region test-region" ] @@ -1702,9 +1565,7 @@ } } }, - "DependsOn": [ - "ClusterNodesInstanceRoleC3C01328" - ] + "DependsOn": ["ClusterNodesInstanceRoleC3C01328"] }, "ClusterNodesASGF172BD19": { "Type": "AWS::AutoScaling::AutoScalingGroup", @@ -1808,10 +1669,7 @@ ] }, "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "ClusterSecurityGroupId" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "ClusterSecurityGroupId"] }, "ToPort": 443 } @@ -1829,10 +1687,7 @@ ] }, "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "ClusterControlPlaneSecurityGroupD274242C", - "GroupId" - ] + "Fn::GetAtt": ["ClusterControlPlaneSecurityGroupD274242C", "GroupId"] }, "ToPort": 443 } @@ -1850,10 +1705,7 @@ ] }, "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "ClusterSecurityGroupId" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "ClusterSecurityGroupId"] }, "ToPort": 65535 } @@ -1871,10 +1723,7 @@ ] }, "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "ClusterControlPlaneSecurityGroupD274242C", - "GroupId" - ] + "Fn::GetAtt": ["ClusterControlPlaneSecurityGroupD274242C", "GroupId"] }, "ToPort": 65535 } @@ -1992,10 +1841,7 @@ ] }, { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "ClusterSecurityGroupId" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "ClusterSecurityGroupId"] } ], "UserData": { @@ -2009,17 +1855,11 @@ }, " --kubelet-extra-args \"--node-labels lifecycle=OnDemand\" --apiserver-endpoint '", { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "Endpoint" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "Endpoint"] }, "' --b64-cluster-ca '", { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "CertificateAuthorityData" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "CertificateAuthorityData"] }, "' --use-max-pods true\n/opt/aws/bin/cfn-signal --exit-code $? --stack aws-cdk-eks-cluster-test --resource ClusterNodesArmASG40A593D0 --region test-region" ] @@ -2027,9 +1867,7 @@ } } }, - "DependsOn": [ - "ClusterNodesArmInstanceRoleB93D3298" - ] + "DependsOn": ["ClusterNodesArmInstanceRoleB93D3298"] }, "ClusterNodesArmASG40A593D0": { "Type": "AWS::AutoScaling::AutoScalingGroup", @@ -2133,10 +1971,7 @@ ] }, "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "ClusterSecurityGroupId" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "ClusterSecurityGroupId"] }, "ToPort": 443 } @@ -2154,10 +1989,7 @@ ] }, "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "ClusterControlPlaneSecurityGroupD274242C", - "GroupId" - ] + "Fn::GetAtt": ["ClusterControlPlaneSecurityGroupD274242C", "GroupId"] }, "ToPort": 443 } @@ -2175,10 +2007,7 @@ ] }, "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "ClusterSecurityGroupId" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "ClusterSecurityGroupId"] }, "ToPort": 65535 } @@ -2196,10 +2025,7 @@ ] }, "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "ClusterControlPlaneSecurityGroupD274242C", - "GroupId" - ] + "Fn::GetAtt": ["ClusterControlPlaneSecurityGroupD274242C", "GroupId"] }, "ToPort": 65535 } @@ -2317,10 +2143,7 @@ ] }, { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "ClusterSecurityGroupId" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "ClusterSecurityGroupId"] } ], "UserData": { @@ -2330,17 +2153,11 @@ [ "\n[settings.kubernetes]\napi-server=\"", { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "Endpoint" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "Endpoint"] }, "\"\ncluster-certificate=\"", { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "CertificateAuthorityData" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "CertificateAuthorityData"] }, "\"\ncluster-name=\"", { @@ -2352,9 +2169,7 @@ } } }, - "DependsOn": [ - "ClusterBottlerocketNodesInstanceRole68E4BCFB" - ] + "DependsOn": ["ClusterBottlerocketNodesInstanceRole68E4BCFB"] }, "ClusterBottlerocketNodesASGA27A9B70": { "Type": "AWS::AutoScaling::AutoScalingGroup", @@ -2432,16 +2247,10 @@ "IpProtocol": "-1", "Description": "from awscdkeksclustertestClusterspotInstanceSecurityGroupF50F5D47:ALL TRAFFIC", "GroupId": { - "Fn::GetAtt": [ - "ClusterspotInstanceSecurityGroup01F7B1CE", - "GroupId" - ] + "Fn::GetAtt": ["ClusterspotInstanceSecurityGroup01F7B1CE", "GroupId"] }, "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "ClusterspotInstanceSecurityGroup01F7B1CE", - "GroupId" - ] + "Fn::GetAtt": ["ClusterspotInstanceSecurityGroup01F7B1CE", "GroupId"] } } }, @@ -2452,16 +2261,10 @@ "Description": "from awscdkeksclustertestClusterClusterSecurityGroupF7265A32:443", "FromPort": 443, "GroupId": { - "Fn::GetAtt": [ - "ClusterspotInstanceSecurityGroup01F7B1CE", - "GroupId" - ] + "Fn::GetAtt": ["ClusterspotInstanceSecurityGroup01F7B1CE", "GroupId"] }, "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "ClusterSecurityGroupId" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "ClusterSecurityGroupId"] }, "ToPort": 443 } @@ -2473,16 +2276,10 @@ "Description": "from awscdkeksclustertestClusterControlPlaneSecurityGroup2F130134:443", "FromPort": 443, "GroupId": { - "Fn::GetAtt": [ - "ClusterspotInstanceSecurityGroup01F7B1CE", - "GroupId" - ] + "Fn::GetAtt": ["ClusterspotInstanceSecurityGroup01F7B1CE", "GroupId"] }, "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "ClusterControlPlaneSecurityGroupD274242C", - "GroupId" - ] + "Fn::GetAtt": ["ClusterControlPlaneSecurityGroupD274242C", "GroupId"] }, "ToPort": 443 } @@ -2494,16 +2291,10 @@ "Description": "from awscdkeksclustertestClusterClusterSecurityGroupF7265A32:1025-65535", "FromPort": 1025, "GroupId": { - "Fn::GetAtt": [ - "ClusterspotInstanceSecurityGroup01F7B1CE", - "GroupId" - ] + "Fn::GetAtt": ["ClusterspotInstanceSecurityGroup01F7B1CE", "GroupId"] }, "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "ClusterSecurityGroupId" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "ClusterSecurityGroupId"] }, "ToPort": 65535 } @@ -2515,16 +2306,10 @@ "Description": "from awscdkeksclustertestClusterControlPlaneSecurityGroup2F130134:1025-65535", "FromPort": 1025, "GroupId": { - "Fn::GetAtt": [ - "ClusterspotInstanceSecurityGroup01F7B1CE", - "GroupId" - ] + "Fn::GetAtt": ["ClusterspotInstanceSecurityGroup01F7B1CE", "GroupId"] }, "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "ClusterControlPlaneSecurityGroupD274242C", - "GroupId" - ] + "Fn::GetAtt": ["ClusterControlPlaneSecurityGroupD274242C", "GroupId"] }, "ToPort": 65535 } @@ -2642,10 +2427,7 @@ ] }, { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "ClusterSecurityGroupId" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "ClusterSecurityGroupId"] } ], "SpotPrice": "0.1094", @@ -2660,17 +2442,11 @@ }, " --kubelet-extra-args \"--node-labels lifecycle=Ec2Spot --register-with-taints=spotInstance=true:PreferNoSchedule --node-labels foo=bar,goo=far\" --apiserver-endpoint '", { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "Endpoint" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "Endpoint"] }, "' --b64-cluster-ca '", { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "CertificateAuthorityData" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "CertificateAuthorityData"] }, "' --use-max-pods true --aws-api-retry-attempts 5\n/opt/aws/bin/cfn-signal --exit-code $? --stack aws-cdk-eks-cluster-test --resource ClusterspotASG857494B6 --region test-region" ] @@ -2678,9 +2454,7 @@ } } }, - "DependsOn": [ - "ClusterspotInstanceRole39043830" - ] + "DependsOn": ["ClusterspotInstanceRole39043830"] }, "ClusterspotASG857494B6": { "Type": "AWS::AutoScaling::AutoScalingGroup", @@ -2743,10 +2517,7 @@ "Ref": "Cluster9EE0221C" }, "RoleArn": { - "Fn::GetAtt": [ - "ClusterCreationRole360249B6", - "Arn" - ] + "Fn::GetAtt": ["ClusterCreationRole360249B6", "Arn"] }, "Release": "ksclustertestclusterchartspotinterrupthandlerf41ba997", "Chart": "aws-node-termination-handler", @@ -2756,9 +2527,7 @@ "Repository": "https://aws.github.io/eks-charts", "CreateNamespace": true }, - "DependsOn": [ - "ClusterKubectlReadyBarrier200052AF" - ], + "DependsOn": ["ClusterKubectlReadyBarrier200052AF"], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, @@ -2816,10 +2585,7 @@ ] }, "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "ClusterSecurityGroupId" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "ClusterSecurityGroupId"] }, "ToPort": 443 } @@ -2837,10 +2603,7 @@ ] }, "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "ClusterControlPlaneSecurityGroupD274242C", - "GroupId" - ] + "Fn::GetAtt": ["ClusterControlPlaneSecurityGroupD274242C", "GroupId"] }, "ToPort": 443 } @@ -2858,10 +2621,7 @@ ] }, "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "ClusterSecurityGroupId" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "ClusterSecurityGroupId"] }, "ToPort": 65535 } @@ -2879,10 +2639,7 @@ ] }, "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "ClusterControlPlaneSecurityGroupD274242C", - "GroupId" - ] + "Fn::GetAtt": ["ClusterControlPlaneSecurityGroupD274242C", "GroupId"] }, "ToPort": 65535 } @@ -3000,10 +2757,7 @@ ] }, { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "ClusterSecurityGroupId" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "ClusterSecurityGroupId"] } ], "UserData": { @@ -3017,17 +2771,11 @@ }, " --kubelet-extra-args \"--node-labels lifecycle=OnDemand\" --apiserver-endpoint '", { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "Endpoint" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "Endpoint"] }, "' --b64-cluster-ca '", { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "CertificateAuthorityData" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "CertificateAuthorityData"] }, "' --use-max-pods true\n/opt/aws/bin/cfn-signal --exit-code $? --stack aws-cdk-eks-cluster-test --resource ClusterInferenceInstancesASGE90717C7 --region test-region" ] @@ -3035,9 +2783,7 @@ } } }, - "DependsOn": [ - "ClusterInferenceInstancesInstanceRole59AC6F56" - ] + "DependsOn": ["ClusterInferenceInstancesInstanceRole59AC6F56"] }, "ClusterInferenceInstancesASGE90717C7": { "Type": "AWS::AutoScaling::AutoScalingGroup", @@ -3101,16 +2847,11 @@ "Ref": "Cluster9EE0221C" }, "RoleArn": { - "Fn::GetAtt": [ - "ClusterCreationRole360249B6", - "Arn" - ] + "Fn::GetAtt": ["ClusterCreationRole360249B6", "Arn"] }, "PruneLabel": "aws.cdk.eks/prune-c88223d575036bcf663303b6778373ae4854f1fe3b" }, - "DependsOn": [ - "ClusterKubectlReadyBarrier200052AF" - ], + "DependsOn": ["ClusterKubectlReadyBarrier200052AF"], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, @@ -3186,10 +2927,7 @@ "Ref": "Cluster9EE0221C" }, "NodeRole": { - "Fn::GetAtt": [ - "ClusterNodegroupextrangNodeGroupRole23AE23D0", - "Arn" - ] + "Fn::GetAtt": ["ClusterNodegroupextrangNodeGroupRole23AE23D0", "Arn"] }, "Subnets": [ { @@ -3204,9 +2942,7 @@ ], "AmiType": "AL2_x86_64", "ForceUpdateEnabled": true, - "InstanceTypes": [ - "t3.small" - ], + "InstanceTypes": ["t3.small"], "ScalingConfig": { "DesiredSize": 1, "MaxSize": 1, @@ -3305,11 +3041,7 @@ "AmiType": "AL2_x86_64", "CapacityType": "SPOT", "ForceUpdateEnabled": true, - "InstanceTypes": [ - "c5.large", - "c5a.large", - "c5d.large" - ], + "InstanceTypes": ["c5.large", "c5a.large", "c5d.large"], "ScalingConfig": { "DesiredSize": 3, "MaxSize": 3, @@ -3407,9 +3139,7 @@ ], "AmiType": "AL2_ARM_64", "ForceUpdateEnabled": true, - "InstanceTypes": [ - "m6g.medium" - ], + "InstanceTypes": ["m6g.medium"], "ScalingConfig": { "DesiredSize": 1, "MaxSize": 1, @@ -3446,10 +3176,7 @@ "Ref": "LaunchTemplate" }, "Version": { - "Fn::GetAtt": [ - "LaunchTemplate", - "DefaultVersionNumber" - ] + "Fn::GetAtt": ["LaunchTemplate", "DefaultVersionNumber"] } }, "ScalingConfig": { @@ -3473,16 +3200,11 @@ "Ref": "Cluster9EE0221C" }, "RoleArn": { - "Fn::GetAtt": [ - "ClusterCreationRole360249B6", - "Arn" - ] + "Fn::GetAtt": ["ClusterCreationRole360249B6", "Arn"] }, "PruneLabel": "aws.cdk.eks/prune-c8f0f7140f7358e29b7f58e81b507dcf744a3908f4" }, - "DependsOn": [ - "ClusterKubectlReadyBarrier200052AF" - ], + "DependsOn": ["ClusterKubectlReadyBarrier200052AF"], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, @@ -3499,10 +3221,7 @@ "Ref": "Cluster9EE0221C" }, "RoleArn": { - "Fn::GetAtt": [ - "ClusterCreationRole360249B6", - "Arn" - ] + "Fn::GetAtt": ["ClusterCreationRole360249B6", "Arn"] }, "Release": "awscdkeksclustertestclusterchartdashboard1f3d83fe", "Chart": "kubernetes-dashboard", @@ -3510,9 +3229,7 @@ "Repository": "https://kubernetes.github.io/dashboard/", "CreateNamespace": true }, - "DependsOn": [ - "ClusterKubectlReadyBarrier200052AF" - ], + "DependsOn": ["ClusterKubectlReadyBarrier200052AF"], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, @@ -3541,16 +3258,11 @@ "Ref": "Cluster9EE0221C" }, "RoleArn": { - "Fn::GetAtt": [ - "ClusterCreationRole360249B6", - "Arn" - ] + "Fn::GetAtt": ["ClusterCreationRole360249B6", "Arn"] }, "PruneLabel": "aws.cdk.eks/prune-c8cd9cb2e127e0b0375ebc544f18d8513721895a27" }, - "DependsOn": [ - "ClusterKubectlReadyBarrier200052AF" - ], + "DependsOn": ["ClusterKubectlReadyBarrier200052AF"], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, @@ -3568,16 +3280,11 @@ "Ref": "Cluster9EE0221C" }, "RoleArn": { - "Fn::GetAtt": [ - "ClusterCreationRole360249B6", - "Arn" - ] + "Fn::GetAtt": ["ClusterCreationRole360249B6", "Arn"] }, "PruneLabel": "aws.cdk.eks/prune-c84fd26f70b01a84daa5d3646e813820af6fde0970" }, - "DependsOn": [ - "ClusterKubectlReadyBarrier200052AF" - ], + "DependsOn": ["ClusterKubectlReadyBarrier200052AF"], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, @@ -3594,10 +3301,7 @@ "Ref": "Cluster9EE0221C" }, "RoleArn": { - "Fn::GetAtt": [ - "ClusterCreationRole360249B6", - "Arn" - ] + "Fn::GetAtt": ["ClusterCreationRole360249B6", "Arn"] }, "Release": "awscdkeksclustertestclusterchartnginxingressa7f70129", "Chart": "nginx-ingress", @@ -3704,10 +3408,7 @@ [ "[{\"apiVersion\":\"v1\",\"kind\":\"ServiceAccount\",\"metadata\":{\"name\":\"awscdkeksclustertestclustermyserviceaccount4080bcdd\",\"namespace\":\"default\",\"labels\":{\"aws.cdk.eks/prune-c8f8dbf23319159cc2fef46283f7450b814e818252\":\"\",\"app.kubernetes.io/name\":\"awscdkeksclustertestclustermyserviceaccount4080bcdd\"},\"annotations\":{\"eks.amazonaws.com/role-arn\":\"", { - "Fn::GetAtt": [ - "ClusterMyServiceAccountRole85337B29", - "Arn" - ] + "Fn::GetAtt": ["ClusterMyServiceAccountRole85337B29", "Arn"] }, "\"}}}]" ] @@ -3717,16 +3418,11 @@ "Ref": "Cluster9EE0221C" }, "RoleArn": { - "Fn::GetAtt": [ - "ClusterCreationRole360249B6", - "Arn" - ] + "Fn::GetAtt": ["ClusterCreationRole360249B6", "Arn"] }, "PruneLabel": "aws.cdk.eks/prune-c8f8dbf23319159cc2fef46283f7450b814e818252" }, - "DependsOn": [ - "ClusterKubectlReadyBarrier200052AF" - ], + "DependsOn": ["ClusterKubectlReadyBarrier200052AF"], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, @@ -3739,17 +3435,10 @@ "Arn" ] }, - "ClientIDList": [ - "sts.amazonaws.com" - ], - "ThumbprintList": [ - "9e99a48a9960b14926bb7f3b02e22da2b0ab7280" - ], + "ClientIDList": ["sts.amazonaws.com"], + "ThumbprintList": ["9e99a48a9960b14926bb7f3b02e22da2b0ab7280"], "Url": { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "OpenIdConnectIssuerUrl" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "OpenIdConnectIssuerUrl"] } }, "UpdateReplacePolicy": "Delete", @@ -3769,16 +3458,11 @@ "Ref": "Cluster9EE0221C" }, "RoleArn": { - "Fn::GetAtt": [ - "ClusterCreationRole360249B6", - "Arn" - ] + "Fn::GetAtt": ["ClusterCreationRole360249B6", "Arn"] }, "PruneLabel": "aws.cdk.eks/prune-c8b6a5b3e6f9f4f1aa9dc400a13c96633da4822b2d" }, - "DependsOn": [ - "ClusterKubectlReadyBarrier200052AF" - ], + "DependsOn": ["ClusterKubectlReadyBarrier200052AF"], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, @@ -3797,10 +3481,7 @@ [ "[{\"kind\":\"Service\",\"apiVersion\":\"v1\",\"metadata\":{\"name\":\"webservice\",\"annotations\":{\"service.beta.kubernetes.io/aws-load-balancer-internal\":\"true\",\"service.beta.kubernetes.io/aws-load-balancer-extra-security-groups\":\"", { - "Fn::GetAtt": [ - "WebServiceSecurityGroupA556AEB5", - "GroupId" - ] + "Fn::GetAtt": ["WebServiceSecurityGroupA556AEB5", "GroupId"] }, "\"},\"labels\":{\"aws.cdk.eks/prune-c84c09bc8d75d4cc4d672e0d3872dcdb35f628dc2c\":\"\"}},\"spec\":{\"type\":\"LoadBalancer\",\"ports\":[{\"port\":9000,\"targetPort\":80}],\"selector\":{\"app\":\"simple-web\"}}}]" ] @@ -3810,16 +3491,11 @@ "Ref": "Cluster9EE0221C" }, "RoleArn": { - "Fn::GetAtt": [ - "ClusterCreationRole360249B6", - "Arn" - ] + "Fn::GetAtt": ["ClusterCreationRole360249B6", "Arn"] }, "PruneLabel": "aws.cdk.eks/prune-c84c09bc8d75d4cc4d672e0d3872dcdb35f628dc2c" }, - "DependsOn": [ - "ClusterKubectlReadyBarrier200052AF" - ], + "DependsOn": ["ClusterKubectlReadyBarrier200052AF"], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, @@ -3836,10 +3512,7 @@ "Ref": "Cluster9EE0221C" }, "RoleArn": { - "Fn::GetAtt": [ - "ClusterCreationRole360249B6", - "Arn" - ] + "Fn::GetAtt": ["ClusterCreationRole360249B6", "Arn"] }, "ObjectType": "service", "ObjectName": "webservice", @@ -3847,9 +3520,7 @@ "JsonPath": ".status.loadBalancer.ingress[0].hostname", "TimeoutSeconds": 300 }, - "DependsOn": [ - "ClusterKubectlReadyBarrier200052AF" - ], + "DependsOn": ["ClusterKubectlReadyBarrier200052AF"], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, @@ -3866,7 +3537,7 @@ }, "/", { - "Ref": "AssetParameters5598bd5ce38da10f7a9c6f8e54d4f50d7c0befd5309540ab64d64985236f2ef9S3BucketC3BFBE73" + "Ref": "AssetParameters4eac204c18d7034bdb83d685748ca8f285edfd054338f3a045a749dbbf285996S3BucketDEC09A4A" }, "/", { @@ -3876,7 +3547,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters5598bd5ce38da10f7a9c6f8e54d4f50d7c0befd5309540ab64d64985236f2ef9S3VersionKeyFA8225D5" + "Ref": "AssetParameters4eac204c18d7034bdb83d685748ca8f285edfd054338f3a045a749dbbf285996S3VersionKey454B1BD5" } ] } @@ -3889,7 +3560,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters5598bd5ce38da10f7a9c6f8e54d4f50d7c0befd5309540ab64d64985236f2ef9S3VersionKeyFA8225D5" + "Ref": "AssetParameters4eac204c18d7034bdb83d685748ca8f285edfd054338f3a045a749dbbf285996S3VersionKey454B1BD5" } ] } @@ -3900,16 +3571,19 @@ }, "Parameters": { "referencetoawscdkeksclustertestClusterCreationRole95F44854Arn": { - "Fn::GetAtt": [ - "ClusterCreationRole360249B6", - "Arn" - ] + "Fn::GetAtt": ["ClusterCreationRole360249B6", "Arn"] + }, + "referencetoawscdkeksclustertestAssetParametersf9e3ed49f5734f267f6dfffed3c6038e2d31d096ca7e70ce257b16aa613a3ffcS3BucketF0C34111Ref": { + "Ref": "AssetParametersf9e3ed49f5734f267f6dfffed3c6038e2d31d096ca7e70ce257b16aa613a3ffcS3Bucket85C441D9" }, - "referencetoawscdkeksclustertestAssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket1516DB0ARef": { - "Ref": "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket14D204F9" + "referencetoawscdkeksclustertestAssetParametersf9e3ed49f5734f267f6dfffed3c6038e2d31d096ca7e70ce257b16aa613a3ffcS3VersionKey01A2F046Ref": { + "Ref": "AssetParametersf9e3ed49f5734f267f6dfffed3c6038e2d31d096ca7e70ce257b16aa613a3ffcS3VersionKeyABBEC6F6" }, - "referencetoawscdkeksclustertestAssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKey2B8F3ED3Ref": { - "Ref": "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyDE8A2F1F" + "referencetoawscdkeksclustertestAssetParameters80bcd5b0641df4315e277c71a1069094a5d7c76f9e2565c46b68a990c522eaefS3Bucket1C7DAFD3Ref": { + "Ref": "AssetParameters80bcd5b0641df4315e277c71a1069094a5d7c76f9e2565c46b68a990c522eaefS3Bucket208EDB42" + }, + "referencetoawscdkeksclustertestAssetParameters80bcd5b0641df4315e277c71a1069094a5d7c76f9e2565c46b68a990c522eaefS3VersionKey6FBDB806Ref": { + "Ref": "AssetParameters80bcd5b0641df4315e277c71a1069094a5d7c76f9e2565c46b68a990c522eaefS3VersionKey08C22772" }, "referencetoawscdkeksclustertestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket0815E7B5Ref": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" @@ -3935,7 +3609,7 @@ }, "/", { - "Ref": "AssetParameterscbbfa09db37e6a37ee43fbb48d73d4d96f216270558c932674a48e856763ce79S3Bucket2C7FA0F3" + "Ref": "AssetParameters0504b861a4c2a9b4228d6d618fb8a60f19b1c36575b96db9f1716e0eb6a2ee52S3Bucket1BC62BBD" }, "/", { @@ -3945,7 +3619,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameterscbbfa09db37e6a37ee43fbb48d73d4d96f216270558c932674a48e856763ce79S3VersionKey4D3075F9" + "Ref": "AssetParameters0504b861a4c2a9b4228d6d618fb8a60f19b1c36575b96db9f1716e0eb6a2ee52S3VersionKey94294964" } ] } @@ -3958,7 +3632,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameterscbbfa09db37e6a37ee43fbb48d73d4d96f216270558c932674a48e856763ce79S3VersionKey4D3075F9" + "Ref": "AssetParameters0504b861a4c2a9b4228d6d618fb8a60f19b1c36575b96db9f1716e0eb6a2ee52S3VersionKey94294964" } ] } @@ -3969,22 +3643,16 @@ }, "Parameters": { "referencetoawscdkeksclustertestClusterD76DFF87Arn": { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "Arn" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "Arn"] }, "referencetoawscdkeksclustertestClusterCreationRole95F44854Arn": { - "Fn::GetAtt": [ - "ClusterCreationRole360249B6", - "Arn" - ] + "Fn::GetAtt": ["ClusterCreationRole360249B6", "Arn"] }, - "referencetoawscdkeksclustertestAssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3Bucket174F3576Ref": { - "Ref": "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3Bucket008DBB35" + "referencetoawscdkeksclustertestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3Bucket3929FA93Ref": { + "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9" }, - "referencetoawscdkeksclustertestAssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKeyE8595856Ref": { - "Ref": "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey97C3E1A0" + "referencetoawscdkeksclustertestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKey14530D6BRef": { + "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421" }, "referencetoawscdkeksclustertestVpcPrivateSubnet1Subnet32A4EC2ARef": { "Ref": "VpcPrivateSubnet1Subnet536B997A" @@ -3996,10 +3664,7 @@ "Ref": "VpcPrivateSubnet3SubnetF258B56E" }, "referencetoawscdkeksclustertestClusterD76DFF87ClusterSecurityGroupId": { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "ClusterSecurityGroupId" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "ClusterSecurityGroupId"] }, "referencetoawscdkeksclustertestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketB4E9C142Ref": { "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7" @@ -4007,11 +3672,11 @@ "referencetoawscdkeksclustertestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKey1C7C1F5FRef": { "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" }, - "referencetoawscdkeksclustertestAssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3BucketBEBB0185Ref": { - "Ref": "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3BucketD4F52C82" + "referencetoawscdkeksclustertestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3Bucket6ADB5CE5Ref": { + "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998" }, - "referencetoawscdkeksclustertestAssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3VersionKey8BEC8371Ref": { - "Ref": "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3VersionKey9D243E8D" + "referencetoawscdkeksclustertestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKey314C5B11Ref": { + "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565" }, "referencetoawscdkeksclustertestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket0815E7B5Ref": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" @@ -4062,17 +3727,12 @@ "Ref": "Cluster9EE0221C" }, "RoleArn": { - "Fn::GetAtt": [ - "ClusterCreationRole360249B6", - "Arn" - ] + "Fn::GetAtt": ["ClusterCreationRole360249B6", "Arn"] }, "PruneLabel": "aws.cdk.eks/prune-c89cbcc5d9bdd35cfc69c0334c0a9af21d1e0e372e", "SkipValidation": true }, - "DependsOn": [ - "ClusterKubectlReadyBarrier200052AF" - ], + "DependsOn": ["ClusterKubectlReadyBarrier200052AF"], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, @@ -4249,9 +3909,7 @@ }, "Runtime": "nodejs12.x" }, - "DependsOn": [ - "AWSCDKCfnUtilsProviderCustomResourceProviderRoleFE0EE867" - ] + "DependsOn": ["AWSCDKCfnUtilsProviderCustomResourceProviderRoleFE0EE867"] }, "WebServiceSecurityGroupA556AEB5": { "Type": "AWS::EC2::SecurityGroup", @@ -4276,16 +3934,10 @@ "Description": "allow http 9000 access from myself", "FromPort": 9000, "GroupId": { - "Fn::GetAtt": [ - "WebServiceSecurityGroupA556AEB5", - "GroupId" - ] + "Fn::GetAtt": ["WebServiceSecurityGroupA556AEB5", "GroupId"] }, "SourceSecurityGroupId": { - "Fn::GetAtt": [ - "WebServiceSecurityGroupA556AEB5", - "GroupId" - ] + "Fn::GetAtt": ["WebServiceSecurityGroupA556AEB5", "GroupId"] }, "ToPort": 9000 } @@ -4375,10 +4027,7 @@ } }, "Role": { - "Fn::GetAtt": [ - "ServicePingerFunctionServiceRole3120191B", - "Arn" - ] + "Fn::GetAtt": ["ServicePingerFunctionServiceRole3120191B", "Arn"] }, "Handler": "index.handler", "Runtime": "python3.6", @@ -4386,10 +4035,7 @@ "VpcConfig": { "SecurityGroupIds": [ { - "Fn::GetAtt": [ - "WebServiceSecurityGroupA556AEB5", - "GroupId" - ] + "Fn::GetAtt": ["WebServiceSecurityGroupA556AEB5", "GroupId"] } ], "SubnetIds": [ @@ -4405,9 +4051,7 @@ ] } }, - "DependsOn": [ - "ServicePingerFunctionServiceRole3120191B" - ] + "DependsOn": ["ServicePingerFunctionServiceRole3120191B"] }, "ServicePingerProviderframeworkonEventServiceRole3DB083B7": { "Type": "AWS::IAM::Role", @@ -4449,10 +4093,7 @@ "Action": "lambda:InvokeFunction", "Effect": "Allow", "Resource": { - "Fn::GetAtt": [ - "ServicePingerFunctionADF51BAF", - "Arn" - ] + "Fn::GetAtt": ["ServicePingerFunctionADF51BAF", "Arn"] } } ], @@ -4517,10 +4158,7 @@ "Environment": { "Variables": { "USER_ON_EVENT_FUNCTION_ARN": { - "Fn::GetAtt": [ - "ServicePingerFunctionADF51BAF", - "Arn" - ] + "Fn::GetAtt": ["ServicePingerFunctionADF51BAF", "Arn"] } } }, @@ -4537,10 +4175,7 @@ "Type": "AWS::CloudFormation::CustomResource", "Properties": { "ServiceToken": { - "Fn::GetAtt": [ - "ServicePingerProviderframeworkonEventEC59DE20", - "Arn" - ] + "Fn::GetAtt": ["ServicePingerProviderframeworkonEventEC59DE20", "Arn"] }, "Url": { "Fn::Join": [ @@ -4574,10 +4209,7 @@ }, " --region test-region --role-arn ", { - "Fn::GetAtt": [ - "AdminRole38563C57", - "Arn" - ] + "Fn::GetAtt": ["AdminRole38563C57", "Arn"] } ] ] @@ -4594,10 +4226,7 @@ }, " --region test-region --role-arn ", { - "Fn::GetAtt": [ - "AdminRole38563C57", - "Arn" - ] + "Fn::GetAtt": ["AdminRole38563C57", "Arn"] } ] ] @@ -4605,50 +4234,32 @@ }, "Response": { "Value": { - "Fn::GetAtt": [ - "ServicePinger01F6DA06", - "Value" - ] + "Fn::GetAtt": ["ServicePinger01F6DA06", "Value"] } }, "ClusterEndpoint": { "Value": { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "Endpoint" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "Endpoint"] } }, "ClusterArn": { "Value": { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "Arn" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "Arn"] } }, "ClusterCertificateAuthorityData": { "Value": { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "CertificateAuthorityData" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "CertificateAuthorityData"] } }, "ClusterSecurityGroupId": { "Value": { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "ClusterSecurityGroupId" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "ClusterSecurityGroupId"] } }, "ClusterEncryptionConfigKeyArn": { "Value": { - "Fn::GetAtt": [ - "Cluster9EE0221C", - "EncryptionConfigKeyArn" - ] + "Fn::GetAtt": ["Cluster9EE0221C", "EncryptionConfigKeyArn"] } }, "ClusterName": { @@ -4658,17 +4269,29 @@ } }, "Parameters": { - "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket14D204F9": { + "AssetParametersf9e3ed49f5734f267f6dfffed3c6038e2d31d096ca7e70ce257b16aa613a3ffcS3Bucket85C441D9": { + "Type": "String", + "Description": "S3 bucket for asset \"f9e3ed49f5734f267f6dfffed3c6038e2d31d096ca7e70ce257b16aa613a3ffc\"" + }, + "AssetParametersf9e3ed49f5734f267f6dfffed3c6038e2d31d096ca7e70ce257b16aa613a3ffcS3VersionKeyABBEC6F6": { + "Type": "String", + "Description": "S3 key for asset version \"f9e3ed49f5734f267f6dfffed3c6038e2d31d096ca7e70ce257b16aa613a3ffc\"" + }, + "AssetParametersf9e3ed49f5734f267f6dfffed3c6038e2d31d096ca7e70ce257b16aa613a3ffcArtifactHashC6D6393C": { + "Type": "String", + "Description": "Artifact hash for asset \"f9e3ed49f5734f267f6dfffed3c6038e2d31d096ca7e70ce257b16aa613a3ffc\"" + }, + "AssetParameters80bcd5b0641df4315e277c71a1069094a5d7c76f9e2565c46b68a990c522eaefS3Bucket208EDB42": { "Type": "String", - "Description": "S3 bucket for asset \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + "Description": "S3 bucket for asset \"80bcd5b0641df4315e277c71a1069094a5d7c76f9e2565c46b68a990c522eaef\"" }, - "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyDE8A2F1F": { + "AssetParameters80bcd5b0641df4315e277c71a1069094a5d7c76f9e2565c46b68a990c522eaefS3VersionKey08C22772": { "Type": "String", - "Description": "S3 key for asset version \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + "Description": "S3 key for asset version \"80bcd5b0641df4315e277c71a1069094a5d7c76f9e2565c46b68a990c522eaef\"" }, - "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaArtifactHash54822A43": { + "AssetParameters80bcd5b0641df4315e277c71a1069094a5d7c76f9e2565c46b68a990c522eaefArtifactHash861FF133": { "Type": "String", - "Description": "Artifact hash for asset \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + "Description": "Artifact hash for asset \"80bcd5b0641df4315e277c71a1069094a5d7c76f9e2565c46b68a990c522eaef\"" }, "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { "Type": "String", @@ -4682,17 +4305,17 @@ "Type": "String", "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" }, - "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3Bucket008DBB35": { + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9": { "Type": "String", - "Description": "S3 bucket for asset \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + "Description": "S3 bucket for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" }, - "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey97C3E1A0": { + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421": { "Type": "String", - "Description": "S3 key for asset version \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + "Description": "S3 key for asset version \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" }, - "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757ArtifactHashF584A7D8": { + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10ArtifactHash528547CD": { "Type": "String", - "Description": "Artifact hash for asset \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + "Description": "Artifact hash for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" }, "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { "Type": "String", @@ -4706,17 +4329,17 @@ "Type": "String", "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" }, - "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3BucketD4F52C82": { + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998": { "Type": "String", - "Description": "S3 bucket for asset \"cd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793\"" + "Description": "S3 bucket for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3VersionKey9D243E8D": { + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565": { "Type": "String", - "Description": "S3 key for asset version \"cd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793\"" + "Description": "S3 key for asset version \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793ArtifactHash42EBA5B2": { + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eArtifactHash4654D012": { "Type": "String", - "Description": "Artifact hash for asset \"cd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793\"" + "Description": "Artifact hash for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, "AssetParametersb7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4S3BucketF7BC1777": { "Type": "String", @@ -4754,29 +4377,29 @@ "Type": "String", "Description": "Artifact hash for asset \"5f49893093e1ad14831626016699156d48da5f0890f19eb930bc3c46cf5f636d\"" }, - "AssetParameters5598bd5ce38da10f7a9c6f8e54d4f50d7c0befd5309540ab64d64985236f2ef9S3BucketC3BFBE73": { + "AssetParameters4eac204c18d7034bdb83d685748ca8f285edfd054338f3a045a749dbbf285996S3BucketDEC09A4A": { "Type": "String", - "Description": "S3 bucket for asset \"5598bd5ce38da10f7a9c6f8e54d4f50d7c0befd5309540ab64d64985236f2ef9\"" + "Description": "S3 bucket for asset \"4eac204c18d7034bdb83d685748ca8f285edfd054338f3a045a749dbbf285996\"" }, - "AssetParameters5598bd5ce38da10f7a9c6f8e54d4f50d7c0befd5309540ab64d64985236f2ef9S3VersionKeyFA8225D5": { + "AssetParameters4eac204c18d7034bdb83d685748ca8f285edfd054338f3a045a749dbbf285996S3VersionKey454B1BD5": { "Type": "String", - "Description": "S3 key for asset version \"5598bd5ce38da10f7a9c6f8e54d4f50d7c0befd5309540ab64d64985236f2ef9\"" + "Description": "S3 key for asset version \"4eac204c18d7034bdb83d685748ca8f285edfd054338f3a045a749dbbf285996\"" }, - "AssetParameters5598bd5ce38da10f7a9c6f8e54d4f50d7c0befd5309540ab64d64985236f2ef9ArtifactHash8F06BD93": { + "AssetParameters4eac204c18d7034bdb83d685748ca8f285edfd054338f3a045a749dbbf285996ArtifactHashC56B9B67": { "Type": "String", - "Description": "Artifact hash for asset \"5598bd5ce38da10f7a9c6f8e54d4f50d7c0befd5309540ab64d64985236f2ef9\"" + "Description": "Artifact hash for asset \"4eac204c18d7034bdb83d685748ca8f285edfd054338f3a045a749dbbf285996\"" }, - "AssetParameterscbbfa09db37e6a37ee43fbb48d73d4d96f216270558c932674a48e856763ce79S3Bucket2C7FA0F3": { + "AssetParameters0504b861a4c2a9b4228d6d618fb8a60f19b1c36575b96db9f1716e0eb6a2ee52S3Bucket1BC62BBD": { "Type": "String", - "Description": "S3 bucket for asset \"cbbfa09db37e6a37ee43fbb48d73d4d96f216270558c932674a48e856763ce79\"" + "Description": "S3 bucket for asset \"0504b861a4c2a9b4228d6d618fb8a60f19b1c36575b96db9f1716e0eb6a2ee52\"" }, - "AssetParameterscbbfa09db37e6a37ee43fbb48d73d4d96f216270558c932674a48e856763ce79S3VersionKey4D3075F9": { + "AssetParameters0504b861a4c2a9b4228d6d618fb8a60f19b1c36575b96db9f1716e0eb6a2ee52S3VersionKey94294964": { "Type": "String", - "Description": "S3 key for asset version \"cbbfa09db37e6a37ee43fbb48d73d4d96f216270558c932674a48e856763ce79\"" + "Description": "S3 key for asset version \"0504b861a4c2a9b4228d6d618fb8a60f19b1c36575b96db9f1716e0eb6a2ee52\"" }, - "AssetParameterscbbfa09db37e6a37ee43fbb48d73d4d96f216270558c932674a48e856763ce79ArtifactHashF865E7E6": { + "AssetParameters0504b861a4c2a9b4228d6d618fb8a60f19b1c36575b96db9f1716e0eb6a2ee52ArtifactHash179183BB": { "Type": "String", - "Description": "Artifact hash for asset \"cbbfa09db37e6a37ee43fbb48d73d4d96f216270558c932674a48e856763ce79\"" + "Description": "Artifact hash for asset \"0504b861a4c2a9b4228d6d618fb8a60f19b1c36575b96db9f1716e0eb6a2ee52\"" }, "SsmParameterValueawsserviceeksoptimizedami121amazonlinux2recommendedimageidC96584B6F00A464EAD1953AFF4B05118Parameter": { "Type": "AWS::SSM::Parameter::Value", @@ -4795,4 +4418,4 @@ "Default": "/aws/service/eks/optimized-ami/1.21/amazon-linux-2-gpu/recommended/image_id" } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-eks/test/integ.eks-oidc-provider.expected.json b/packages/@aws-cdk/aws-eks/test/integ.eks-oidc-provider.expected.json index 0f0a5c61cdf67..e6c0db319aae8 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.eks-oidc-provider.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.eks-oidc-provider.expected.json @@ -9,12 +9,8 @@ "Arn" ] }, - "ClientIDList": [ - "sts.amazonaws.com" - ], - "ThumbprintList": [ - "9e99a48a9960b14926bb7f3b02e22da2b0ab7280" - ], + "ClientIDList": ["sts.amazonaws.com"], + "ThumbprintList": ["9e99a48a9960b14926bb7f3b02e22da2b0ab7280"], "Url": { "Fn::Join": [ "", @@ -145,4 +141,4 @@ "Description": "Artifact hash for asset \"b7d38dc0eeb2c5d024919020e09d2590b68559eab4a5264c3b1aa7a429d1edd4\"" } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.expected.json b/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.expected.json index 895978548bc4c..8b4f65a8578c6 100644 --- a/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.expected.json +++ b/packages/@aws-cdk/aws-eks/test/integ.fargate-cluster.expected.json @@ -84,9 +84,7 @@ "Ref": "FargateClusterDefaultVpcIGWFD9278DA" } }, - "DependsOn": [ - "FargateClusterDefaultVpcVPCGWA7F012E1" - ] + "DependsOn": ["FargateClusterDefaultVpcVPCGWA7F012E1"] }, "FargateClusterDefaultVpcPublicSubnet1EIP0093A4E0": { "Type": "AWS::EC2::EIP", @@ -197,9 +195,7 @@ "Ref": "FargateClusterDefaultVpcIGWFD9278DA" } }, - "DependsOn": [ - "FargateClusterDefaultVpcVPCGWA7F012E1" - ] + "DependsOn": ["FargateClusterDefaultVpcVPCGWA7F012E1"] }, "FargateClusterDefaultVpcPublicSubnet2EIPA4C07B68": { "Type": "AWS::EC2::EIP", @@ -310,9 +306,7 @@ "Ref": "FargateClusterDefaultVpcIGWFD9278DA" } }, - "DependsOn": [ - "FargateClusterDefaultVpcVPCGWA7F012E1" - ] + "DependsOn": ["FargateClusterDefaultVpcVPCGWA7F012E1"] }, "FargateClusterDefaultVpcPublicSubnet3EIP46E028EF": { "Type": "AWS::EC2::EIP", @@ -705,10 +699,7 @@ "Action": "iam:PassRole", "Effect": "Allow", "Resource": { - "Fn::GetAtt": [ - "FargateClusterRole8E36B33A", - "Arn" - ] + "Fn::GetAtt": ["FargateClusterRole8E36B33A", "Arn"] } }, { @@ -724,9 +715,7 @@ "eks:UntagResource" ], "Effect": "Allow", - "Resource": [ - "*" - ] + "Resource": ["*"] }, { "Action": [ @@ -737,10 +726,7 @@ "Resource": "*" }, { - "Action": [ - "iam:GetRole", - "iam:listAttachedRolePolicies" - ], + "Action": ["iam:GetRole", "iam:listAttachedRolePolicies"], "Effect": "Allow", "Resource": "*" }, @@ -830,10 +816,7 @@ "Config": { "version": "1.21", "roleArn": { - "Fn::GetAtt": [ - "FargateClusterRole8E36B33A", - "Arn" - ] + "Fn::GetAtt": ["FargateClusterRole8E36B33A", "Arn"] }, "resourcesVpcConfig": { "subnetIds": [ @@ -869,10 +852,7 @@ } }, "AssumeRoleArn": { - "Fn::GetAtt": [ - "FargateClusterCreationRole8C524AD8", - "Arn" - ] + "Fn::GetAtt": ["FargateClusterCreationRole8C524AD8", "Arn"] }, "AttributesRevision": 2 }, @@ -973,17 +953,11 @@ [ "[{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"aws-auth\",\"namespace\":\"kube-system\"},\"data\":{\"mapRoles\":\"[{\\\"rolearn\\\":\\\"", { - "Fn::GetAtt": [ - "FargateClusterMastersRole50BAF9FD", - "Arn" - ] + "Fn::GetAtt": ["FargateClusterMastersRole50BAF9FD", "Arn"] }, "\\\",\\\"username\\\":\\\"", { - "Fn::GetAtt": [ - "FargateClusterMastersRole50BAF9FD", - "Arn" - ] + "Fn::GetAtt": ["FargateClusterMastersRole50BAF9FD", "Arn"] }, "\\\",\\\"groups\\\":[\\\"system:masters\\\"]},{\\\"rolearn\\\":\\\"", { @@ -1000,16 +974,11 @@ "Ref": "FargateCluster019F03E8" }, "RoleArn": { - "Fn::GetAtt": [ - "FargateClusterCreationRole8C524AD8", - "Arn" - ] + "Fn::GetAtt": ["FargateClusterCreationRole8C524AD8", "Arn"] }, "Overwrite": true }, - "DependsOn": [ - "FargateClusterKubectlReadyBarrier93746934" - ], + "DependsOn": ["FargateClusterKubectlReadyBarrier93746934"], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, @@ -1030,16 +999,11 @@ "Ref": "FargateCluster019F03E8" }, "RoleArn": { - "Fn::GetAtt": [ - "FargateClusterCreationRole8C524AD8", - "Arn" - ] + "Fn::GetAtt": ["FargateClusterCreationRole8C524AD8", "Arn"] }, "PatchType": "strategic" }, - "DependsOn": [ - "FargateClusterKubectlReadyBarrier93746934" - ], + "DependsOn": ["FargateClusterKubectlReadyBarrier93746934"], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, @@ -1084,10 +1048,7 @@ ] }, "AssumeRoleArn": { - "Fn::GetAtt": [ - "FargateClusterCreationRole8C524AD8", - "Arn" - ] + "Fn::GetAtt": ["FargateClusterCreationRole8C524AD8", "Arn"] }, "Config": { "clusterName": { @@ -1125,7 +1086,7 @@ }, "/", { - "Ref": "AssetParameters8f90971131eea6a356f7cfb4997f4b70bb577cf34d007550f5e28c342f6c47f7S3Bucket3C7D361B" + "Ref": "AssetParameters4c4969b4a5efb3bab0be954e7004f3c4f427bb7ebcf996b97782bff6d1c7c8c1S3BucketDA43FC2B" }, "/", { @@ -1135,7 +1096,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters8f90971131eea6a356f7cfb4997f4b70bb577cf34d007550f5e28c342f6c47f7S3VersionKey455B40AC" + "Ref": "AssetParameters4c4969b4a5efb3bab0be954e7004f3c4f427bb7ebcf996b97782bff6d1c7c8c1S3VersionKey8EEC8DF7" } ] } @@ -1148,7 +1109,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters8f90971131eea6a356f7cfb4997f4b70bb577cf34d007550f5e28c342f6c47f7S3VersionKey455B40AC" + "Ref": "AssetParameters4c4969b4a5efb3bab0be954e7004f3c4f427bb7ebcf996b97782bff6d1c7c8c1S3VersionKey8EEC8DF7" } ] } @@ -1159,16 +1120,19 @@ }, "Parameters": { "referencetoawscdkeksfargateclustertestFargateClusterCreationRoleFB2229CFArn": { - "Fn::GetAtt": [ - "FargateClusterCreationRole8C524AD8", - "Arn" - ] + "Fn::GetAtt": ["FargateClusterCreationRole8C524AD8", "Arn"] + }, + "referencetoawscdkeksfargateclustertestAssetParameters2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7eS3Bucket276E8116Ref": { + "Ref": "AssetParameters2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7eS3Bucket575E2F4C" }, - "referencetoawscdkeksfargateclustertestAssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket122A6EA8Ref": { - "Ref": "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket14D204F9" + "referencetoawscdkeksfargateclustertestAssetParameters2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7eS3VersionKey0311C20FRef": { + "Ref": "AssetParameters2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7eS3VersionKeyFB3EB544" }, - "referencetoawscdkeksfargateclustertestAssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKey56570425Ref": { - "Ref": "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyDE8A2F1F" + "referencetoawscdkeksfargateclustertestAssetParametersd1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6S3Bucket4227CCC8Ref": { + "Ref": "AssetParametersd1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6S3Bucket04F6B25B" + }, + "referencetoawscdkeksfargateclustertestAssetParametersd1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6S3VersionKeyD7B57F35Ref": { + "Ref": "AssetParametersd1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6S3VersionKey6A7508AF" }, "referencetoawscdkeksfargateclustertestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket8EEF0922Ref": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" @@ -1194,7 +1158,7 @@ }, "/", { - "Ref": "AssetParametersb8180d6aa1f3be56dff3c797e0e2b7efda1b899b5ce276930cbccf6ce61b6ff9S3BucketDEA37CED" + "Ref": "AssetParameters43ce4fd59055093cb506c39ae8eccdf3cdbe53b4d310ac381b3a9db3c523d730S3Bucket9850F63C" }, "/", { @@ -1204,7 +1168,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersb8180d6aa1f3be56dff3c797e0e2b7efda1b899b5ce276930cbccf6ce61b6ff9S3VersionKey2C845455" + "Ref": "AssetParameters43ce4fd59055093cb506c39ae8eccdf3cdbe53b4d310ac381b3a9db3c523d730S3VersionKey916810E5" } ] } @@ -1217,7 +1181,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersb8180d6aa1f3be56dff3c797e0e2b7efda1b899b5ce276930cbccf6ce61b6ff9S3VersionKey2C845455" + "Ref": "AssetParameters43ce4fd59055093cb506c39ae8eccdf3cdbe53b4d310ac381b3a9db3c523d730S3VersionKey916810E5" } ] } @@ -1228,22 +1192,16 @@ }, "Parameters": { "referencetoawscdkeksfargateclustertestFargateCluster8588769EArn": { - "Fn::GetAtt": [ - "FargateCluster019F03E8", - "Arn" - ] + "Fn::GetAtt": ["FargateCluster019F03E8", "Arn"] }, "referencetoawscdkeksfargateclustertestFargateClusterCreationRoleFB2229CFArn": { - "Fn::GetAtt": [ - "FargateClusterCreationRole8C524AD8", - "Arn" - ] + "Fn::GetAtt": ["FargateClusterCreationRole8C524AD8", "Arn"] }, - "referencetoawscdkeksfargateclustertestAssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3Bucket78A48DE4Ref": { - "Ref": "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3Bucket008DBB35" + "referencetoawscdkeksfargateclustertestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC4DF4301Ref": { + "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9" }, - "referencetoawscdkeksfargateclustertestAssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey69DB854ARef": { - "Ref": "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey97C3E1A0" + "referencetoawscdkeksfargateclustertestAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKey013AD4DERef": { + "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421" }, "referencetoawscdkeksfargateclustertestFargateClusterDefaultVpcPrivateSubnet1Subnet0278E6BCRef": { "Ref": "FargateClusterDefaultVpcPrivateSubnet1Subnet50EA43AA" @@ -1255,10 +1213,7 @@ "Ref": "FargateClusterDefaultVpcPrivateSubnet3Subnet1F8A52F1" }, "referencetoawscdkeksfargateclustertestFargateCluster8588769EClusterSecurityGroupId": { - "Fn::GetAtt": [ - "FargateCluster019F03E8", - "ClusterSecurityGroupId" - ] + "Fn::GetAtt": ["FargateCluster019F03E8", "ClusterSecurityGroupId"] }, "referencetoawscdkeksfargateclustertestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3Bucket4F20F642Ref": { "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7" @@ -1266,11 +1221,11 @@ "referencetoawscdkeksfargateclustertestAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyB82BAEF8Ref": { "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" }, - "referencetoawscdkeksfargateclustertestAssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3BucketC0936E6ARef": { - "Ref": "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3BucketD4F52C82" + "referencetoawscdkeksfargateclustertestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3Bucket899EE5ABRef": { + "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998" }, - "referencetoawscdkeksfargateclustertestAssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3VersionKey3CFF45CERef": { - "Ref": "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3VersionKey9D243E8D" + "referencetoawscdkeksfargateclustertestAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKey1296E713Ref": { + "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565" }, "referencetoawscdkeksfargateclustertestAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3Bucket8EEF0922Ref": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" @@ -1296,10 +1251,7 @@ }, " --region test-region --role-arn ", { - "Fn::GetAtt": [ - "FargateClusterMastersRole50BAF9FD", - "Arn" - ] + "Fn::GetAtt": ["FargateClusterMastersRole50BAF9FD", "Arn"] } ] ] @@ -1316,10 +1268,7 @@ }, " --region test-region --role-arn ", { - "Fn::GetAtt": [ - "FargateClusterMastersRole50BAF9FD", - "Arn" - ] + "Fn::GetAtt": ["FargateClusterMastersRole50BAF9FD", "Arn"] } ] ] @@ -1327,17 +1276,29 @@ } }, "Parameters": { - "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket14D204F9": { + "AssetParameters2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7eS3Bucket575E2F4C": { + "Type": "String", + "Description": "S3 bucket for asset \"2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7e\"" + }, + "AssetParameters2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7eS3VersionKeyFB3EB544": { + "Type": "String", + "Description": "S3 key for asset version \"2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7e\"" + }, + "AssetParameters2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7eArtifactHashDB8E8B5A": { + "Type": "String", + "Description": "Artifact hash for asset \"2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7e\"" + }, + "AssetParametersd1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6S3Bucket04F6B25B": { "Type": "String", - "Description": "S3 bucket for asset \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + "Description": "S3 bucket for asset \"d1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6\"" }, - "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyDE8A2F1F": { + "AssetParametersd1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6S3VersionKey6A7508AF": { "Type": "String", - "Description": "S3 key for asset version \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + "Description": "S3 key for asset version \"d1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6\"" }, - "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaArtifactHash54822A43": { + "AssetParametersd1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6ArtifactHashF7473C14": { "Type": "String", - "Description": "Artifact hash for asset \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + "Description": "Artifact hash for asset \"d1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6\"" }, "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { "Type": "String", @@ -1351,17 +1312,17 @@ "Type": "String", "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" }, - "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3Bucket008DBB35": { + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9": { "Type": "String", - "Description": "S3 bucket for asset \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + "Description": "S3 bucket for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" }, - "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey97C3E1A0": { + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421": { "Type": "String", - "Description": "S3 key for asset version \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + "Description": "S3 key for asset version \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" }, - "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757ArtifactHashF584A7D8": { + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10ArtifactHash528547CD": { "Type": "String", - "Description": "Artifact hash for asset \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + "Description": "Artifact hash for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" }, "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { "Type": "String", @@ -1375,41 +1336,41 @@ "Type": "String", "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" }, - "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3BucketD4F52C82": { + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998": { "Type": "String", - "Description": "S3 bucket for asset \"cd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793\"" + "Description": "S3 bucket for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793S3VersionKey9D243E8D": { + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565": { "Type": "String", - "Description": "S3 key for asset version \"cd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793\"" + "Description": "S3 key for asset version \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParameterscd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793ArtifactHash42EBA5B2": { + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eArtifactHash4654D012": { "Type": "String", - "Description": "Artifact hash for asset \"cd15c6fb3a2eee6979f62b25e35a7df43d506bc62054eb8bf9355d1a71a3a793\"" + "Description": "Artifact hash for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParameters8f90971131eea6a356f7cfb4997f4b70bb577cf34d007550f5e28c342f6c47f7S3Bucket3C7D361B": { + "AssetParameters4c4969b4a5efb3bab0be954e7004f3c4f427bb7ebcf996b97782bff6d1c7c8c1S3BucketDA43FC2B": { "Type": "String", - "Description": "S3 bucket for asset \"8f90971131eea6a356f7cfb4997f4b70bb577cf34d007550f5e28c342f6c47f7\"" + "Description": "S3 bucket for asset \"4c4969b4a5efb3bab0be954e7004f3c4f427bb7ebcf996b97782bff6d1c7c8c1\"" }, - "AssetParameters8f90971131eea6a356f7cfb4997f4b70bb577cf34d007550f5e28c342f6c47f7S3VersionKey455B40AC": { + "AssetParameters4c4969b4a5efb3bab0be954e7004f3c4f427bb7ebcf996b97782bff6d1c7c8c1S3VersionKey8EEC8DF7": { "Type": "String", - "Description": "S3 key for asset version \"8f90971131eea6a356f7cfb4997f4b70bb577cf34d007550f5e28c342f6c47f7\"" + "Description": "S3 key for asset version \"4c4969b4a5efb3bab0be954e7004f3c4f427bb7ebcf996b97782bff6d1c7c8c1\"" }, - "AssetParameters8f90971131eea6a356f7cfb4997f4b70bb577cf34d007550f5e28c342f6c47f7ArtifactHashA258B8DC": { + "AssetParameters4c4969b4a5efb3bab0be954e7004f3c4f427bb7ebcf996b97782bff6d1c7c8c1ArtifactHashBE7188C3": { "Type": "String", - "Description": "Artifact hash for asset \"8f90971131eea6a356f7cfb4997f4b70bb577cf34d007550f5e28c342f6c47f7\"" + "Description": "Artifact hash for asset \"4c4969b4a5efb3bab0be954e7004f3c4f427bb7ebcf996b97782bff6d1c7c8c1\"" }, - "AssetParametersb8180d6aa1f3be56dff3c797e0e2b7efda1b899b5ce276930cbccf6ce61b6ff9S3BucketDEA37CED": { + "AssetParameters43ce4fd59055093cb506c39ae8eccdf3cdbe53b4d310ac381b3a9db3c523d730S3Bucket9850F63C": { "Type": "String", - "Description": "S3 bucket for asset \"b8180d6aa1f3be56dff3c797e0e2b7efda1b899b5ce276930cbccf6ce61b6ff9\"" + "Description": "S3 bucket for asset \"43ce4fd59055093cb506c39ae8eccdf3cdbe53b4d310ac381b3a9db3c523d730\"" }, - "AssetParametersb8180d6aa1f3be56dff3c797e0e2b7efda1b899b5ce276930cbccf6ce61b6ff9S3VersionKey2C845455": { + "AssetParameters43ce4fd59055093cb506c39ae8eccdf3cdbe53b4d310ac381b3a9db3c523d730S3VersionKey916810E5": { "Type": "String", - "Description": "S3 key for asset version \"b8180d6aa1f3be56dff3c797e0e2b7efda1b899b5ce276930cbccf6ce61b6ff9\"" + "Description": "S3 key for asset version \"43ce4fd59055093cb506c39ae8eccdf3cdbe53b4d310ac381b3a9db3c523d730\"" }, - "AssetParametersb8180d6aa1f3be56dff3c797e0e2b7efda1b899b5ce276930cbccf6ce61b6ff9ArtifactHashAC123599": { + "AssetParameters43ce4fd59055093cb506c39ae8eccdf3cdbe53b4d310ac381b3a9db3c523d730ArtifactHash20D7E89E": { "Type": "String", - "Description": "Artifact hash for asset \"b8180d6aa1f3be56dff3c797e0e2b7efda1b899b5ce276930cbccf6ce61b6ff9\"" + "Description": "Artifact hash for asset \"43ce4fd59055093cb506c39ae8eccdf3cdbe53b4d310ac381b3a9db3c523d730\"" } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-eks/test/user-data.test.ts b/packages/@aws-cdk/aws-eks/test/user-data.test.ts index a7ed42a5f3759..2e808ed723bca 100644 --- a/packages/@aws-cdk/aws-eks/test/user-data.test.ts +++ b/packages/@aws-cdk/aws-eks/test/user-data.test.ts @@ -35,8 +35,66 @@ describe('user data', () => { }, '/opt/aws/bin/cfn-signal --exit-code $? --stack my-stack --resource ASG46ED3070 --region us-west-33', ]); + }); + + test('imported cluster without clusterEndpoint', () => { + // GIVEN + const { asg, stack, cluster } = newFixtures(); + + const importedCluster = Cluster.fromClusterAttributes(stack, 'ImportedCluster', { + clusterName: cluster.clusterName, + openIdConnectProvider: cluster.openIdConnectProvider, + clusterCertificateAuthorityData: cluster.clusterCertificateAuthorityData, + }); + + // WHEN + const userData = stack.resolve(renderAmazonLinuxUserData(importedCluster, asg)); + + // THEN + expect(userData).toEqual([ + 'set -o xtrace', + { + 'Fn::Join': [ + '', + [ + '/etc/eks/bootstrap.sh ', + { Ref: 'clusterC5B25D0D' }, + ' --kubelet-extra-args "--node-labels lifecycle=OnDemand" --use-max-pods true', + ], + ], + }, + '/opt/aws/bin/cfn-signal --exit-code $? --stack my-stack --resource ASG46ED3070 --region us-west-33', + ]); + }); + + test('imported cluster without clusterCertificateAuthorityData', () => { + // GIVEN + const { asg, stack, cluster } = newFixtures(); + const importedCluster = Cluster.fromClusterAttributes(stack, 'ImportedCluster', { + clusterName: cluster.clusterName, + openIdConnectProvider: cluster.openIdConnectProvider, + clusterEndpoint: cluster.clusterEndpoint, + }); + // WHEN + const userData = stack.resolve(renderAmazonLinuxUserData(importedCluster, asg)); + + // THEN + expect(userData).toEqual([ + 'set -o xtrace', + { + 'Fn::Join': [ + '', + [ + '/etc/eks/bootstrap.sh ', + { Ref: 'clusterC5B25D0D' }, + ' --kubelet-extra-args "--node-labels lifecycle=OnDemand" --use-max-pods true', + ], + ], + }, + '/opt/aws/bin/cfn-signal --exit-code $? --stack my-stack --resource ASG46ED3070 --region us-west-33', + ]); }); test('--use-max-pods=true', () => { diff --git a/packages/@aws-cdk/aws-elasticache/.eslintrc.js b/packages/@aws-cdk/aws-elasticache/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-elasticache/.eslintrc.js +++ b/packages/@aws-cdk/aws-elasticache/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticache/jest.config.js b/packages/@aws-cdk/aws-elasticache/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-elasticache/jest.config.js +++ b/packages/@aws-cdk/aws-elasticache/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticache/package.json b/packages/@aws-cdk/aws-elasticache/package.json index 8a8a5a70c6c16..8176496ecfad9 100644 --- a/packages/@aws-cdk/aws-elasticache/package.json +++ b/packages/@aws-cdk/aws-elasticache/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::ElastiCache", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-elasticbeanstalk/.eslintrc.js b/packages/@aws-cdk/aws-elasticbeanstalk/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-elasticbeanstalk/.eslintrc.js +++ b/packages/@aws-cdk/aws-elasticbeanstalk/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticbeanstalk/jest.config.js b/packages/@aws-cdk/aws-elasticbeanstalk/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-elasticbeanstalk/jest.config.js +++ b/packages/@aws-cdk/aws-elasticbeanstalk/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticbeanstalk/package.json b/packages/@aws-cdk/aws-elasticbeanstalk/package.json index a9bde94b14589..a7523e7a9bf58 100644 --- a/packages/@aws-cdk/aws-elasticbeanstalk/package.json +++ b/packages/@aws-cdk/aws-elasticbeanstalk/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::ElasticBeanstalk", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/.eslintrc.js b/packages/@aws-cdk/aws-elasticloadbalancing/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/.eslintrc.js +++ b/packages/@aws-cdk/aws-elasticloadbalancing/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/jest.config.js b/packages/@aws-cdk/aws-elasticloadbalancing/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/jest.config.js +++ b/packages/@aws-cdk/aws-elasticloadbalancing/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/package.json b/packages/@aws-cdk/aws-elasticloadbalancing/package.json index e20392648d2dd..9b73054622979 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancing/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::ElasticLoadBalancing", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,12 +72,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/.eslintrc.js b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/.eslintrc.js index 01db0e3e9f01c..1a3b4ca2b6aec 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/.eslintrc.js +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/.eslintrc.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/jest.config.js b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/jest.config.js index 5c1ef76634a9f..751c263a6e75c 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/jest.config.js +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json index 053caf2ce49a5..a431ef48ddbd5 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-actions/package.json @@ -65,27 +65,27 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { + "@aws-cdk/aws-cognito": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", - "@aws-cdk/aws-cognito": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { + "@aws-cdk/aws-cognito": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", - "@aws-cdk/aws-cognito": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, @@ -99,7 +99,6 @@ "announce": false }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/.eslintrc.js b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/.eslintrc.js +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/jest.config.js b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/jest.config.js +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json index e25ccb5ccd96f..37f4fe6c1d5ce 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json @@ -65,12 +65,12 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", @@ -104,7 +104,6 @@ "announce": false }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/.eslintrc.js b/packages/@aws-cdk/aws-elasticloadbalancingv2/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/.eslintrc.js +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/jest.config.js b/packages/@aws-cdk/aws-elasticloadbalancingv2/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/jest.config.js +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts index a1ea49a3b18a6..1a2e6c55ee815 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts @@ -42,7 +42,7 @@ export interface BaseApplicationListenerProps { readonly certificateArns?: string[]; /** - * Certificate list of ACM cert ARNs + * Certificate list of ACM cert ARNs. You must provide exactly one certificate if the listener protocol is HTTPS or TLS. * * @default - No certificates. */ diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts index 4c3085f2d5a66..d1329665ba7d6 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts @@ -376,11 +376,21 @@ export class ApplicationTargetGroup extends TargetGroupBase implements IApplicat ret.push('At least one of \'port\' or \'protocol\' is required for a non-Lambda TargetGroup'); } - if (this.healthCheck && this.healthCheck.protocol && !ALB_HEALTH_CHECK_PROTOCOLS.includes(this.healthCheck.protocol)) { - ret.push([ - `Health check protocol '${this.healthCheck.protocol}' is not supported. `, - `Must be one of [${ALB_HEALTH_CHECK_PROTOCOLS.join(', ')}]`, - ].join('')); + if (this.healthCheck && this.healthCheck.protocol) { + + if (ALB_HEALTH_CHECK_PROTOCOLS.includes(this.healthCheck.protocol)) { + if (this.healthCheck.interval && this.healthCheck.timeout && + this.healthCheck.interval.toMilliseconds() <= this.healthCheck.timeout.toMilliseconds()) { + ret.push(`Healthcheck interval ${this.healthCheck.interval.toHumanString()} must be greater than the timeout ${this.healthCheck.timeout.toHumanString()}`); + } + } + + if (!ALB_HEALTH_CHECK_PROTOCOLS.includes(this.healthCheck.protocol)) { + ret.push([ + `Health check protocol '${this.healthCheck.protocol}' is not supported. `, + `Must be one of [${ALB_HEALTH_CHECK_PROTOCOLS.join(', ')}]`, + ].join('')); + } } return ret; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-listener.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-listener.ts index 2a5fbce2a28a1..4cfed265217f5 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-listener.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-listener.ts @@ -53,7 +53,7 @@ export interface BaseNetworkListenerProps { readonly protocol?: Protocol; /** - * Certificate list of ACM cert ARNs + * Certificate list of ACM cert ARNs. You must provide exactly one certificate if the listener protocol is HTTPS or TLS. * * @default - No certificates. */ diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts index 96acd45b34a4c..29a9cb707556e 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts @@ -269,7 +269,7 @@ export abstract class TargetGroupBase extends CoreConstruct implements ITargetGr healthyThresholdCount: cdk.Lazy.number({ produce: () => this.healthCheck?.healthyThresholdCount }), unhealthyThresholdCount: cdk.Lazy.number({ produce: () => this.healthCheck?.unhealthyThresholdCount }), matcher: cdk.Lazy.any({ - produce: () => this.healthCheck?.healthyHttpCodes !== undefined ||Β this.healthCheck?.healthyGrpcCodes !== undefined ? { + produce: () => this.healthCheck?.healthyHttpCodes !== undefined || this.healthCheck?.healthyGrpcCodes !== undefined ? { grpcCode: this.healthCheck.healthyGrpcCodes, httpCode: this.healthCheck.healthyHttpCodes, } : undefined, @@ -297,11 +297,6 @@ export abstract class TargetGroupBase extends CoreConstruct implements ITargetGr * Set/replace the target group's health check */ public configureHealthCheck(healthCheck: HealthCheck) { - if (healthCheck.interval && healthCheck.timeout) { - if (healthCheck.interval.toMilliseconds() <= healthCheck.timeout.toMilliseconds()) { - throw new Error(`Healthcheck interval ${healthCheck.interval.toHumanString()} must be greater than the timeout ${healthCheck.timeout.toHumanString()}`); - } - } this.healthCheck = healthCheck; } diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json index cf411cbd32c88..2a74598925bbb 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::ElasticLoadBalancingV2", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,12 +72,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", @@ -104,8 +103,8 @@ "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "constructs": "^3.3.69", - "@aws-cdk/region-info": "0.0.0" + "@aws-cdk/region-info": "0.0.0", + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/load-balancer.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/load-balancer.test.ts index 7cf10a01d7595..d935a915d55e7 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/load-balancer.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/load-balancer.test.ts @@ -5,7 +5,7 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as elbv2 from '../../lib'; const s3GrantWriteCtx = { [cxapi.S3_GRANT_WRITE_WITHOUT_ACL]: true }; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts index f1a3db5eb9508..078be310dd3f8 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/alb/target-group.test.ts @@ -282,44 +282,187 @@ describe('tests', () => { }); }); - test('Interval equal to timeout', () => { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Stack'); - const vpc = new ec2.Vpc(stack, 'VPC', {}); + test.each([elbv2.Protocol.UDP, elbv2.Protocol.TCP_UDP, elbv2.Protocol.TLS])( + 'Throws validation error, when `healthCheck` has `protocol` set to %s', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + + // WHEN + new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { + vpc, + healthCheck: { + protocol: protocol, + }, + }); - // WHEN - const tg = new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { - vpc, + // THEN + expect(() => { + app.synth(); + }).toThrow(`Health check protocol '${protocol}' is not supported. Must be one of [HTTP, HTTPS]`); }); - // THEN - expect(() => { + test.each([elbv2.Protocol.UDP, elbv2.Protocol.TCP_UDP, elbv2.Protocol.TLS])( + 'Throws validation error, when `configureHealthCheck()` has `protocol` set to %s', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + const tg = new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { + vpc, + }); + + // WHEN + tg.configureHealthCheck({ + protocol: protocol, + }); + + // THEN + expect(() => { + app.synth(); + }).toThrow(`Health check protocol '${protocol}' is not supported. Must be one of [HTTP, HTTPS]`); + }); + + test.each([elbv2.Protocol.HTTP, elbv2.Protocol.HTTPS])( + 'Does not throw validation error, when `healthCheck` has `protocol` set to %s', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + + // WHEN + new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { + vpc, + healthCheck: { + protocol: protocol, + }, + }); + + // THEN + expect(() => { + app.synth(); + }).not.toThrowError(); + }); + + test.each([elbv2.Protocol.HTTP, elbv2.Protocol.HTTPS])( + 'Does not throw validation error, when `configureHealthCheck()` has `protocol` set to %s', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + const tg = new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { + vpc, + }); + + // WHEN + tg.configureHealthCheck({ + protocol: protocol, + }); + + // THEN + expect(() => { + app.synth(); + }).not.toThrowError(); + }); + + test.each([elbv2.Protocol.HTTP, elbv2.Protocol.HTTPS])( + 'Throws validation error, when `healthCheck` has `protocol` set to %s and `interval` is equal to `timeout`', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + + // WHEN + new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { + vpc, + healthCheck: { + interval: cdk.Duration.seconds(60), + timeout: cdk.Duration.seconds(60), + protocol: protocol, + }, + }); + + // THEN + expect(() => { + app.synth(); + }).toThrow('Healthcheck interval 1 minute must be greater than the timeout 1 minute'); + }); + + test.each([elbv2.Protocol.HTTP, elbv2.Protocol.HTTPS])( + 'Throws validation error, when `healthCheck` has `protocol` set to %s and `interval` is smaller than `timeout`', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + + // WHEN + new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { + vpc, + healthCheck: { + interval: cdk.Duration.seconds(60), + timeout: cdk.Duration.seconds(120), + protocol: protocol, + }, + }); + + // THEN + expect(() => { + app.synth(); + }).toThrow('Healthcheck interval 1 minute must be greater than the timeout 2 minutes'); + }); + + test.each([elbv2.Protocol.HTTP, elbv2.Protocol.HTTPS])( + 'Throws validation error, when `configureHealthCheck()` has `protocol` set to %s and `interval` is equal to `timeout`', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + const tg = new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { + vpc, + }); + + // WHEN tg.configureHealthCheck({ interval: cdk.Duration.seconds(60), timeout: cdk.Duration.seconds(60), + protocol: protocol, }); - }).toThrow(/Healthcheck interval 1 minute must be greater than the timeout 1 minute/); - }); - - test('Interval smaller than timeout', () => { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Stack'); - const vpc = new ec2.Vpc(stack, 'VPC', {}); - // WHEN - const tg = new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { - vpc, + // THEN + expect(() => { + app.synth(); + }).toThrow('Healthcheck interval 1 minute must be greater than the timeout 1 minute'); }); - // THEN - expect(() => { + test.each([elbv2.Protocol.HTTP, elbv2.Protocol.HTTPS])( + 'Throws validation error, when `configureHealthCheck()` has `protocol` set to %s and `interval` is smaller than `timeout`', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + const tg = new elbv2.ApplicationTargetGroup(stack, 'TargetGroup', { + vpc, + }); + + // WHEN tg.configureHealthCheck({ interval: cdk.Duration.seconds(60), timeout: cdk.Duration.seconds(120), + protocol: protocol, }); - }).toThrow(/Healthcheck interval 1 minute must be greater than the timeout 2 minutes/); - }); + // THEN + expect(() => { + app.synth(); + }).toThrow('Healthcheck interval 1 minute must be greater than the timeout 2 minutes'); + }); }); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/load-balancer.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/load-balancer.test.ts index 63cfc2462bddf..ccfb2924e211e 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/load-balancer.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/load-balancer.test.ts @@ -4,7 +4,7 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as elbv2 from '../../lib'; const s3GrantWriteCtx = { [cxapi.S3_GRANT_WRITE_WITHOUT_ACL]: true }; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/target-group.test.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/target-group.test.ts index 90aa39b37141b..1b35e2a2f232b 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/target-group.test.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/target-group.test.ts @@ -126,19 +126,6 @@ describe('tests', () => { }); }); - test('Throws error for unacceptable protocol', () => { - const stack = new cdk.Stack(); - const vpc = new ec2.Vpc(stack, 'Vpc'); - - expect(() => { - new elbv2.NetworkTargetGroup(stack, 'Group', { - vpc, - port: 80, - protocol: elbv2.Protocol.HTTPS, - }); - }).toThrow(); - }); - test('Throws error for invalid health check interval', () => { const app = new cdk.App(); const stack = new cdk.Stack(app, 'Stack'); @@ -157,42 +144,243 @@ describe('tests', () => { }).toThrow(/Health check interval '5' not supported. Must be one of the following values '10,30'./); }); - test('Throws error for invalid health check protocol', () => { - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Stack'); - const vpc = new ec2.Vpc(stack, 'Vpc'); + test.each([elbv2.Protocol.UDP, elbv2.Protocol.TCP_UDP, elbv2.Protocol.TLS])( + 'Throws validation error, when `healthCheck` has `protocol` set to %s', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); - new elbv2.NetworkTargetGroup(stack, 'Group', { - vpc, - port: 80, - healthCheck: { - protocol: elbv2.Protocol.UDP, - }, + // WHEN + new elbv2.NetworkTargetGroup(stack, 'TargetGroup', { + vpc, + port: 80, + healthCheck: { + protocol: protocol, + }, + }); + + // THEN + expect(() => { + app.synth(); + }).toThrow(`Health check protocol '${protocol}' is not supported. Must be one of [HTTP, HTTPS, TCP]`); }); - expect(() => { - app.synth(); - }).toThrow(/Health check protocol 'UDP' is not supported. Must be one of \[HTTP, HTTPS, TCP\]/); - }); + test.each([elbv2.Protocol.UDP, elbv2.Protocol.TCP_UDP, elbv2.Protocol.TLS])( + 'Throws validation error, when `configureHealthCheck()` has `protocol` set to %s', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + const tg = new elbv2.NetworkTargetGroup(stack, 'TargetGroup', { + vpc, + port: 80, + }); - test('Throws error for health check path property when protocol does not support it', () => { - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Stack'); - const vpc = new ec2.Vpc(stack, 'Vpc'); + // WHEN + tg.configureHealthCheck({ + protocol: protocol, + }); - new elbv2.NetworkTargetGroup(stack, 'Group', { - vpc, - port: 80, - healthCheck: { + // THEN + expect(() => { + app.synth(); + }).toThrow(`Health check protocol '${protocol}' is not supported. Must be one of [HTTP, HTTPS, TCP]`); + }); + + test.each([elbv2.Protocol.HTTP, elbv2.Protocol.HTTPS, elbv2.Protocol.TCP])( + 'Does not throw validation error, when `healthCheck` has `protocol` set to %s', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + + // WHEN + new elbv2.NetworkTargetGroup(stack, 'TargetGroup', { + vpc, + port: 80, + healthCheck: { + protocol: protocol, + }, + }); + + // THEN + expect(() => { + app.synth(); + }).not.toThrowError(); + }); + + test.each([elbv2.Protocol.HTTP, elbv2.Protocol.HTTPS, elbv2.Protocol.TCP])( + 'Does not throw validation error, when `configureHealthCheck()` has `protocol` set to %s', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + const tg = new elbv2.NetworkTargetGroup(stack, 'TargetGroup', { + vpc, + port: 80, + }); + + // WHEN + tg.configureHealthCheck({ + protocol: protocol, + }); + + // THEN + expect(() => { + app.synth(); + }).not.toThrowError(); + }); + + test.each([elbv2.Protocol.TCP, elbv2.Protocol.HTTPS])( + 'Does not throw a validation error, when `healthCheck` has `protocol` set to %s and `interval` is equal to `timeout`', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + + // WHEN + new elbv2.NetworkTargetGroup(stack, 'TargetGroup', { + vpc, + port: 80, + healthCheck: { + interval: cdk.Duration.seconds(10), + timeout: cdk.Duration.seconds(10), + protocol: protocol, + }, + }); + + // THEN + expect(() => { + app.synth(); + }).not.toThrowError(); + }); + + test.each([elbv2.Protocol.TCP, elbv2.Protocol.HTTPS])( + 'Does not throw a validation error, when `configureHealthCheck()` has `protocol` set to %s and `interval` is equal to `timeout`', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + const tg = new elbv2.NetworkTargetGroup(stack, 'TargetGroup', { + vpc, + port: 80, + }); + + // WHEN + tg.configureHealthCheck({ + interval: cdk.Duration.seconds(10), + timeout: cdk.Duration.seconds(10), + protocol: protocol, + }); + + // THEN + expect(() => { + app.synth(); + }).not.toThrowError(); + }); + + test.each([elbv2.Protocol.UDP, elbv2.Protocol.TCP_UDP, elbv2.Protocol.TLS])( + 'Throws validation error,`healthCheck` has `protocol` set to %s and `path` is provided', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + + // WHEN + new elbv2.NetworkTargetGroup(stack, 'TargetGroup', { + vpc, + port: 80, + healthCheck: { + path: '/my-path', + protocol: protocol, + }, + }); + + // THEN + expect(() => { + app.synth(); + }).toThrow(`'${protocol}' health checks do not support the path property. Must be one of [HTTP, HTTPS]`); + }); + + test.each([elbv2.Protocol.UDP, elbv2.Protocol.TCP_UDP, elbv2.Protocol.TLS])( + 'Throws validation error, when `configureHealthCheck()` has `protocol` set to %s and `path` is provided', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + const tg = new elbv2.NetworkTargetGroup(stack, 'TargetGroup', { + vpc, + port: 80, + }); + + // WHEN + tg.configureHealthCheck({ path: '/my-path', - protocol: elbv2.Protocol.TCP, - }, + protocol: protocol, + }); + + // THEN + expect(() => { + app.synth(); + }).toThrow(`'${protocol}' health checks do not support the path property. Must be one of [HTTP, HTTPS]`); }); - expect(() => { - app.synth(); - }).toThrow(/'TCP' health checks do not support the path property. Must be one of \[HTTP, HTTPS\]/); - }); + test.each([elbv2.Protocol.HTTP, elbv2.Protocol.HTTPS])( + 'Does not throw validation error, when `healthCheck` has `protocol` set to %s and `path` is provided', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + + // WHEN + new elbv2.NetworkTargetGroup(stack, 'TargetGroup', { + vpc, + port: 80, + healthCheck: { + path: '/my-path', + protocol: protocol, + }, + }); + + // THEN + expect(() => { + app.synth(); + }).not.toThrowError(); + }); + + test.each([elbv2.Protocol.HTTP, elbv2.Protocol.HTTPS])( + 'Does not throw validation error, when `configureHealthCheck()` has `protocol` set to %s and `path` is provided', + (protocol) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const vpc = new ec2.Vpc(stack, 'VPC', {}); + const tg = new elbv2.NetworkTargetGroup(stack, 'TargetGroup', { + vpc, + port: 80, + }); + + // WHEN + tg.configureHealthCheck({ + path: '/my-path', + protocol: protocol, + }); + + // THEN + expect(() => { + app.synth(); + }).not.toThrowError(); + }); test('Throws error for invalid health check healthy threshold', () => { const app = new cdk.App(); diff --git a/packages/@aws-cdk/aws-elasticsearch/.eslintrc.js b/packages/@aws-cdk/aws-elasticsearch/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-elasticsearch/.eslintrc.js +++ b/packages/@aws-cdk/aws-elasticsearch/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticsearch/jest.config.js b/packages/@aws-cdk/aws-elasticsearch/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-elasticsearch/jest.config.js +++ b/packages/@aws-cdk/aws-elasticsearch/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-elasticsearch/package.json b/packages/@aws-cdk/aws-elasticsearch/package.json index 37c35b69393b2..bed6ead349ed2 100644 --- a/packages/@aws-cdk/aws-elasticsearch/package.json +++ b/packages/@aws-cdk/aws-elasticsearch/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::Elasticsearch", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,12 +72,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", @@ -89,8 +88,8 @@ "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-route53": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", - "@aws-cdk/custom-resources": "0.0.0", "@aws-cdk/core": "0.0.0", + "@aws-cdk/custom-resources": "0.0.0", "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", @@ -103,8 +102,8 @@ "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-route53": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", - "@aws-cdk/custom-resources": "0.0.0", "@aws-cdk/core": "0.0.0", + "@aws-cdk/custom-resources": "0.0.0", "constructs": "^3.3.69" }, "engines": { diff --git a/packages/@aws-cdk/aws-emr/.eslintrc.js b/packages/@aws-cdk/aws-emr/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-emr/.eslintrc.js +++ b/packages/@aws-cdk/aws-emr/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-emr/jest.config.js b/packages/@aws-cdk/aws-emr/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-emr/jest.config.js +++ b/packages/@aws-cdk/aws-emr/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-emr/package.json b/packages/@aws-cdk/aws-emr/package.json index 337790cd07b03..a4983f2f01503 100644 --- a/packages/@aws-cdk/aws-emr/package.json +++ b/packages/@aws-cdk/aws-emr/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::EMR", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-emrcontainers/.eslintrc.js b/packages/@aws-cdk/aws-emrcontainers/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-emrcontainers/.eslintrc.js +++ b/packages/@aws-cdk/aws-emrcontainers/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-emrcontainers/jest.config.js b/packages/@aws-cdk/aws-emrcontainers/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-emrcontainers/jest.config.js +++ b/packages/@aws-cdk/aws-emrcontainers/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-emrcontainers/package.json b/packages/@aws-cdk/aws-emrcontainers/package.json index 8ea1659c08e57..4efce3b89f65d 100644 --- a/packages/@aws-cdk/aws-emrcontainers/package.json +++ b/packages/@aws-cdk/aws-emrcontainers/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::EMRContainers", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-events-targets/.eslintrc.js b/packages/@aws-cdk/aws-events-targets/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-events-targets/.eslintrc.js +++ b/packages/@aws-cdk/aws-events-targets/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-events-targets/jest.config.js b/packages/@aws-cdk/aws-events-targets/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-events-targets/jest.config.js +++ b/packages/@aws-cdk/aws-events-targets/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-events-targets/package.json b/packages/@aws-cdk/aws-events-targets/package.json index 3658b64701804..c2e0d3762085f 100644 --- a/packages/@aws-cdk/aws-events-targets/package.json +++ b/packages/@aws-cdk/aws-events-targets/package.json @@ -53,7 +53,6 @@ "build+test+extract": "yarn build+test && yarn rosetta:extract" }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,17 +72,17 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/aws-batch": "0.0.0", "@aws-cdk/aws-codecommit": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", - "@aws-cdk/aws-batch": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", "aws-sdk": "^2.848.0", - "aws-sdk-mock": "^5.2.1", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "aws-sdk-mock": "^5.4.0", + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-apigateway": "0.0.0", @@ -99,8 +98,8 @@ "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", - "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/aws-sns-subscriptions": "0.0.0", + "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/aws-stepfunctions": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", @@ -121,8 +120,8 @@ "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", - "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/aws-sns-subscriptions": "0.0.0", + "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/aws-stepfunctions": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", diff --git a/packages/@aws-cdk/aws-events/.eslintrc.js b/packages/@aws-cdk/aws-events/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-events/.eslintrc.js +++ b/packages/@aws-cdk/aws-events/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-events/jest.config.js b/packages/@aws-cdk/aws-events/jest.config.js index cd664e1d069e5..34818e1593f6b 100644 --- a/packages/@aws-cdk/aws-events/jest.config.js +++ b/packages/@aws-cdk/aws-events/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-events/lib/event-pattern.ts b/packages/@aws-cdk/aws-events/lib/event-pattern.ts index bdd586f7e0e78..523223d3903d2 100644 --- a/packages/@aws-cdk/aws-events/lib/event-pattern.ts +++ b/packages/@aws-cdk/aws-events/lib/event-pattern.ts @@ -2,10 +2,14 @@ * Events in Amazon CloudWatch Events are represented as JSON objects. For more * information about JSON objects, see RFC 7159. * + * **Important**: this class can only be used with a `Rule` class. In particular, + * do not use it with `CfnRule` class: your pattern will not be rendered + * correctly. In a `CfnRule` class, write the pattern as you normally would when + * directly writing CloudFormation. + * * Rules use event patterns to select events and route them to targets. A * pattern either matches an event or it doesn't. Event patterns are represented - * as JSON objects with a structure that is similar to that of events, for - * example: + * as JSON objects with a structure that is similar to that of events. * * It is important to remember the following about event pattern matching: * diff --git a/packages/@aws-cdk/aws-events/package.json b/packages/@aws-cdk/aws-events/package.json index cf480c87c1dfe..e2cefb728f130 100644 --- a/packages/@aws-cdk/aws-events/package.json +++ b/packages/@aws-cdk/aws-events/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::Events", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -75,13 +74,12 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "@types/nodeunit": "^0.0.32", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", diff --git a/packages/@aws-cdk/aws-events/test/rule.test.ts b/packages/@aws-cdk/aws-events/test/rule.test.ts index 5cc3b6c5f03e1..21782c089b40c 100644 --- a/packages/@aws-cdk/aws-events/test/rule.test.ts +++ b/packages/@aws-cdk/aws-events/test/rule.test.ts @@ -1055,7 +1055,7 @@ describe('rule', () => { }); class SomeTarget implements IRuleTarget { - // eslint-disable-next-line cdk/no-core-construct + // eslint-disable-next-line @aws-cdk/no-core-construct public constructor(private readonly id?: string, private readonly resource?: cdk.IConstruct) { } diff --git a/packages/@aws-cdk/aws-eventschemas/.eslintrc.js b/packages/@aws-cdk/aws-eventschemas/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-eventschemas/.eslintrc.js +++ b/packages/@aws-cdk/aws-eventschemas/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-eventschemas/jest.config.js b/packages/@aws-cdk/aws-eventschemas/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-eventschemas/jest.config.js +++ b/packages/@aws-cdk/aws-eventschemas/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-eventschemas/package.json b/packages/@aws-cdk/aws-eventschemas/package.json index 2d9ea8b2602d6..817e1564b28d1 100644 --- a/packages/@aws-cdk/aws-eventschemas/package.json +++ b/packages/@aws-cdk/aws-eventschemas/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::EventSchemas", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-finspace/.eslintrc.js b/packages/@aws-cdk/aws-finspace/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-finspace/.eslintrc.js +++ b/packages/@aws-cdk/aws-finspace/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-finspace/jest.config.js b/packages/@aws-cdk/aws-finspace/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-finspace/jest.config.js +++ b/packages/@aws-cdk/aws-finspace/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-finspace/package.json b/packages/@aws-cdk/aws-finspace/package.json index 1886725b8d68e..bb869ef40b45d 100644 --- a/packages/@aws-cdk/aws-finspace/package.json +++ b/packages/@aws-cdk/aws-finspace/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::FinSpace", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-fis/.eslintrc.js b/packages/@aws-cdk/aws-fis/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-fis/.eslintrc.js +++ b/packages/@aws-cdk/aws-fis/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-fis/jest.config.js b/packages/@aws-cdk/aws-fis/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-fis/jest.config.js +++ b/packages/@aws-cdk/aws-fis/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-fis/package.json b/packages/@aws-cdk/aws-fis/package.json index ba17edd8f186f..3a0c6ab86b87b 100644 --- a/packages/@aws-cdk/aws-fis/package.json +++ b/packages/@aws-cdk/aws-fis/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::FIS", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-fms/.eslintrc.js b/packages/@aws-cdk/aws-fms/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-fms/.eslintrc.js +++ b/packages/@aws-cdk/aws-fms/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-fms/jest.config.js b/packages/@aws-cdk/aws-fms/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-fms/jest.config.js +++ b/packages/@aws-cdk/aws-fms/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-fms/package.json b/packages/@aws-cdk/aws-fms/package.json index d9056b520b7f1..f00081ac0ea9a 100644 --- a/packages/@aws-cdk/aws-fms/package.json +++ b/packages/@aws-cdk/aws-fms/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::FMS", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-frauddetector/.eslintrc.js b/packages/@aws-cdk/aws-frauddetector/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-frauddetector/.eslintrc.js +++ b/packages/@aws-cdk/aws-frauddetector/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-frauddetector/jest.config.js b/packages/@aws-cdk/aws-frauddetector/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-frauddetector/jest.config.js +++ b/packages/@aws-cdk/aws-frauddetector/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-frauddetector/package.json b/packages/@aws-cdk/aws-frauddetector/package.json index 84cfc1ce40738..0b8c48451b6b5 100644 --- a/packages/@aws-cdk/aws-frauddetector/package.json +++ b/packages/@aws-cdk/aws-frauddetector/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::FraudDetector", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-fsx/.eslintrc.js b/packages/@aws-cdk/aws-fsx/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-fsx/.eslintrc.js +++ b/packages/@aws-cdk/aws-fsx/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-fsx/jest.config.js b/packages/@aws-cdk/aws-fsx/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-fsx/jest.config.js +++ b/packages/@aws-cdk/aws-fsx/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-fsx/package.json b/packages/@aws-cdk/aws-fsx/package.json index 1370bae1727de..6c5b236e7037a 100644 --- a/packages/@aws-cdk/aws-fsx/package.json +++ b/packages/@aws-cdk/aws-fsx/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::FSx", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,12 +74,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-gamelift/.eslintrc.js b/packages/@aws-cdk/aws-gamelift/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-gamelift/.eslintrc.js +++ b/packages/@aws-cdk/aws-gamelift/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-gamelift/jest.config.js b/packages/@aws-cdk/aws-gamelift/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-gamelift/jest.config.js +++ b/packages/@aws-cdk/aws-gamelift/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-gamelift/package.json b/packages/@aws-cdk/aws-gamelift/package.json index 299bf7e8ca563..9e3d586dbab6b 100644 --- a/packages/@aws-cdk/aws-gamelift/package.json +++ b/packages/@aws-cdk/aws-gamelift/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::GameLift", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-globalaccelerator-endpoints/.eslintrc.js b/packages/@aws-cdk/aws-globalaccelerator-endpoints/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-globalaccelerator-endpoints/.eslintrc.js +++ b/packages/@aws-cdk/aws-globalaccelerator-endpoints/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-globalaccelerator-endpoints/jest.config.js b/packages/@aws-cdk/aws-globalaccelerator-endpoints/jest.config.js index 49e81658a0875..e5862b88aa35e 100644 --- a/packages/@aws-cdk/aws-globalaccelerator-endpoints/jest.config.js +++ b/packages/@aws-cdk/aws-globalaccelerator-endpoints/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/aws-globalaccelerator-endpoints/package.json b/packages/@aws-cdk/aws-globalaccelerator-endpoints/package.json index 532b01de2fbe9..3991e52d8a5c8 100644 --- a/packages/@aws-cdk/aws-globalaccelerator-endpoints/package.json +++ b/packages/@aws-cdk/aws-globalaccelerator-endpoints/package.json @@ -52,7 +52,6 @@ "build+test+extract": "yarn build+test && yarn rosetta:extract" }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -70,14 +69,14 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", "aws-sdk": "^2.848.0", - "aws-sdk-mock": "^5.2.1", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0" + "aws-sdk-mock": "^5.4.0", + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-globalaccelerator/.eslintrc.js b/packages/@aws-cdk/aws-globalaccelerator/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-globalaccelerator/.eslintrc.js +++ b/packages/@aws-cdk/aws-globalaccelerator/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-globalaccelerator/jest.config.js b/packages/@aws-cdk/aws-globalaccelerator/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-globalaccelerator/jest.config.js +++ b/packages/@aws-cdk/aws-globalaccelerator/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-globalaccelerator/package.json b/packages/@aws-cdk/aws-globalaccelerator/package.json index b4b0e90197370..40f27c8a9d3b8 100644 --- a/packages/@aws-cdk/aws-globalaccelerator/package.json +++ b/packages/@aws-cdk/aws-globalaccelerator/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::GlobalAccelerator", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,13 +74,13 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", @@ -92,8 +91,8 @@ "peerDependencies": { "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/core": "0.0.0", - "constructs": "^3.3.69", - "@aws-cdk/custom-resources": "0.0.0" + "@aws-cdk/custom-resources": "0.0.0", + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-glue/.eslintrc.js b/packages/@aws-cdk/aws-glue/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-glue/.eslintrc.js +++ b/packages/@aws-cdk/aws-glue/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-glue/jest.config.js b/packages/@aws-cdk/aws-glue/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-glue/jest.config.js +++ b/packages/@aws-cdk/aws-glue/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-glue/package.json b/packages/@aws-cdk/aws-glue/package.json index daaba9400606c..50a535d9810eb 100644 --- a/packages/@aws-cdk/aws-glue/package.json +++ b/packages/@aws-cdk/aws-glue/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::Glue", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -73,24 +72,23 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "@types/nodeunit": "^0.0.32", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0" + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", - "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", - "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", + "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/core": "0.0.0", @@ -100,11 +98,11 @@ "peerDependencies": { "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", - "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", - "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", + "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-glue/test/table.test.ts b/packages/@aws-cdk/aws-glue/test/table.test.ts index fbb1424f766c1..6afc880d41dbb 100644 --- a/packages/@aws-cdk/aws-glue/test/table.test.ts +++ b/packages/@aws-cdk/aws-glue/test/table.test.ts @@ -4,8 +4,9 @@ import * as kms from '@aws-cdk/aws-kms'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as glue from '../lib'; +import { CfnTable } from '../lib/glue.generated'; const s3GrantWriteCtx = { [cxapi.S3_GRANT_WRITE_WITHOUT_ACL]: true }; @@ -245,7 +246,7 @@ test('table.node.defaultChild', () => { }); // THEN - expect(table.node.defaultChild instanceof glue.CfnTable).toEqual(true); + expect(table.node.defaultChild instanceof CfnTable).toEqual(true); }); test('encrypted table: SSE-S3', () => { diff --git a/packages/@aws-cdk/aws-greengrass/.eslintrc.js b/packages/@aws-cdk/aws-greengrass/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-greengrass/.eslintrc.js +++ b/packages/@aws-cdk/aws-greengrass/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-greengrass/jest.config.js b/packages/@aws-cdk/aws-greengrass/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-greengrass/jest.config.js +++ b/packages/@aws-cdk/aws-greengrass/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-greengrass/package.json b/packages/@aws-cdk/aws-greengrass/package.json index e5909de8cf591..e360765daf13a 100644 --- a/packages/@aws-cdk/aws-greengrass/package.json +++ b/packages/@aws-cdk/aws-greengrass/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Greengrass", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-greengrassv2/.eslintrc.js b/packages/@aws-cdk/aws-greengrassv2/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-greengrassv2/.eslintrc.js +++ b/packages/@aws-cdk/aws-greengrassv2/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-greengrassv2/jest.config.js b/packages/@aws-cdk/aws-greengrassv2/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-greengrassv2/jest.config.js +++ b/packages/@aws-cdk/aws-greengrassv2/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-greengrassv2/package.json b/packages/@aws-cdk/aws-greengrassv2/package.json index 4c21e7594e26b..b36f81ae49a34 100644 --- a/packages/@aws-cdk/aws-greengrassv2/package.json +++ b/packages/@aws-cdk/aws-greengrassv2/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::GreengrassV2", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-groundstation/.eslintrc.js b/packages/@aws-cdk/aws-groundstation/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-groundstation/.eslintrc.js +++ b/packages/@aws-cdk/aws-groundstation/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-groundstation/jest.config.js b/packages/@aws-cdk/aws-groundstation/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-groundstation/jest.config.js +++ b/packages/@aws-cdk/aws-groundstation/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-groundstation/package.json b/packages/@aws-cdk/aws-groundstation/package.json index f24da08699f70..bc3c56193416e 100644 --- a/packages/@aws-cdk/aws-groundstation/package.json +++ b/packages/@aws-cdk/aws-groundstation/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::GroundStation", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-guardduty/.eslintrc.js b/packages/@aws-cdk/aws-guardduty/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-guardduty/.eslintrc.js +++ b/packages/@aws-cdk/aws-guardduty/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-guardduty/jest.config.js b/packages/@aws-cdk/aws-guardduty/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-guardduty/jest.config.js +++ b/packages/@aws-cdk/aws-guardduty/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-guardduty/package.json b/packages/@aws-cdk/aws-guardduty/package.json index 0fb30da82ef61..dee1ab10f4c53 100644 --- a/packages/@aws-cdk/aws-guardduty/package.json +++ b/packages/@aws-cdk/aws-guardduty/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::GuardDuty", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-healthlake/.eslintrc.js b/packages/@aws-cdk/aws-healthlake/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-healthlake/.eslintrc.js +++ b/packages/@aws-cdk/aws-healthlake/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-healthlake/jest.config.js b/packages/@aws-cdk/aws-healthlake/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-healthlake/jest.config.js +++ b/packages/@aws-cdk/aws-healthlake/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-healthlake/package.json b/packages/@aws-cdk/aws-healthlake/package.json index c9e23a6b293b6..ea2c9d0aac3bf 100644 --- a/packages/@aws-cdk/aws-healthlake/package.json +++ b/packages/@aws-cdk/aws-healthlake/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::HealthLake", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-iam/.eslintrc.js b/packages/@aws-cdk/aws-iam/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-iam/.eslintrc.js +++ b/packages/@aws-cdk/aws-iam/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iam/jest.config.js b/packages/@aws-cdk/aws-iam/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-iam/jest.config.js +++ b/packages/@aws-cdk/aws-iam/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iam/lib/user.ts b/packages/@aws-cdk/aws-iam/lib/user.ts index 4874e84f791df..47be80bf7b0ee 100644 --- a/packages/@aws-cdk/aws-iam/lib/user.ts +++ b/packages/@aws-cdk/aws-iam/lib/user.ts @@ -156,6 +156,9 @@ export class User extends Resource implements IIdentity, IUser { /** * Import an existing user given a user ARN. * + * If the ARN comes from a Token, the User cannot have a path; if so, any attempt + * to reference its username will fail. + * * @param scope construct scope * @param id construct id * @param userArn the ARN of an existing user to import @@ -167,6 +170,9 @@ export class User extends Resource implements IIdentity, IUser { /** * Import an existing user given user attributes. * + * If the ARN comes from a Token, the User cannot have a path; if so, any attempt + * to reference its username will fail. + * * @param scope construct scope * @param id construct id * @param attrs the attributes of the user to import @@ -175,7 +181,10 @@ export class User extends Resource implements IIdentity, IUser { class Import extends Resource implements IUser { public readonly grantPrincipal: IPrincipal = this; public readonly principalAccount = Aws.ACCOUNT_ID; - public readonly userName: string = Arn.extractResourceName(attrs.userArn, 'user'); + // Resource name with path can have multiple elements separated by slash. + // Therefore, use element after last slash as userName. Happens to work for Tokens since + // they don't have a '/' in them. + public readonly userName: string = Arn.extractResourceName(attrs.userArn, 'user').split('/').pop()!; public readonly userArn: string = attrs.userArn; public readonly assumeRoleAction: string = 'sts:AssumeRole'; public readonly policyFragment: PrincipalPolicyFragment = new ArnPrincipal(attrs.userArn).policyFragment; diff --git a/packages/@aws-cdk/aws-iam/package.json b/packages/@aws-cdk/aws-iam/package.json index ef766c83c1a25..1449128836c09 100644 --- a/packages/@aws-cdk/aws-iam/package.json +++ b/packages/@aws-cdk/aws-iam/package.json @@ -57,8 +57,7 @@ "cloudformation": "AWS::IAM", "env": { "AWSLINT_BASE_CONSTRUCT": "true" - }, - "jest": true + } }, "keywords": [ "aws", @@ -73,16 +72,16 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/aws-lambda": "^8.10.79", + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/aws-lambda": "^8.10.83", "@types/jest": "^26.0.24", "@types/sinon": "^9.0.11", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0", - "sinon": "^9.2.4", - "@aws-cdk/assert-internal": "0.0.0" + "sinon": "^9.2.4" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-iam/test/integ.user.expected.json b/packages/@aws-cdk/aws-iam/test/integ.user.expected.json index a57b3db4c6f32..648d9de3e9107 100644 --- a/packages/@aws-cdk/aws-iam/test/integ.user.expected.json +++ b/packages/@aws-cdk/aws-iam/test/integ.user.expected.json @@ -15,9 +15,21 @@ "NameForUserImportedByArn": { "Value": "rossrhodes" }, + "NameForUserImportedByArnPath": { + "Value": "johndoe" + }, + "NameForUserImportedByArnPathMultiple": { + "Value": "johndoe" + }, "NameForUserImportedByAttributes": { "Value": "johndoe" }, + "NameForUserImportedByAttributesPath": { + "Value": "johndoe" + }, + "NameForUserImportedByAttributesPathMultiple": { + "Value": "johndoe" + }, "NameForUserImportedByName": { "Value": "janedoe" } diff --git a/packages/@aws-cdk/aws-iam/test/integ.user.ts b/packages/@aws-cdk/aws-iam/test/integ.user.ts index 7f8d00695742c..c2e196b6af5bc 100644 --- a/packages/@aws-cdk/aws-iam/test/integ.user.ts +++ b/packages/@aws-cdk/aws-iam/test/integ.user.ts @@ -12,13 +12,25 @@ new User(stack, 'MyUser', { }); const userImportedByArn = User.fromUserArn(stack, 'ImportedUserByArn', 'arn:aws:iam::123456789012:user/rossrhodes'); +const userImportedByArnWithPath = User.fromUserArn(stack, 'ImportedUserByArnPath', 'arn:aws:iam::123456789012:user/path/johndoe'); +const userImportedByArnPathMultiple = User.fromUserArn(stack, 'ImportedUserByArnPathMultiple', 'arn:aws:iam::123456789012:user/p/a/t/h/johndoe'); const userImportedByAttributes = User.fromUserAttributes(stack, 'ImportedUserByAttributes', { userArn: 'arn:aws:iam::123456789012:user/johndoe', }); +const userImportedByAttributesPath = User.fromUserAttributes(stack, 'ImportedUserByAttributesPath', { + userArn: 'arn:aws:iam::123456789012:user/path/johndoe', +}); +const userImportedByAttributesPathMultiple = User.fromUserAttributes(stack, 'ImportedUserByAttributesPathMultiple', { + userArn: 'arn:aws:iam::123456789012:user/p/a/t/h/johndoe', +}); const userImportedByName = User.fromUserName(stack, 'ImportedUserByName', 'janedoe'); new CfnOutput(stack, 'NameForUserImportedByArn', { value: userImportedByArn.userName }); +new CfnOutput(stack, 'NameForUserImportedByArnPath', { value: userImportedByArnWithPath.userName }); +new CfnOutput(stack, 'NameForUserImportedByArnPathMultiple', { value: userImportedByArnPathMultiple.userName }); new CfnOutput(stack, 'NameForUserImportedByAttributes', { value: userImportedByAttributes.userName }); +new CfnOutput(stack, 'NameForUserImportedByAttributesPath', { value: userImportedByAttributesPath.userName }); +new CfnOutput(stack, 'NameForUserImportedByAttributesPathMultiple', { value: userImportedByAttributesPathMultiple.userName }); new CfnOutput(stack, 'NameForUserImportedByName', { value: userImportedByName.userName }); app.synth(); diff --git a/packages/@aws-cdk/aws-iam/test/user.test.ts b/packages/@aws-cdk/aws-iam/test/user.test.ts index 5cc42ae015619..d7435b08cbf24 100644 --- a/packages/@aws-cdk/aws-iam/test/user.test.ts +++ b/packages/@aws-cdk/aws-iam/test/user.test.ts @@ -1,5 +1,5 @@ import '@aws-cdk/assert-internal/jest'; -import { App, SecretValue, Stack } from '@aws-cdk/core'; +import { App, SecretValue, Stack, Token } from '@aws-cdk/core'; import { Group, ManagedPolicy, Policy, PolicyStatement, User } from '../lib'; describe('IAM user', () => { @@ -106,6 +106,58 @@ describe('IAM user', () => { expect(stack.resolve(user.userName)).toStrictEqual(userName); }); + test('user imported by tokenized user ARN has a name', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + const user = User.fromUserArn(stack, 'import', Token.asString({ Ref: 'ARN' })); + + // THEN + expect(stack.resolve(user.userName)).toStrictEqual({ + 'Fn::Select': [1, { 'Fn::Split': [':user/', { Ref: 'ARN' }] }], + }); + }); + + test('user imported by user ARN with path', () => { + // GIVEN + const stack = new Stack(); + const userName = 'MyUserName'; + + // WHEN + const user = User.fromUserArn(stack, 'import', `arn:aws:iam::account-id:user/path/${userName}`); + + // THEN + expect(stack.resolve(user.userName)).toStrictEqual(userName); + }); + + test('user imported by user ARN with path (multiple elements)', () => { + // GIVEN + const stack = new Stack(); + const userName = 'MyUserName'; + + // WHEN + const user = User.fromUserArn(stack, 'import', `arn:aws:iam::account-id:user/p/a/t/h/${userName}`); + + // THEN + expect(stack.resolve(user.userName)).toStrictEqual(userName); + }); + + test('user imported by tokenized user attributes has a name', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + const user = User.fromUserAttributes(stack, 'import', { + userArn: Token.asString({ Ref: 'ARN' }), + }); + + // THEN + expect(stack.resolve(user.userName)).toStrictEqual({ + 'Fn::Select': [1, { 'Fn::Split': [':user/', { Ref: 'ARN' }] }], + }); + }); + test('user imported by user attributes has a name', () => { // GIVEN const stack = new Stack(); @@ -120,6 +172,34 @@ describe('IAM user', () => { expect(stack.resolve(user.userName)).toStrictEqual(userName); }); + test('user imported by user attributes with path has a name', () => { + // GIVEN + const stack = new Stack(); + const userName = 'MyUserName'; + + // WHEN + const user = User.fromUserAttributes(stack, 'import', { + userArn: `arn:aws:iam::account-id:user/path/${userName}`, + }); + + // THEN + expect(stack.resolve(user.userName)).toStrictEqual(userName); + }); + + test('user imported by user attributes with path (multiple elements) has a name', () => { + // GIVEN + const stack = new Stack(); + const userName = 'MyUserName'; + + // WHEN + const user = User.fromUserAttributes(stack, 'import', { + userArn: `arn:aws:iam::account-id:user/p/a/t/h/${userName}`, + }); + + // THEN + expect(stack.resolve(user.userName)).toStrictEqual(userName); + }); + test('add to policy of imported user', () => { // GIVEN const stack = new Stack(); diff --git a/packages/@aws-cdk/aws-imagebuilder/.eslintrc.js b/packages/@aws-cdk/aws-imagebuilder/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-imagebuilder/.eslintrc.js +++ b/packages/@aws-cdk/aws-imagebuilder/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-imagebuilder/jest.config.js b/packages/@aws-cdk/aws-imagebuilder/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-imagebuilder/jest.config.js +++ b/packages/@aws-cdk/aws-imagebuilder/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-imagebuilder/package.json b/packages/@aws-cdk/aws-imagebuilder/package.json index 64537f6b27401..e3a90f5b90246 100644 --- a/packages/@aws-cdk/aws-imagebuilder/package.json +++ b/packages/@aws-cdk/aws-imagebuilder/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::ImageBuilder", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-inspector/.eslintrc.js b/packages/@aws-cdk/aws-inspector/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-inspector/.eslintrc.js +++ b/packages/@aws-cdk/aws-inspector/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-inspector/jest.config.js b/packages/@aws-cdk/aws-inspector/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-inspector/jest.config.js +++ b/packages/@aws-cdk/aws-inspector/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-inspector/package.json b/packages/@aws-cdk/aws-inspector/package.json index dad54ff5b2e51..aa8e421f9b561 100644 --- a/packages/@aws-cdk/aws-inspector/package.json +++ b/packages/@aws-cdk/aws-inspector/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::Inspector", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-iot/.eslintrc.js b/packages/@aws-cdk/aws-iot/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-iot/.eslintrc.js +++ b/packages/@aws-cdk/aws-iot/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iot/jest.config.js b/packages/@aws-cdk/aws-iot/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-iot/jest.config.js +++ b/packages/@aws-cdk/aws-iot/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iot/package.json b/packages/@aws-cdk/aws-iot/package.json index f816d5f680164..9960168c78ec1 100644 --- a/packages/@aws-cdk/aws-iot/package.json +++ b/packages/@aws-cdk/aws-iot/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::IoT", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-iot1click/.eslintrc.js b/packages/@aws-cdk/aws-iot1click/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-iot1click/.eslintrc.js +++ b/packages/@aws-cdk/aws-iot1click/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iot1click/jest.config.js b/packages/@aws-cdk/aws-iot1click/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-iot1click/jest.config.js +++ b/packages/@aws-cdk/aws-iot1click/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iot1click/package.json b/packages/@aws-cdk/aws-iot1click/package.json index 17ad106a288f2..eda66e8a3a082 100644 --- a/packages/@aws-cdk/aws-iot1click/package.json +++ b/packages/@aws-cdk/aws-iot1click/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::IoT1Click", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -74,11 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-iotanalytics/.eslintrc.js b/packages/@aws-cdk/aws-iotanalytics/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-iotanalytics/.eslintrc.js +++ b/packages/@aws-cdk/aws-iotanalytics/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotanalytics/jest.config.js b/packages/@aws-cdk/aws-iotanalytics/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-iotanalytics/jest.config.js +++ b/packages/@aws-cdk/aws-iotanalytics/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotanalytics/package.json b/packages/@aws-cdk/aws-iotanalytics/package.json index 66434d4db2d33..37630cf29c02f 100644 --- a/packages/@aws-cdk/aws-iotanalytics/package.json +++ b/packages/@aws-cdk/aws-iotanalytics/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::IoTAnalytics", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-iotcoredeviceadvisor/.eslintrc.js b/packages/@aws-cdk/aws-iotcoredeviceadvisor/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-iotcoredeviceadvisor/.eslintrc.js +++ b/packages/@aws-cdk/aws-iotcoredeviceadvisor/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotcoredeviceadvisor/jest.config.js b/packages/@aws-cdk/aws-iotcoredeviceadvisor/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-iotcoredeviceadvisor/jest.config.js +++ b/packages/@aws-cdk/aws-iotcoredeviceadvisor/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotcoredeviceadvisor/package.json b/packages/@aws-cdk/aws-iotcoredeviceadvisor/package.json index 80fc81f75a022..45422d829b797 100644 --- a/packages/@aws-cdk/aws-iotcoredeviceadvisor/package.json +++ b/packages/@aws-cdk/aws-iotcoredeviceadvisor/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::IoTCoreDeviceAdvisor", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-iotevents/.eslintrc.js b/packages/@aws-cdk/aws-iotevents/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-iotevents/.eslintrc.js +++ b/packages/@aws-cdk/aws-iotevents/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotevents/jest.config.js b/packages/@aws-cdk/aws-iotevents/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-iotevents/jest.config.js +++ b/packages/@aws-cdk/aws-iotevents/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotevents/package.json b/packages/@aws-cdk/aws-iotevents/package.json index 9125c6a9a05b1..859cb5169f16a 100644 --- a/packages/@aws-cdk/aws-iotevents/package.json +++ b/packages/@aws-cdk/aws-iotevents/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::IoTEvents", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-iotfleethub/.eslintrc.js b/packages/@aws-cdk/aws-iotfleethub/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-iotfleethub/.eslintrc.js +++ b/packages/@aws-cdk/aws-iotfleethub/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotfleethub/jest.config.js b/packages/@aws-cdk/aws-iotfleethub/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-iotfleethub/jest.config.js +++ b/packages/@aws-cdk/aws-iotfleethub/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotfleethub/package.json b/packages/@aws-cdk/aws-iotfleethub/package.json index 69891556a7f4b..f0c4a45a394a0 100644 --- a/packages/@aws-cdk/aws-iotfleethub/package.json +++ b/packages/@aws-cdk/aws-iotfleethub/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::IoTFleetHub", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-iotsitewise/.eslintrc.js b/packages/@aws-cdk/aws-iotsitewise/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-iotsitewise/.eslintrc.js +++ b/packages/@aws-cdk/aws-iotsitewise/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotsitewise/jest.config.js b/packages/@aws-cdk/aws-iotsitewise/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-iotsitewise/jest.config.js +++ b/packages/@aws-cdk/aws-iotsitewise/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotsitewise/package.json b/packages/@aws-cdk/aws-iotsitewise/package.json index 9c86ba4bcd889..ccf98918699ad 100644 --- a/packages/@aws-cdk/aws-iotsitewise/package.json +++ b/packages/@aws-cdk/aws-iotsitewise/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::IoTSiteWise", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-iotthingsgraph/.eslintrc.js b/packages/@aws-cdk/aws-iotthingsgraph/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-iotthingsgraph/.eslintrc.js +++ b/packages/@aws-cdk/aws-iotthingsgraph/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotthingsgraph/jest.config.js b/packages/@aws-cdk/aws-iotthingsgraph/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-iotthingsgraph/jest.config.js +++ b/packages/@aws-cdk/aws-iotthingsgraph/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotthingsgraph/package.json b/packages/@aws-cdk/aws-iotthingsgraph/package.json index a00fc435787fe..5e2833e52494b 100644 --- a/packages/@aws-cdk/aws-iotthingsgraph/package.json +++ b/packages/@aws-cdk/aws-iotthingsgraph/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::IoTThingsGraph", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-iotwireless/.eslintrc.js b/packages/@aws-cdk/aws-iotwireless/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-iotwireless/.eslintrc.js +++ b/packages/@aws-cdk/aws-iotwireless/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotwireless/jest.config.js b/packages/@aws-cdk/aws-iotwireless/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-iotwireless/jest.config.js +++ b/packages/@aws-cdk/aws-iotwireless/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-iotwireless/package.json b/packages/@aws-cdk/aws-iotwireless/package.json index ee46fc9ca58ec..16e1afdc9ae88 100644 --- a/packages/@aws-cdk/aws-iotwireless/package.json +++ b/packages/@aws-cdk/aws-iotwireless/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::IoTWireless", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-ivs/.eslintrc.js b/packages/@aws-cdk/aws-ivs/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-ivs/.eslintrc.js +++ b/packages/@aws-cdk/aws-ivs/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ivs/jest.config.js b/packages/@aws-cdk/aws-ivs/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-ivs/jest.config.js +++ b/packages/@aws-cdk/aws-ivs/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ivs/package.json b/packages/@aws-cdk/aws-ivs/package.json index b199d66182db2..922a5672829a6 100644 --- a/packages/@aws-cdk/aws-ivs/package.json +++ b/packages/@aws-cdk/aws-ivs/package.json @@ -65,7 +65,6 @@ }, "cdk-build": { "cloudformation": "AWS::IVS", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -86,11 +85,11 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-kendra/.eslintrc.js b/packages/@aws-cdk/aws-kendra/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-kendra/.eslintrc.js +++ b/packages/@aws-cdk/aws-kendra/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kendra/jest.config.js b/packages/@aws-cdk/aws-kendra/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-kendra/jest.config.js +++ b/packages/@aws-cdk/aws-kendra/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kendra/package.json b/packages/@aws-cdk/aws-kendra/package.json index 33ab4f2afa7f2..8b2a1b20396e1 100644 --- a/packages/@aws-cdk/aws-kendra/package.json +++ b/packages/@aws-cdk/aws-kendra/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Kendra", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-kinesis/.eslintrc.js b/packages/@aws-cdk/aws-kinesis/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-kinesis/.eslintrc.js +++ b/packages/@aws-cdk/aws-kinesis/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kinesis/jest.config.js b/packages/@aws-cdk/aws-kinesis/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-kinesis/jest.config.js +++ b/packages/@aws-cdk/aws-kinesis/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kinesis/package.json b/packages/@aws-cdk/aws-kinesis/package.json index 51697ec9931df..b1464884fb740 100644 --- a/packages/@aws-cdk/aws-kinesis/package.json +++ b/packages/@aws-cdk/aws-kinesis/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::Kinesis", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,13 +72,13 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", diff --git a/packages/@aws-cdk/aws-kinesis/test/stream.test.ts b/packages/@aws-cdk/aws-kinesis/test/stream.test.ts index 388ac8b0caac5..089261c6ebdae 100644 --- a/packages/@aws-cdk/aws-kinesis/test/stream.test.ts +++ b/packages/@aws-cdk/aws-kinesis/test/stream.test.ts @@ -4,7 +4,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import { App, Duration, Stack, CfnParameter } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior, testLegacyBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior, testLegacyBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import { Stream, StreamEncryption } from '../lib'; /* eslint-disable quote-props */ diff --git a/packages/@aws-cdk/aws-kinesisanalytics-flink/.eslintrc.js b/packages/@aws-cdk/aws-kinesisanalytics-flink/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics-flink/.eslintrc.js +++ b/packages/@aws-cdk/aws-kinesisanalytics-flink/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kinesisanalytics-flink/jest.config.js b/packages/@aws-cdk/aws-kinesisanalytics-flink/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics-flink/jest.config.js +++ b/packages/@aws-cdk/aws-kinesisanalytics-flink/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kinesisanalytics-flink/lib/application.ts b/packages/@aws-cdk/aws-kinesisanalytics-flink/lib/application.ts index af11281fb71b7..5091d39c7f959 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics-flink/lib/application.ts +++ b/packages/@aws-cdk/aws-kinesisanalytics-flink/lib/application.ts @@ -1,5 +1,5 @@ import * as iam from '@aws-cdk/aws-iam'; -import * as ka from '@aws-cdk/aws-kinesisanalytics'; +import { CfnApplicationCloudWatchLoggingOptionV2, CfnApplicationV2 } from '@aws-cdk/aws-kinesisanalytics'; import * as logs from '@aws-cdk/aws-logs'; import * as core from '@aws-cdk/core'; import { Construct } from 'constructs'; @@ -261,7 +261,7 @@ export class Application extends ApplicationBase { const code = props.code.bind(this); code.bucket.grantRead(this); - const resource = new ka.CfnApplicationV2(this, 'Resource', { + const resource = new CfnApplicationV2(this, 'Resource', { applicationName: props.applicationName, runtimeEnvironment: props.runtime.value, serviceExecutionRole: this.role.roleArn, @@ -313,7 +313,7 @@ export class Application extends ApplicationBase { resources: [logStreamArn], })); - new ka.CfnApplicationCloudWatchLoggingOptionV2(this, 'LoggingOption', { + new CfnApplicationCloudWatchLoggingOptionV2(this, 'LoggingOption', { applicationName: resource.ref, cloudWatchLoggingOption: { logStreamArn, diff --git a/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json b/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json index d9ee895e0ed29..f54538e7a374f 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json +++ b/packages/@aws-cdk/aws-kinesisanalytics-flink/package.json @@ -67,33 +67,33 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/assets": "0.0.0", - "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kinesisanalytics": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", + "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/assets": "0.0.0", - "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kinesisanalytics": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", + "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "engines": { @@ -110,7 +110,6 @@ "announce": false }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-kinesisanalytics/.eslintrc.js b/packages/@aws-cdk/aws-kinesisanalytics/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics/.eslintrc.js +++ b/packages/@aws-cdk/aws-kinesisanalytics/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kinesisanalytics/jest.config.js b/packages/@aws-cdk/aws-kinesisanalytics/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics/jest.config.js +++ b/packages/@aws-cdk/aws-kinesisanalytics/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kinesisanalytics/package.json b/packages/@aws-cdk/aws-kinesisanalytics/package.json index db7c571c963c8..1e345f2fdb47b 100644 --- a/packages/@aws-cdk/aws-kinesisanalytics/package.json +++ b/packages/@aws-cdk/aws-kinesisanalytics/package.json @@ -58,7 +58,6 @@ "AWS::KinesisAnalytics", "AWS::KinesisAnalyticsV2" ], - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -76,11 +75,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-kinesisfirehose-destinations/.eslintrc.js b/packages/@aws-cdk/aws-kinesisfirehose-destinations/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose-destinations/.eslintrc.js +++ b/packages/@aws-cdk/aws-kinesisfirehose-destinations/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kinesisfirehose-destinations/jest.config.js b/packages/@aws-cdk/aws-kinesisfirehose-destinations/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose-destinations/jest.config.js +++ b/packages/@aws-cdk/aws-kinesisfirehose-destinations/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kinesisfirehose-destinations/lib/private/helpers.ts b/packages/@aws-cdk/aws-kinesisfirehose-destinations/lib/private/helpers.ts index d8ef3d4ac43a5..b841776a47d4c 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose-destinations/lib/private/helpers.ts +++ b/packages/@aws-cdk/aws-kinesisfirehose-destinations/lib/private/helpers.ts @@ -1,5 +1,6 @@ import * as iam from '@aws-cdk/aws-iam'; import * as firehose from '@aws-cdk/aws-kinesisfirehose'; +import { CfnDeliveryStream } from '@aws-cdk/aws-kinesisfirehose'; import * as kms from '@aws-cdk/aws-kms'; import * as logs from '@aws-cdk/aws-logs'; import * as s3 from '@aws-cdk/aws-s3'; @@ -48,14 +49,14 @@ export interface DestinationLoggingConfig extends ConfigWithDependables { /** * Logging options that will be injected into the destination configuration. */ - readonly loggingOptions: firehose.CfnDeliveryStream.CloudWatchLoggingOptionsProperty; + readonly loggingOptions: CfnDeliveryStream.CloudWatchLoggingOptionsProperty; } export interface DestinationBackupConfig extends ConfigWithDependables { /** * S3 backup configuration that will be injected into the destination configuration. */ - readonly backupConfig: firehose.CfnDeliveryStream.S3DestinationConfigurationProperty; + readonly backupConfig: CfnDeliveryStream.S3DestinationConfigurationProperty; } export function createLoggingOptions(scope: Construct, props: DestinationLoggingProps): DestinationLoggingConfig | undefined { @@ -80,7 +81,7 @@ export function createLoggingOptions(scope: Construct, props: DestinationLogging export function createBufferingHints( interval?: cdk.Duration, size?: cdk.Size, -): firehose.CfnDeliveryStream.BufferingHintsProperty | undefined { +): CfnDeliveryStream.BufferingHintsProperty | undefined { if (!interval && !size) { return undefined; } @@ -99,7 +100,7 @@ export function createBufferingHints( export function createEncryptionConfig( role: iam.IRole, encryptionKey?: kms.IKey, -): firehose.CfnDeliveryStream.EncryptionConfigurationProperty | undefined { +): CfnDeliveryStream.EncryptionConfigurationProperty | undefined { encryptionKey?.grantEncryptDecrypt(role); return encryptionKey ? { kmsEncryptionConfig: { awskmsKeyArn: encryptionKey.keyArn } } @@ -110,7 +111,7 @@ export function createProcessingConfig( scope: Construct, role: iam.IRole, dataProcessor?: firehose.IDataProcessor, -): firehose.CfnDeliveryStream.ProcessingConfigurationProperty | undefined { +): CfnDeliveryStream.ProcessingConfigurationProperty | undefined { return dataProcessor ? { enabled: true, @@ -123,7 +124,7 @@ function renderDataProcessor( processor: firehose.IDataProcessor, scope: Construct, role: iam.IRole, -): firehose.CfnDeliveryStream.ProcessorProperty { +): CfnDeliveryStream.ProcessorProperty { const processorConfig = processor.bind(scope, { role }); const parameters = [{ parameterName: 'RoleArn', parameterValue: role.roleArn }]; parameters.push(processorConfig.processorIdentifier); diff --git a/packages/@aws-cdk/aws-kinesisfirehose-destinations/package.json b/packages/@aws-cdk/aws-kinesisfirehose-destinations/package.json index 6633645989caf..36c981f2c54cd 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose-destinations/package.json +++ b/packages/@aws-cdk/aws-kinesisfirehose-destinations/package.json @@ -72,14 +72,14 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", - "@aws-cdk/aws-lambda-nodejs": "0.0.0" + "@aws-cdk/aws-lambda-nodejs": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", @@ -112,7 +112,6 @@ "announce": false }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-kinesisfirehose-destinations/test/integ.s3-bucket.lit.expected.json b/packages/@aws-cdk/aws-kinesisfirehose-destinations/test/integ.s3-bucket.lit.expected.json index ba6e2aecacda8..5ae3347a50989 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose-destinations/test/integ.s3-bucket.lit.expected.json +++ b/packages/@aws-cdk/aws-kinesisfirehose-destinations/test/integ.s3-bucket.lit.expected.json @@ -2,6 +2,14 @@ "Resources": { "Bucket83908E77": { "Type": "AWS::S3::Bucket", + "Properties": { + "Tags": [ + { + "Key": "aws-cdk:auto-delete-objects", + "Value": "true" + } + ] + }, "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, @@ -102,7 +110,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersfe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9S3BucketD715D8B0" + "Ref": "AssetParameters3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9S3Bucket4673BB1A" }, "S3Key": { "Fn::Join": [ @@ -115,7 +123,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersfe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9S3VersionKey6E76822C" + "Ref": "AssetParameters3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9S3VersionKey46E40510" } ] } @@ -128,7 +136,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersfe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9S3VersionKey6E76822C" + "Ref": "AssetParameters3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9S3VersionKey46E40510" } ] } @@ -167,6 +175,14 @@ }, "BackupBucket26B8E51C": { "Type": "AWS::S3::Bucket", + "Properties": { + "Tags": [ + { + "Key": "aws-cdk:auto-delete-objects", + "Value": "true" + } + ] + }, "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, @@ -751,17 +767,17 @@ } }, "Parameters": { - "AssetParametersfe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9S3BucketD715D8B0": { + "AssetParameters3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9S3Bucket4673BB1A": { "Type": "String", - "Description": "S3 bucket for asset \"fe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9\"" + "Description": "S3 bucket for asset \"3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9\"" }, - "AssetParametersfe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9S3VersionKey6E76822C": { + "AssetParameters3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9S3VersionKey46E40510": { "Type": "String", - "Description": "S3 key for asset version \"fe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9\"" + "Description": "S3 key for asset version \"3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9\"" }, - "AssetParametersfe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9ArtifactHash9AE3702B": { + "AssetParameters3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9ArtifactHashBD621721": { "Type": "String", - "Description": "Artifact hash for asset \"fe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9\"" + "Description": "Artifact hash for asset \"3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9\"" }, "AssetParameters5ee078f2a1957fe672d6cfd84faf49e07b8460758b5cd2669b3df1212a14cd19S3BucketFEDDFB43": { "Type": "String", diff --git a/packages/@aws-cdk/aws-kinesisfirehose/.eslintrc.js b/packages/@aws-cdk/aws-kinesisfirehose/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose/.eslintrc.js +++ b/packages/@aws-cdk/aws-kinesisfirehose/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kinesisfirehose/jest.config.js b/packages/@aws-cdk/aws-kinesisfirehose/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose/jest.config.js +++ b/packages/@aws-cdk/aws-kinesisfirehose/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kinesisfirehose/package.json b/packages/@aws-cdk/aws-kinesisfirehose/package.json index fe73affa84c97..abaabc25fc1c7 100644 --- a/packages/@aws-cdk/aws-kinesisfirehose/package.json +++ b/packages/@aws-cdk/aws-kinesisfirehose/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::KinesisFirehose", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ "devDependencies": { "@aws-cdk/assertions": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", diff --git a/packages/@aws-cdk/aws-kms/.eslintrc.js b/packages/@aws-cdk/aws-kms/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-kms/.eslintrc.js +++ b/packages/@aws-cdk/aws-kms/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kms/jest.config.js b/packages/@aws-cdk/aws-kms/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-kms/jest.config.js +++ b/packages/@aws-cdk/aws-kms/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-kms/package.json b/packages/@aws-cdk/aws-kms/package.json index 9bb9e8b04c1f8..74fd0a5f586aa 100644 --- a/packages/@aws-cdk/aws-kms/package.json +++ b/packages/@aws-cdk/aws-kms/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::KMS", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -73,28 +72,28 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", "@aws-cdk/assert-internal": "0.0.0", - "@aws-cdk/cloud-assembly-schema": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/cloud-assembly-schema": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "constructs": "^3.3.69", - "@aws-cdk/cloud-assembly-schema": "0.0.0" + "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "constructs": "^3.3.69", - "@aws-cdk/cloud-assembly-schema": "0.0.0" + "constructs": "^3.3.69" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" diff --git a/packages/@aws-cdk/aws-kms/test/alias.test.ts b/packages/@aws-cdk/aws-kms/test/alias.test.ts index 3ad224ef6e681..094d2a3e7dbed 100644 --- a/packages/@aws-cdk/aws-kms/test/alias.test.ts +++ b/packages/@aws-cdk/aws-kms/test/alias.test.ts @@ -124,7 +124,7 @@ test('can be used wherever a key is expected', () => { aliasName: 'alias/myAlias', }); - /* eslint-disable cdk/no-core-construct */ + /* eslint-disable @aws-cdk/no-core-construct */ class MyConstruct extends Construct { constructor(scope: Construct, id: string, key: IKey) { super(scope, id); @@ -138,7 +138,7 @@ test('can be used wherever a key is expected', () => { } } new MyConstruct(stack, 'MyConstruct', myAlias); - /* eslint-enable cdk/no-core-construct */ + /* eslint-enable @aws-cdk/no-core-construct */ expect(stack).toHaveOutput({ outputName: 'OutId', @@ -165,7 +165,7 @@ test('imported alias by name - can be used where a key is expected', () => { const myAlias = Alias.fromAliasName(stack, 'MyAlias', 'alias/myAlias'); - /* eslint-disable cdk/no-core-construct */ + /* eslint-disable @aws-cdk/no-core-construct */ class MyConstruct extends Construct { constructor(scope: Construct, id: string, key: IKey) { super(scope, id); @@ -179,7 +179,7 @@ test('imported alias by name - can be used where a key is expected', () => { } } new MyConstruct(stack, 'MyConstruct', myAlias); - /* eslint-enable cdk/no-core-construct */ + /* eslint-enable @aws-cdk/no-core-construct */ expect(stack).toHaveOutput({ outputName: 'OutId', diff --git a/packages/@aws-cdk/aws-kms/test/key.test.ts b/packages/@aws-cdk/aws-kms/test/key.test.ts index a7144cbb950d7..fae1564223d45 100644 --- a/packages/@aws-cdk/aws-kms/test/key.test.ts +++ b/packages/@aws-cdk/aws-kms/test/key.test.ts @@ -3,7 +3,7 @@ import '@aws-cdk/assert-internal/jest'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior, testLegacyBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior, testLegacyBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as kms from '../lib'; const ADMIN_ACTIONS: string[] = [ diff --git a/packages/@aws-cdk/aws-lakeformation/.eslintrc.js b/packages/@aws-cdk/aws-lakeformation/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-lakeformation/.eslintrc.js +++ b/packages/@aws-cdk/aws-lakeformation/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lakeformation/jest.config.js b/packages/@aws-cdk/aws-lakeformation/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-lakeformation/jest.config.js +++ b/packages/@aws-cdk/aws-lakeformation/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lakeformation/package.json b/packages/@aws-cdk/aws-lakeformation/package.json index 87af67a50de81..7609498bebed8 100644 --- a/packages/@aws-cdk/aws-lakeformation/package.json +++ b/packages/@aws-cdk/aws-lakeformation/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::LakeFormation", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-lambda-destinations/.eslintrc.js b/packages/@aws-cdk/aws-lambda-destinations/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-lambda-destinations/.eslintrc.js +++ b/packages/@aws-cdk/aws-lambda-destinations/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda-destinations/jest.config.js b/packages/@aws-cdk/aws-lambda-destinations/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-lambda-destinations/jest.config.js +++ b/packages/@aws-cdk/aws-lambda-destinations/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda-destinations/package.json b/packages/@aws-cdk/aws-lambda-destinations/package.json index 4156149551b5b..66dea74b84119 100644 --- a/packages/@aws-cdk/aws-lambda-destinations/package.json +++ b/packages/@aws-cdk/aws-lambda-destinations/package.json @@ -64,13 +64,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-events": "0.0.0", @@ -103,7 +103,6 @@ }, "maturity": "stable", "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-lambda-event-sources/.eslintrc.js b/packages/@aws-cdk/aws-lambda-event-sources/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/.eslintrc.js +++ b/packages/@aws-cdk/aws-lambda-event-sources/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda-event-sources/jest.config.js b/packages/@aws-cdk/aws-lambda-event-sources/jest.config.js index cd664e1d069e5..34818e1593f6b 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/jest.config.js +++ b/packages/@aws-cdk/aws-lambda-event-sources/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda-event-sources/package.json b/packages/@aws-cdk/aws-lambda-event-sources/package.json index 0db8f4d09f9a6..1660dfe07b24a 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/package.json +++ b/packages/@aws-cdk/aws-lambda-event-sources/package.json @@ -64,12 +64,12 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-apigateway": "0.0.0", @@ -129,7 +129,6 @@ }, "maturity": "stable", "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-lambda-go/.eslintrc.js b/packages/@aws-cdk/aws-lambda-go/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-lambda-go/.eslintrc.js +++ b/packages/@aws-cdk/aws-lambda-go/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda-go/jest.config.js b/packages/@aws-cdk/aws-lambda-go/jest.config.js index 33885f40aacf1..92ed1d466ea3f 100644 --- a/packages/@aws-cdk/aws-lambda-go/jest.config.js +++ b/packages/@aws-cdk/aws-lambda-go/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require("cdk-build-tools/config/jest.config"); +const baseConfig = require("@aws-cdk/cdk-build-tools/config/jest.config"); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda-go/package.json b/packages/@aws-cdk/aws-lambda-go/package.json index 5ab8238df938e..4fca8e06193ad 100644 --- a/packages/@aws-cdk/aws-lambda-go/package.json +++ b/packages/@aws-cdk/aws-lambda-go/package.json @@ -67,11 +67,11 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", - "@types/jest": "^26.0.24", "@aws-cdk/aws-ec2": "0.0.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-lambda": "0.0.0", @@ -97,9 +97,6 @@ "docker" ] }, - "cdk-build": { - "jest": true - }, "publishConfig": { "tag": "latest" } diff --git a/packages/@aws-cdk/aws-lambda-nodejs/.eslintrc.js b/packages/@aws-cdk/aws-lambda-nodejs/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/.eslintrc.js +++ b/packages/@aws-cdk/aws-lambda-nodejs/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda-nodejs/jest.config.js b/packages/@aws-cdk/aws-lambda-nodejs/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/jest.config.js +++ b/packages/@aws-cdk/aws-lambda-nodejs/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda-nodejs/package.json b/packages/@aws-cdk/aws-lambda-nodejs/package.json index ce16b825a12fc..f289622c2e0dd 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/package.json +++ b/packages/@aws-cdk/aws-lambda-nodejs/package.json @@ -64,14 +64,14 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", "delay": "5.0.0", - "esbuild": "^0.12.15", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "esbuild": "^0.13.3" }, "dependencies": { "@aws-cdk/aws-lambda": "0.0.0", @@ -93,9 +93,6 @@ "announce": false }, "nozem": false, - "cdk-build": { - "jest": true - }, "publishConfig": { "tag": "latest" } diff --git a/packages/@aws-cdk/aws-lambda-python/.eslintrc.js b/packages/@aws-cdk/aws-lambda-python/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-lambda-python/.eslintrc.js +++ b/packages/@aws-cdk/aws-lambda-python/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda-python/jest.config.js b/packages/@aws-cdk/aws-lambda-python/jest.config.js index fc310b5014407..d052cbb29f05d 100644 --- a/packages/@aws-cdk/aws-lambda-python/jest.config.js +++ b/packages/@aws-cdk/aws-lambda-python/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/aws-lambda-python/package.json b/packages/@aws-cdk/aws-lambda-python/package.json index 72e5a12de703a..b58c0fd91d57c 100644 --- a/packages/@aws-cdk/aws-lambda-python/package.json +++ b/packages/@aws-cdk/aws-lambda-python/package.json @@ -65,22 +65,22 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { + "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/core": "0.0.0", - "@aws-cdk/aws-ec2": "0.0.0", "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { + "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/core": "0.0.0", - "@aws-cdk/aws-ec2": "0.0.0", "constructs": "^3.3.69" }, "engines": { @@ -91,9 +91,6 @@ "awscdkio": { "announce": false }, - "cdk-build": { - "jest": true - }, "nozem": { "ostools": [ "docker" diff --git a/packages/@aws-cdk/aws-lambda/.eslintrc.js b/packages/@aws-cdk/aws-lambda/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-lambda/.eslintrc.js +++ b/packages/@aws-cdk/aws-lambda/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda/README.md b/packages/@aws-cdk/aws-lambda/README.md index c6098ff19fe11..63b0a97e5df4a 100644 --- a/packages/@aws-cdk/aws-lambda/README.md +++ b/packages/@aws-cdk/aws-lambda/README.md @@ -326,6 +326,31 @@ new LayerVersion(this, 'MyLayer', { }); ``` +## Architecture + +Lambda functions, by default, run on compute systems that have the 64 bit x86 architecture. + +The AWS Lambda service also runs compute on the ARM architecture, which can reduce cost +for some workloads. + +A lambda function can be configured to be run on one or both of these platforms - + +```ts +new Function(this, 'MyFunction', { + ... + architectures: [ Architecture.X86_64, Architecture.ARM_64 ], +}); +``` + +Similarly, lambda layer versions can also be tagged with architectures it is compatible with. + +```ts +new LayerVersion(this, 'MyLayer', { + ... + compatibleArchitectures: [ Architecture.X86_64, Architecture.ARM_64 ], +}); +``` + ## Lambda Insights Lambda functions can be configured to use CloudWatch [Lambda Insights](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Lambda-Insights.html) diff --git a/packages/@aws-cdk/aws-lambda/jest.config.js b/packages/@aws-cdk/aws-lambda/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-lambda/jest.config.js +++ b/packages/@aws-cdk/aws-lambda/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda/lib/architecture.ts b/packages/@aws-cdk/aws-lambda/lib/architecture.ts new file mode 100644 index 0000000000000..40edee1896755 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda/lib/architecture.ts @@ -0,0 +1,32 @@ +/** + * Architectures supported by AWS Lambda + */ +export class Architecture { + /** + * 64 bit architecture with x86 instruction set. + */ + public static readonly X86_64 = new Architecture('x86_64'); + + /** + * 64 bit architecture with the ARM instruction set. + */ + public static readonly ARM_64 = new Architecture('arm64'); + + /** + * Used to specify a custom architecture name. + * Use this if the architecture name is not yet supported by the CDK. + * @param name the architecture name as recognized by AWS Lambda. + */ + public static custom(name: string) { + return new Architecture(name); + } + + /** + * The name of the architecture as recognized by the AWS Lambda service APIs. + */ + public readonly name: string; + + private constructor(archName: string) { + this.name = archName; + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda/lib/function.ts b/packages/@aws-cdk/aws-lambda/lib/function.ts index 9cd67a478f003..72ae40d5babbe 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function.ts @@ -7,6 +7,7 @@ import * as logs from '@aws-cdk/aws-logs'; import * as sqs from '@aws-cdk/aws-sqs'; import { Annotations, CfnResource, Duration, Fn, Lazy, Names, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; +import { Architecture } from './architecture'; import { Code, CodeConfig } from './code'; import { ICodeSigningConfig } from './code-signing-config'; import { EventInvokeConfigOptions } from './event-invoke-config'; @@ -310,6 +311,12 @@ export interface FunctionOptions extends EventInvokeConfigOptions { * @default - Not Sign the Code */ readonly codeSigningConfig?: ICodeSigningConfig; + + /** + * The system architectures compatible with this lambda function. + * @default [Architecture.X86_64] + */ + readonly architectures?: Architecture[]; } export interface FunctionProps extends FunctionOptions { @@ -680,6 +687,7 @@ export class Function extends FunctionBase { kmsKeyArn: props.environmentEncryption?.keyArn, fileSystemConfigs, codeSigningConfigArn: props.codeSigningConfig?.codeSigningConfigArn, + architectures: props.architectures?.map(a => a.name), }); resource.node.addDependency(this.role); @@ -792,6 +800,11 @@ export class Function extends FunctionBase { const runtimes = layer.compatibleRuntimes.map(runtime => runtime.name).join(', '); throw new Error(`This lambda function uses a runtime that is incompatible with this layer (${this.runtime.name} is not in [${runtimes}])`); } + + // Currently no validations for compatible architectures since Lambda service + // allows layers configured with one architecture to be used with a Lambda function + // from another architecture. + this.layers.push(layer); } } diff --git a/packages/@aws-cdk/aws-lambda/lib/index.ts b/packages/@aws-cdk/aws-lambda/lib/index.ts index 41c77bb8d038d..875e05e995631 100644 --- a/packages/@aws-cdk/aws-lambda/lib/index.ts +++ b/packages/@aws-cdk/aws-lambda/lib/index.ts @@ -19,6 +19,7 @@ export * from './scalable-attribute-api'; export * from './code-signing-config'; export * from './lambda-insights'; export * from './log-retention'; +export * from './architecture'; // AWS::Lambda CloudFormation Resources: export * from './lambda.generated'; diff --git a/packages/@aws-cdk/aws-lambda/lib/layers.ts b/packages/@aws-cdk/aws-lambda/lib/layers.ts index babf91079b8b6..7176badb0ee42 100644 --- a/packages/@aws-cdk/aws-lambda/lib/layers.ts +++ b/packages/@aws-cdk/aws-lambda/lib/layers.ts @@ -1,5 +1,6 @@ import { IResource, RemovalPolicy, Resource } from '@aws-cdk/core'; import { Construct } from 'constructs'; +import { Architecture } from './architecture'; import { Code } from './code'; import { CfnLayerVersion, CfnLayerVersionPermission } from './lambda.generated'; import { Runtime } from './runtime'; @@ -46,6 +47,12 @@ export interface LayerVersionProps extends LayerVersionOptions { */ readonly compatibleRuntimes?: Runtime[]; + /** + * The system architectures compatible with this layer. + * @default [Architecture.X86_64] + */ + readonly compatibleArchitectures?: Architecture[]; + /** * The content of this Layer. * @@ -196,6 +203,7 @@ export class LayerVersion extends LayerVersionBase { const resource: CfnLayerVersion = new CfnLayerVersion(this, 'Resource', { compatibleRuntimes: props.compatibleRuntimes && props.compatibleRuntimes.map(r => r.name), + compatibleArchitectures: props.compatibleArchitectures?.map(a => a.name), content: { s3Bucket: code.s3Location.bucketName, s3Key: code.s3Location.objectKey, diff --git a/packages/@aws-cdk/aws-lambda/package.json b/packages/@aws-cdk/aws-lambda/package.json index 7c2ece3a6bd33..3e5d5286bc86e 100644 --- a/packages/@aws-cdk/aws-lambda/package.json +++ b/packages/@aws-cdk/aws-lambda/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::Lambda", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,16 +76,16 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/aws-lambda": "^8.10.83", "@types/jest": "^26.0.24", - "@types/aws-lambda": "^8.10.79", - "@types/lodash": "^4.14.171", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", + "@types/lodash": "^4.14.175", "jest": "^26.6.3", - "lodash": "^4.17.21", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "lodash": "^4.17.21" }, "dependencies": { "@aws-cdk/aws-applicationautoscaling": "0.0.0", diff --git a/packages/@aws-cdk/aws-lambda/test/code.test.ts b/packages/@aws-cdk/aws-lambda/test/code.test.ts index 49e87cf220ebe..194ebda9aff37 100644 --- a/packages/@aws-cdk/aws-lambda/test/code.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/code.test.ts @@ -4,7 +4,7 @@ import { ABSENT, ResourcePart } from '@aws-cdk/assert-internal'; import * as ecr from '@aws-cdk/aws-ecr'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as lambda from '../lib'; /* eslint-disable dot-notation */ diff --git a/packages/@aws-cdk/aws-lambda/test/function.test.ts b/packages/@aws-cdk/aws-lambda/test/function.test.ts index b4f79aff6cc9e..a4aa4a31e10cc 100644 --- a/packages/@aws-cdk/aws-lambda/test/function.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/function.test.ts @@ -2174,6 +2174,21 @@ describe('function', () => { })).toThrow(/Layers are not supported for container image functions/); }); + test('specified architecture is recognized', () => { + const stack = new cdk.Stack(); + new lambda.Function(stack, 'MyFunction', { + code: lambda.Code.fromInline('foo'), + runtime: lambda.Runtime.NODEJS_12_X, + handler: 'index.handler', + + architectures: [lambda.Architecture.ARM_64], + }); + + expect(stack).toHaveResource('AWS::Lambda::Function', { + Architectures: ['arm64'], + }); + }); + }); function newTestLambda(scope: constructs.Construct) { diff --git a/packages/@aws-cdk/aws-lambda/test/layers.test.ts b/packages/@aws-cdk/aws-lambda/test/layers.test.ts index 3d8cc9d70de6f..1c416236c0980 100644 --- a/packages/@aws-cdk/aws-lambda/test/layers.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/layers.test.ts @@ -103,4 +103,18 @@ describe('layers', () => { DeletionPolicy: 'Retain', }, ResourcePart.CompleteDefinition); }); + + test('specified compatible architectures is recognized', () => { + const stack = new cdk.Stack(); + const bucket = new s3.Bucket(stack, 'Bucket'); + const code = new lambda.S3Code(bucket, 'ObjectKey'); + new lambda.LayerVersion(stack, 'MyLayer', { + code, + compatibleArchitectures: [lambda.Architecture.ARM_64], + }); + + expect(stack).toHaveResource('AWS::Lambda::LayerVersion', { + CompatibleArchitectures: ['arm64'], + }); + }); }); diff --git a/packages/@aws-cdk/aws-licensemanager/.eslintrc.js b/packages/@aws-cdk/aws-licensemanager/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-licensemanager/.eslintrc.js +++ b/packages/@aws-cdk/aws-licensemanager/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-licensemanager/jest.config.js b/packages/@aws-cdk/aws-licensemanager/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-licensemanager/jest.config.js +++ b/packages/@aws-cdk/aws-licensemanager/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-licensemanager/package.json b/packages/@aws-cdk/aws-licensemanager/package.json index 0219ff3d93dc0..0e2ca75813a54 100644 --- a/packages/@aws-cdk/aws-licensemanager/package.json +++ b/packages/@aws-cdk/aws-licensemanager/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::LicenseManager", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-location/.eslintrc.js b/packages/@aws-cdk/aws-location/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-location/.eslintrc.js +++ b/packages/@aws-cdk/aws-location/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-location/jest.config.js b/packages/@aws-cdk/aws-location/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-location/jest.config.js +++ b/packages/@aws-cdk/aws-location/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-location/package.json b/packages/@aws-cdk/aws-location/package.json index 5a9473d0d22dd..745400558765a 100644 --- a/packages/@aws-cdk/aws-location/package.json +++ b/packages/@aws-cdk/aws-location/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::Location", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-logs-destinations/.eslintrc.js b/packages/@aws-cdk/aws-logs-destinations/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-logs-destinations/.eslintrc.js +++ b/packages/@aws-cdk/aws-logs-destinations/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-logs-destinations/jest.config.js b/packages/@aws-cdk/aws-logs-destinations/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-logs-destinations/jest.config.js +++ b/packages/@aws-cdk/aws-logs-destinations/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-logs-destinations/package.json b/packages/@aws-cdk/aws-logs-destinations/package.json index 5d13936533fcc..13f8f5c567006 100644 --- a/packages/@aws-cdk/aws-logs-destinations/package.json +++ b/packages/@aws-cdk/aws-logs-destinations/package.json @@ -64,13 +64,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", @@ -98,7 +98,6 @@ }, "maturity": "stable", "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-logs/.eslintrc.js b/packages/@aws-cdk/aws-logs/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-logs/.eslintrc.js +++ b/packages/@aws-cdk/aws-logs/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-logs/jest.config.js b/packages/@aws-cdk/aws-logs/jest.config.js index d737012e12863..6adf60b166cac 100644 --- a/packages/@aws-cdk/aws-logs/jest.config.js +++ b/packages/@aws-cdk/aws-logs/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/aws-logs/package.json b/packages/@aws-cdk/aws-logs/package.json index eb68f23c4e252..9e13692d15a14 100644 --- a/packages/@aws-cdk/aws-logs/package.json +++ b/packages/@aws-cdk/aws-logs/package.json @@ -57,8 +57,7 @@ "cloudformation": "AWS::Logs", "env": { "AWSLINT_BASE_CONSTRUCT": true - }, - "jest": true + } }, "keywords": [ "aws", @@ -73,19 +72,19 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/aws-lambda": "^8.10.83", "@types/jest": "^26.0.24", - "@types/aws-lambda": "^8.10.79", "@types/sinon": "^9.0.11", "aws-sdk": "^2.848.0", - "aws-sdk-mock": "^5.2.1", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "nock": "^13.1.1", + "aws-sdk-mock": "^5.4.0", "jest": "^26.6.3", - "pkglint": "0.0.0", - "sinon": "^9.2.4", - "@aws-cdk/assert-internal": "0.0.0" + "nock": "^13.1.3", + "sinon": "^9.2.4" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", diff --git a/packages/@aws-cdk/aws-lookoutequipment/.eslintrc.js b/packages/@aws-cdk/aws-lookoutequipment/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-lookoutequipment/.eslintrc.js +++ b/packages/@aws-cdk/aws-lookoutequipment/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lookoutequipment/jest.config.js b/packages/@aws-cdk/aws-lookoutequipment/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-lookoutequipment/jest.config.js +++ b/packages/@aws-cdk/aws-lookoutequipment/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lookoutequipment/package.json b/packages/@aws-cdk/aws-lookoutequipment/package.json index 3d3d93d1a9bb4..583212fe12b16 100644 --- a/packages/@aws-cdk/aws-lookoutequipment/package.json +++ b/packages/@aws-cdk/aws-lookoutequipment/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::LookoutEquipment", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-lookoutmetrics/.eslintrc.js b/packages/@aws-cdk/aws-lookoutmetrics/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-lookoutmetrics/.eslintrc.js +++ b/packages/@aws-cdk/aws-lookoutmetrics/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lookoutmetrics/jest.config.js b/packages/@aws-cdk/aws-lookoutmetrics/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-lookoutmetrics/jest.config.js +++ b/packages/@aws-cdk/aws-lookoutmetrics/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lookoutmetrics/package.json b/packages/@aws-cdk/aws-lookoutmetrics/package.json index f79a8e599ed12..b1da867ff825e 100644 --- a/packages/@aws-cdk/aws-lookoutmetrics/package.json +++ b/packages/@aws-cdk/aws-lookoutmetrics/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::LookoutMetrics", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-lookoutvision/.eslintrc.js b/packages/@aws-cdk/aws-lookoutvision/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-lookoutvision/.eslintrc.js +++ b/packages/@aws-cdk/aws-lookoutvision/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lookoutvision/jest.config.js b/packages/@aws-cdk/aws-lookoutvision/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-lookoutvision/jest.config.js +++ b/packages/@aws-cdk/aws-lookoutvision/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lookoutvision/package.json b/packages/@aws-cdk/aws-lookoutvision/package.json index 33ede00a2af8c..41f2c0c5d20c0 100644 --- a/packages/@aws-cdk/aws-lookoutvision/package.json +++ b/packages/@aws-cdk/aws-lookoutvision/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::LookoutVision", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-macie/.eslintrc.js b/packages/@aws-cdk/aws-macie/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-macie/.eslintrc.js +++ b/packages/@aws-cdk/aws-macie/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-macie/jest.config.js b/packages/@aws-cdk/aws-macie/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-macie/jest.config.js +++ b/packages/@aws-cdk/aws-macie/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-macie/package.json b/packages/@aws-cdk/aws-macie/package.json index cd1d450bd73b6..bf3b4f9104a59 100644 --- a/packages/@aws-cdk/aws-macie/package.json +++ b/packages/@aws-cdk/aws-macie/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Macie", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-managedblockchain/.eslintrc.js b/packages/@aws-cdk/aws-managedblockchain/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-managedblockchain/.eslintrc.js +++ b/packages/@aws-cdk/aws-managedblockchain/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-managedblockchain/jest.config.js b/packages/@aws-cdk/aws-managedblockchain/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-managedblockchain/jest.config.js +++ b/packages/@aws-cdk/aws-managedblockchain/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-managedblockchain/package.json b/packages/@aws-cdk/aws-managedblockchain/package.json index 09d5ad7a954ea..3994b29d5fa75 100644 --- a/packages/@aws-cdk/aws-managedblockchain/package.json +++ b/packages/@aws-cdk/aws-managedblockchain/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::ManagedBlockchain", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-mediaconnect/.eslintrc.js b/packages/@aws-cdk/aws-mediaconnect/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-mediaconnect/.eslintrc.js +++ b/packages/@aws-cdk/aws-mediaconnect/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-mediaconnect/jest.config.js b/packages/@aws-cdk/aws-mediaconnect/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-mediaconnect/jest.config.js +++ b/packages/@aws-cdk/aws-mediaconnect/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-mediaconnect/package.json b/packages/@aws-cdk/aws-mediaconnect/package.json index d0f29ba806f03..c329c2d368efc 100644 --- a/packages/@aws-cdk/aws-mediaconnect/package.json +++ b/packages/@aws-cdk/aws-mediaconnect/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::MediaConnect", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-mediaconvert/.eslintrc.js b/packages/@aws-cdk/aws-mediaconvert/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-mediaconvert/.eslintrc.js +++ b/packages/@aws-cdk/aws-mediaconvert/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-mediaconvert/jest.config.js b/packages/@aws-cdk/aws-mediaconvert/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-mediaconvert/jest.config.js +++ b/packages/@aws-cdk/aws-mediaconvert/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-mediaconvert/package.json b/packages/@aws-cdk/aws-mediaconvert/package.json index 725541270f71b..172cd0658252e 100644 --- a/packages/@aws-cdk/aws-mediaconvert/package.json +++ b/packages/@aws-cdk/aws-mediaconvert/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::MediaConvert", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-medialive/.eslintrc.js b/packages/@aws-cdk/aws-medialive/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-medialive/.eslintrc.js +++ b/packages/@aws-cdk/aws-medialive/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-medialive/jest.config.js b/packages/@aws-cdk/aws-medialive/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-medialive/jest.config.js +++ b/packages/@aws-cdk/aws-medialive/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-medialive/package.json b/packages/@aws-cdk/aws-medialive/package.json index dd9f764f06d1b..cdf5f7caac8fe 100644 --- a/packages/@aws-cdk/aws-medialive/package.json +++ b/packages/@aws-cdk/aws-medialive/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::MediaLive", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-mediapackage/.eslintrc.js b/packages/@aws-cdk/aws-mediapackage/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-mediapackage/.eslintrc.js +++ b/packages/@aws-cdk/aws-mediapackage/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-mediapackage/jest.config.js b/packages/@aws-cdk/aws-mediapackage/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-mediapackage/jest.config.js +++ b/packages/@aws-cdk/aws-mediapackage/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-mediapackage/package.json b/packages/@aws-cdk/aws-mediapackage/package.json index 9910b1dc2f864..817eafaaea6da 100644 --- a/packages/@aws-cdk/aws-mediapackage/package.json +++ b/packages/@aws-cdk/aws-mediapackage/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::MediaPackage", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-mediastore/.eslintrc.js b/packages/@aws-cdk/aws-mediastore/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-mediastore/.eslintrc.js +++ b/packages/@aws-cdk/aws-mediastore/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-mediastore/jest.config.js b/packages/@aws-cdk/aws-mediastore/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-mediastore/jest.config.js +++ b/packages/@aws-cdk/aws-mediastore/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-mediastore/package.json b/packages/@aws-cdk/aws-mediastore/package.json index 5a5ec1ff16709..34e48b7593020 100644 --- a/packages/@aws-cdk/aws-mediastore/package.json +++ b/packages/@aws-cdk/aws-mediastore/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::MediaStore", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/tools/individual-pkg-gen/.eslintrc.js b/packages/@aws-cdk/aws-memorydb/.eslintrc.js similarity index 56% rename from tools/individual-pkg-gen/.eslintrc.js rename to packages/@aws-cdk/aws-memorydb/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/tools/individual-pkg-gen/.eslintrc.js +++ b/packages/@aws-cdk/aws-memorydb/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-memorydb/.gitignore b/packages/@aws-cdk/aws-memorydb/.gitignore new file mode 100644 index 0000000000000..62ebc95d75ce6 --- /dev/null +++ b/packages/@aws-cdk/aws-memorydb/.gitignore @@ -0,0 +1,19 @@ +*.js +*.js.map +*.d.ts +tsconfig.json +node_modules +*.generated.ts +dist +.jsii + +.LAST_BUILD +.nyc_output +coverage +.nycrc +.LAST_PACKAGE +*.snk +nyc.config.js +!.eslintrc.js +!jest.config.js +junit.xml diff --git a/packages/@aws-cdk/aws-memorydb/.npmignore b/packages/@aws-cdk/aws-memorydb/.npmignore new file mode 100644 index 0000000000000..f931fede67c44 --- /dev/null +++ b/packages/@aws-cdk/aws-memorydb/.npmignore @@ -0,0 +1,29 @@ +# Don't include original .ts files when doing `npm pack` +*.ts +!*.d.ts +coverage +.nyc_output +*.tgz + +dist +.LAST_PACKAGE +.LAST_BUILD +!*.js + +# Include .jsii +!.jsii + +*.snk + +*.tsbuildinfo + +tsconfig.json + +.eslintrc.js +jest.config.js + +# exclude cdk artifacts +**/cdk.out +junit.xml +test/ +!*.lit.ts diff --git a/tools/cdk-build-tools/LICENSE b/packages/@aws-cdk/aws-memorydb/LICENSE similarity index 100% rename from tools/cdk-build-tools/LICENSE rename to packages/@aws-cdk/aws-memorydb/LICENSE diff --git a/tools/cdk-build-tools/NOTICE b/packages/@aws-cdk/aws-memorydb/NOTICE similarity index 100% rename from tools/cdk-build-tools/NOTICE rename to packages/@aws-cdk/aws-memorydb/NOTICE diff --git a/packages/@aws-cdk/aws-memorydb/README.md b/packages/@aws-cdk/aws-memorydb/README.md new file mode 100644 index 0000000000000..e2b1d4faa518a --- /dev/null +++ b/packages/@aws-cdk/aws-memorydb/README.md @@ -0,0 +1,20 @@ +# AWS::MemoryDB Construct Library + + +--- + +![cfn-resources: Stable](https://img.shields.io/badge/cfn--resources-stable-success.svg?style=for-the-badge) + +> All classes with the `Cfn` prefix in this module ([CFN Resources]) are always stable and safe to use. +> +> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib + +--- + + + +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts +import memorydb = require('@aws-cdk/aws-memorydb'); +``` diff --git a/packages/@aws-cdk/aws-memorydb/jest.config.js b/packages/@aws-cdk/aws-memorydb/jest.config.js new file mode 100644 index 0000000000000..3a2fd93a1228a --- /dev/null +++ b/packages/@aws-cdk/aws-memorydb/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-memorydb/lib/index.ts b/packages/@aws-cdk/aws-memorydb/lib/index.ts new file mode 100644 index 0000000000000..99e822affff5c --- /dev/null +++ b/packages/@aws-cdk/aws-memorydb/lib/index.ts @@ -0,0 +1,2 @@ +// AWS::MemoryDB CloudFormation Resources: +export * from './memorydb.generated'; diff --git a/packages/@aws-cdk/aws-memorydb/package.json b/packages/@aws-cdk/aws-memorydb/package.json new file mode 100644 index 0000000000000..4ecfac53a2db6 --- /dev/null +++ b/packages/@aws-cdk/aws-memorydb/package.json @@ -0,0 +1,103 @@ +{ + "name": "@aws-cdk/aws-memorydb", + "version": "0.0.0", + "description": "The CDK Construct Library for AWS::MemoryDB", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "projectReferences": true, + "targets": { + "dotnet": { + "namespace": "Amazon.CDK.AWS.MemoryDB", + "packageId": "Amazon.CDK.AWS.MemoryDB", + "signAssembly": true, + "assemblyOriginatorKeyFile": "../../key.snk", + "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png" + }, + "java": { + "package": "software.amazon.awscdk.services.memorydb", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "memorydb" + } + }, + "python": { + "classifiers": [ + "Framework :: AWS CDK", + "Framework :: AWS CDK :: 1" + ], + "distName": "aws-cdk.aws-memorydb", + "module": "aws_cdk.aws_memorydb" + } + } + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/aws-memorydb" + }, + "homepage": "https://github.com/aws/aws-cdk", + "scripts": { + "build": "cdk-build", + "watch": "cdk-watch", + "lint": "cdk-lint", + "test": "cdk-test", + "integ": "cdk-integ", + "pkglint": "pkglint -f", + "package": "cdk-package", + "awslint": "cdk-awslint", + "cfn2ts": "cfn2ts", + "build+test": "yarn build && yarn test", + "build+test+package": "yarn build+test && yarn package", + "compat": "cdk-compat", + "gen": "cfn2ts", + "rosetta:extract": "yarn --silent jsii-rosetta extract", + "build+extract": "yarn build && yarn rosetta:extract", + "build+test+extract": "yarn build+test && yarn rosetta:extract" + }, + "cdk-build": { + "cloudformation": "AWS::MemoryDB", + "jest": true, + "env": { + "AWSLINT_BASE_CONSTRUCT": "true" + } + }, + "keywords": [ + "aws", + "cdk", + "constructs", + "AWS::MemoryDB", + "aws-memorydb" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" + }, + "dependencies": { + "@aws-cdk/core": "0.0.0" + }, + "peerDependencies": { + "@aws-cdk/core": "0.0.0" + }, + "engines": { + "node": ">= 10.13.0 <13 || >=13.7.0" + }, + "stability": "experimental", + "maturity": "cfn-only", + "awscdkio": { + "announce": false + }, + "publishConfig": { + "tag": "latest" + } +} diff --git a/packages/@aws-cdk/aws-apprunner/test/apprunner.test.ts b/packages/@aws-cdk/aws-memorydb/test/memorydb.test.ts similarity index 100% rename from packages/@aws-cdk/aws-apprunner/test/apprunner.test.ts rename to packages/@aws-cdk/aws-memorydb/test/memorydb.test.ts diff --git a/packages/@aws-cdk/aws-msk/.eslintrc.js b/packages/@aws-cdk/aws-msk/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-msk/.eslintrc.js +++ b/packages/@aws-cdk/aws-msk/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-msk/jest.config.js b/packages/@aws-cdk/aws-msk/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-msk/jest.config.js +++ b/packages/@aws-cdk/aws-msk/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-msk/lib/cluster.ts b/packages/@aws-cdk/aws-msk/lib/cluster.ts index 6123f6896138c..be29d3a7a749d 100644 --- a/packages/@aws-cdk/aws-msk/lib/cluster.ts +++ b/packages/@aws-cdk/aws-msk/lib/cluster.ts @@ -9,7 +9,8 @@ import * as core from '@aws-cdk/core'; import * as cr from '@aws-cdk/custom-resources'; import * as constructs from 'constructs'; import { addressOf } from 'constructs/lib/private/uniqueid'; -import { CfnCluster, KafkaVersion } from './'; +import { KafkaVersion } from './'; +import { CfnCluster } from './msk.generated'; /** * Represents a MSK Cluster diff --git a/packages/@aws-cdk/aws-msk/package.json b/packages/@aws-cdk/aws-msk/package.json index dd1523cffaf01..7c5d79482230f 100644 --- a/packages/@aws-cdk/aws-msk/package.json +++ b/packages/@aws-cdk/aws-msk/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::MSK", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -76,34 +75,34 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "cdk-integ-tools": "0.0.0", - "pkglint": "0.0.0", "jest": "^26.6.3" }, "dependencies": { - "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-acmpca": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", - "@aws-cdk/aws-kms": "0.0.0", - "@aws-cdk/aws-iam": "0.0.0", - "@aws-cdk/aws-ec2": "0.0.0", - "@aws-cdk/custom-resources": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", + "@aws-cdk/core": "0.0.0", + "@aws-cdk/custom-resources": "0.0.0", "constructs": "^3.3.69" }, "peerDependencies": { - "@aws-cdk/core": "0.0.0", "@aws-cdk/aws-acmpca": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", - "@aws-cdk/aws-kms": "0.0.0", - "@aws-cdk/aws-iam": "0.0.0", - "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", + "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", "constructs": "^3.3.69" }, diff --git a/packages/@aws-cdk/aws-mwaa/.eslintrc.js b/packages/@aws-cdk/aws-mwaa/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-mwaa/.eslintrc.js +++ b/packages/@aws-cdk/aws-mwaa/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-mwaa/jest.config.js b/packages/@aws-cdk/aws-mwaa/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-mwaa/jest.config.js +++ b/packages/@aws-cdk/aws-mwaa/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-mwaa/package.json b/packages/@aws-cdk/aws-mwaa/package.json index 0a784d8121200..e7c300df1afa8 100644 --- a/packages/@aws-cdk/aws-mwaa/package.json +++ b/packages/@aws-cdk/aws-mwaa/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::MWAA", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-neptune/.eslintrc.js b/packages/@aws-cdk/aws-neptune/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-neptune/.eslintrc.js +++ b/packages/@aws-cdk/aws-neptune/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-neptune/jest.config.js b/packages/@aws-cdk/aws-neptune/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-neptune/jest.config.js +++ b/packages/@aws-cdk/aws-neptune/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-neptune/package.json b/packages/@aws-cdk/aws-neptune/package.json index b3a429fb6642a..fd8bf57f76a8e 100644 --- a/packages/@aws-cdk/aws-neptune/package.json +++ b/packages/@aws-cdk/aws-neptune/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Neptune", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-networkfirewall/.eslintrc.js b/packages/@aws-cdk/aws-networkfirewall/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-networkfirewall/.eslintrc.js +++ b/packages/@aws-cdk/aws-networkfirewall/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-networkfirewall/jest.config.js b/packages/@aws-cdk/aws-networkfirewall/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-networkfirewall/jest.config.js +++ b/packages/@aws-cdk/aws-networkfirewall/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-networkfirewall/package.json b/packages/@aws-cdk/aws-networkfirewall/package.json index 3b6617b2582c5..a0205fb192de7 100644 --- a/packages/@aws-cdk/aws-networkfirewall/package.json +++ b/packages/@aws-cdk/aws-networkfirewall/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::NetworkFirewall", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-networkmanager/.eslintrc.js b/packages/@aws-cdk/aws-networkmanager/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-networkmanager/.eslintrc.js +++ b/packages/@aws-cdk/aws-networkmanager/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-networkmanager/jest.config.js b/packages/@aws-cdk/aws-networkmanager/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-networkmanager/jest.config.js +++ b/packages/@aws-cdk/aws-networkmanager/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-networkmanager/package.json b/packages/@aws-cdk/aws-networkmanager/package.json index dd671b4ffd623..6891e55cb1b6e 100644 --- a/packages/@aws-cdk/aws-networkmanager/package.json +++ b/packages/@aws-cdk/aws-networkmanager/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::NetworkManager", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-nimblestudio/.eslintrc.js b/packages/@aws-cdk/aws-nimblestudio/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-nimblestudio/.eslintrc.js +++ b/packages/@aws-cdk/aws-nimblestudio/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-nimblestudio/jest.config.js b/packages/@aws-cdk/aws-nimblestudio/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-nimblestudio/jest.config.js +++ b/packages/@aws-cdk/aws-nimblestudio/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-nimblestudio/package.json b/packages/@aws-cdk/aws-nimblestudio/package.json index 8270304b555fa..c0291fea71a29 100644 --- a/packages/@aws-cdk/aws-nimblestudio/package.json +++ b/packages/@aws-cdk/aws-nimblestudio/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::NimbleStudio", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-opensearchservice/.eslintrc.js b/packages/@aws-cdk/aws-opensearchservice/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-opensearchservice/.eslintrc.js +++ b/packages/@aws-cdk/aws-opensearchservice/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-opensearchservice/README.md b/packages/@aws-cdk/aws-opensearchservice/README.md index dddddf5b24f09..d0ddd81e7c0d4 100644 --- a/packages/@aws-cdk/aws-opensearchservice/README.md +++ b/packages/@aws-cdk/aws-opensearchservice/README.md @@ -24,14 +24,14 @@ Higher level constructs for Domain | ![Stable](https://img.shields.io/badge/stab Amazon OpenSearch Service is the successor to Amazon Elasticsearch Service. -See [Migrating to OpenSearch](https://docs.aws.amazon.com/cdk/api/latest/docs/aws-elasticsearch-readme.html#migrating-to-opensearch) for migration instructions from `@aws-cdk/aws-elasticsearch` to this module, `@aws-cdk/aws-opensearch`. +See [Migrating to OpenSearch](https://docs.aws.amazon.com/cdk/api/latest/docs/aws-elasticsearch-readme.html#migrating-to-opensearch) for migration instructions from `@aws-cdk/aws-elasticsearch` to this module, `@aws-cdk/aws-opensearchservice`. ## Quick start Create a development cluster by simply specifying the version: ```ts -import * as opensearch from '@aws-cdk/aws-opensearch'; +import * as opensearch from '@aws-cdk/aws-opensearchservice'; const devDomain = new opensearch.Domain(this, 'Domain', { version: opensearch.EngineVersion.OPENSEARCH_1_0, @@ -41,7 +41,7 @@ const devDomain = new opensearch.Domain(this, 'Domain', { To perform version upgrades without replacing the entire domain, specify the `enableVersionUpgrade` property. ```ts -import * as opensearch from '@aws-cdk/aws-opensearch'; +import * as opensearch from '@aws-cdk/aws-opensearchservice'; const devDomain = new opensearch.Domain(this, 'Domain', { version: opensearch.EngineVersion.OPENSEARCH_1_0, diff --git a/packages/@aws-cdk/aws-opensearchservice/jest.config.js b/packages/@aws-cdk/aws-opensearchservice/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-opensearchservice/jest.config.js +++ b/packages/@aws-cdk/aws-opensearchservice/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-opensearchservice/package.json b/packages/@aws-cdk/aws-opensearchservice/package.json index e00852181986c..523f58fe1caea 100644 --- a/packages/@aws-cdk/aws-opensearchservice/package.json +++ b/packages/@aws-cdk/aws-opensearchservice/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::OpenSearchService", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -78,12 +77,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assert-internal": "0.0.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", @@ -94,8 +93,8 @@ "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-route53": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", - "@aws-cdk/custom-resources": "0.0.0", "@aws-cdk/core": "0.0.0", + "@aws-cdk/custom-resources": "0.0.0", "constructs": "^3.3.69" }, "peerDependencies": { @@ -107,8 +106,8 @@ "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-route53": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", - "@aws-cdk/custom-resources": "0.0.0", "@aws-cdk/core": "0.0.0", + "@aws-cdk/custom-resources": "0.0.0", "constructs": "^3.3.69" }, "engines": { diff --git a/packages/@aws-cdk/aws-opsworks/.eslintrc.js b/packages/@aws-cdk/aws-opsworks/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-opsworks/.eslintrc.js +++ b/packages/@aws-cdk/aws-opsworks/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-opsworks/jest.config.js b/packages/@aws-cdk/aws-opsworks/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-opsworks/jest.config.js +++ b/packages/@aws-cdk/aws-opsworks/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-opsworks/package.json b/packages/@aws-cdk/aws-opsworks/package.json index 5d6f8b77a7d04..0933f51bad400 100644 --- a/packages/@aws-cdk/aws-opsworks/package.json +++ b/packages/@aws-cdk/aws-opsworks/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::OpsWorks", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-opsworkscm/.eslintrc.js b/packages/@aws-cdk/aws-opsworkscm/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-opsworkscm/.eslintrc.js +++ b/packages/@aws-cdk/aws-opsworkscm/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-opsworkscm/jest.config.js b/packages/@aws-cdk/aws-opsworkscm/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-opsworkscm/jest.config.js +++ b/packages/@aws-cdk/aws-opsworkscm/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-opsworkscm/package.json b/packages/@aws-cdk/aws-opsworkscm/package.json index 03870f42fa5a0..95389c6c13394 100644 --- a/packages/@aws-cdk/aws-opsworkscm/package.json +++ b/packages/@aws-cdk/aws-opsworkscm/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::OpsWorksCM", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-pinpoint/.eslintrc.js b/packages/@aws-cdk/aws-pinpoint/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-pinpoint/.eslintrc.js +++ b/packages/@aws-cdk/aws-pinpoint/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-pinpoint/jest.config.js b/packages/@aws-cdk/aws-pinpoint/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-pinpoint/jest.config.js +++ b/packages/@aws-cdk/aws-pinpoint/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-pinpoint/package.json b/packages/@aws-cdk/aws-pinpoint/package.json index 8475739eaa6f7..e095a349312ac 100644 --- a/packages/@aws-cdk/aws-pinpoint/package.json +++ b/packages/@aws-cdk/aws-pinpoint/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Pinpoint", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-pinpointemail/.eslintrc.js b/packages/@aws-cdk/aws-pinpointemail/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-pinpointemail/.eslintrc.js +++ b/packages/@aws-cdk/aws-pinpointemail/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-pinpointemail/jest.config.js b/packages/@aws-cdk/aws-pinpointemail/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-pinpointemail/jest.config.js +++ b/packages/@aws-cdk/aws-pinpointemail/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-pinpointemail/package.json b/packages/@aws-cdk/aws-pinpointemail/package.json index d57fe0f9ac922..f95e74754de4c 100644 --- a/packages/@aws-cdk/aws-pinpointemail/package.json +++ b/packages/@aws-cdk/aws-pinpointemail/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::PinpointEmail", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-qldb/.eslintrc.js b/packages/@aws-cdk/aws-qldb/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-qldb/.eslintrc.js +++ b/packages/@aws-cdk/aws-qldb/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-qldb/jest.config.js b/packages/@aws-cdk/aws-qldb/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-qldb/jest.config.js +++ b/packages/@aws-cdk/aws-qldb/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-qldb/package.json b/packages/@aws-cdk/aws-qldb/package.json index 3922e74b5a384..519381dd6de63 100644 --- a/packages/@aws-cdk/aws-qldb/package.json +++ b/packages/@aws-cdk/aws-qldb/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::QLDB", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-quicksight/.eslintrc.js b/packages/@aws-cdk/aws-quicksight/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-quicksight/.eslintrc.js +++ b/packages/@aws-cdk/aws-quicksight/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-quicksight/jest.config.js b/packages/@aws-cdk/aws-quicksight/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-quicksight/jest.config.js +++ b/packages/@aws-cdk/aws-quicksight/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-quicksight/package.json b/packages/@aws-cdk/aws-quicksight/package.json index 00f42d396c801..a611643089d80 100644 --- a/packages/@aws-cdk/aws-quicksight/package.json +++ b/packages/@aws-cdk/aws-quicksight/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::QuickSight", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-ram/.eslintrc.js b/packages/@aws-cdk/aws-ram/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-ram/.eslintrc.js +++ b/packages/@aws-cdk/aws-ram/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ram/jest.config.js b/packages/@aws-cdk/aws-ram/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-ram/jest.config.js +++ b/packages/@aws-cdk/aws-ram/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ram/package.json b/packages/@aws-cdk/aws-ram/package.json index 6f817b0f45b4b..cab6b01c59df3 100644 --- a/packages/@aws-cdk/aws-ram/package.json +++ b/packages/@aws-cdk/aws-ram/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::RAM", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-rds/.eslintrc.js b/packages/@aws-cdk/aws-rds/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-rds/.eslintrc.js +++ b/packages/@aws-cdk/aws-rds/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-rds/jest.config.js b/packages/@aws-cdk/aws-rds/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-rds/jest.config.js +++ b/packages/@aws-cdk/aws-rds/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-rds/package.json b/packages/@aws-cdk/aws-rds/package.json index d3fcb9f70771c..e2add95207135 100644 --- a/packages/@aws-cdk/aws-rds/package.json +++ b/packages/@aws-cdk/aws-rds/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::RDS", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,16 +72,16 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-events-targets": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "jest": "^26.6.3", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", @@ -105,9 +104,9 @@ "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", + "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/core": "0.0.0", - "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "constructs": "^3.3.69" }, diff --git a/packages/@aws-cdk/aws-rds/test/cluster.test.ts b/packages/@aws-cdk/aws-rds/test/cluster.test.ts index ed3ec587d7c86..97d5548611fcd 100644 --- a/packages/@aws-cdk/aws-rds/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-rds/test/cluster.test.ts @@ -7,7 +7,7 @@ import * as logs from '@aws-cdk/aws-logs'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import { AuroraEngineVersion, AuroraMysqlEngineVersion, AuroraPostgresEngineVersion, CfnDBCluster, Credentials, DatabaseCluster, DatabaseClusterEngine, DatabaseClusterFromSnapshot, ParameterGroup, PerformanceInsightRetention, SubnetGroup, DatabaseSecret, diff --git a/packages/@aws-cdk/aws-rds/test/instance.test.ts b/packages/@aws-cdk/aws-rds/test/instance.test.ts index 7cabc2258dc6b..7364599e4ed25 100644 --- a/packages/@aws-cdk/aws-rds/test/instance.test.ts +++ b/packages/@aws-cdk/aws-rds/test/instance.test.ts @@ -9,7 +9,7 @@ import * as logs from '@aws-cdk/aws-logs'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as rds from '../lib'; let stack: cdk.Stack; diff --git a/packages/@aws-cdk/aws-redshift/.eslintrc.js b/packages/@aws-cdk/aws-redshift/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-redshift/.eslintrc.js +++ b/packages/@aws-cdk/aws-redshift/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-redshift/jest.config.js b/packages/@aws-cdk/aws-redshift/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-redshift/jest.config.js +++ b/packages/@aws-cdk/aws-redshift/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-redshift/package.json b/packages/@aws-cdk/aws-redshift/package.json index fe7a1c23393a2..d6ed1ff2f96ca 100644 --- a/packages/@aws-cdk/aws-redshift/package.json +++ b/packages/@aws-cdk/aws-redshift/package.json @@ -62,7 +62,6 @@ }, "cdk-build": { "cloudformation": "AWS::Redshift", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -81,13 +80,13 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", "aws-sdk": "^2.848.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-redshift/test/cluster.test.ts b/packages/@aws-cdk/aws-redshift/test/cluster.test.ts index 28f2fbfd4655b..910319b91bcd4 100644 --- a/packages/@aws-cdk/aws-redshift/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-redshift/test/cluster.test.ts @@ -3,7 +3,8 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as kms from '@aws-cdk/aws-kms'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; -import { CfnCluster, Cluster, ClusterParameterGroup, ClusterSubnetGroup, ClusterType } from '../lib'; +import { Cluster, ClusterParameterGroup, ClusterSubnetGroup, ClusterType } from '../lib'; +import { CfnCluster } from '../lib/redshift.generated'; let stack: cdk.Stack; let vpc: ec2.IVpc; diff --git a/packages/@aws-cdk/aws-resourcegroups/.eslintrc.js b/packages/@aws-cdk/aws-resourcegroups/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-resourcegroups/.eslintrc.js +++ b/packages/@aws-cdk/aws-resourcegroups/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-resourcegroups/jest.config.js b/packages/@aws-cdk/aws-resourcegroups/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-resourcegroups/jest.config.js +++ b/packages/@aws-cdk/aws-resourcegroups/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-resourcegroups/package.json b/packages/@aws-cdk/aws-resourcegroups/package.json index 88e73e2bd2426..2f9b4f2ee4163 100644 --- a/packages/@aws-cdk/aws-resourcegroups/package.json +++ b/packages/@aws-cdk/aws-resourcegroups/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::ResourceGroups", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-robomaker/.eslintrc.js b/packages/@aws-cdk/aws-robomaker/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-robomaker/.eslintrc.js +++ b/packages/@aws-cdk/aws-robomaker/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-robomaker/jest.config.js b/packages/@aws-cdk/aws-robomaker/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-robomaker/jest.config.js +++ b/packages/@aws-cdk/aws-robomaker/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-robomaker/package.json b/packages/@aws-cdk/aws-robomaker/package.json index 124451f52e67b..000b195520ffd 100644 --- a/packages/@aws-cdk/aws-robomaker/package.json +++ b/packages/@aws-cdk/aws-robomaker/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::RoboMaker", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-route53-patterns/.eslintrc.js b/packages/@aws-cdk/aws-route53-patterns/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-route53-patterns/.eslintrc.js +++ b/packages/@aws-cdk/aws-route53-patterns/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53-patterns/jest.config.js b/packages/@aws-cdk/aws-route53-patterns/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-route53-patterns/jest.config.js +++ b/packages/@aws-cdk/aws-route53-patterns/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53-patterns/package.json b/packages/@aws-cdk/aws-route53-patterns/package.json index 4692f1c25903d..02e94d1139a5d 100644 --- a/packages/@aws-cdk/aws-route53-patterns/package.json +++ b/packages/@aws-cdk/aws-route53-patterns/package.json @@ -65,13 +65,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-certificatemanager": "0.0.0", @@ -105,7 +105,6 @@ "announce": false }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-route53-targets/.eslintrc.js b/packages/@aws-cdk/aws-route53-targets/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-route53-targets/.eslintrc.js +++ b/packages/@aws-cdk/aws-route53-targets/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53-targets/jest.config.js b/packages/@aws-cdk/aws-route53-targets/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-route53-targets/jest.config.js +++ b/packages/@aws-cdk/aws-route53-targets/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53-targets/lib/api-gateway-domain-name.ts b/packages/@aws-cdk/aws-route53-targets/lib/api-gateway-domain-name.ts index c87e26568d6b8..0cc215d5c5eed 100644 --- a/packages/@aws-cdk/aws-route53-targets/lib/api-gateway-domain-name.ts +++ b/packages/@aws-cdk/aws-route53-targets/lib/api-gateway-domain-name.ts @@ -26,7 +26,7 @@ export class ApiGatewayDomain implements route53.IAliasRecordTarget { * `ApiGatewayDomain` class. */ export class ApiGateway extends ApiGatewayDomain { - constructor(api: apig.RestApi) { + constructor(api: apig.RestApiBase) { if (!api.domainName) { throw new Error('API does not define a default domain name'); } diff --git a/packages/@aws-cdk/aws-route53-targets/package.json b/packages/@aws-cdk/aws-route53-targets/package.json index 0d42c4d83462f..8da79638f150b 100644 --- a/packages/@aws-cdk/aws-route53-targets/package.json +++ b/packages/@aws-cdk/aws-route53-targets/package.json @@ -64,16 +64,16 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/aws-apigatewayv2": "0.0.0", "@aws-cdk/aws-certificatemanager": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", - "@aws-cdk/aws-apigatewayv2": "0.0.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-apigateway": "0.0.0", @@ -82,8 +82,8 @@ "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-elasticloadbalancing": "0.0.0", "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", - "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-globalaccelerator": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-route53": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", @@ -98,8 +98,8 @@ "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-elasticloadbalancing": "0.0.0", "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", - "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-globalaccelerator": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-route53": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", @@ -115,7 +115,6 @@ }, "maturity": "stable", "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-route53-targets/test/apigateway-target.test.ts b/packages/@aws-cdk/aws-route53-targets/test/apigateway-target.test.ts index e62c87b59c385..5658a1f56323a 100644 --- a/packages/@aws-cdk/aws-route53-targets/test/apigateway-target.test.ts +++ b/packages/@aws-cdk/aws-route53-targets/test/apigateway-target.test.ts @@ -106,3 +106,51 @@ test('fails if an ApiGateway is used with an API that does not define a domain n }); }).toThrow(/API does not define a default domain name/); }); + +test('targets.ApiGateway accepts a SpecRestApi', () => { + // GIVEN + const stack = new Stack(); + const cert = new acm.Certificate(stack, 'cert', { domainName: 'example.com' }); + const api = new apigw.SpecRestApi(stack, 'api', { + domainName: { + domainName: 'example.com', + certificate: cert, + }, + apiDefinition: apigw.ApiDefinition.fromInline({ + key1: 'val1', + }), + }); + const zone = new route53.HostedZone(stack, 'zone', { + zoneName: 'example.com', + }); + api.root.addMethod('GET'); + + // WHEN + new route53.ARecord(stack, 'A', { + zone, + target: route53.RecordTarget.fromAlias(new targets.ApiGateway(api)), + }); + + // THEN + expectStack(stack).to(haveResource('AWS::Route53::RecordSet', { + Name: 'example.com.', + Type: 'A', + AliasTarget: { + DNSName: { + 'Fn::GetAtt': [ + 'apiCustomDomain64773C4F', + 'RegionalDomainName', + ], + }, + HostedZoneId: { + 'Fn::GetAtt': [ + 'apiCustomDomain64773C4F', + 'RegionalHostedZoneId', + ], + }, + }, + HostedZoneId: { + Ref: 'zoneEB40FF1E', + }, + })); +}); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-route53/.eslintrc.js b/packages/@aws-cdk/aws-route53/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-route53/.eslintrc.js +++ b/packages/@aws-cdk/aws-route53/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53/jest.config.js b/packages/@aws-cdk/aws-route53/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-route53/jest.config.js +++ b/packages/@aws-cdk/aws-route53/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53/package.json b/packages/@aws-cdk/aws-route53/package.json index 24e72e9300c93..2c775b5bd89d8 100644 --- a/packages/@aws-cdk/aws-route53/package.json +++ b/packages/@aws-cdk/aws-route53/package.json @@ -57,8 +57,7 @@ "cloudformation": "AWS::Route53", "env": { "AWSLINT_BASE_CONSTRUCT": true - }, - "jest": true + } }, "keywords": [ "aws", @@ -73,23 +72,22 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/aws-lambda": "^8.10.79", + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/aws-lambda": "^8.10.83", "@types/jest": "^26.0.24", - "@types/nodeunit": "^0.0.32", "aws-sdk": "^2.848.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", - "@aws-cdk/core": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", + "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", "constructs": "^3.3.69" }, @@ -98,8 +96,8 @@ "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", - "@aws-cdk/core": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", + "@aws-cdk/core": "0.0.0", "@aws-cdk/custom-resources": "0.0.0", "constructs": "^3.3.69" }, diff --git a/packages/@aws-cdk/aws-route53recoverycontrol/.eslintrc.js b/packages/@aws-cdk/aws-route53recoverycontrol/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-route53recoverycontrol/.eslintrc.js +++ b/packages/@aws-cdk/aws-route53recoverycontrol/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53recoverycontrol/jest.config.js b/packages/@aws-cdk/aws-route53recoverycontrol/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-route53recoverycontrol/jest.config.js +++ b/packages/@aws-cdk/aws-route53recoverycontrol/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53recoverycontrol/package.json b/packages/@aws-cdk/aws-route53recoverycontrol/package.json index 8ceaa50512b21..71c0d5c3e12b9 100644 --- a/packages/@aws-cdk/aws-route53recoverycontrol/package.json +++ b/packages/@aws-cdk/aws-route53recoverycontrol/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::Route53RecoveryControl", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-route53recoveryreadiness/.eslintrc.js b/packages/@aws-cdk/aws-route53recoveryreadiness/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-route53recoveryreadiness/.eslintrc.js +++ b/packages/@aws-cdk/aws-route53recoveryreadiness/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53recoveryreadiness/jest.config.js b/packages/@aws-cdk/aws-route53recoveryreadiness/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-route53recoveryreadiness/jest.config.js +++ b/packages/@aws-cdk/aws-route53recoveryreadiness/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53recoveryreadiness/package.json b/packages/@aws-cdk/aws-route53recoveryreadiness/package.json index afa6c384f2f7b..386a35690f2dc 100644 --- a/packages/@aws-cdk/aws-route53recoveryreadiness/package.json +++ b/packages/@aws-cdk/aws-route53recoveryreadiness/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::Route53RecoveryReadiness", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.22", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-route53resolver/.eslintrc.js b/packages/@aws-cdk/aws-route53resolver/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-route53resolver/.eslintrc.js +++ b/packages/@aws-cdk/aws-route53resolver/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53resolver/jest.config.js b/packages/@aws-cdk/aws-route53resolver/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-route53resolver/jest.config.js +++ b/packages/@aws-cdk/aws-route53resolver/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-route53resolver/lib/firewall-domain-list.ts b/packages/@aws-cdk/aws-route53resolver/lib/firewall-domain-list.ts index a6303b2c78114..80f211ab07f66 100644 --- a/packages/@aws-cdk/aws-route53resolver/lib/firewall-domain-list.ts +++ b/packages/@aws-cdk/aws-route53resolver/lib/firewall-domain-list.ts @@ -45,8 +45,8 @@ export abstract class FirewallDomains { */ public static fromList(list: string[]): FirewallDomains { for (const domain of list) { - if (!/^[\w-.]+$/.test(domain)) { - throw new Error(`Invalid domain: ${domain}. Valid characters: A-Z, a-z, 0-9, _, -, .`); + if (!/^([\w-.]{1,255}|\*[\w-.]{1,254})$/.test(domain)) { + throw new Error(`Invalid domain: ${domain}. Domain can optionally start with *. Max length of 255. Valid characters: A-Z, a-z, 0-9, _, -, .`); } } diff --git a/packages/@aws-cdk/aws-route53resolver/package.json b/packages/@aws-cdk/aws-route53resolver/package.json index 5e24de4caaffb..74d7bd95b363b 100644 --- a/packages/@aws-cdk/aws-route53resolver/package.json +++ b/packages/@aws-cdk/aws-route53resolver/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Route53Resolver", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -74,12 +73,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", @@ -106,7 +105,7 @@ "props-physical-name:@aws-cdk/aws-route53resolver.FirewallRuleGroupProps", "props-physical-name:@aws-cdk/aws-route53resolver.FirewallRuleGroupAssociationProps" ] - }, + }, "awscdkio": { "announce": false }, diff --git a/packages/@aws-cdk/aws-route53resolver/test/firewall-domain-list.test.ts b/packages/@aws-cdk/aws-route53resolver/test/firewall-domain-list.test.ts index 3806a59c670ba..5eaef3352d702 100644 --- a/packages/@aws-cdk/aws-route53resolver/test/firewall-domain-list.test.ts +++ b/packages/@aws-cdk/aws-route53resolver/test/firewall-domain-list.test.ts @@ -12,7 +12,11 @@ beforeEach(() => { test('domain list from strings', () => { // WHEN new FirewallDomainList(stack, 'List', { - domains: FirewallDomains.fromList(['first-domain.com', 'second-domain.net']), + domains: FirewallDomains.fromList([ + 'first-domain.com', + 'second-domain.net', + '*.wildcard.com', + ]), }); // THEN @@ -20,6 +24,7 @@ test('domain list from strings', () => { Domains: [ 'first-domain.com', 'second-domain.net', + '*.wildcard.com', ], }); }); diff --git a/packages/@aws-cdk/aws-s3-assets/.eslintrc.js b/packages/@aws-cdk/aws-s3-assets/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-s3-assets/.eslintrc.js +++ b/packages/@aws-cdk/aws-s3-assets/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-s3-assets/jest.config.js b/packages/@aws-cdk/aws-s3-assets/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-s3-assets/jest.config.js +++ b/packages/@aws-cdk/aws-s3-assets/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-s3-assets/package.json b/packages/@aws-cdk/aws-s3-assets/package.json index 987039fd3ab4b..8ab66aee891bb 100644 --- a/packages/@aws-cdk/aws-s3-assets/package.json +++ b/packages/@aws-cdk/aws-s3-assets/package.json @@ -52,7 +52,6 @@ "build+test+extract": "yarn build+test && yarn rosetta:extract" }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -71,18 +70,18 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "pkglint": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", - "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", + "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "constructs": "^3.3.69" @@ -91,8 +90,8 @@ "peerDependencies": { "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", - "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", + "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "constructs": "^3.3.69" diff --git a/packages/@aws-cdk/aws-s3-deployment/.eslintrc.js b/packages/@aws-cdk/aws-s3-deployment/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-s3-deployment/.eslintrc.js +++ b/packages/@aws-cdk/aws-s3-deployment/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-s3-deployment/jest.config.js b/packages/@aws-cdk/aws-s3-deployment/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-s3-deployment/jest.config.js +++ b/packages/@aws-cdk/aws-s3-deployment/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-s3-deployment/lib/bucket-deployment.ts b/packages/@aws-cdk/aws-s3-deployment/lib/bucket-deployment.ts index 439af53a90dd9..8e25826647a64 100644 --- a/packages/@aws-cdk/aws-s3-deployment/lib/bucket-deployment.ts +++ b/packages/@aws-cdk/aws-s3-deployment/lib/bucket-deployment.ts @@ -278,7 +278,7 @@ export class BucketDeployment extends CoreConstruct { uuid: this.renderSingletonUuid(props.memoryLimit, props.vpc), code: lambda.Code.fromAsset(path.join(__dirname, 'lambda')), layers: [new AwsCliLayer(this, 'AwsCliLayer')], - runtime: lambda.Runtime.PYTHON_3_6, + runtime: lambda.Runtime.PYTHON_3_7, environment: props.useEfs ? { MOUNT_PATH: mountPath, } : undefined, diff --git a/packages/@aws-cdk/aws-s3-deployment/package.json b/packages/@aws-cdk/aws-s3-deployment/package.json index 3d1f7e7659f5e..102b6e90ffc00 100644 --- a/packages/@aws-cdk/aws-s3-deployment/package.json +++ b/packages/@aws-cdk/aws-s3-deployment/package.json @@ -52,7 +52,6 @@ "build+test+extract": "yarn build+test && yarn rosetta:extract" }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -79,13 +78,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", "@aws-cdk/cx-api": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-cloudfront": "0.0.0", @@ -95,22 +94,22 @@ "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", - "@aws-cdk/lambda-layer-awscli": "0.0.0", "@aws-cdk/core": "0.0.0", + "@aws-cdk/lambda-layer-awscli": "0.0.0", "case": "1.6.3", "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/aws-cloudfront": "0.0.0", - "@aws-cdk/aws-efs": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/aws-efs": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", - "@aws-cdk/lambda-layer-awscli": "0.0.0", "@aws-cdk/core": "0.0.0", + "@aws-cdk/lambda-layer-awscli": "0.0.0", "constructs": "^3.3.69" }, "bundledDependencies": [ diff --git a/packages/@aws-cdk/aws-s3-deployment/test/bucket-deployment.test.ts b/packages/@aws-cdk/aws-s3-deployment/test/bucket-deployment.test.ts index b7a0e258b6393..7f799b2f9ff65 100644 --- a/packages/@aws-cdk/aws-s3-deployment/test/bucket-deployment.test.ts +++ b/packages/@aws-cdk/aws-s3-deployment/test/bucket-deployment.test.ts @@ -6,7 +6,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as s3deploy from '../lib'; /* eslint-disable max-len */ diff --git a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-cloudfront.expected.json b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-cloudfront.expected.json index bd5c7309210e3..ee73484606056 100644 --- a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-cloudfront.expected.json +++ b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-cloudfront.expected.json @@ -343,7 +343,7 @@ "Ref": "DeployWithInvalidationAwsCliLayerDEDD5787" } ], - "Runtime": "python3.6", + "Runtime": "python3.7", "Timeout": 900 }, "DependsOn": [ diff --git a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment.expected.json b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment.expected.json index 8b247a49a4428..28a59330cb59b 100644 --- a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment.expected.json +++ b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment.expected.json @@ -352,7 +352,7 @@ "Ref": "DeployMeAwsCliLayer5F9219E9" } ], - "Runtime": "python3.6", + "Runtime": "python3.7", "Timeout": 900 }, "DependsOn": [ @@ -1495,7 +1495,7 @@ "Ref": "DeployMeWithEfsStorageAwsCliLayer1619A3EE" } ], - "Runtime": "python3.6", + "Runtime": "python3.7", "Timeout": 900, "VpcConfig": { "SecurityGroupIds": [ diff --git a/packages/@aws-cdk/aws-s3-notifications/.eslintrc.js b/packages/@aws-cdk/aws-s3-notifications/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-s3-notifications/.eslintrc.js +++ b/packages/@aws-cdk/aws-s3-notifications/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-s3-notifications/jest.config.js b/packages/@aws-cdk/aws-s3-notifications/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-s3-notifications/jest.config.js +++ b/packages/@aws-cdk/aws-s3-notifications/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-s3-notifications/package.json b/packages/@aws-cdk/aws-s3-notifications/package.json index 62602ff1b6ce4..2ffab562221db 100644 --- a/packages/@aws-cdk/aws-s3-notifications/package.json +++ b/packages/@aws-cdk/aws-s3-notifications/package.json @@ -64,12 +64,12 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", @@ -99,7 +99,6 @@ }, "maturity": "stable", "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-s3/.eslintrc.js b/packages/@aws-cdk/aws-s3/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-s3/.eslintrc.js +++ b/packages/@aws-cdk/aws-s3/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-s3/README.md b/packages/@aws-cdk/aws-s3/README.md index 3470a526ded88..cd573f4c167e1 100644 --- a/packages/@aws-cdk/aws-s3/README.md +++ b/packages/@aws-cdk/aws-s3/README.md @@ -99,7 +99,7 @@ const result = bucket.addToResourcePolicy(new iam.PolicyStatement({ })); ``` -If you try to add a policy statement to an existing bucket, this method will +If you try to add a policy statement to an existing bucket, this method will not do anything: ```ts @@ -111,8 +111,8 @@ const result = bucket.addToResourcePolicy(new iam.PolicyStatement({ })); ``` -That's because it's not possible to tell whether the bucket -already has a policy attached, let alone to re-use that policy to add more +That's because it's not possible to tell whether the bucket +already has a policy attached, let alone to re-use that policy to add more statements to it. We recommend that you always check the result of the call: ```ts @@ -445,3 +445,8 @@ const bucket = new Bucket(this, 'MyTempFileBucket', { autoDeleteObjects: true, }); ``` + +**Warning** if you have deployed a bucket with `autoDeleteObjects: true`, +switching this to `false` in a CDK version *before* `1.126.0` will lead to all +objects in the bucket being deleted. Be sure to update to version `1.126.0` or +later before switching this value to `false`. diff --git a/packages/@aws-cdk/aws-s3/jest.config.js b/packages/@aws-cdk/aws-s3/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-s3/jest.config.js +++ b/packages/@aws-cdk/aws-s3/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-s3/lib/auto-delete-objects-handler/index.ts b/packages/@aws-cdk/aws-s3/lib/auto-delete-objects-handler/index.ts index f431aacf3fca2..fed602825c6a0 100644 --- a/packages/@aws-cdk/aws-s3/lib/auto-delete-objects-handler/index.ts +++ b/packages/@aws-cdk/aws-s3/lib/auto-delete-objects-handler/index.ts @@ -1,6 +1,8 @@ // eslint-disable-next-line import/no-extraneous-dependencies import { S3 } from 'aws-sdk'; +const AUTO_DELETE_OBJECTS_TAG = 'aws-cdk:auto-delete-objects'; + const s3 = new S3(); export async function handler(event: AWSLambda.CloudFormationCustomResourceEvent) { @@ -52,5 +54,22 @@ async function onDelete(bucketName?: string) { if (!bucketName) { throw new Error('No BucketName was provided.'); } + if (!await isBucketTaggedForDeletion(bucketName)) { + process.stdout.write(`Bucket does not have '${AUTO_DELETE_OBJECTS_TAG}' tag, skipping cleaning.\n`); + return; + } await emptyBucket(bucketName); } + +/** + * The bucket will only be tagged for deletion if it's being deleted in the same + * deployment as this Custom Resource. + * + * If the Custom Resource is every deleted before the bucket, it must be because + * `autoDeleteObjects` has been switched to false, in which case the tag would have + * been removed before we get to this Delete event. + */ +async function isBucketTaggedForDeletion(bucketName: string) { + const response = await s3.getBucketTagging({ Bucket: bucketName }).promise(); + return response.TagSet.some(tag => tag.Key === AUTO_DELETE_OBJECTS_TAG && tag.Value === 'true'); +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-s3/lib/bucket.ts b/packages/@aws-cdk/aws-s3/lib/bucket.ts index 970710c9a3dc4..1da58cd3db260 100644 --- a/packages/@aws-cdk/aws-s3/lib/bucket.ts +++ b/packages/@aws-cdk/aws-s3/lib/bucket.ts @@ -5,7 +5,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import { Fn, IResource, Lazy, RemovalPolicy, Resource, ResourceProps, Stack, Token, - CustomResource, CustomResourceProvider, CustomResourceProviderRuntime, FeatureFlags, + CustomResource, CustomResourceProvider, CustomResourceProviderRuntime, FeatureFlags, Tags, } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { Construct } from 'constructs'; @@ -18,6 +18,7 @@ import { CfnBucket } from './s3.generated'; import { parseBucketArn, parseBucketName } from './util'; const AUTO_DELETE_OBJECTS_RESOURCE_TYPE = 'Custom::S3AutoDeleteObjects'; +const AUTO_DELETE_OBJECTS_TAG = 'aws-cdk:auto-delete-objects'; export interface IBucket extends IResource { /** @@ -460,7 +461,7 @@ export abstract class BucketBase extends Resource implements IBucket { * Indicates if a bucket resource policy should automatically created upon * the first call to `addToResourcePolicy`. */ - protected abstract autoCreatePolicy = false; + protected abstract autoCreatePolicy: boolean; /** * Whether to disallow public access @@ -1228,6 +1229,11 @@ export interface BucketProps { * * Requires the `removalPolicy` to be set to `RemovalPolicy.DESTROY`. * + * **Warning** if you have deployed a bucket with `autoDeleteObjects: true`, + * switching this to `false` in a CDK version *before* `1.126.0` will lead to + * all objects in the bucket being deleted. Be sure to update to version `1.126.0` + * or later before switching this value to `false`. + * * @default false */ readonly autoDeleteObjects?: boolean; @@ -1443,6 +1449,7 @@ export class Bucket extends BucketBase { private readonly metrics: BucketMetrics[] = []; private readonly cors: CorsRule[] = []; private readonly inventories: Inventory[] = []; + private readonly _resource: CfnBucket; constructor(scope: Construct, id: string, props: BucketProps = {}) { super(scope, id, { @@ -1470,6 +1477,7 @@ export class Bucket extends BucketBase { inventoryConfigurations: Lazy.any({ produce: () => this.parseInventoryConfiguration() }), ownershipControls: this.parseOwnershipControls(props), }); + this._resource = resource; resource.applyRemovalPolicy(props.removalPolicy); @@ -1943,6 +1951,13 @@ export class Bucket extends BucketBase { if (this.policy) { customResource.node.addDependency(this.policy); } + + // We also tag the bucket to record the fact that we want it autodeleted. + // The custom resource will check this tag before actually doing the delete. + // Because tagging and untagging will ALWAYS happen before the CR is deleted, + // we can set `autoDeleteObjects: false` without the removal of the CR emptying + // the bucket as a side effect. + Tags.of(this._resource).add(AUTO_DELETE_OBJECTS_TAG, 'true'); } } diff --git a/packages/@aws-cdk/aws-s3/package.json b/packages/@aws-cdk/aws-s3/package.json index 865be5d5232b8..752032c268f34 100644 --- a/packages/@aws-cdk/aws-s3/package.json +++ b/packages/@aws-cdk/aws-s3/package.json @@ -57,8 +57,7 @@ "cloudformation": "AWS::S3", "env": { "AWSLINT_BASE_CONSTRUCT": "true" - }, - "jest": true + } }, "keywords": [ "aws", @@ -73,14 +72,14 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/aws-lambda": "^8.10.79", + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/aws-lambda": "^8.10.83", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-events": "0.0.0", diff --git a/packages/@aws-cdk/aws-s3/test/auto-delete-objects-handler.test.ts b/packages/@aws-cdk/aws-s3/test/auto-delete-objects-handler.test.ts index b09b9e5e4f5b3..51cc65b3d5466 100644 --- a/packages/@aws-cdk/aws-s3/test/auto-delete-objects-handler.test.ts +++ b/packages/@aws-cdk/aws-s3/test/auto-delete-objects-handler.test.ts @@ -1,6 +1,7 @@ const mockS3Client = { - listObjectVersions: jest.fn().mockReturnThis(), - deleteObjects: jest.fn().mockReturnThis(), + listObjectVersions: jest.fn(), + deleteObjects: jest.fn(), + getBucketTagging: jest.fn(), promise: jest.fn(), }; @@ -13,6 +14,7 @@ jest.mock('aws-sdk', () => { beforeEach(() => { mockS3Client.listObjectVersions.mockReturnThis(); mockS3Client.deleteObjects.mockReturnThis(); + givenTaggedForDeletion(); }); afterEach(() => { @@ -119,7 +121,7 @@ test('does nothing on update event when the new resource properties are absent', test('deletes all objects when the name changes on update event', async () => { // GIVEN - mockS3Client.promise.mockResolvedValue({ // listObjectVersions() call + mockAwsPromise(mockS3Client.listObjectVersions, { Versions: [ { Key: 'Key1', VersionId: 'VersionId1' }, { Key: 'Key2', VersionId: 'VersionId2' }, @@ -158,7 +160,7 @@ test('deletes all objects when the name changes on update event', async () => { test('deletes no objects on delete event when bucket has no objects', async () => { // GIVEN - mockS3Client.promise.mockResolvedValue({ Versions: [] }); // listObjectVersions() call + mockAwsPromise(mockS3Client.listObjectVersions, { Versions: [] }); // WHEN const event: Partial = { @@ -178,7 +180,7 @@ test('deletes no objects on delete event when bucket has no objects', async () = test('deletes all objects on delete event', async () => { // GIVEN - mockS3Client.promise.mockResolvedValue({ // listObjectVersions() call + mockAwsPromise(mockS3Client.listObjectVersions, { Versions: [ { Key: 'Key1', VersionId: 'VersionId1' }, { Key: 'Key2', VersionId: 'VersionId2' }, @@ -210,23 +212,46 @@ test('deletes all objects on delete event', async () => { }); }); +test('does not empty bucket if it is not tagged', async () => { + // GIVEN + givenNotTaggedForDeletion(); + mockAwsPromise(mockS3Client.listObjectVersions, { + Versions: [ + { Key: 'Key1', VersionId: 'VersionId1' }, + { Key: 'Key2', VersionId: 'VersionId2' }, + ], + }); + + // WHEN + const event: Partial = { + RequestType: 'Delete', + ResourceProperties: { + ServiceToken: 'Foo', + BucketName: 'MyBucket', + }, + }; + await invokeHandler(event); + + // THEN + expect(mockS3Client.listObjectVersions).not.toHaveBeenCalled(); +}); + test('delete event where bucket has many objects does recurse appropriately', async () => { // GIVEN - mockS3Client.promise // listObjectVersions() call - .mockResolvedValueOnce({ - Versions: [ - { Key: 'Key1', VersionId: 'VersionId1' }, - { Key: 'Key2', VersionId: 'VersionId2' }, - ], - IsTruncated: true, - }) - .mockResolvedValueOnce(undefined) // deleteObjects() call - .mockResolvedValueOnce({ // listObjectVersions() call - Versions: [ - { Key: 'Key3', VersionId: 'VersionId3' }, - { Key: 'Key4', VersionId: 'VersionId4' }, - ], - }); + mockAwsPromise(mockS3Client.listObjectVersions, { + Versions: [ + { Key: 'Key1', VersionId: 'VersionId1' }, + { Key: 'Key2', VersionId: 'VersionId2' }, + ], + IsTruncated: true, + }, 'once'); + mockAwsPromise(mockS3Client.listObjectVersions, { + Versions: [ + { Key: 'Key3', VersionId: 'VersionId3' }, + { Key: 'Key4', VersionId: 'VersionId4' }, + ], + }, 'once'); + mockAwsPromise(mockS3Client.deleteObjects, {}); // WHEN const event: Partial = { @@ -267,3 +292,27 @@ test('delete event where bucket has many objects does recurse appropriately', as async function invokeHandler(event: Partial) { return handler(event as AWSLambda.CloudFormationCustomResourceEvent); } + +function mockAwsPromise(fn: jest.Mock, value: A, when: 'once' | 'always' = 'always') { + (when === 'always' ? fn.mockReturnValue : fn.mockReturnValueOnce).call(fn, { + promise: () => value, + }); +} + +function givenTaggedForDeletion() { + mockAwsPromise(mockS3Client.getBucketTagging, { + TagSet: [ + { + Key: 'aws-cdk:auto-delete-objects', + Value: 'true', + }, + ], + + }); +} + +function givenNotTaggedForDeletion() { + mockAwsPromise(mockS3Client.getBucketTagging, { + TagSet: [], + }); +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-s3/test/bucket.test.ts b/packages/@aws-cdk/aws-s3/test/bucket.test.ts index d9be67427ab9c..3ef166722c1b6 100644 --- a/packages/@aws-cdk/aws-s3/test/bucket.test.ts +++ b/packages/@aws-cdk/aws-s3/test/bucket.test.ts @@ -5,7 +5,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior, testLegacyBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior, testLegacyBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as s3 from '../lib'; // to make it easy to copy & paste from output: diff --git a/packages/@aws-cdk/aws-s3/test/integ.bucket-auto-delete-objects.expected.json b/packages/@aws-cdk/aws-s3/test/integ.bucket-auto-delete-objects.expected.json index 6623d9d3e7a8c..7a935337c08b2 100644 --- a/packages/@aws-cdk/aws-s3/test/integ.bucket-auto-delete-objects.expected.json +++ b/packages/@aws-cdk/aws-s3/test/integ.bucket-auto-delete-objects.expected.json @@ -2,6 +2,14 @@ "Resources": { "Bucket83908E77": { "Type": "AWS::S3::Bucket", + "Properties": { + "Tags": [ + { + "Key": "aws-cdk:auto-delete-objects", + "Value": "true" + } + ] + }, "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, @@ -102,7 +110,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersfe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9S3BucketD715D8B0" + "Ref": "AssetParameters3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9S3Bucket4673BB1A" }, "S3Key": { "Fn::Join": [ @@ -115,7 +123,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersfe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9S3VersionKey6E76822C" + "Ref": "AssetParameters3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9S3VersionKey46E40510" } ] } @@ -128,7 +136,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersfe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9S3VersionKey6E76822C" + "Ref": "AssetParameters3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9S3VersionKey46E40510" } ] } @@ -220,7 +228,7 @@ "Properties": { "Code": { "S3Bucket": { - "Ref": "AssetParametersf7ee44e9b6217d201200d9abd42c6493b0b11e86be8a7f36163c3ea049c54653S3BucketDB5FAF47" + "Ref": "AssetParameters618bbe9863c0edd5c4ca2e24b5063762f020fafec018cd06f57e2bd9f2f48abfS3BucketE1985B35" }, "S3Key": { "Fn::Join": [ @@ -233,7 +241,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersf7ee44e9b6217d201200d9abd42c6493b0b11e86be8a7f36163c3ea049c54653S3VersionKey9809F0E6" + "Ref": "AssetParameters618bbe9863c0edd5c4ca2e24b5063762f020fafec018cd06f57e2bd9f2f48abfS3VersionKey610C6DE2" } ] } @@ -246,7 +254,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersf7ee44e9b6217d201200d9abd42c6493b0b11e86be8a7f36163c3ea049c54653S3VersionKey9809F0E6" + "Ref": "AssetParameters618bbe9863c0edd5c4ca2e24b5063762f020fafec018cd06f57e2bd9f2f48abfS3VersionKey610C6DE2" } ] } @@ -289,29 +297,29 @@ } }, "Parameters": { - "AssetParametersfe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9S3BucketD715D8B0": { + "AssetParameters3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9S3Bucket4673BB1A": { "Type": "String", - "Description": "S3 bucket for asset \"fe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9\"" + "Description": "S3 bucket for asset \"3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9\"" }, - "AssetParametersfe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9S3VersionKey6E76822C": { + "AssetParameters3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9S3VersionKey46E40510": { "Type": "String", - "Description": "S3 key for asset version \"fe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9\"" + "Description": "S3 key for asset version \"3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9\"" }, - "AssetParametersfe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9ArtifactHash9AE3702B": { + "AssetParameters3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9ArtifactHashBD621721": { "Type": "String", - "Description": "Artifact hash for asset \"fe5df38824187483182e1459db47adfae2a515aa4caedd437fc4033a0c5b3de9\"" + "Description": "Artifact hash for asset \"3993fb4cd942505a050d08b09d5444e14c265cf9cd0fb8b0c5f621446b6cead9\"" }, - "AssetParametersf7ee44e9b6217d201200d9abd42c6493b0b11e86be8a7f36163c3ea049c54653S3BucketDB5FAF47": { + "AssetParameters618bbe9863c0edd5c4ca2e24b5063762f020fafec018cd06f57e2bd9f2f48abfS3BucketE1985B35": { "Type": "String", - "Description": "S3 bucket for asset \"f7ee44e9b6217d201200d9abd42c6493b0b11e86be8a7f36163c3ea049c54653\"" + "Description": "S3 bucket for asset \"618bbe9863c0edd5c4ca2e24b5063762f020fafec018cd06f57e2bd9f2f48abf\"" }, - "AssetParametersf7ee44e9b6217d201200d9abd42c6493b0b11e86be8a7f36163c3ea049c54653S3VersionKey9809F0E6": { + "AssetParameters618bbe9863c0edd5c4ca2e24b5063762f020fafec018cd06f57e2bd9f2f48abfS3VersionKey610C6DE2": { "Type": "String", - "Description": "S3 key for asset version \"f7ee44e9b6217d201200d9abd42c6493b0b11e86be8a7f36163c3ea049c54653\"" + "Description": "S3 key for asset version \"618bbe9863c0edd5c4ca2e24b5063762f020fafec018cd06f57e2bd9f2f48abf\"" }, - "AssetParametersf7ee44e9b6217d201200d9abd42c6493b0b11e86be8a7f36163c3ea049c54653ArtifactHash7CDE16B1": { + "AssetParameters618bbe9863c0edd5c4ca2e24b5063762f020fafec018cd06f57e2bd9f2f48abfArtifactHash467DFC33": { "Type": "String", - "Description": "Artifact hash for asset \"f7ee44e9b6217d201200d9abd42c6493b0b11e86be8a7f36163c3ea049c54653\"" + "Description": "Artifact hash for asset \"618bbe9863c0edd5c4ca2e24b5063762f020fafec018cd06f57e2bd9f2f48abf\"" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-s3/test/integ.bucket-auto-delete-objects.ts b/packages/@aws-cdk/aws-s3/test/integ.bucket-auto-delete-objects.ts index 8052dd340d888..e89e12c83eeb9 100644 --- a/packages/@aws-cdk/aws-s3/test/integ.bucket-auto-delete-objects.ts +++ b/packages/@aws-cdk/aws-s3/test/integ.bucket-auto-delete-objects.ts @@ -1,3 +1,4 @@ +/// !cdk-integ pragma:ignore-assets import * as path from 'path'; import { App, CustomResource, CustomResourceProvider, CustomResourceProviderRuntime, RemovalPolicy, Stack, StackProps } from '@aws-cdk/core'; import { Construct } from 'constructs'; diff --git a/packages/@aws-cdk/aws-s3/test/put-objects-handler/index.ts b/packages/@aws-cdk/aws-s3/test/put-objects-handler/index.ts index d4137760eb591..4a392db00cb66 100644 --- a/packages/@aws-cdk/aws-s3/test/put-objects-handler/index.ts +++ b/packages/@aws-cdk/aws-s3/test/put-objects-handler/index.ts @@ -6,6 +6,9 @@ const s3 = new S3(); export async function handler(event: AWSLambda.CloudFormationCustomResourceEvent): Promise { switch (event.RequestType) { case 'Create': + if (event.ResourceProperties.Fail) { + throw new Error('Failing on request!'); + } const bucketName = event.ResourceProperties.BucketName; if (!bucketName) { throw new Error('Missing BucketName'); diff --git a/packages/@aws-cdk/aws-s3objectlambda/.eslintrc.js b/packages/@aws-cdk/aws-s3objectlambda/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-s3objectlambda/.eslintrc.js +++ b/packages/@aws-cdk/aws-s3objectlambda/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-s3objectlambda/jest.config.js b/packages/@aws-cdk/aws-s3objectlambda/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-s3objectlambda/jest.config.js +++ b/packages/@aws-cdk/aws-s3objectlambda/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-s3objectlambda/package.json b/packages/@aws-cdk/aws-s3objectlambda/package.json index f8e0d0986fe8a..8890f752cefe4 100644 --- a/packages/@aws-cdk/aws-s3objectlambda/package.json +++ b/packages/@aws-cdk/aws-s3objectlambda/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::S3ObjectLambda", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-s3outposts/.eslintrc.js b/packages/@aws-cdk/aws-s3outposts/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-s3outposts/.eslintrc.js +++ b/packages/@aws-cdk/aws-s3outposts/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-s3outposts/jest.config.js b/packages/@aws-cdk/aws-s3outposts/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-s3outposts/jest.config.js +++ b/packages/@aws-cdk/aws-s3outposts/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-s3outposts/package.json b/packages/@aws-cdk/aws-s3outposts/package.json index da5317e14e7b3..930f149e5fb6e 100644 --- a/packages/@aws-cdk/aws-s3outposts/package.json +++ b/packages/@aws-cdk/aws-s3outposts/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::S3Outposts", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-sagemaker/.eslintrc.js b/packages/@aws-cdk/aws-sagemaker/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-sagemaker/.eslintrc.js +++ b/packages/@aws-cdk/aws-sagemaker/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sagemaker/jest.config.js b/packages/@aws-cdk/aws-sagemaker/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-sagemaker/jest.config.js +++ b/packages/@aws-cdk/aws-sagemaker/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sagemaker/package.json b/packages/@aws-cdk/aws-sagemaker/package.json index 136d5ad52ea25..538e00d0afb5a 100644 --- a/packages/@aws-cdk/aws-sagemaker/package.json +++ b/packages/@aws-cdk/aws-sagemaker/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::SageMaker", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -74,11 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-sam/.eslintrc.js b/packages/@aws-cdk/aws-sam/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-sam/.eslintrc.js +++ b/packages/@aws-cdk/aws-sam/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sam/jest.config.js b/packages/@aws-cdk/aws-sam/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-sam/jest.config.js +++ b/packages/@aws-cdk/aws-sam/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sam/package.json b/packages/@aws-cdk/aws-sam/package.json index 9083b5b5d83bf..9bd8d5caa4a13 100644 --- a/packages/@aws-cdk/aws-sam/package.json +++ b/packages/@aws-cdk/aws-sam/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Serverless", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -74,13 +73,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0", - "ts-jest": "^26.5.6", - "@aws-cdk/assertions": "0.0.0" + "ts-jest": "^26.5.6" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-sdb/.eslintrc.js b/packages/@aws-cdk/aws-sdb/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-sdb/.eslintrc.js +++ b/packages/@aws-cdk/aws-sdb/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sdb/jest.config.js b/packages/@aws-cdk/aws-sdb/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-sdb/jest.config.js +++ b/packages/@aws-cdk/aws-sdb/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sdb/package.json b/packages/@aws-cdk/aws-sdb/package.json index 9863fe0333e24..cce3519d22c62 100644 --- a/packages/@aws-cdk/aws-sdb/package.json +++ b/packages/@aws-cdk/aws-sdb/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::SDB", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-secretsmanager/.eslintrc.js b/packages/@aws-cdk/aws-secretsmanager/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-secretsmanager/.eslintrc.js +++ b/packages/@aws-cdk/aws-secretsmanager/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-secretsmanager/jest.config.js b/packages/@aws-cdk/aws-secretsmanager/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-secretsmanager/jest.config.js +++ b/packages/@aws-cdk/aws-secretsmanager/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-secretsmanager/package.json b/packages/@aws-cdk/aws-secretsmanager/package.json index 8e465f8d54c77..9cc6876067018 100644 --- a/packages/@aws-cdk/aws-secretsmanager/package.json +++ b/packages/@aws-cdk/aws-secretsmanager/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::SecretsManager", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -74,12 +73,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-secretsmanager/test/secret.test.ts b/packages/@aws-cdk/aws-secretsmanager/test/secret.test.ts index d3da8d52a6c74..7f154c77b5f7f 100644 --- a/packages/@aws-cdk/aws-secretsmanager/test/secret.test.ts +++ b/packages/@aws-cdk/aws-secretsmanager/test/secret.test.ts @@ -4,7 +4,7 @@ import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; import * as lambda from '@aws-cdk/aws-lambda'; import * as cdk from '@aws-cdk/core'; -import { testFutureBehavior, testLegacyBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior, testLegacyBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as secretsmanager from '../lib'; let app: cdk.App; diff --git a/packages/@aws-cdk/aws-securityhub/.eslintrc.js b/packages/@aws-cdk/aws-securityhub/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-securityhub/.eslintrc.js +++ b/packages/@aws-cdk/aws-securityhub/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-securityhub/jest.config.js b/packages/@aws-cdk/aws-securityhub/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-securityhub/jest.config.js +++ b/packages/@aws-cdk/aws-securityhub/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-securityhub/package.json b/packages/@aws-cdk/aws-securityhub/package.json index e71153d4822ad..b4102e4918385 100644 --- a/packages/@aws-cdk/aws-securityhub/package.json +++ b/packages/@aws-cdk/aws-securityhub/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::SecurityHub", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-servicecatalog/.eslintrc.js b/packages/@aws-cdk/aws-servicecatalog/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-servicecatalog/.eslintrc.js +++ b/packages/@aws-cdk/aws-servicecatalog/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-servicecatalog/jest.config.js b/packages/@aws-cdk/aws-servicecatalog/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-servicecatalog/jest.config.js +++ b/packages/@aws-cdk/aws-servicecatalog/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-servicecatalog/package.json b/packages/@aws-cdk/aws-servicecatalog/package.json index bc482eedff82e..de3bfcfb667a5 100644 --- a/packages/@aws-cdk/aws-servicecatalog/package.json +++ b/packages/@aws-cdk/aws-servicecatalog/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::ServiceCatalog", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -74,11 +73,11 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", diff --git a/packages/@aws-cdk/aws-servicecatalogappregistry/.eslintrc.js b/packages/@aws-cdk/aws-servicecatalogappregistry/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-servicecatalogappregistry/.eslintrc.js +++ b/packages/@aws-cdk/aws-servicecatalogappregistry/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-servicecatalogappregistry/jest.config.js b/packages/@aws-cdk/aws-servicecatalogappregistry/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-servicecatalogappregistry/jest.config.js +++ b/packages/@aws-cdk/aws-servicecatalogappregistry/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-servicecatalogappregistry/package.json b/packages/@aws-cdk/aws-servicecatalogappregistry/package.json index 921cb1fd4de60..440022bde6091 100644 --- a/packages/@aws-cdk/aws-servicecatalogappregistry/package.json +++ b/packages/@aws-cdk/aws-servicecatalogappregistry/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::ServiceCatalogAppRegistry", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -78,11 +77,11 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-servicediscovery/.eslintrc.js b/packages/@aws-cdk/aws-servicediscovery/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-servicediscovery/.eslintrc.js +++ b/packages/@aws-cdk/aws-servicediscovery/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-servicediscovery/jest.config.js b/packages/@aws-cdk/aws-servicediscovery/jest.config.js index cd664e1d069e5..34818e1593f6b 100644 --- a/packages/@aws-cdk/aws-servicediscovery/jest.config.js +++ b/packages/@aws-cdk/aws-servicediscovery/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-servicediscovery/package.json b/packages/@aws-cdk/aws-servicediscovery/package.json index f23d76efe7566..4169aaadae0ca 100644 --- a/packages/@aws-cdk/aws-servicediscovery/package.json +++ b/packages/@aws-cdk/aws-servicediscovery/package.json @@ -57,8 +57,7 @@ "cloudformation": "AWS::ServiceDiscovery", "env": { "AWSLINT_BASE_CONSTRUCT": true - }, - "jest": true + } }, "nyc": { "statements": 75 @@ -76,13 +75,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-ses-actions/.eslintrc.js b/packages/@aws-cdk/aws-ses-actions/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-ses-actions/.eslintrc.js +++ b/packages/@aws-cdk/aws-ses-actions/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ses-actions/jest.config.js b/packages/@aws-cdk/aws-ses-actions/jest.config.js index fc310b5014407..d052cbb29f05d 100644 --- a/packages/@aws-cdk/aws-ses-actions/jest.config.js +++ b/packages/@aws-cdk/aws-ses-actions/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/aws-ses-actions/package.json b/packages/@aws-cdk/aws-ses-actions/package.json index 37ead111df047..5f5be5276102c 100644 --- a/packages/@aws-cdk/aws-ses-actions/package.json +++ b/packages/@aws-cdk/aws-ses-actions/package.json @@ -65,13 +65,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", @@ -115,7 +115,6 @@ "announce": false }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-ses/.eslintrc.js b/packages/@aws-cdk/aws-ses/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-ses/.eslintrc.js +++ b/packages/@aws-cdk/aws-ses/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ses/jest.config.js b/packages/@aws-cdk/aws-ses/jest.config.js index cd664e1d069e5..34818e1593f6b 100644 --- a/packages/@aws-cdk/aws-ses/jest.config.js +++ b/packages/@aws-cdk/aws-ses/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ses/package.json b/packages/@aws-cdk/aws-ses/package.json index 4c2c765ef6982..9948c950af6f6 100644 --- a/packages/@aws-cdk/aws-ses/package.json +++ b/packages/@aws-cdk/aws-ses/package.json @@ -57,8 +57,7 @@ "cloudformation": "AWS::SES", "env": { "AWSLINT_BASE_CONSTRUCT": true - }, - "jest": true + } }, "keywords": [ "aws", @@ -73,14 +72,14 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/aws-lambda": "^8.10.79", + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/aws-lambda": "^8.10.83", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", diff --git a/packages/@aws-cdk/aws-signer/.eslintrc.js b/packages/@aws-cdk/aws-signer/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-signer/.eslintrc.js +++ b/packages/@aws-cdk/aws-signer/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-signer/jest.config.js b/packages/@aws-cdk/aws-signer/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-signer/jest.config.js +++ b/packages/@aws-cdk/aws-signer/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-signer/package.json b/packages/@aws-cdk/aws-signer/package.json index e0318b1bcf011..84489e43c845b 100644 --- a/packages/@aws-cdk/aws-signer/package.json +++ b/packages/@aws-cdk/aws-signer/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Signer", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-sns-subscriptions/.eslintrc.js b/packages/@aws-cdk/aws-sns-subscriptions/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/.eslintrc.js +++ b/packages/@aws-cdk/aws-sns-subscriptions/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sns-subscriptions/jest.config.js b/packages/@aws-cdk/aws-sns-subscriptions/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/jest.config.js +++ b/packages/@aws-cdk/aws-sns-subscriptions/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sns-subscriptions/package.json b/packages/@aws-cdk/aws-sns-subscriptions/package.json index 9d0b4db805c67..9bc3880a4ba23 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/package.json +++ b/packages/@aws-cdk/aws-sns-subscriptions/package.json @@ -64,13 +64,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", @@ -100,7 +100,6 @@ }, "maturity": "stable", "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-sns/.eslintrc.js b/packages/@aws-cdk/aws-sns/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-sns/.eslintrc.js +++ b/packages/@aws-cdk/aws-sns/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sns/jest.config.js b/packages/@aws-cdk/aws-sns/jest.config.js index 1f611abd50de4..dcc7c22a3aae9 100644 --- a/packages/@aws-cdk/aws-sns/jest.config.js +++ b/packages/@aws-cdk/aws-sns/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/aws-sns/lib/subscription-filter.ts b/packages/@aws-cdk/aws-sns/lib/subscription-filter.ts index c6fc1be95d247..69be08bb1db26 100644 --- a/packages/@aws-cdk/aws-sns/lib/subscription-filter.ts +++ b/packages/@aws-cdk/aws-sns/lib/subscription-filter.ts @@ -162,19 +162,19 @@ export class SubscriptionFilter { conditions.push(...allowlist.map(v => ({ numeric: ['=', v] }))); } - if (numericConditions.greaterThan) { + if (numericConditions.greaterThan !== undefined) { conditions.push({ numeric: ['>', numericConditions.greaterThan] }); } - if (numericConditions.greaterThanOrEqualTo) { + if (numericConditions.greaterThanOrEqualTo !== undefined) { conditions.push({ numeric: ['>=', numericConditions.greaterThanOrEqualTo] }); } - if (numericConditions.lessThan) { + if (numericConditions.lessThan !== undefined) { conditions.push({ numeric: ['<', numericConditions.lessThan] }); } - if (numericConditions.lessThanOrEqualTo) { + if (numericConditions.lessThanOrEqualTo !== undefined) { conditions.push({ numeric: ['<=', numericConditions.lessThanOrEqualTo] }); } diff --git a/packages/@aws-cdk/aws-sns/package.json b/packages/@aws-cdk/aws-sns/package.json index 26d7441d5ee6d..8e27308a61703 100644 --- a/packages/@aws-cdk/aws-sns/package.json +++ b/packages/@aws-cdk/aws-sns/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::SNS", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -78,12 +77,12 @@ "devDependencies": { "@aws-cdk/assertions": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", diff --git a/packages/@aws-cdk/aws-sns/test/subscription.test.ts b/packages/@aws-cdk/aws-sns/test/subscription.test.ts index a495769648d4b..dd0f9588d2296 100644 --- a/packages/@aws-cdk/aws-sns/test/subscription.test.ts +++ b/packages/@aws-cdk/aws-sns/test/subscription.test.ts @@ -153,6 +153,40 @@ describe('Subscription', () => { }); + test('with numeric filter and 0 values', () => { + // GIVEN + const stack = new cdk.Stack(); + const topic = new sns.Topic(stack, 'Topic'); + + // WHEN + new sns.Subscription(stack, 'Subscription', { + endpoint: 'endpoint', + filterPolicy: { + price: sns.SubscriptionFilter.numericFilter({ + greaterThan: 0, + greaterThanOrEqualTo: 0, + lessThan: 0, + lessThanOrEqualTo: 0, + }), + }, + protocol: sns.SubscriptionProtocol.LAMBDA, + topic, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::SNS::Subscription', { + FilterPolicy: { + price: [ + { numeric: ['>', 0] }, + { numeric: ['>=', 0] }, + { numeric: ['<', 0] }, + { numeric: ['<=', 0] }, + ], + }, + }); + + }); + test('with existsFilter', () => { // GIVEN const stack = new cdk.Stack(); diff --git a/packages/@aws-cdk/aws-sqs/.eslintrc.js b/packages/@aws-cdk/aws-sqs/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-sqs/.eslintrc.js +++ b/packages/@aws-cdk/aws-sqs/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sqs/.gitignore b/packages/@aws-cdk/aws-sqs/.gitignore index d0a956699806b..be330198b9888 100644 --- a/packages/@aws-cdk/aws-sqs/.gitignore +++ b/packages/@aws-cdk/aws-sqs/.gitignore @@ -16,4 +16,5 @@ nyc.config.js *.snk !.eslintrc.js -junit.xml \ No newline at end of file +junit.xml +!jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-sqs/.npmignore b/packages/@aws-cdk/aws-sqs/.npmignore index 9a032ae80868c..e8acf10a468a1 100644 --- a/packages/@aws-cdk/aws-sqs/.npmignore +++ b/packages/@aws-cdk/aws-sqs/.npmignore @@ -24,4 +24,5 @@ tsconfig.json **/cdk.out junit.xml test/ -!*.lit.ts \ No newline at end of file +!*.lit.ts +jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-sqs/jest.config.js b/packages/@aws-cdk/aws-sqs/jest.config.js new file mode 100644 index 0000000000000..34818e1593f6b --- /dev/null +++ b/packages/@aws-cdk/aws-sqs/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sqs/package.json b/packages/@aws-cdk/aws-sqs/package.json index 7daec64f522f5..d3ab48584fd61 100644 --- a/packages/@aws-cdk/aws-sqs/package.json +++ b/packages/@aws-cdk/aws-sqs/package.json @@ -72,15 +72,15 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", - "@types/nodeunit": "^0.0.32", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", "aws-sdk": "^2.848.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "nodeunit": "^0.11.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", diff --git a/packages/@aws-cdk/aws-sqs/test/sqs.test.ts b/packages/@aws-cdk/aws-sqs/test/sqs.test.ts new file mode 100644 index 0000000000000..3f86e6d68b6da --- /dev/null +++ b/packages/@aws-cdk/aws-sqs/test/sqs.test.ts @@ -0,0 +1,601 @@ +import { ResourcePart } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +import * as iam from '@aws-cdk/aws-iam'; +import * as kms from '@aws-cdk/aws-kms'; +import { CfnParameter, Duration, Stack, App, Token } from '@aws-cdk/core'; +import * as sqs from '../lib'; + +/* eslint-disable quote-props */ + +test('default properties', () => { + const stack = new Stack(); + const q = new sqs.Queue(stack, 'Queue'); + + expect(q.fifo).toEqual(false); + + expect(stack).toMatchTemplate({ + 'Resources': { + 'Queue4A7E3555': { + 'Type': 'AWS::SQS::Queue', + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', + }, + }, + }); + + expect(stack).toHaveResource('AWS::SQS::Queue', { + DeletionPolicy: 'Delete', + }, ResourcePart.CompleteDefinition); +}); + +test('with a dead letter queue', () => { + const stack = new Stack(); + const dlq = new sqs.Queue(stack, 'DLQ'); + new sqs.Queue(stack, 'Queue', { deadLetterQueue: { queue: dlq, maxReceiveCount: 3 } }); + + expect(stack).toMatchTemplate({ + 'Resources': { + 'DLQ581697C4': { + 'Type': 'AWS::SQS::Queue', + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', + }, + 'Queue4A7E3555': { + 'Type': 'AWS::SQS::Queue', + 'Properties': { + 'RedrivePolicy': { + 'deadLetterTargetArn': { + 'Fn::GetAtt': [ + 'DLQ581697C4', + 'Arn', + ], + }, + 'maxReceiveCount': 3, + }, + }, + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', + }, + }, + }); +}); + +test('message retention period must be between 1 minute to 14 days', () => { + // GIVEN + const stack = new Stack(); + + // THEN + expect(() => new sqs.Queue(stack, 'MyQueue', { + retentionPeriod: Duration.seconds(30), + })).toThrow(/message retention period must be 60 seconds or more/); + + expect(() => new sqs.Queue(stack, 'AnotherQueue', { + retentionPeriod: Duration.days(15), + })).toThrow(/message retention period must be 1209600 seconds or less/); +}); + +test('message retention period can be provided as a parameter', () => { + // GIVEN + const stack = new Stack(); + const parameter = new CfnParameter(stack, 'my-retention-period', { + type: 'Number', + default: 30, + }); + + // WHEN + new sqs.Queue(stack, 'MyQueue', { + retentionPeriod: Duration.seconds(parameter.valueAsNumber), + }); + + // THEN + expect(stack).toMatchTemplate({ + 'Parameters': { + 'myretentionperiod': { + 'Type': 'Number', + 'Default': 30, + }, + }, + 'Resources': { + 'MyQueueE6CA6235': { + 'Type': 'AWS::SQS::Queue', + 'Properties': { + 'MessageRetentionPeriod': { + 'Ref': 'myretentionperiod', + }, + }, + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', + }, + }, + }); +}); + +test('addToPolicy will automatically create a policy for this queue', () => { + const stack = new Stack(); + const queue = new sqs.Queue(stack, 'MyQueue'); + queue.addToResourcePolicy(new iam.PolicyStatement({ + resources: ['*'], + actions: ['sqs:*'], + principals: [new iam.ArnPrincipal('arn')], + })); + + expect(stack).toMatchTemplate({ + 'Resources': { + 'MyQueueE6CA6235': { + 'Type': 'AWS::SQS::Queue', + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', + }, + 'MyQueuePolicy6BBEDDAC': { + 'Type': 'AWS::SQS::QueuePolicy', + 'Properties': { + 'PolicyDocument': { + 'Statement': [ + { + 'Action': 'sqs:*', + 'Effect': 'Allow', + 'Principal': { + 'AWS': 'arn', + }, + 'Resource': '*', + }, + ], + 'Version': '2012-10-17', + }, + 'Queues': [ + { + 'Ref': 'MyQueueE6CA6235', + }, + ], + }, + }, + }, + }); +}); + +describe('export and import', () => { + test('importing works correctly', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + const imports = sqs.Queue.fromQueueArn(stack, 'Imported', 'arn:aws:sqs:us-east-1:123456789012:queue1'); + + // THEN + + // "import" returns an IQueue bound to `Fn::ImportValue`s. + expect(stack.resolve(imports.queueArn)).toEqual('arn:aws:sqs:us-east-1:123456789012:queue1'); + expect(stack.resolve(imports.queueUrl)).toEqual({ + 'Fn::Join': + ['', ['https://sqs.us-east-1.', { Ref: 'AWS::URLSuffix' }, '/123456789012/queue1']], + }); + expect(stack.resolve(imports.queueName)).toEqual('queue1'); + }); + + test('importing fifo and standard queues are detected correctly', () => { + const stack = new Stack(); + const stdQueue = sqs.Queue.fromQueueArn(stack, 'StdQueue', 'arn:aws:sqs:us-east-1:123456789012:queue1'); + const fifoQueue = sqs.Queue.fromQueueArn(stack, 'FifoQueue', 'arn:aws:sqs:us-east-1:123456789012:queue2.fifo'); + expect(stdQueue.fifo).toEqual(false); + expect(fifoQueue.fifo).toEqual(true); + }); + + test('import queueArn from token, fifo and standard queues can be defined', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + const stdQueue1 = sqs.Queue.fromQueueAttributes(stack, 'StdQueue1', { + queueArn: Token.asString({ Ref: 'ARN' }), + }); + const stdQueue2 = sqs.Queue.fromQueueAttributes(stack, 'StdQueue2', { + queueArn: Token.asString({ Ref: 'ARN' }), + fifo: false, + }); + const fifoQueue = sqs.Queue.fromQueueAttributes(stack, 'FifoQueue', { + queueArn: Token.asString({ Ref: 'ARN' }), + fifo: true, + }); + + // THEN + expect(stdQueue1.fifo).toEqual(false); + expect(stdQueue2.fifo).toEqual(false); + expect(fifoQueue.fifo).toEqual(true); + }); + + test('import queueArn from token, check attributes', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + const stdQueue1 = sqs.Queue.fromQueueArn(stack, 'StdQueue', Token.asString({ Ref: 'ARN' })); + + // THEN + expect(stack.resolve(stdQueue1.queueArn)).toEqual({ + Ref: 'ARN', + }); + expect(stack.resolve(stdQueue1.queueName)).toEqual({ + 'Fn::Select': [5, { 'Fn::Split': [':', { Ref: 'ARN' }] }], + }); + expect(stack.resolve(stdQueue1.queueUrl)).toEqual({ + 'Fn::Join': + ['', + ['https://sqs.', + { 'Fn::Select': [3, { 'Fn::Split': [':', { Ref: 'ARN' }] }] }, + '.', + { Ref: 'AWS::URLSuffix' }, + '/', + { 'Fn::Select': [4, { 'Fn::Split': [':', { Ref: 'ARN' }] }] }, + '/', + { 'Fn::Select': [5, { 'Fn::Split': [':', { Ref: 'ARN' }] }] }]], + }); + expect(stdQueue1.fifo).toEqual(false); + }); + + test('fails if fifo flag is set for non fifo queue name', () => { + // GIVEN + const app = new App(); + const stack = new Stack(app, 'my-stack'); + + // THEN + expect(() => sqs.Queue.fromQueueAttributes(stack, 'ImportedStdQueue', { + queueArn: 'arn:aws:sqs:us-west-2:123456789012:queue1', + fifo: true, + })).toThrow(/FIFO queue names must end in '.fifo'/); + }); + + test('fails if fifo flag is false for fifo queue name', () => { + // GIVEN + const app = new App(); + const stack = new Stack(app, 'my-stack'); + + // THEN + expect(() => sqs.Queue.fromQueueAttributes(stack, 'ImportedFifoQueue', { + queueArn: 'arn:aws:sqs:us-west-2:123456789012:queue1.fifo', + fifo: false, + })).toThrow(/Non-FIFO queue name may not end in '.fifo'/); + }); + + test('importing works correctly for cross region queue', () => { + // GIVEN + const stack = new Stack(undefined, 'Stack', { env: { region: 'us-east-1' } }); + + // WHEN + const imports = sqs.Queue.fromQueueArn(stack, 'Imported', 'arn:aws:sqs:us-west-2:123456789012:queue1'); + + // THEN + + // "import" returns an IQueue bound to `Fn::ImportValue`s. + expect(stack.resolve(imports.queueArn)).toEqual('arn:aws:sqs:us-west-2:123456789012:queue1'); + expect(stack.resolve(imports.queueUrl)).toEqual({ + 'Fn::Join': + ['', ['https://sqs.us-west-2.', { Ref: 'AWS::URLSuffix' }, '/123456789012/queue1']], + }); + expect(stack.resolve(imports.queueName)).toEqual('queue1'); + }); +}); + +describe('grants', () => { + test('grantConsumeMessages', () => { + testGrant((q, p) => q.grantConsumeMessages(p), + 'sqs:ReceiveMessage', + 'sqs:ChangeMessageVisibility', + 'sqs:GetQueueUrl', + 'sqs:DeleteMessage', + 'sqs:GetQueueAttributes', + ); + }); + + test('grantSendMessages', () => { + testGrant((q, p) => q.grantSendMessages(p), + 'sqs:SendMessage', + 'sqs:GetQueueAttributes', + 'sqs:GetQueueUrl', + ); + }); + + test('grantPurge', () => { + testGrant((q, p) => q.grantPurge(p), + 'sqs:PurgeQueue', + 'sqs:GetQueueAttributes', + 'sqs:GetQueueUrl', + ); + }); + + test('grant() is general purpose', () => { + testGrant((q, p) => q.grant(p, 'service:hello', 'service:world'), + 'service:hello', + 'service:world', + ); + }); + + test('grants also work on imported queues', () => { + const stack = new Stack(); + const queue = sqs.Queue.fromQueueAttributes(stack, 'Import', { + queueArn: 'arn:aws:sqs:us-east-1:123456789012:queue1', + queueUrl: 'https://queue-url', + }); + + const user = new iam.User(stack, 'User'); + + queue.grantPurge(user); + + expect(stack).toHaveResource('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': [ + { + 'Action': [ + 'sqs:PurgeQueue', + 'sqs:GetQueueAttributes', + 'sqs:GetQueueUrl', + ], + 'Effect': 'Allow', + 'Resource': 'arn:aws:sqs:us-east-1:123456789012:queue1', + }, + ], + 'Version': '2012-10-17', + }, + }); + }); +}); + +describe('queue encryption', () => { + test('encryptionMasterKey can be set to a custom KMS key', () => { + const stack = new Stack(); + + const key = new kms.Key(stack, 'CustomKey'); + const queue = new sqs.Queue(stack, 'Queue', { encryptionMasterKey: key }); + + expect(queue.encryptionMasterKey).toEqual(key); + expect(stack).toHaveResource('AWS::SQS::Queue', { + 'KmsMasterKeyId': { 'Fn::GetAtt': ['CustomKey1E6D0D07', 'Arn'] }, + }); + }); + + test('a kms key will be allocated if encryption = kms but a master key is not specified', () => { + const stack = new Stack(); + + new sqs.Queue(stack, 'Queue', { encryption: sqs.QueueEncryption.KMS }); + + expect(stack).toHaveResource('AWS::KMS::Key'); + expect(stack).toHaveResource('AWS::SQS::Queue', { + 'KmsMasterKeyId': { + 'Fn::GetAtt': [ + 'QueueKey39FCBAE6', + 'Arn', + ], + }, + }); + }); + + test('it is possible to use a managed kms key', () => { + const stack = new Stack(); + + new sqs.Queue(stack, 'Queue', { encryption: sqs.QueueEncryption.KMS_MANAGED }); + expect(stack).toMatchTemplate({ + 'Resources': { + 'Queue4A7E3555': { + 'Type': 'AWS::SQS::Queue', + 'Properties': { + 'KmsMasterKeyId': 'alias/aws/sqs', + }, + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', + }, + }, + }); + }); + + test('grant also affects key on encrypted queue', () => { + // GIVEN + const stack = new Stack(); + const queue = new sqs.Queue(stack, 'Queue', { + encryption: sqs.QueueEncryption.KMS, + }); + const role = new iam.Role(stack, 'Role', { + assumedBy: new iam.ServicePrincipal('someone'), + }); + + // WHEN + queue.grantSendMessages(role); + + // THEN + expect(stack).toHaveResource('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': [ + { + 'Action': [ + 'sqs:SendMessage', + 'sqs:GetQueueAttributes', + 'sqs:GetQueueUrl', + ], + 'Effect': 'Allow', + 'Resource': { 'Fn::GetAtt': ['Queue4A7E3555', 'Arn'] }, + }, + { + 'Action': [ + 'kms:Decrypt', + 'kms:Encrypt', + 'kms:ReEncrypt*', + 'kms:GenerateDataKey*', + ], + 'Effect': 'Allow', + 'Resource': { 'Fn::GetAtt': ['QueueKey39FCBAE6', 'Arn'] }, + }, + ], + 'Version': '2012-10-17', + }, + }); + }); +}); + +test('test ".fifo" suffixed queues register as fifo', () => { + const stack = new Stack(); + const queue = new sqs.Queue(stack, 'Queue', { + queueName: 'MyQueue.fifo', + }); + + expect(queue.fifo).toEqual(true); + + expect(stack).toMatchTemplate({ + 'Resources': { + 'Queue4A7E3555': { + 'Type': 'AWS::SQS::Queue', + 'Properties': { + 'QueueName': 'MyQueue.fifo', + 'FifoQueue': true, + }, + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', + }, + }, + }); +}); + +test('test a fifo queue is observed when the "fifo" property is specified', () => { + const stack = new Stack(); + const queue = new sqs.Queue(stack, 'Queue', { + fifo: true, + }); + + expect(queue.fifo).toEqual(true); + + expect(stack).toMatchTemplate({ + 'Resources': { + 'Queue4A7E3555': { + 'Type': 'AWS::SQS::Queue', + 'Properties': { + 'FifoQueue': true, + }, + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', + }, + }, + }); +}); + +test('test a fifo queue is observed when high throughput properties are specified', () => { + const stack = new Stack(); + const queue = new sqs.Queue(stack, 'Queue', { + fifo: true, + fifoThroughputLimit: sqs.FifoThroughputLimit.PER_MESSAGE_GROUP_ID, + deduplicationScope: sqs.DeduplicationScope.MESSAGE_GROUP, + }); + + expect(queue.fifo).toEqual(true); + expect(stack).toMatchTemplate({ + 'Resources': { + 'Queue4A7E3555': { + 'Type': 'AWS::SQS::Queue', + 'Properties': { + 'DeduplicationScope': 'messageGroup', + 'FifoQueue': true, + 'FifoThroughputLimit': 'perMessageGroupId', + }, + 'UpdateReplacePolicy': 'Delete', + 'DeletionPolicy': 'Delete', + }, + }, + }); +}); + +test('test a queue throws when fifoThroughputLimit specified on non fifo queue', () => { + const stack = new Stack(); + expect(() => { + new sqs.Queue(stack, 'Queue', { + fifo: false, + fifoThroughputLimit: sqs.FifoThroughputLimit.PER_MESSAGE_GROUP_ID, + }); + }).toThrow(); +}); + +test('test a queue throws when deduplicationScope specified on non fifo queue', () => { + const stack = new Stack(); + expect(() => { + new sqs.Queue(stack, 'Queue', { + fifo: false, + deduplicationScope: sqs.DeduplicationScope.MESSAGE_GROUP, + }); + }).toThrow(); +}); + +test('test metrics', () => { + // GIVEN + const stack = new Stack(); + const queue = new sqs.Queue(stack, 'Queue'); + + // THEN + expect(stack.resolve(queue.metricNumberOfMessagesSent())).toEqual({ + dimensions: { QueueName: { 'Fn::GetAtt': ['Queue4A7E3555', 'QueueName'] } }, + namespace: 'AWS/SQS', + metricName: 'NumberOfMessagesSent', + period: Duration.minutes(5), + statistic: 'Sum', + }); + + expect(stack.resolve(queue.metricSentMessageSize())).toEqual({ + dimensions: { QueueName: { 'Fn::GetAtt': ['Queue4A7E3555', 'QueueName'] } }, + namespace: 'AWS/SQS', + metricName: 'SentMessageSize', + period: Duration.minutes(5), + statistic: 'Average', + }); +}); + +test('fails if queue policy has no actions', () => { + // GIVEN + const app = new App(); + const stack = new Stack(app, 'my-stack'); + const queue = new sqs.Queue(stack, 'Queue'); + + // WHEN + queue.addToResourcePolicy(new iam.PolicyStatement({ + resources: ['*'], + principals: [new iam.ArnPrincipal('arn')], + })); + + // THEN + expect(() => app.synth()).toThrow(/A PolicyStatement must specify at least one \'action\' or \'notAction\'/); +}); + +test('fails if queue policy has no IAM principals', () => { + // GIVEN + const app = new App(); + const stack = new Stack(app, 'my-stack'); + const queue = new sqs.Queue(stack, 'Queue'); + + // WHEN + queue.addToResourcePolicy(new iam.PolicyStatement({ + resources: ['*'], + actions: ['sqs:*'], + })); + + // THEN + expect(() => app.synth()).toThrow(/A PolicyStatement used in a resource-based policy must specify at least one IAM principal/); +}); + +function testGrant(action: (q: sqs.Queue, principal: iam.IPrincipal) => void, ...expectedActions: string[]) { + const stack = new Stack(); + const queue = new sqs.Queue(stack, 'MyQueue'); + const principal = new iam.User(stack, 'User'); + + action(queue, principal); + + expect(stack).toHaveResource('AWS::IAM::Policy', { + 'PolicyDocument': { + 'Statement': [ + { + 'Action': expectedActions, + 'Effect': 'Allow', + 'Resource': { + 'Fn::GetAtt': [ + 'MyQueueE6CA6235', + 'Arn', + ], + }, + }, + ], + 'Version': '2012-10-17', + }, + }); +} diff --git a/packages/@aws-cdk/aws-sqs/test/test.sqs.ts b/packages/@aws-cdk/aws-sqs/test/test.sqs.ts deleted file mode 100644 index ae334e5fcd4d3..0000000000000 --- a/packages/@aws-cdk/aws-sqs/test/test.sqs.ts +++ /dev/null @@ -1,644 +0,0 @@ -import { expect, haveResource, ResourcePart } from '@aws-cdk/assert-internal'; -import * as iam from '@aws-cdk/aws-iam'; -import * as kms from '@aws-cdk/aws-kms'; -import { CfnParameter, Duration, Stack, App, Token } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; -import * as sqs from '../lib'; - -/* eslint-disable quote-props */ - -export = { - 'default properties'(test: Test) { - const stack = new Stack(); - const q = new sqs.Queue(stack, 'Queue'); - - test.deepEqual(q.fifo, false); - - expect(stack).toMatch({ - 'Resources': { - 'Queue4A7E3555': { - 'Type': 'AWS::SQS::Queue', - 'UpdateReplacePolicy': 'Delete', - 'DeletionPolicy': 'Delete', - }, - }, - }); - - expect(stack).to(haveResource('AWS::SQS::Queue', { - DeletionPolicy: 'Delete', - }, ResourcePart.CompleteDefinition)); - - test.done(); - }, - 'with a dead letter queue'(test: Test) { - const stack = new Stack(); - const dlq = new sqs.Queue(stack, 'DLQ'); - new sqs.Queue(stack, 'Queue', { deadLetterQueue: { queue: dlq, maxReceiveCount: 3 } }); - - expect(stack).toMatch({ - 'Resources': { - 'DLQ581697C4': { - 'Type': 'AWS::SQS::Queue', - 'UpdateReplacePolicy': 'Delete', - 'DeletionPolicy': 'Delete', - }, - 'Queue4A7E3555': { - 'Type': 'AWS::SQS::Queue', - 'Properties': { - 'RedrivePolicy': { - 'deadLetterTargetArn': { - 'Fn::GetAtt': [ - 'DLQ581697C4', - 'Arn', - ], - }, - 'maxReceiveCount': 3, - }, - }, - 'UpdateReplacePolicy': 'Delete', - 'DeletionPolicy': 'Delete', - }, - }, - }); - - test.done(); - }, - - 'message retention period must be between 1 minute to 14 days'(test: Test) { - // GIVEN - const stack = new Stack(); - - // THEN - test.throws(() => new sqs.Queue(stack, 'MyQueue', { - retentionPeriod: Duration.seconds(30), - }), /message retention period must be 60 seconds or more/); - - test.throws(() => new sqs.Queue(stack, 'AnotherQueue', { - retentionPeriod: Duration.days(15), - }), /message retention period must be 1209600 seconds or less/); - - test.done(); - }, - - 'message retention period can be provided as a parameter'(test: Test) { - // GIVEN - const stack = new Stack(); - const parameter = new CfnParameter(stack, 'my-retention-period', { - type: 'Number', - default: 30, - }); - - // WHEN - new sqs.Queue(stack, 'MyQueue', { - retentionPeriod: Duration.seconds(parameter.valueAsNumber), - }); - - // THEN - expect(stack).toMatch({ - 'Parameters': { - 'myretentionperiod': { - 'Type': 'Number', - 'Default': 30, - }, - }, - 'Resources': { - 'MyQueueE6CA6235': { - 'Type': 'AWS::SQS::Queue', - 'Properties': { - 'MessageRetentionPeriod': { - 'Ref': 'myretentionperiod', - }, - }, - 'UpdateReplacePolicy': 'Delete', - 'DeletionPolicy': 'Delete', - }, - }, - }); - - test.done(); - }, - - 'addToPolicy will automatically create a policy for this queue'(test: Test) { - const stack = new Stack(); - const queue = new sqs.Queue(stack, 'MyQueue'); - queue.addToResourcePolicy(new iam.PolicyStatement({ - resources: ['*'], - actions: ['sqs:*'], - principals: [new iam.ArnPrincipal('arn')], - })); - - expect(stack).toMatch({ - 'Resources': { - 'MyQueueE6CA6235': { - 'Type': 'AWS::SQS::Queue', - 'UpdateReplacePolicy': 'Delete', - 'DeletionPolicy': 'Delete', - }, - 'MyQueuePolicy6BBEDDAC': { - 'Type': 'AWS::SQS::QueuePolicy', - 'Properties': { - 'PolicyDocument': { - 'Statement': [ - { - 'Action': 'sqs:*', - 'Effect': 'Allow', - 'Principal': { - 'AWS': 'arn', - }, - 'Resource': '*', - }, - ], - 'Version': '2012-10-17', - }, - 'Queues': [ - { - 'Ref': 'MyQueueE6CA6235', - }, - ], - }, - }, - }, - }); - test.done(); - }, - - 'export and import': { - 'importing works correctly'(test: Test) { - // GIVEN - const stack = new Stack(); - - // WHEN - const imports = sqs.Queue.fromQueueArn(stack, 'Imported', 'arn:aws:sqs:us-east-1:123456789012:queue1'); - - // THEN - - // "import" returns an IQueue bound to `Fn::ImportValue`s. - test.deepEqual(stack.resolve(imports.queueArn), 'arn:aws:sqs:us-east-1:123456789012:queue1'); - test.deepEqual(stack.resolve(imports.queueUrl), { - 'Fn::Join': - ['', ['https://sqs.us-east-1.', { Ref: 'AWS::URLSuffix' }, '/123456789012/queue1']], - }); - test.deepEqual(stack.resolve(imports.queueName), 'queue1'); - test.done(); - }, - - 'importing fifo and standard queues are detected correctly'(test: Test) { - const stack = new Stack(); - const stdQueue = sqs.Queue.fromQueueArn(stack, 'StdQueue', 'arn:aws:sqs:us-east-1:123456789012:queue1'); - const fifoQueue = sqs.Queue.fromQueueArn(stack, 'FifoQueue', 'arn:aws:sqs:us-east-1:123456789012:queue2.fifo'); - test.deepEqual(stdQueue.fifo, false); - test.deepEqual(fifoQueue.fifo, true); - test.done(); - }, - - 'import queueArn from token, fifo and standard queues can be defined'(test: Test) { - // GIVEN - const stack = new Stack(); - - // WHEN - const stdQueue1 = sqs.Queue.fromQueueAttributes(stack, 'StdQueue1', { - queueArn: Token.asString({ Ref: 'ARN' }), - }); - const stdQueue2 = sqs.Queue.fromQueueAttributes(stack, 'StdQueue2', { - queueArn: Token.asString({ Ref: 'ARN' }), - fifo: false, - }); - const fifoQueue = sqs.Queue.fromQueueAttributes(stack, 'FifoQueue', { - queueArn: Token.asString({ Ref: 'ARN' }), - fifo: true, - }); - - // THEN - test.deepEqual(stdQueue1.fifo, false); - test.deepEqual(stdQueue2.fifo, false); - test.deepEqual(fifoQueue.fifo, true); - test.done(); - }, - - 'import queueArn from token, check attributes'(test: Test) { - // GIVEN - const stack = new Stack(); - - // WHEN - const stdQueue1 = sqs.Queue.fromQueueArn(stack, 'StdQueue', Token.asString({ Ref: 'ARN' })); - - // THEN - test.deepEqual(stack.resolve(stdQueue1.queueArn), { - Ref: 'ARN', - }); - test.deepEqual(stack.resolve(stdQueue1.queueName), { - 'Fn::Select': [5, { 'Fn::Split': [':', { Ref: 'ARN' }] }], - }); - test.deepEqual(stack.resolve(stdQueue1.queueUrl), { - 'Fn::Join': - ['', - ['https://sqs.', - { 'Fn::Select': [3, { 'Fn::Split': [':', { Ref: 'ARN' }] }] }, - '.', - { Ref: 'AWS::URLSuffix' }, - '/', - { 'Fn::Select': [4, { 'Fn::Split': [':', { Ref: 'ARN' }] }] }, - '/', - { 'Fn::Select': [5, { 'Fn::Split': [':', { Ref: 'ARN' }] }] }]], - }); - test.deepEqual(stdQueue1.fifo, false); - test.done(); - }, - - 'fails if fifo flag is set for non fifo queue name'(test: Test) { - // GIVEN - const app = new App(); - const stack = new Stack(app, 'my-stack'); - - // THEN - test.throws(() => sqs.Queue.fromQueueAttributes(stack, 'ImportedStdQueue', { - queueArn: 'arn:aws:sqs:us-west-2:123456789012:queue1', - fifo: true, - }), /FIFO queue names must end in '.fifo'/); - test.done(); - }, - - - 'fails if fifo flag is false for fifo queue name'(test: Test) { - // GIVEN - const app = new App(); - const stack = new Stack(app, 'my-stack'); - - // THEN - test.throws(() => sqs.Queue.fromQueueAttributes(stack, 'ImportedFifoQueue', { - queueArn: 'arn:aws:sqs:us-west-2:123456789012:queue1.fifo', - fifo: false, - }), /Non-FIFO queue name may not end in '.fifo'/); - test.done(); - }, - - 'importing works correctly for cross region queue'(test: Test) { - // GIVEN - const stack = new Stack(undefined, 'Stack', { env: { region: 'us-east-1' } }); - - // WHEN - const imports = sqs.Queue.fromQueueArn(stack, 'Imported', 'arn:aws:sqs:us-west-2:123456789012:queue1'); - - // THEN - - // "import" returns an IQueue bound to `Fn::ImportValue`s. - test.deepEqual(stack.resolve(imports.queueArn), 'arn:aws:sqs:us-west-2:123456789012:queue1'); - test.deepEqual(stack.resolve(imports.queueUrl), { - 'Fn::Join': - ['', ['https://sqs.us-west-2.', { Ref: 'AWS::URLSuffix' }, '/123456789012/queue1']], - }); - test.deepEqual(stack.resolve(imports.queueName), 'queue1'); - test.done(); - }, - }, - - 'grants': { - 'grantConsumeMessages'(test: Test) { - testGrant((q, p) => q.grantConsumeMessages(p), - 'sqs:ReceiveMessage', - 'sqs:ChangeMessageVisibility', - 'sqs:GetQueueUrl', - 'sqs:DeleteMessage', - 'sqs:GetQueueAttributes', - ); - test.done(); - }, - - 'grantSendMessages'(test: Test) { - testGrant((q, p) => q.grantSendMessages(p), - 'sqs:SendMessage', - 'sqs:GetQueueAttributes', - 'sqs:GetQueueUrl', - ); - test.done(); - }, - - 'grantPurge'(test: Test) { - testGrant((q, p) => q.grantPurge(p), - 'sqs:PurgeQueue', - 'sqs:GetQueueAttributes', - 'sqs:GetQueueUrl', - ); - test.done(); - }, - - 'grant() is general purpose'(test: Test) { - testGrant((q, p) => q.grant(p, 'service:hello', 'service:world'), - 'service:hello', - 'service:world', - ); - test.done(); - }, - - 'grants also work on imported queues'(test: Test) { - const stack = new Stack(); - const queue = sqs.Queue.fromQueueAttributes(stack, 'Import', { - queueArn: 'arn:aws:sqs:us-east-1:123456789012:queue1', - queueUrl: 'https://queue-url', - }); - - const user = new iam.User(stack, 'User'); - - queue.grantPurge(user); - - expect(stack).to(haveResource('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': [ - { - 'Action': [ - 'sqs:PurgeQueue', - 'sqs:GetQueueAttributes', - 'sqs:GetQueueUrl', - ], - 'Effect': 'Allow', - 'Resource': 'arn:aws:sqs:us-east-1:123456789012:queue1', - }, - ], - 'Version': '2012-10-17', - }, - })); - - test.done(); - }, - }, - - 'queue encryption': { - 'encryptionMasterKey can be set to a custom KMS key'(test: Test) { - const stack = new Stack(); - - const key = new kms.Key(stack, 'CustomKey'); - const queue = new sqs.Queue(stack, 'Queue', { encryptionMasterKey: key }); - - test.same(queue.encryptionMasterKey, key); - expect(stack).to(haveResource('AWS::SQS::Queue', { - 'KmsMasterKeyId': { 'Fn::GetAtt': ['CustomKey1E6D0D07', 'Arn'] }, - })); - - test.done(); - }, - - 'a kms key will be allocated if encryption = kms but a master key is not specified'(test: Test) { - const stack = new Stack(); - - new sqs.Queue(stack, 'Queue', { encryption: sqs.QueueEncryption.KMS }); - - expect(stack).to(haveResource('AWS::KMS::Key')); - expect(stack).to(haveResource('AWS::SQS::Queue', { - 'KmsMasterKeyId': { - 'Fn::GetAtt': [ - 'QueueKey39FCBAE6', - 'Arn', - ], - }, - })); - - test.done(); - }, - - 'it is possible to use a managed kms key'(test: Test) { - const stack = new Stack(); - - new sqs.Queue(stack, 'Queue', { encryption: sqs.QueueEncryption.KMS_MANAGED }); - expect(stack).toMatch({ - 'Resources': { - 'Queue4A7E3555': { - 'Type': 'AWS::SQS::Queue', - 'Properties': { - 'KmsMasterKeyId': 'alias/aws/sqs', - }, - 'UpdateReplacePolicy': 'Delete', - 'DeletionPolicy': 'Delete', - }, - }, - }); - test.done(); - }, - - 'grant also affects key on encrypted queue'(test: Test) { - // GIVEN - const stack = new Stack(); - const queue = new sqs.Queue(stack, 'Queue', { - encryption: sqs.QueueEncryption.KMS, - }); - const role = new iam.Role(stack, 'Role', { - assumedBy: new iam.ServicePrincipal('someone'), - }); - - // WHEN - queue.grantSendMessages(role); - - // THEN - expect(stack).to(haveResource('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': [ - { - 'Action': [ - 'sqs:SendMessage', - 'sqs:GetQueueAttributes', - 'sqs:GetQueueUrl', - ], - 'Effect': 'Allow', - 'Resource': { 'Fn::GetAtt': ['Queue4A7E3555', 'Arn'] }, - }, - { - 'Action': [ - 'kms:Decrypt', - 'kms:Encrypt', - 'kms:ReEncrypt*', - 'kms:GenerateDataKey*', - ], - 'Effect': 'Allow', - 'Resource': { 'Fn::GetAtt': ['QueueKey39FCBAE6', 'Arn'] }, - }, - ], - 'Version': '2012-10-17', - }, - })); - - test.done(); - }, - }, - - 'test ".fifo" suffixed queues register as fifo'(test: Test) { - const stack = new Stack(); - const queue = new sqs.Queue(stack, 'Queue', { - queueName: 'MyQueue.fifo', - }); - - test.deepEqual(queue.fifo, true); - - expect(stack).toMatch({ - 'Resources': { - 'Queue4A7E3555': { - 'Type': 'AWS::SQS::Queue', - 'Properties': { - 'QueueName': 'MyQueue.fifo', - 'FifoQueue': true, - }, - 'UpdateReplacePolicy': 'Delete', - 'DeletionPolicy': 'Delete', - }, - }, - }); - - test.done(); - }, - - 'test a fifo queue is observed when the "fifo" property is specified'(test: Test) { - const stack = new Stack(); - const queue = new sqs.Queue(stack, 'Queue', { - fifo: true, - }); - - test.deepEqual(queue.fifo, true); - - expect(stack).toMatch({ - 'Resources': { - 'Queue4A7E3555': { - 'Type': 'AWS::SQS::Queue', - 'Properties': { - 'FifoQueue': true, - }, - 'UpdateReplacePolicy': 'Delete', - 'DeletionPolicy': 'Delete', - }, - }, - }); - - test.done(); - }, - - 'test a fifo queue is observed when high throughput properties are specified'(test: Test) { - const stack = new Stack(); - const queue = new sqs.Queue(stack, 'Queue', { - fifo: true, - fifoThroughputLimit: sqs.FifoThroughputLimit.PER_MESSAGE_GROUP_ID, - deduplicationScope: sqs.DeduplicationScope.MESSAGE_GROUP, - }); - - test.deepEqual(queue.fifo, true); - expect(stack).toMatch({ - 'Resources': { - 'Queue4A7E3555': { - 'Type': 'AWS::SQS::Queue', - 'Properties': { - 'DeduplicationScope': 'messageGroup', - 'FifoQueue': true, - 'FifoThroughputLimit': 'perMessageGroupId', - }, - 'UpdateReplacePolicy': 'Delete', - 'DeletionPolicy': 'Delete', - }, - }, - }); - - test.done(); - }, - - 'test a queue throws when fifoThroughputLimit specified on non fifo queue'(test: Test) { - const stack = new Stack(); - test.throws(() => { - new sqs.Queue(stack, 'Queue', { - fifo: false, - fifoThroughputLimit: sqs.FifoThroughputLimit.PER_MESSAGE_GROUP_ID, - }); - }); - test.done(); - }, - - 'test a queue throws when deduplicationScope specified on non fifo queue'(test: Test) { - const stack = new Stack(); - test.throws(() => { - new sqs.Queue(stack, 'Queue', { - fifo: false, - deduplicationScope: sqs.DeduplicationScope.MESSAGE_GROUP, - }); - }); - test.done(); - }, - - 'test metrics'(test: Test) { - // GIVEN - const stack = new Stack(); - const queue = new sqs.Queue(stack, 'Queue'); - - // THEN - test.deepEqual(stack.resolve(queue.metricNumberOfMessagesSent()), { - dimensions: { QueueName: { 'Fn::GetAtt': ['Queue4A7E3555', 'QueueName'] } }, - namespace: 'AWS/SQS', - metricName: 'NumberOfMessagesSent', - period: Duration.minutes(5), - statistic: 'Sum', - }); - - test.deepEqual(stack.resolve(queue.metricSentMessageSize()), { - dimensions: { QueueName: { 'Fn::GetAtt': ['Queue4A7E3555', 'QueueName'] } }, - namespace: 'AWS/SQS', - metricName: 'SentMessageSize', - period: Duration.minutes(5), - statistic: 'Average', - }); - - test.done(); - }, - - 'fails if queue policy has no actions'(test: Test) { - // GIVEN - const app = new App(); - const stack = new Stack(app, 'my-stack'); - const queue = new sqs.Queue(stack, 'Queue'); - - // WHEN - queue.addToResourcePolicy(new iam.PolicyStatement({ - resources: ['*'], - principals: [new iam.ArnPrincipal('arn')], - })); - - // THEN - test.throws(() => app.synth(), /A PolicyStatement must specify at least one \'action\' or \'notAction\'/); - test.done(); - }, - - 'fails if queue policy has no IAM principals'(test: Test) { - // GIVEN - const app = new App(); - const stack = new Stack(app, 'my-stack'); - const queue = new sqs.Queue(stack, 'Queue'); - - // WHEN - queue.addToResourcePolicy(new iam.PolicyStatement({ - resources: ['*'], - actions: ['sqs:*'], - })); - - // THEN - test.throws(() => app.synth(), /A PolicyStatement used in a resource-based policy must specify at least one IAM principal/); - test.done(); - }, -}; - -function testGrant(action: (q: sqs.Queue, principal: iam.IPrincipal) => void, ...expectedActions: string[]) { - const stack = new Stack(); - const queue = new sqs.Queue(stack, 'MyQueue'); - const principal = new iam.User(stack, 'User'); - - action(queue, principal); - - expect(stack).to(haveResource('AWS::IAM::Policy', { - 'PolicyDocument': { - 'Statement': [ - { - 'Action': expectedActions, - 'Effect': 'Allow', - 'Resource': { - 'Fn::GetAtt': [ - 'MyQueueE6CA6235', - 'Arn', - ], - }, - }, - ], - 'Version': '2012-10-17', - }, - })); -} diff --git a/packages/@aws-cdk/aws-ssm/.eslintrc.js b/packages/@aws-cdk/aws-ssm/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-ssm/.eslintrc.js +++ b/packages/@aws-cdk/aws-ssm/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ssm/jest.config.js b/packages/@aws-cdk/aws-ssm/jest.config.js index f5d5c4c8ad18f..34818e1593f6b 100644 --- a/packages/@aws-cdk/aws-ssm/jest.config.js +++ b/packages/@aws-cdk/aws-ssm/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); -module.exports = baseConfig; \ No newline at end of file +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ssm/package.json b/packages/@aws-cdk/aws-ssm/package.json index 47f9ff90a4852..c30ae7e97c8f1 100644 --- a/packages/@aws-cdk/aws-ssm/package.json +++ b/packages/@aws-cdk/aws-ssm/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::SSM", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,27 +72,27 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", - "@aws-cdk/core": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", + "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", - "@aws-cdk/core": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", + "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "engines": { diff --git a/packages/@aws-cdk/aws-ssmcontacts/.eslintrc.js b/packages/@aws-cdk/aws-ssmcontacts/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-ssmcontacts/.eslintrc.js +++ b/packages/@aws-cdk/aws-ssmcontacts/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ssmcontacts/jest.config.js b/packages/@aws-cdk/aws-ssmcontacts/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-ssmcontacts/jest.config.js +++ b/packages/@aws-cdk/aws-ssmcontacts/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ssmcontacts/package.json b/packages/@aws-cdk/aws-ssmcontacts/package.json index 350d243514340..cc6f3d5c34464 100644 --- a/packages/@aws-cdk/aws-ssmcontacts/package.json +++ b/packages/@aws-cdk/aws-ssmcontacts/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::SSMContacts", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-ssmincidents/.eslintrc.js b/packages/@aws-cdk/aws-ssmincidents/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-ssmincidents/.eslintrc.js +++ b/packages/@aws-cdk/aws-ssmincidents/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ssmincidents/jest.config.js b/packages/@aws-cdk/aws-ssmincidents/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-ssmincidents/jest.config.js +++ b/packages/@aws-cdk/aws-ssmincidents/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-ssmincidents/package.json b/packages/@aws-cdk/aws-ssmincidents/package.json index 668f68e02fd64..bbc9103e668fa 100644 --- a/packages/@aws-cdk/aws-ssmincidents/package.json +++ b/packages/@aws-cdk/aws-ssmincidents/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::SSMIncidents", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-sso/.eslintrc.js b/packages/@aws-cdk/aws-sso/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-sso/.eslintrc.js +++ b/packages/@aws-cdk/aws-sso/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sso/jest.config.js b/packages/@aws-cdk/aws-sso/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-sso/jest.config.js +++ b/packages/@aws-cdk/aws-sso/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-sso/package.json b/packages/@aws-cdk/aws-sso/package.json index b6361b2336306..12b8dfc9536d2 100644 --- a/packages/@aws-cdk/aws-sso/package.json +++ b/packages/@aws-cdk/aws-sso/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::SSO", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/.eslintrc.js b/packages/@aws-cdk/aws-stepfunctions-tasks/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/.eslintrc.js +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/jest.config.js b/packages/@aws-cdk/aws-stepfunctions-tasks/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/jest.config.js +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/eval-nodejs-handler/index.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/eval-nodejs-handler/index.ts index 52db50f92605e..c40aeb340bfbb 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/eval-nodejs-handler/index.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/eval-nodejs-handler/index.ts @@ -15,5 +15,5 @@ export async function handler(event: Event): Promise { ); console.log(`Expression: ${expression}`); - return await eval(expression); + return eval(expression); } diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/package.json b/packages/@aws-cdk/aws-stepfunctions-tasks/package.json index dc297c9d37bfc..1853a14deb2cb 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/package.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/package.json @@ -71,19 +71,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "@aws-cdk/aws-s3-assets": "0.0.0", - "@aws-cdk/aws-sns-subscriptions": "0.0.0", - "@aws-cdk/aws-glue": "0.0.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-apigatewayv2": "0.0.0", "@aws-cdk/aws-apigatewayv2-integrations": "0.0.0", "@aws-cdk/aws-batch": "0.0.0", "@aws-cdk/aws-databrew": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/aws-glue": "0.0.0", + "@aws-cdk/aws-s3-assets": "0.0.0", + "@aws-cdk/aws-sns-subscriptions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-apigateway": "0.0.0", @@ -137,7 +137,6 @@ "announce": false }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/integ.call.expected.json b/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/integ.call.expected.json index 64b6481aab74f..8e3bc703cbde7 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/integ.call.expected.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/test/eks/integ.call.expected.json @@ -84,9 +84,7 @@ "Ref": "EksClusterDefaultVpcIGWCA6A3220" } }, - "DependsOn": [ - "EksClusterDefaultVpcVPCGW0E4A5673" - ] + "DependsOn": ["EksClusterDefaultVpcVPCGW0E4A5673"] }, "EksClusterDefaultVpcPublicSubnet1EIPF53713C9": { "Type": "AWS::EC2::EIP", @@ -107,15 +105,15 @@ "EksClusterDefaultVpcPublicSubnet1NATGateway548C2CDF": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "EksClusterDefaultVpcPublicSubnet1SubnetCB1D1047" + }, "AllocationId": { "Fn::GetAtt": [ "EksClusterDefaultVpcPublicSubnet1EIPF53713C9", "AllocationId" ] }, - "SubnetId": { - "Ref": "EksClusterDefaultVpcPublicSubnet1SubnetCB1D1047" - }, "Tags": [ { "Key": "kubernetes.io/role/elb", @@ -197,9 +195,7 @@ "Ref": "EksClusterDefaultVpcIGWCA6A3220" } }, - "DependsOn": [ - "EksClusterDefaultVpcVPCGW0E4A5673" - ] + "DependsOn": ["EksClusterDefaultVpcVPCGW0E4A5673"] }, "EksClusterDefaultVpcPublicSubnet2EIP16D41D80": { "Type": "AWS::EC2::EIP", @@ -220,15 +216,15 @@ "EksClusterDefaultVpcPublicSubnet2NATGateway869DDCBF": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "EksClusterDefaultVpcPublicSubnet2SubnetA8FE675D" + }, "AllocationId": { "Fn::GetAtt": [ "EksClusterDefaultVpcPublicSubnet2EIP16D41D80", "AllocationId" ] }, - "SubnetId": { - "Ref": "EksClusterDefaultVpcPublicSubnet2SubnetA8FE675D" - }, "Tags": [ { "Key": "kubernetes.io/role/elb", @@ -310,9 +306,7 @@ "Ref": "EksClusterDefaultVpcIGWCA6A3220" } }, - "DependsOn": [ - "EksClusterDefaultVpcVPCGW0E4A5673" - ] + "DependsOn": ["EksClusterDefaultVpcVPCGW0E4A5673"] }, "EksClusterDefaultVpcPublicSubnet3EIPF8D34EDE": { "Type": "AWS::EC2::EIP", @@ -333,15 +327,15 @@ "EksClusterDefaultVpcPublicSubnet3NATGatewayC35C74D3": { "Type": "AWS::EC2::NatGateway", "Properties": { + "SubnetId": { + "Ref": "EksClusterDefaultVpcPublicSubnet3SubnetA04EFFC1" + }, "AllocationId": { "Fn::GetAtt": [ "EksClusterDefaultVpcPublicSubnet3EIPF8D34EDE", "AllocationId" ] }, - "SubnetId": { - "Ref": "EksClusterDefaultVpcPublicSubnet3SubnetA04EFFC1" - }, "Tags": [ { "Key": "kubernetes.io/role/elb", @@ -709,10 +703,7 @@ "Action": "iam:PassRole", "Effect": "Allow", "Resource": { - "Fn::GetAtt": [ - "EksClusterRoleC84B376F", - "Arn" - ] + "Fn::GetAtt": ["EksClusterRoleC84B376F", "Arn"] } }, { @@ -799,10 +790,7 @@ } }, { - "Action": [ - "iam:GetRole", - "iam:listAttachedRolePolicies" - ], + "Action": ["iam:GetRole", "iam:listAttachedRolePolicies"], "Effect": "Allow", "Resource": "*" }, @@ -883,10 +871,7 @@ "name": "eksCluster", "version": "1.18", "roleArn": { - "Fn::GetAtt": [ - "EksClusterRoleC84B376F", - "Arn" - ] + "Fn::GetAtt": ["EksClusterRoleC84B376F", "Arn"] }, "resourcesVpcConfig": { "subnetIds": [ @@ -922,10 +907,7 @@ } }, "AssumeRoleArn": { - "Fn::GetAtt": [ - "EksClusterCreationRole75AABE42", - "Arn" - ] + "Fn::GetAtt": ["EksClusterCreationRole75AABE42", "Arn"] }, "AttributesRevision": 2 }, @@ -1028,17 +1010,11 @@ [ "[{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"aws-auth\",\"namespace\":\"kube-system\",\"labels\":{\"aws.cdk.eks/prune-c8f58087a1a3e6c10f65d847befda9c1aa2145a8fc\":\"\"}},\"data\":{\"mapRoles\":\"[{\\\"rolearn\\\":\\\"", { - "Fn::GetAtt": [ - "EksClusterMastersRole3F49FAC3", - "Arn" - ] + "Fn::GetAtt": ["EksClusterMastersRole3F49FAC3", "Arn"] }, "\\\",\\\"username\\\":\\\"", { - "Fn::GetAtt": [ - "EksClusterMastersRole3F49FAC3", - "Arn" - ] + "Fn::GetAtt": ["EksClusterMastersRole3F49FAC3", "Arn"] }, "\\\",\\\"groups\\\":[\\\"system:masters\\\"]},{\\\"rolearn\\\":\\\"", { @@ -1049,17 +1025,11 @@ }, "\\\",\\\"username\\\":\\\"system:node:{{EC2PrivateDNSName}}\\\",\\\"groups\\\":[\\\"system:bootstrappers\\\",\\\"system:nodes\\\"]},{\\\"rolearn\\\":\\\"", { - "Fn::GetAtt": [ - "Role1ABCC5F0", - "Arn" - ] + "Fn::GetAtt": ["Role1ABCC5F0", "Arn"] }, "\\\",\\\"username\\\":\\\"", { - "Fn::GetAtt": [ - "Role1ABCC5F0", - "Arn" - ] + "Fn::GetAtt": ["Role1ABCC5F0", "Arn"] }, "\\\",\\\"groups\\\":[\\\"system:masters\\\"]}]\",\"mapUsers\":\"[]\",\"mapAccounts\":\"[]\"}}]" ] @@ -1069,17 +1039,12 @@ "Ref": "EksClusterFAB68BDB" }, "RoleArn": { - "Fn::GetAtt": [ - "EksClusterCreationRole75AABE42", - "Arn" - ] + "Fn::GetAtt": ["EksClusterCreationRole75AABE42", "Arn"] }, "PruneLabel": "aws.cdk.eks/prune-c8f58087a1a3e6c10f65d847befda9c1aa2145a8fc", "Overwrite": true }, - "DependsOn": [ - "EksClusterKubectlReadyBarrier502B0E83" - ], + "DependsOn": ["EksClusterKubectlReadyBarrier502B0E83"], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, @@ -1173,9 +1138,7 @@ ], "AmiType": "AL2_x86_64", "ForceUpdateEnabled": true, - "InstanceTypes": [ - "m5.large" - ], + "InstanceTypes": ["m5.large"], "ScalingConfig": { "DesiredSize": 2, "MaxSize": 2, @@ -1200,7 +1163,7 @@ }, "/", { - "Ref": "AssetParametersf14dbf982bfb4e61285bf9e6e91f20eb00e8a36c79c981ceec2437b42a02e216S3BucketE0529475" + "Ref": "AssetParameters0b198930f902d53efb864e939b03a42215307ad763b6c49e200b860e0bf87ba8S3Bucket0CDB4070" }, "/", { @@ -1210,7 +1173,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersf14dbf982bfb4e61285bf9e6e91f20eb00e8a36c79c981ceec2437b42a02e216S3VersionKey736B6614" + "Ref": "AssetParameters0b198930f902d53efb864e939b03a42215307ad763b6c49e200b860e0bf87ba8S3VersionKey9304E721" } ] } @@ -1223,7 +1186,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParametersf14dbf982bfb4e61285bf9e6e91f20eb00e8a36c79c981ceec2437b42a02e216S3VersionKey736B6614" + "Ref": "AssetParameters0b198930f902d53efb864e939b03a42215307ad763b6c49e200b860e0bf87ba8S3VersionKey9304E721" } ] } @@ -1234,16 +1197,19 @@ }, "Parameters": { "referencetoawsstepfunctionstasksekscallintegEksClusterCreationRole00B486C4Arn": { - "Fn::GetAtt": [ - "EksClusterCreationRole75AABE42", - "Arn" - ] + "Fn::GetAtt": ["EksClusterCreationRole75AABE42", "Arn"] + }, + "referencetoawsstepfunctionstasksekscallintegAssetParameters2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7eS3Bucket7F9374E5Ref": { + "Ref": "AssetParameters2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7eS3Bucket575E2F4C" }, - "referencetoawsstepfunctionstasksekscallintegAssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket61AA45E5Ref": { - "Ref": "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket14D204F9" + "referencetoawsstepfunctionstasksekscallintegAssetParameters2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7eS3VersionKey43EAF22DRef": { + "Ref": "AssetParameters2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7eS3VersionKeyFB3EB544" }, - "referencetoawsstepfunctionstasksekscallintegAssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKey48ACDBCFRef": { - "Ref": "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyDE8A2F1F" + "referencetoawsstepfunctionstasksekscallintegAssetParametersd1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6S3Bucket32160528Ref": { + "Ref": "AssetParametersd1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6S3Bucket04F6B25B" + }, + "referencetoawsstepfunctionstasksekscallintegAssetParametersd1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6S3VersionKeyCEEE7AF3Ref": { + "Ref": "AssetParametersd1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6S3VersionKey6A7508AF" }, "referencetoawsstepfunctionstasksekscallintegAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketCF9FB24DRef": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" @@ -1273,7 +1239,7 @@ }, "/", { - "Ref": "AssetParameters9d41118c36f364bd9f7de59dda09afbef182ac0f726496523af8ffd24aafc604S3BucketCAFDB26C" + "Ref": "AssetParameters71b4be22b7489e3746d72802bb115cc0c5c2c2a8efac49a7e81e6257bec20ae5S3BucketEC7134BF" }, "/", { @@ -1283,7 +1249,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters9d41118c36f364bd9f7de59dda09afbef182ac0f726496523af8ffd24aafc604S3VersionKey3CF353E9" + "Ref": "AssetParameters71b4be22b7489e3746d72802bb115cc0c5c2c2a8efac49a7e81e6257bec20ae5S3VersionKey3EC7EA95" } ] } @@ -1296,7 +1262,7 @@ "Fn::Split": [ "||", { - "Ref": "AssetParameters9d41118c36f364bd9f7de59dda09afbef182ac0f726496523af8ffd24aafc604S3VersionKey3CF353E9" + "Ref": "AssetParameters71b4be22b7489e3746d72802bb115cc0c5c2c2a8efac49a7e81e6257bec20ae5S3VersionKey3EC7EA95" } ] } @@ -1307,22 +1273,16 @@ }, "Parameters": { "referencetoawsstepfunctionstasksekscallintegEksClusterCA674174Arn": { - "Fn::GetAtt": [ - "EksClusterFAB68BDB", - "Arn" - ] + "Fn::GetAtt": ["EksClusterFAB68BDB", "Arn"] }, "referencetoawsstepfunctionstasksekscallintegEksClusterCreationRole00B486C4Arn": { - "Fn::GetAtt": [ - "EksClusterCreationRole75AABE42", - "Arn" - ] + "Fn::GetAtt": ["EksClusterCreationRole75AABE42", "Arn"] }, - "referencetoawsstepfunctionstasksekscallintegAssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3BucketB45933E2Ref": { - "Ref": "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3Bucket008DBB35" + "referencetoawsstepfunctionstasksekscallintegAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketF4AF10B8Ref": { + "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9" }, - "referencetoawsstepfunctionstasksekscallintegAssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey897E2F88Ref": { - "Ref": "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey97C3E1A0" + "referencetoawsstepfunctionstasksekscallintegAssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKey04C67745Ref": { + "Ref": "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421" }, "referencetoawsstepfunctionstasksekscallintegEksClusterDefaultVpcPrivateSubnet1Subnet3A6964EARef": { "Ref": "EksClusterDefaultVpcPrivateSubnet1Subnet4D665A2F" @@ -1334,10 +1294,7 @@ "Ref": "EksClusterDefaultVpcPrivateSubnet3Subnet6C4BFC07" }, "referencetoawsstepfunctionstasksekscallintegEksClusterCA674174ClusterSecurityGroupId": { - "Fn::GetAtt": [ - "EksClusterFAB68BDB", - "ClusterSecurityGroupId" - ] + "Fn::GetAtt": ["EksClusterFAB68BDB", "ClusterSecurityGroupId"] }, "referencetoawsstepfunctionstasksekscallintegAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3Bucket3F56B6C0Ref": { "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7" @@ -1345,11 +1302,11 @@ "referencetoawsstepfunctionstasksekscallintegAssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKey14F73D88Ref": { "Ref": "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3VersionKeyE415415F" }, - "referencetoawsstepfunctionstasksekscallintegAssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3Bucket82DB0998Ref": { - "Ref": "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3Bucket6ABE1927" + "referencetoawsstepfunctionstasksekscallintegAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3Bucket91831D54Ref": { + "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998" }, - "referencetoawsstepfunctionstasksekscallintegAssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKey5CB2DA63Ref": { - "Ref": "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKeyF55A2EA9" + "referencetoawsstepfunctionstasksekscallintegAssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyAFE7B9F9Ref": { + "Ref": "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565" }, "referencetoawsstepfunctionstasksekscallintegAssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketCF9FB24DRef": { "Ref": "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1" @@ -1395,10 +1352,7 @@ "Type": "AWS::StepFunctions::StateMachine", "Properties": { "RoleArn": { - "Fn::GetAtt": [ - "Role1ABCC5F0", - "Arn" - ] + "Fn::GetAtt": ["Role1ABCC5F0", "Arn"] }, "DefinitionString": { "Fn::Join": [ @@ -1414,26 +1368,18 @@ }, "\",\"CertificateAuthority\":\"", { - "Fn::GetAtt": [ - "EksClusterFAB68BDB", - "CertificateAuthorityData" - ] + "Fn::GetAtt": ["EksClusterFAB68BDB", "CertificateAuthorityData"] }, "\",\"Endpoint\":\"", { - "Fn::GetAtt": [ - "EksClusterFAB68BDB", - "Endpoint" - ] + "Fn::GetAtt": ["EksClusterFAB68BDB", "Endpoint"] }, "\",\"Method\":\"GET\",\"Path\":\"/api/v1/namespaces/default/pods\"}}},\"TimeoutSeconds\":30}" ] ] } }, - "DependsOn": [ - "Role1ABCC5F0" - ] + "DependsOn": ["Role1ABCC5F0"] } }, "Outputs": { @@ -1452,10 +1398,7 @@ }, " --role-arn ", { - "Fn::GetAtt": [ - "EksClusterMastersRole3F49FAC3", - "Arn" - ] + "Fn::GetAtt": ["EksClusterMastersRole3F49FAC3", "Arn"] } ] ] @@ -1476,10 +1419,7 @@ }, " --role-arn ", { - "Fn::GetAtt": [ - "EksClusterMastersRole3F49FAC3", - "Arn" - ] + "Fn::GetAtt": ["EksClusterMastersRole3F49FAC3", "Arn"] } ] ] @@ -1492,17 +1432,29 @@ } }, "Parameters": { - "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3Bucket14D204F9": { + "AssetParameters2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7eS3Bucket575E2F4C": { + "Type": "String", + "Description": "S3 bucket for asset \"2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7e\"" + }, + "AssetParameters2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7eS3VersionKeyFB3EB544": { + "Type": "String", + "Description": "S3 key for asset version \"2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7e\"" + }, + "AssetParameters2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7eArtifactHashDB8E8B5A": { + "Type": "String", + "Description": "Artifact hash for asset \"2fbc509041827d9042c1a07f5a1b3629c583224b5543800048ed8be264460e7e\"" + }, + "AssetParametersd1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6S3Bucket04F6B25B": { "Type": "String", - "Description": "S3 bucket for asset \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + "Description": "S3 bucket for asset \"d1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6\"" }, - "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaS3VersionKeyDE8A2F1F": { + "AssetParametersd1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6S3VersionKey6A7508AF": { "Type": "String", - "Description": "S3 key for asset version \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + "Description": "S3 key for asset version \"d1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6\"" }, - "AssetParameters87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dbaArtifactHash54822A43": { + "AssetParametersd1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6ArtifactHashF7473C14": { "Type": "String", - "Description": "Artifact hash for asset \"87b1e2c41f84590d14f7ab8cb0f338c51d6fa3efe78943867af07fa959593dba\"" + "Description": "Artifact hash for asset \"d1380bb36e9a4e378cf1d8fe7779efa967f218e380fd40aad493f588a9872dd6\"" }, "AssetParametersdaeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1S3BucketDC4B98B1": { "Type": "String", @@ -1516,17 +1468,17 @@ "Type": "String", "Description": "Artifact hash for asset \"daeb79e3cee39c9b902dc0d5c780223e227ed573ea60976252947adab5fb2be1\"" }, - "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3Bucket008DBB35": { + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3BucketC6FAEEC9": { "Type": "String", - "Description": "S3 bucket for asset \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + "Description": "S3 bucket for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" }, - "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757S3VersionKey97C3E1A0": { + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10S3VersionKeyA7EE7421": { "Type": "String", - "Description": "S3 key for asset version \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + "Description": "S3 key for asset version \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" }, - "AssetParametersbafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757ArtifactHashF584A7D8": { + "AssetParameters4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10ArtifactHash528547CD": { "Type": "String", - "Description": "Artifact hash for asset \"bafd50ae9f214e496ff8c72c6425f93dca3ccd590e20963706d5d610d9c75757\"" + "Description": "Artifact hash for asset \"4129bbca38164ecb28fee8e5b674f0d05e5957b4b8ed97d9c950527b5cc4ce10\"" }, "AssetParameterse9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68S3BucketAEADE8C7": { "Type": "String", @@ -1540,41 +1492,41 @@ "Type": "String", "Description": "Artifact hash for asset \"e9882ab123687399f934da0d45effe675ecc8ce13b40cb946f3e1d6141fe8d68\"" }, - "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3Bucket6ABE1927": { + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3BucketD3288998": { "Type": "String", - "Description": "S3 bucket for asset \"844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0\"" + "Description": "S3 bucket for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0S3VersionKeyF55A2EA9": { + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eS3VersionKeyB00C0565": { "Type": "String", - "Description": "S3 key for asset version \"844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0\"" + "Description": "S3 key for asset version \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParameters844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0ArtifactHash1D7A2D6E": { + "AssetParametersea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03eArtifactHash4654D012": { "Type": "String", - "Description": "Artifact hash for asset \"844c1a4b13479b359ea0e607dccb4a04b73e22cf88cf9b64feed2c5f0de213c0\"" + "Description": "Artifact hash for asset \"ea17febe6d04c66048f3e8e060c71685c0cb53122abceff44842d27bc0d4a03e\"" }, - "AssetParametersf14dbf982bfb4e61285bf9e6e91f20eb00e8a36c79c981ceec2437b42a02e216S3BucketE0529475": { + "AssetParameters0b198930f902d53efb864e939b03a42215307ad763b6c49e200b860e0bf87ba8S3Bucket0CDB4070": { "Type": "String", - "Description": "S3 bucket for asset \"f14dbf982bfb4e61285bf9e6e91f20eb00e8a36c79c981ceec2437b42a02e216\"" + "Description": "S3 bucket for asset \"0b198930f902d53efb864e939b03a42215307ad763b6c49e200b860e0bf87ba8\"" }, - "AssetParametersf14dbf982bfb4e61285bf9e6e91f20eb00e8a36c79c981ceec2437b42a02e216S3VersionKey736B6614": { + "AssetParameters0b198930f902d53efb864e939b03a42215307ad763b6c49e200b860e0bf87ba8S3VersionKey9304E721": { "Type": "String", - "Description": "S3 key for asset version \"f14dbf982bfb4e61285bf9e6e91f20eb00e8a36c79c981ceec2437b42a02e216\"" + "Description": "S3 key for asset version \"0b198930f902d53efb864e939b03a42215307ad763b6c49e200b860e0bf87ba8\"" }, - "AssetParametersf14dbf982bfb4e61285bf9e6e91f20eb00e8a36c79c981ceec2437b42a02e216ArtifactHash85D00783": { + "AssetParameters0b198930f902d53efb864e939b03a42215307ad763b6c49e200b860e0bf87ba8ArtifactHash27112E89": { "Type": "String", - "Description": "Artifact hash for asset \"f14dbf982bfb4e61285bf9e6e91f20eb00e8a36c79c981ceec2437b42a02e216\"" + "Description": "Artifact hash for asset \"0b198930f902d53efb864e939b03a42215307ad763b6c49e200b860e0bf87ba8\"" }, - "AssetParameters9d41118c36f364bd9f7de59dda09afbef182ac0f726496523af8ffd24aafc604S3BucketCAFDB26C": { + "AssetParameters71b4be22b7489e3746d72802bb115cc0c5c2c2a8efac49a7e81e6257bec20ae5S3BucketEC7134BF": { "Type": "String", - "Description": "S3 bucket for asset \"9d41118c36f364bd9f7de59dda09afbef182ac0f726496523af8ffd24aafc604\"" + "Description": "S3 bucket for asset \"71b4be22b7489e3746d72802bb115cc0c5c2c2a8efac49a7e81e6257bec20ae5\"" }, - "AssetParameters9d41118c36f364bd9f7de59dda09afbef182ac0f726496523af8ffd24aafc604S3VersionKey3CF353E9": { + "AssetParameters71b4be22b7489e3746d72802bb115cc0c5c2c2a8efac49a7e81e6257bec20ae5S3VersionKey3EC7EA95": { "Type": "String", - "Description": "S3 key for asset version \"9d41118c36f364bd9f7de59dda09afbef182ac0f726496523af8ffd24aafc604\"" + "Description": "S3 key for asset version \"71b4be22b7489e3746d72802bb115cc0c5c2c2a8efac49a7e81e6257bec20ae5\"" }, - "AssetParameters9d41118c36f364bd9f7de59dda09afbef182ac0f726496523af8ffd24aafc604ArtifactHashEC502675": { + "AssetParameters71b4be22b7489e3746d72802bb115cc0c5c2c2a8efac49a7e81e6257bec20ae5ArtifactHashCD2D1888": { "Type": "String", - "Description": "Artifact hash for asset \"9d41118c36f364bd9f7de59dda09afbef182ac0f726496523af8ffd24aafc604\"" + "Description": "Artifact hash for asset \"71b4be22b7489e3746d72802bb115cc0c5c2c2a8efac49a7e81e6257bec20ae5\"" } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-stepfunctions/.eslintrc.js b/packages/@aws-cdk/aws-stepfunctions/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-stepfunctions/.eslintrc.js +++ b/packages/@aws-cdk/aws-stepfunctions/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-stepfunctions/README.md b/packages/@aws-cdk/aws-stepfunctions/README.md index 6171bac75805a..908d40d376dfd 100644 --- a/packages/@aws-cdk/aws-stepfunctions/README.md +++ b/packages/@aws-cdk/aws-stepfunctions/README.md @@ -22,6 +22,7 @@ example](https://docs.aws.amazon.com/step-functions/latest/dg/job-status-poller- ## Example ```ts +import * as cdk from '@aws-cdk/core'; import * as sfn from '@aws-cdk/aws-stepfunctions'; import * as tasks from '@aws-cdk/aws-stepfunctions-tasks'; import * as lambda from '@aws-cdk/aws-lambda'; @@ -70,7 +71,7 @@ const definition = submitJob new sfn.StateMachine(this, 'StateMachine', { definition, - timeout: Duration.minutes(5) + timeout: cdk.Duration.minutes(5) }); ``` @@ -353,8 +354,8 @@ the State Machine uses. The following example uses the `DynamoDB` service integration to insert data into a DynamoDB table. ```ts -import * as ddb from '@aws-cdk/aws-dynamodb'; import * as cdk from '@aws-cdk/core'; +import * as ddb from '@aws-cdk/aws-dynamodb'; import * as sfn from '@aws-cdk/aws-stepfunctions'; // create a table diff --git a/packages/@aws-cdk/aws-stepfunctions/jest.config.js b/packages/@aws-cdk/aws-stepfunctions/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-stepfunctions/jest.config.js +++ b/packages/@aws-cdk/aws-stepfunctions/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-stepfunctions/package.json b/packages/@aws-cdk/aws-stepfunctions/package.json index a5141b16bf045..dbbb99ff04844 100644 --- a/packages/@aws-cdk/aws-stepfunctions/package.json +++ b/packages/@aws-cdk/aws-stepfunctions/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::StepFunctions", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,12 +72,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", diff --git a/packages/@aws-cdk/aws-synthetics/.eslintrc.js b/packages/@aws-cdk/aws-synthetics/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-synthetics/.eslintrc.js +++ b/packages/@aws-cdk/aws-synthetics/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-synthetics/README.md b/packages/@aws-cdk/aws-synthetics/README.md index bd4fcaede272c..ccda6db1260a9 100644 --- a/packages/@aws-cdk/aws-synthetics/README.md +++ b/packages/@aws-cdk/aws-synthetics/README.md @@ -87,6 +87,27 @@ The Canary code will be executed in a lambda function created by Synthetics on y To learn more about Synthetics capabilities, check out the [docs](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries.html). + +### Canary Schedule + +You can specify the schedule on which a canary runs by providing a +[`Schedule`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-synthetics.Schedule.html) +object to the `schedule` property. + +Configure a run rate of up to 60 minutes with `Schedule.rate`: + +```ts +Schedule.rate(Duration.minutes(5)), // Runs every 5 minutes. +``` + +You can also specify a [cron expression](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_cron.html) via `Schedule.expression`: + +```ts +Schedule.expression('cron(0 0,8,16 * * ? *)'), // Run at 12am, 8am, 4pm UTC every day +``` + +If you want the canary to run just once upon deployment, you can use `Schedule.once()`. + ### Configuring the Canary Script To configure the script the canary executes, use the `test` property. The `test` property accepts a `Test` instance that can be initialized by the `Test` class static methods. Currently, the only implemented method is `Test.custom()`, which allows you to bring your own code. In the future, other methods will be added. `Test.custom()` accepts `code` and `handler` properties -- both are required by Synthetics to create a lambda function on your behalf. diff --git a/packages/@aws-cdk/aws-synthetics/jest.config.js b/packages/@aws-cdk/aws-synthetics/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-synthetics/jest.config.js +++ b/packages/@aws-cdk/aws-synthetics/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-synthetics/package.json b/packages/@aws-cdk/aws-synthetics/package.json index 7febc7e87b686..6504764f4f218 100644 --- a/packages/@aws-cdk/aws-synthetics/package.json +++ b/packages/@aws-cdk/aws-synthetics/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Synthetics", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,27 +74,27 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { + "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/core": "0.0.0", - "@aws-cdk/aws-cloudwatch": "0.0.0", "constructs": "^3.3.69" }, "peerDependencies": { - "@aws-cdk/core": "0.0.0", + "@aws-cdk/aws-cloudwatch": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", - "@aws-cdk/aws-iam": "0.0.0", - "@aws-cdk/aws-cloudwatch": "0.0.0", + "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "engines": { diff --git a/packages/@aws-cdk/aws-timestream/.eslintrc.js b/packages/@aws-cdk/aws-timestream/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-timestream/.eslintrc.js +++ b/packages/@aws-cdk/aws-timestream/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-timestream/jest.config.js b/packages/@aws-cdk/aws-timestream/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-timestream/jest.config.js +++ b/packages/@aws-cdk/aws-timestream/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-timestream/package.json b/packages/@aws-cdk/aws-timestream/package.json index 82e1fb198680b..8e812faac660d 100644 --- a/packages/@aws-cdk/aws-timestream/package.json +++ b/packages/@aws-cdk/aws-timestream/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Timestream", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/aws-transfer/.eslintrc.js b/packages/@aws-cdk/aws-transfer/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-transfer/.eslintrc.js +++ b/packages/@aws-cdk/aws-transfer/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-transfer/jest.config.js b/packages/@aws-cdk/aws-transfer/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-transfer/jest.config.js +++ b/packages/@aws-cdk/aws-transfer/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-transfer/package.json b/packages/@aws-cdk/aws-transfer/package.json index 4d8e05fab19f5..3dcd461a79ab6 100644 --- a/packages/@aws-cdk/aws-transfer/package.json +++ b/packages/@aws-cdk/aws-transfer/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::Transfer", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-waf/.eslintrc.js b/packages/@aws-cdk/aws-waf/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-waf/.eslintrc.js +++ b/packages/@aws-cdk/aws-waf/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-waf/jest.config.js b/packages/@aws-cdk/aws-waf/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-waf/jest.config.js +++ b/packages/@aws-cdk/aws-waf/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-waf/package.json b/packages/@aws-cdk/aws-waf/package.json index 8c4f85f3402b7..33482a6fa8f12 100644 --- a/packages/@aws-cdk/aws-waf/package.json +++ b/packages/@aws-cdk/aws-waf/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::WAF", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-wafregional/.eslintrc.js b/packages/@aws-cdk/aws-wafregional/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-wafregional/.eslintrc.js +++ b/packages/@aws-cdk/aws-wafregional/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-wafregional/jest.config.js b/packages/@aws-cdk/aws-wafregional/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-wafregional/jest.config.js +++ b/packages/@aws-cdk/aws-wafregional/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-wafregional/package.json b/packages/@aws-cdk/aws-wafregional/package.json index e82afe0e25e4a..4710718baec70 100644 --- a/packages/@aws-cdk/aws-wafregional/package.json +++ b/packages/@aws-cdk/aws-wafregional/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::WAFRegional", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-wafv2/.eslintrc.js b/packages/@aws-cdk/aws-wafv2/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-wafv2/.eslintrc.js +++ b/packages/@aws-cdk/aws-wafv2/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-wafv2/jest.config.js b/packages/@aws-cdk/aws-wafv2/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-wafv2/jest.config.js +++ b/packages/@aws-cdk/aws-wafv2/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-wafv2/package.json b/packages/@aws-cdk/aws-wafv2/package.json index c46028b894625..6ac9c2eb572fa 100644 --- a/packages/@aws-cdk/aws-wafv2/package.json +++ b/packages/@aws-cdk/aws-wafv2/package.json @@ -56,7 +56,6 @@ }, "cdk-build": { "cloudformation": "AWS::WAFv2", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -75,11 +74,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-workspaces/.eslintrc.js b/packages/@aws-cdk/aws-workspaces/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-workspaces/.eslintrc.js +++ b/packages/@aws-cdk/aws-workspaces/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-workspaces/jest.config.js b/packages/@aws-cdk/aws-workspaces/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-workspaces/jest.config.js +++ b/packages/@aws-cdk/aws-workspaces/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-workspaces/package.json b/packages/@aws-cdk/aws-workspaces/package.json index 84f7406237f45..8a7f2477621a5 100644 --- a/packages/@aws-cdk/aws-workspaces/package.json +++ b/packages/@aws-cdk/aws-workspaces/package.json @@ -55,7 +55,6 @@ }, "cdk-build": { "cloudformation": "AWS::WorkSpaces", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,11 +72,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0", - "@aws-cdk/assertions": "0.0.0" + "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-xray/.eslintrc.js b/packages/@aws-cdk/aws-xray/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/aws-xray/.eslintrc.js +++ b/packages/@aws-cdk/aws-xray/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-xray/jest.config.js b/packages/@aws-cdk/aws-xray/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/aws-xray/jest.config.js +++ b/packages/@aws-cdk/aws-xray/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-xray/package.json b/packages/@aws-cdk/aws-xray/package.json index e5ec9ff9da5fa..f1219a428f2fb 100644 --- a/packages/@aws-cdk/aws-xray/package.json +++ b/packages/@aws-cdk/aws-xray/package.json @@ -58,7 +58,6 @@ }, "cdk-build": { "cloudformation": "AWS::XRay", - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -77,11 +76,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", "@aws-cdk/assertions": "0.0.0", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24" }, "dependencies": { "@aws-cdk/core": "0.0.0" diff --git a/packages/@aws-cdk/cdk-assets-schema/.eslintrc.js b/packages/@aws-cdk/cdk-assets-schema/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/cdk-assets-schema/.eslintrc.js +++ b/packages/@aws-cdk/cdk-assets-schema/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/cdk-assets-schema/jest.config.js b/packages/@aws-cdk/cdk-assets-schema/jest.config.js index 5c1ef76634a9f..751c263a6e75c 100644 --- a/packages/@aws-cdk/cdk-assets-schema/jest.config.js +++ b/packages/@aws-cdk/cdk-assets-schema/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/cdk-assets-schema/package.json b/packages/@aws-cdk/cdk-assets-schema/package.json index f4e5ef6cb1b5f..a2a06573cbefc 100644 --- a/packages/@aws-cdk/cdk-assets-schema/package.json +++ b/packages/@aws-cdk/cdk-assets-schema/package.json @@ -52,10 +52,10 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0" + "jest": "^26.6.3" }, "repository": { "url": "https://github.com/aws/aws-cdk.git", @@ -76,9 +76,6 @@ }, "deprecated": "merged into @aws-cdk/cloud-assembly-schema", "maturity": "deprecated", - "cdk-build": { - "jest": true - }, "publishConfig": { "tag": "latest" } diff --git a/packages/@aws-cdk/cfnspec/.eslintrc.js b/packages/@aws-cdk/cfnspec/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/cfnspec/.eslintrc.js +++ b/packages/@aws-cdk/cfnspec/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/cfnspec/.gitignore b/packages/@aws-cdk/cfnspec/.gitignore index c7d816ca89794..01db1803f53af 100644 --- a/packages/@aws-cdk/cfnspec/.gitignore +++ b/packages/@aws-cdk/cfnspec/.gitignore @@ -12,3 +12,5 @@ dist .LAST_PACKAGE *.snk !.eslintrc.js + +!jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/cfnspec/.npmignore b/packages/@aws-cdk/cfnspec/.npmignore index 3c75fd13efb4a..34100f8a5b6ee 100644 --- a/packages/@aws-cdk/cfnspec/.npmignore +++ b/packages/@aws-cdk/cfnspec/.npmignore @@ -7,3 +7,6 @@ dist .LAST_BUILD *.snk .eslintrc.js + +test/ +jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/cfnspec/CHANGELOG.md b/packages/@aws-cdk/cfnspec/CHANGELOG.md index b95283e3d0114..2d57129b35373 100644 --- a/packages/@aws-cdk/cfnspec/CHANGELOG.md +++ b/packages/@aws-cdk/cfnspec/CHANGELOG.md @@ -1,3 +1,76 @@ +# CloudFormation Resource Specification v42.0.0 + +## New Resource Types + +* AWS::MemoryDB::ACL +* AWS::MemoryDB::Cluster +* AWS::MemoryDB::ParameterGroup +* AWS::MemoryDB::SubnetGroup +* AWS::MemoryDB::User + +## Attribute Changes + +* AWS::ApiGateway::GatewayResponse Id (__added__) +* AWS::Config::AggregationAuthorization AggregationAuthorizationArn (__added__) + +## Property Changes + +* AWS::ApiGateway::GatewayResponse ResponseParameters.DuplicatesAllowed (__deleted__) +* AWS::ApiGateway::GatewayResponse ResponseTemplates.DuplicatesAllowed (__deleted__) +* AWS::AppSync::DataSource OpenSearchServiceConfig (__added__) +* AWS::Backup::BackupVault LockConfiguration (__added__) +* AWS::Config::AggregationAuthorization Tags.DuplicatesAllowed (__added__) +* AWS::MSK::Cluster ClientAuthentication.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::MSK::Cluster EncryptionInfo.UpdateType (__changed__) + * Old: Immutable + * New: Mutable + +## Property Type Changes + +* AWS::AppSync::DataSource.OpenSearchServiceConfig (__added__) +* AWS::Backup::BackupVault.LockConfigurationType (__added__) +* AWS::IoT::TopicRule.OpenSearchAction (__added__) +* AWS::MSK::Cluster.Unauthenticated (__added__) +* AWS::ImageBuilder::ImageRecipe.AdditionalInstanceConfiguration UserDataOverride.Required (__changed__) + * Old: true + * New: false +* AWS::ImageBuilder::ImageRecipe.SystemsManagerAgent UninstallAfterBuild.Required (__changed__) + * Old: true + * New: false +* AWS::IoT::TopicRule.Action OpenSearch (__added__) +* AWS::MSK::Cluster.ClientAuthentication Unauthenticated (__added__) +* AWS::MSK::Cluster.ClientAuthentication Sasl.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::MSK::Cluster.ClientAuthentication Tls.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::MSK::Cluster.EncryptionInTransit ClientBroker.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::MSK::Cluster.EncryptionInfo EncryptionInTransit.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::MSK::Cluster.Iam Enabled.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::MSK::Cluster.Sasl Iam.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::MSK::Cluster.Sasl Scram.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::MSK::Cluster.Scram Enabled.UpdateType (__changed__) + * Old: Immutable + * New: Mutable +* AWS::MSK::Cluster.Tls Enabled (__added__) +* AWS::MSK::Cluster.Tls CertificateAuthorityArnList.UpdateType (__changed__) + * Old: Immutable + * New: Mutable + + # CloudFormation Resource Specification v41.2.0 ## New Resource Types 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 db1edab50e8a4..a8900329a3917 100644 --- a/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts +++ b/packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts @@ -178,11 +178,11 @@ async function main() { }, license: 'Apache-2.0', devDependencies: { - '@types/jest': '^26.0.22', '@aws-cdk/assertions': version, - 'cdk-build-tools': version, - 'cfn2ts': version, - 'pkglint': version, + '@aws-cdk/cdk-build-tools': version, + '@aws-cdk/cfn2ts': version, + '@aws-cdk/pkglint': version, + '@types/jest': '^26.0.22', }, dependencies: { '@aws-cdk/core': version, @@ -295,13 +295,13 @@ async function main() { ]); await write('.eslintrc.js', [ - "const baseConfig = require('cdk-build-tools/config/eslintrc');", + "const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc');", "baseConfig.parserOptions.project = __dirname + '/tsconfig.json';", 'module.exports = baseConfig;', ]); await write('jest.config.js', [ - "const baseConfig = require('cdk-build-tools/config/jest.config');", + "const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config');", 'module.exports = baseConfig;', ]); diff --git a/packages/@aws-cdk/cfnspec/cfn.version b/packages/@aws-cdk/cfnspec/cfn.version index 6b3b6773a39be..59b3a909cdd4d 100644 --- a/packages/@aws-cdk/cfnspec/cfn.version +++ b/packages/@aws-cdk/cfnspec/cfn.version @@ -1 +1 @@ -41.2.0 +42.0.0 diff --git a/packages/@aws-cdk/cfnspec/jest.config.js b/packages/@aws-cdk/cfnspec/jest.config.js new file mode 100644 index 0000000000000..35bb1719cf56f --- /dev/null +++ b/packages/@aws-cdk/cfnspec/jest.config.js @@ -0,0 +1,10 @@ +const baseConfig = require('../../../tools/@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = { + ...baseConfig, + coverageThreshold: { + global: { + statements: 70, + branches: 50, + } + } +}; diff --git a/packages/@aws-cdk/cfnspec/package.json b/packages/@aws-cdk/cfnspec/package.json index f9c34feb21e7a..1109498bfe092 100644 --- a/packages/@aws-cdk/cfnspec/package.json +++ b/packages/@aws-cdk/cfnspec/package.json @@ -20,21 +20,24 @@ "statements": 50, "lines": 50 }, + "cdk-build": { + "jest": true + }, "pkglint": { "ignore": true }, "main": "lib/index.js", "types": "lib/index.d.ts", "devDependencies": { + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/fs-extra": "^8.1.2", + "@types/jest": "^26.0.24", "@types/md5": "^2.3.1", - "@types/nodeunit": "^0.0.32", - "cdk-build-tools": "0.0.0", "fast-json-patch": "^2.2.1", "fs-extra": "^9.1.0", + "jest": "^26.6.3", "json-diff": "^0.5.4", - "nodeunit": "^0.11.3", - "pkglint": "0.0.0", "sort-json": "^2.0.0" }, "dependencies": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/000_CloudFormationResourceSpecification.json b/packages/@aws-cdk/cfnspec/spec-source/000_CloudFormationResourceSpecification.json index af011f312a399..d7d147ad6d46e 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/000_CloudFormationResourceSpecification.json +++ b/packages/@aws-cdk/cfnspec/spec-source/000_CloudFormationResourceSpecification.json @@ -7077,6 +7077,23 @@ } } }, + "AWS::AppSync::DataSource.OpenSearchServiceConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appsync-datasource-opensearchserviceconfig.html", + "Properties": { + "AwsRegion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appsync-datasource-opensearchserviceconfig.html#cfn-appsync-datasource-opensearchserviceconfig-awsregion", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Endpoint": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appsync-datasource-opensearchserviceconfig.html#cfn-appsync-datasource-opensearchserviceconfig-endpoint", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::AppSync::DataSource.RdsHttpEndpointConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appsync-datasource-rdshttpendpointconfig.html", "Properties": { @@ -9354,6 +9371,29 @@ } } }, + "AWS::Backup::BackupVault.LockConfigurationType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-backupvault-lockconfigurationtype.html", + "Properties": { + "changeableForDays": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-backupvault-lockconfigurationtype.html#cfn-backup-backupvault-lockconfigurationtype-changeablefordays", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Mutable" + }, + "maxRetentionDays": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-backupvault-lockconfigurationtype.html#cfn-backup-backupvault-lockconfigurationtype-maxretentiondays", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Mutable" + }, + "minRetentionDays": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-backupvault-lockconfigurationtype.html#cfn-backup-backupvault-lockconfigurationtype-minretentiondays", + "PrimitiveType": "Double", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::Backup::BackupVault.NotificationObjectType": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-backup-backupvault-notificationobjecttype.html", "Properties": { @@ -32649,7 +32689,7 @@ "UserDataOverride": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-imagerecipe-additionalinstanceconfiguration.html#cfn-imagebuilder-imagerecipe-additionalinstanceconfiguration-userdataoverride", "PrimitiveType": "String", - "Required": true, + "Required": false, "UpdateType": "Mutable" } } @@ -32772,7 +32812,7 @@ "UninstallAfterBuild": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-imagebuilder-imagerecipe-systemsmanageragent.html#cfn-imagebuilder-imagerecipe-systemsmanageragent-uninstallafterbuild", "PrimitiveType": "Boolean", - "Required": true, + "Required": false, "UpdateType": "Mutable" } } @@ -33473,6 +33513,12 @@ "Type": "LambdaAction", "UpdateType": "Mutable" }, + "OpenSearch": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-action.html#cfn-iot-topicrule-action-opensearch", + "Required": false, + "Type": "OpenSearchAction", + "UpdateType": "Mutable" + }, "Republish": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-action.html#cfn-iot-topicrule-action-republish", "Required": false, @@ -34007,6 +34053,41 @@ } } }, + "AWS::IoT::TopicRule.OpenSearchAction": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-opensearchaction.html", + "Properties": { + "Endpoint": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-opensearchaction.html#cfn-iot-topicrule-opensearchaction-endpoint", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Id": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-opensearchaction.html#cfn-iot-topicrule-opensearchaction-id", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Index": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-opensearchaction.html#cfn-iot-topicrule-opensearchaction-index", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "RoleArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-opensearchaction.html#cfn-iot-topicrule-opensearchaction-rolearn", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "Type": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-opensearchaction.html#cfn-iot-topicrule-opensearchaction-type", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + } + } + }, "AWS::IoT::TopicRule.PutAssetPropertyValueEntry": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iot-topicrule-putassetpropertyvalueentry.html", "Properties": { @@ -41832,13 +41913,19 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-clientauthentication.html#cfn-msk-cluster-clientauthentication-sasl", "Required": false, "Type": "Sasl", - "UpdateType": "Immutable" + "UpdateType": "Mutable" }, "Tls": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-clientauthentication.html#cfn-msk-cluster-clientauthentication-tls", "Required": false, "Type": "Tls", - "UpdateType": "Immutable" + "UpdateType": "Mutable" + }, + "Unauthenticated": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-clientauthentication.html#cfn-msk-cluster-clientauthentication-unauthenticated", + "Required": false, + "Type": "Unauthenticated", + "UpdateType": "Mutable" } } }, @@ -41905,7 +41992,7 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-encryptionintransit.html#cfn-msk-cluster-encryptionintransit-clientbroker", "PrimitiveType": "String", "Required": false, - "UpdateType": "Immutable" + "UpdateType": "Mutable" }, "InCluster": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-encryptionintransit.html#cfn-msk-cluster-encryptionintransit-incluster", @@ -41928,7 +42015,7 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-encryptioninfo.html#cfn-msk-cluster-encryptioninfo-encryptionintransit", "Required": false, "Type": "EncryptionInTransit", - "UpdateType": "Immutable" + "UpdateType": "Mutable" } } }, @@ -41956,7 +42043,7 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-iam.html#cfn-msk-cluster-iam-enabled", "PrimitiveType": "Boolean", "Required": true, - "UpdateType": "Immutable" + "UpdateType": "Mutable" } } }, @@ -42051,13 +42138,13 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-sasl.html#cfn-msk-cluster-sasl-iam", "Required": false, "Type": "Iam", - "UpdateType": "Immutable" + "UpdateType": "Mutable" }, "Scram": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-sasl.html#cfn-msk-cluster-sasl-scram", "Required": false, "Type": "Scram", - "UpdateType": "Immutable" + "UpdateType": "Mutable" } } }, @@ -42068,7 +42155,7 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-scram.html#cfn-msk-cluster-scram-enabled", "PrimitiveType": "Boolean", "Required": true, - "UpdateType": "Immutable" + "UpdateType": "Mutable" } } }, @@ -42091,7 +42178,24 @@ "PrimitiveItemType": "String", "Required": false, "Type": "List", - "UpdateType": "Immutable" + "UpdateType": "Mutable" + }, + "Enabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-tls.html#cfn-msk-cluster-tls-enabled", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + } + } + }, + "AWS::MSK::Cluster.Unauthenticated": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-unauthenticated.html", + "Properties": { + "Enabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-msk-cluster-unauthenticated.html#cfn-msk-cluster-unauthenticated-enabled", + "PrimitiveType": "Boolean", + "Required": true, + "UpdateType": "Mutable" } } }, @@ -48253,6 +48357,23 @@ } } }, + "AWS::MemoryDB::Cluster.Endpoint": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-memorydb-cluster-endpoint.html", + "Properties": { + "Address": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-memorydb-cluster-endpoint.html#cfn-memorydb-cluster-endpoint-address", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Port": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-memorydb-cluster-endpoint.html#cfn-memorydb-cluster-endpoint-port", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + } + } + }, "AWS::Neptune::DBCluster.DBClusterRole": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-neptune-dbcluster-dbclusterrole.html", "Properties": { @@ -62540,7 +62661,7 @@ } } }, - "ResourceSpecificationVersion": "41.2.0", + "ResourceSpecificationVersion": "42.0.0", "ResourceTypes": { "AWS::ACMPCA::Certificate": { "Attributes": { @@ -63637,11 +63758,15 @@ } }, "AWS::ApiGateway::GatewayResponse": { + "Attributes": { + "Id": { + "PrimitiveType": "String" + } + }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-gatewayresponse.html", "Properties": { "ResponseParameters": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-gatewayresponse.html#cfn-apigateway-gatewayresponse-responseparameters", - "DuplicatesAllowed": false, "PrimitiveItemType": "String", "Required": false, "Type": "Map", @@ -63649,7 +63774,6 @@ }, "ResponseTemplates": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-gatewayresponse.html#cfn-apigateway-gatewayresponse-responsetemplates", - "DuplicatesAllowed": false, "PrimitiveItemType": "String", "Required": false, "Type": "Map", @@ -66273,6 +66397,12 @@ "Required": true, "UpdateType": "Immutable" }, + "OpenSearchServiceConfig": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appsync-datasource.html#cfn-appsync-datasource-opensearchserviceconfig", + "Required": false, + "Type": "OpenSearchServiceConfig", + "UpdateType": "Mutable" + }, "RelationalDatabaseConfig": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appsync-datasource.html#cfn-appsync-datasource-relationaldatabaseconfig", "Required": false, @@ -67618,6 +67748,12 @@ "Required": false, "UpdateType": "Immutable" }, + "LockConfiguration": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-backup-backupvault.html#cfn-backup-backupvault-lockconfiguration", + "Required": false, + "Type": "LockConfigurationType", + "UpdateType": "Mutable" + }, "Notifications": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-backup-backupvault.html#cfn-backup-backupvault-notifications", "Required": false, @@ -71196,6 +71332,11 @@ } }, "AWS::Config::AggregationAuthorization": { + "Attributes": { + "AggregationAuthorizationArn": { + "PrimitiveType": "String" + } + }, "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-config-aggregationauthorization.html", "Properties": { "AuthorizedAccountId": { @@ -71212,6 +71353,7 @@ }, "Tags": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-config-aggregationauthorization.html#cfn-config-aggregationauthorization-tags", + "DuplicatesAllowed": false, "ItemType": "Tag", "Required": false, "Type": "List", @@ -88431,7 +88573,7 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-msk-cluster.html#cfn-msk-cluster-clientauthentication", "Required": false, "Type": "ClientAuthentication", - "UpdateType": "Immutable" + "UpdateType": "Mutable" }, "ClusterName": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-msk-cluster.html#cfn-msk-cluster-clustername", @@ -88449,7 +88591,7 @@ "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-msk-cluster.html#cfn-msk-cluster-encryptioninfo", "Required": false, "Type": "EncryptionInfo", - "UpdateType": "Immutable" + "UpdateType": "Mutable" }, "EnhancedMonitoring": { "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-msk-cluster.html#cfn-msk-cluster-enhancedmonitoring", @@ -89838,6 +89980,332 @@ } } }, + "AWS::MemoryDB::ACL": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, + "Status": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-acl.html", + "Properties": { + "ACLName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-acl.html#cfn-memorydb-acl-aclname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-acl.html#cfn-memorydb-acl-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "UserNames": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-acl.html#cfn-memorydb-acl-usernames", + "DuplicatesAllowed": false, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::MemoryDB::Cluster": { + "Attributes": { + "ARN": { + "PrimitiveType": "String" + }, + "ClusterEndpoint.Address": { + "PrimitiveType": "String" + }, + "ClusterEndpoint.Port": { + "PrimitiveType": "Integer" + }, + "ParameterGroupStatus": { + "PrimitiveType": "String" + }, + "Status": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html", + "Properties": { + "ACLName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-aclname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "AutoMinorVersionUpgrade": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-autominorversionupgrade", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Mutable" + }, + "ClusterEndpoint": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-clusterendpoint", + "Required": false, + "Type": "Endpoint", + "UpdateType": "Mutable" + }, + "ClusterName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-clustername", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "EngineVersion": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-engineversion", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "FinalSnapshotName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-finalsnapshotname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "KmsKeyId": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-kmskeyid", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "MaintenanceWindow": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-maintenancewindow", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "NodeType": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-nodetype", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "NumReplicasPerShard": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-numreplicaspershard", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "NumShards": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-numshards", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "ParameterGroupName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-parametergroupname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "Port": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-port", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Immutable" + }, + "SecurityGroupIds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-securitygroupids", + "DuplicatesAllowed": true, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "SnapshotArns": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-snapshotarns", + "DuplicatesAllowed": true, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Immutable" + }, + "SnapshotName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-snapshotname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "SnapshotRetentionLimit": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-snapshotretentionlimit", + "PrimitiveType": "Integer", + "Required": false, + "UpdateType": "Mutable" + }, + "SnapshotWindow": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-snapshotwindow", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SnsTopicArn": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-snstopicarn", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SnsTopicStatus": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-snstopicstatus", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SubnetGroupName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-subnetgroupname", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "TLSEnabled": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-tlsenabled", + "PrimitiveType": "Boolean", + "Required": false, + "UpdateType": "Immutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-cluster.html#cfn-memorydb-cluster-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::MemoryDB::ParameterGroup": { + "Attributes": { + "ARN": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-parametergroup.html", + "Properties": { + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-parametergroup.html#cfn-memorydb-parametergroup-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "Family": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-parametergroup.html#cfn-memorydb-parametergroup-family", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Immutable" + }, + "ParameterGroupName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-parametergroup.html#cfn-memorydb-parametergroup-parametergroupname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "Parameters": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-parametergroup.html#cfn-memorydb-parametergroup-parameters", + "PrimitiveType": "Json", + "Required": false, + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-parametergroup.html#cfn-memorydb-parametergroup-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::MemoryDB::SubnetGroup": { + "Attributes": { + "ARN": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-subnetgroup.html", + "Properties": { + "Description": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-subnetgroup.html#cfn-memorydb-subnetgroup-description", + "PrimitiveType": "String", + "Required": false, + "UpdateType": "Mutable" + }, + "SubnetGroupName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-subnetgroup.html#cfn-memorydb-subnetgroup-subnetgroupname", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + }, + "SubnetIds": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-subnetgroup.html#cfn-memorydb-subnetgroup-subnetids", + "DuplicatesAllowed": false, + "PrimitiveItemType": "String", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-subnetgroup.html#cfn-memorydb-subnetgroup-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + } + } + }, + "AWS::MemoryDB::User": { + "Attributes": { + "Arn": { + "PrimitiveType": "String" + }, + "Status": { + "PrimitiveType": "String" + } + }, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-user.html", + "Properties": { + "AccessString": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-user.html#cfn-memorydb-user-accessstring", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Mutable" + }, + "AuthenticationMode": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-user.html#cfn-memorydb-user-authenticationmode", + "PrimitiveType": "Json", + "Required": true, + "UpdateType": "Mutable" + }, + "Tags": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-user.html#cfn-memorydb-user-tags", + "DuplicatesAllowed": false, + "ItemType": "Tag", + "Required": false, + "Type": "List", + "UpdateType": "Mutable" + }, + "UserName": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-memorydb-user.html#cfn-memorydb-user-username", + "PrimitiveType": "String", + "Required": true, + "UpdateType": "Immutable" + } + } + }, "AWS::Neptune::DBCluster": { "Attributes": { "ClusterResourceId": { diff --git a/packages/@aws-cdk/cfnspec/spec-source/530_Lambda_ARM_patch.json b/packages/@aws-cdk/cfnspec/spec-source/530_Lambda_ARM_patch.json new file mode 100644 index 0000000000000..13c481eff424d --- /dev/null +++ b/packages/@aws-cdk/cfnspec/spec-source/530_Lambda_ARM_patch.json @@ -0,0 +1,41 @@ +{ + "ResourceType": { + "AWS::Lambda::Function": { + "patch": { + "description": "AWS::Lambda::Function changes for early support of Lambda ARM launch. Remove once CFN spec is updated", + "operations": [ + { + "op": "add", + "path": "/Properties/Architectures", + "value": { + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-architectures", + "UpdateType": "Mutable", + "Required": false, + "Type": "List", + "PrimitiveItemType": "String", + "DuplicatesAllowed": true + } + } + ] + } + }, + "AWS::Lambda::LayerVersion": { + "patch": { + "description": "AWS::Lambda::LayerVersion changes for early support of Lambda ARM launch. Remove once CFN spec is updated", + "operations": [ + { + "op": "add", + "path": "/Properties/CompatibleArchitectures", + "value": { + "PrimitiveItemType": "String", + "Type": "List", + "Required": false, + "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-layerversion.html#cfn-lambda-layerversion-compatiblearchitectures", + "UpdateType": "Immutable" + } + } + ] + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/cfnspec/test/augmentation.test.ts b/packages/@aws-cdk/cfnspec/test/augmentation.test.ts new file mode 100644 index 0000000000000..74931a754b3a7 --- /dev/null +++ b/packages/@aws-cdk/cfnspec/test/augmentation.test.ts @@ -0,0 +1,26 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import * as cfnspec from '../lib'; +import { MetricType } from '../lib/schema'; + +function resourceAugmentationTest(resource: string) { + return () => { + const model = cfnspec.resourceAugmentation(resource); + + if (model.metrics) { + expect(typeof(model.metrics.namespace) === 'string').toBeTruthy(); + expect(typeof(model.metrics.dimensions) === 'object').toBeTruthy(); + for (const metric of model.metrics.metrics) { + expect(typeof metric.name === 'string').toBeTruthy(); + expect(typeof metric.documentation === 'string').toBeTruthy(); + expect(metric.type === undefined || [MetricType.Attrib, MetricType.Count, MetricType.Gauge].includes(metric.type)).toBeTruthy(); + } + } + }; +} + +const files = fs.readdirSync(path.resolve(__dirname, '../lib/augmentations')); +for (const file of files) { + const resource = file.replace(/\.json$/, '').replace(/_/g, '::'); + test(`Validate augmentation schema for ${resource}`, resourceAugmentationTest(resource)); +} diff --git a/packages/@aws-cdk/cfnspec/test/build.test.ts b/packages/@aws-cdk/cfnspec/test/build.test.ts new file mode 100644 index 0000000000000..6612fe9f15b43 --- /dev/null +++ b/packages/@aws-cdk/cfnspec/test/build.test.ts @@ -0,0 +1,63 @@ +import { massageSpec } from '../build-tools/massage-spec'; +import { schema } from '../lib'; + +test('dropTypelessAttributes works correctly', () => { + const spec: schema.Specification = { + Fingerprint: 'some-fingerprint', + PropertyTypes: { + 'CDK::Test::Property': { + Properties: { + Type: ({ + PrimitiveType: 'String', + } as schema.ScalarProperty), // ts is being weird and doesn't correctly match the type + }, + }, + }, + ResourceTypes: { + 'CDK::Test::Resource': { + Attributes: { + Attribute1: ({ + PrimitiveType: 'String', + } as schema.PrimitiveAttribute), // ts is being weird and doesn't correctly match the type + Attribute2: ({} as schema.PrimitiveAttribute), + }, + Documentation: 'https://documentation-url/cdk/test/resource', + Properties: { + ResourceArn: ({ + PrimitiveType: 'String', + } as schema.PrimitiveProperty), // ts is being weird and doesn't correctly match the type + }, + }, + }, + }; + + massageSpec(spec); + + expect(spec).toEqual({ + Fingerprint: 'some-fingerprint', + PropertyTypes: { + 'CDK::Test::Property': { + Properties: { + Type: ({ + PrimitiveType: 'String', + } as schema.ScalarProperty), // ts is being weird and doesn't correctly match the type + }, + }, + }, + ResourceTypes: { + 'CDK::Test::Resource': { + Attributes: { + Attribute1: ({ + PrimitiveType: 'String', + }), + }, + Documentation: 'https://documentation-url/cdk/test/resource', + Properties: { + ResourceArn: { + PrimitiveType: 'String', + }, + }, + }, + }, + }); +}); diff --git a/packages/@aws-cdk/cfnspec/test/canned-metrics.test.ts b/packages/@aws-cdk/cfnspec/test/canned-metrics.test.ts new file mode 100644 index 0000000000000..db884768588cf --- /dev/null +++ b/packages/@aws-cdk/cfnspec/test/canned-metrics.test.ts @@ -0,0 +1,31 @@ +import * as cfnspec from '../lib'; + +test('spot-check DynamoDB metrics', () => { + const metrics = cfnspec.cannedMetricsForService('AWS::DynamoDB'); + expect(metrics.length).toBeGreaterThan(0); + + const resLatency = metrics.find(m => m.metricName === 'SuccessfulRequestLatency'); + expect(resLatency).toBeTruthy(); + + expect(resLatency?.dimensions).toEqual([['Operation', 'TableName']]); +}); + +test('spot-check MediaStore metrics', () => { + const metrics = cfnspec.cannedMetricsForService('AWS::MediaStore'); + expect(metrics.length).toBeGreaterThan(0); +}); + +/** + * Test that we can read canned metrics for all namespaces in the spec without throwing an error + */ +for (const _namespace of cfnspec.namespaces()) { + const namespace = _namespace; + test(`Validate canned metrics for ${namespace}`, () => { + const metrics = cfnspec.cannedMetricsForService(namespace); + + // Check that there are no duplicates in these list (duplicates may occur because of duplicate + // dimensions, but those have readly been combined). + const uniqueMetricNames = new Set(metrics.map(m => `${m.namespace}/${m.metricName}`)); + expect(uniqueMetricNames.size).toEqual(metrics.length); + }); +}; \ No newline at end of file diff --git a/packages/@aws-cdk/cfnspec/test/cfnlint-annotations.test.ts b/packages/@aws-cdk/cfnspec/test/cfnlint-annotations.test.ts new file mode 100644 index 0000000000000..776cac3df6a1d --- /dev/null +++ b/packages/@aws-cdk/cfnspec/test/cfnlint-annotations.test.ts @@ -0,0 +1,19 @@ +import * as cfnspec from '../lib'; + +test('spot-check Bucket statefulness', () => { + const anno = cfnspec.cfnLintAnnotations('AWS::S3::Bucket'); + expect(anno.stateful).toBeTruthy(); + expect(anno.mustBeEmptyToDelete).toBeTruthy(); +}); + +test('spot-check Table statefulness', () => { + const anno = cfnspec.cfnLintAnnotations('AWS::DynamoDB::Table'); + expect(anno.stateful).toBeTruthy(); + expect(anno.mustBeEmptyToDelete).toBeFalsy(); +}); + +test('spot-check MediaStore metrics', () => { + const anno = cfnspec.cfnLintAnnotations('AWS::MediaStore::Thingy'); + expect(anno.stateful).toBeFalsy(); +}); + diff --git a/packages/@aws-cdk/cfnspec/test/filtered-specification.test.ts b/packages/@aws-cdk/cfnspec/test/filtered-specification.test.ts new file mode 100644 index 0000000000000..a4bd359517da1 --- /dev/null +++ b/packages/@aws-cdk/cfnspec/test/filtered-specification.test.ts @@ -0,0 +1,24 @@ +import { filteredSpecification, resourceTypes, specification } from '../lib/index'; +import { validateSpecification } from './spec-validators'; + +test('filteredSpecification(/^AWS::S3::.*/)', () => { + const filteredSpec = filteredSpecification(/^AWS::S3::.*/); + expect(filteredSpec).not.toEqual(specification); + expect(filteredSpec.ResourceTypes).not.toEqual({}); +}); + +test('filteredSpecification(s => s.startsWith("AWS::S3::")', () => { + const filteredSpec = filteredSpecification(s => s.startsWith('AWS::S3::')); + expect(filteredSpec).not.toEqual(specification); + expect(filteredSpec.ResourceTypes).not.toEqual({}); +}); + +for (const name of resourceTypes().sort()) { + test(`filteredSpecification(${JSON.stringify(name)})`, () => { + const filteredSpec = filteredSpecification(name); + expect(filteredSpec).not.toEqual(specification); + expect(filteredSpec.ResourceTypes).not.toEqual({}); + // Validate the spec is conform & coherent. + validateSpecification(filteredSpec); + }); +} diff --git a/packages/@aws-cdk/cfnspec/test/namespaces.test.ts b/packages/@aws-cdk/cfnspec/test/namespaces.test.ts new file mode 100644 index 0000000000000..860fd5ed15db9 --- /dev/null +++ b/packages/@aws-cdk/cfnspec/test/namespaces.test.ts @@ -0,0 +1,5 @@ +import { namespaces } from '../lib/index'; + +test('namespaces() includes some namespaces', () => { + expect(namespaces().length).toBeGreaterThan(10); +}); diff --git a/packages/@aws-cdk/cfnspec/test/scrutiny.test.ts b/packages/@aws-cdk/cfnspec/test/scrutiny.test.ts new file mode 100644 index 0000000000000..8343f0bdf1116 --- /dev/null +++ b/packages/@aws-cdk/cfnspec/test/scrutiny.test.ts @@ -0,0 +1,52 @@ +import { propertySpecification, resourceSpecification } from '../lib'; +import { PropertyScrutinyType, ResourceScrutinyType } from '../lib/schema'; + +test('spot-check IAM identity tags', () => { + const prop = propertySpecification('AWS::IAM::Role', 'Policies'); + expect(prop.ScrutinyType).toEqual(PropertyScrutinyType.InlineIdentityPolicies); +}); + +test('IAM AssumeRolePolicy', () => { + // AssumeRolePolicyDocument is a resource policy, because it applies to the Role itself! + const prop = propertySpecification('AWS::IAM::Role', 'AssumeRolePolicyDocument'); + expect(prop.ScrutinyType).toEqual(PropertyScrutinyType.InlineResourcePolicy); +}); + +test('spot-check IAM resource tags', () => { + const prop = propertySpecification('AWS::KMS::Key', 'KeyPolicy'); + expect(prop.ScrutinyType).toEqual(PropertyScrutinyType.InlineResourcePolicy); +}); + +test('spot-check resource policy resources', () => { + expect(resourceSpecification('AWS::S3::BucketPolicy').ScrutinyType).toEqual(ResourceScrutinyType.ResourcePolicyResource); +}); + +test('spot-check no misclassified tags', () => { + const prop = propertySpecification('AWS::SNS::Subscription', 'DeliveryPolicy'); + expect(prop.ScrutinyType).toEqual(PropertyScrutinyType.None); +}); + +test('check Lambda permission resource scrutiny', () => { + expect(resourceSpecification('AWS::Lambda::Permission').ScrutinyType).toEqual(ResourceScrutinyType.LambdaPermission); +}); + +test('check role managedpolicyarns', () => { + const prop = propertySpecification('AWS::IAM::Role', 'ManagedPolicyArns'); + expect(prop.ScrutinyType).toEqual(PropertyScrutinyType.ManagedPolicies); +}); + +test('check securityGroup scrutinies', () => { + const inProp = propertySpecification('AWS::EC2::SecurityGroup', 'SecurityGroupIngress'); + expect(inProp.ScrutinyType).toEqual(PropertyScrutinyType.IngressRules); + + const eProp = propertySpecification('AWS::EC2::SecurityGroup', 'SecurityGroupEgress'); + expect(eProp.ScrutinyType).toEqual(PropertyScrutinyType.EgressRules); +}); + +test('check securityGroupRule scrutinies', () => { + const inRes = resourceSpecification('AWS::EC2::SecurityGroupIngress'); + expect(inRes.ScrutinyType).toEqual(ResourceScrutinyType.IngressRuleResource); + + const eRes = resourceSpecification('AWS::EC2::SecurityGroupEgress'); + expect(eRes.ScrutinyType).toEqual(ResourceScrutinyType.EgressRuleResource); +}); \ No newline at end of file diff --git a/packages/@aws-cdk/cfnspec/test/spec-validators.ts b/packages/@aws-cdk/cfnspec/test/spec-validators.ts index c09fb7dc0e27f..d7507f2753d27 100644 --- a/packages/@aws-cdk/cfnspec/test/spec-validators.ts +++ b/packages/@aws-cdk/cfnspec/test/spec-validators.ts @@ -1,153 +1,148 @@ -import { Test } from 'nodeunit'; import * as schema from '../lib/schema'; -export function validateSpecification(test: Test, specification: schema.Specification) { - validateResourceTypes(test, specification); - validatePropertyTypes(test, specification); +export function validateSpecification(specification: schema.Specification) { + validateResourceTypes(specification); + validatePropertyTypes(specification); } -function validateResourceTypes(test: Test, specification: schema.Specification) { +function validateResourceTypes(specification: schema.Specification) { for (const typeName of Object.keys(specification.ResourceTypes)) { - test.ok(typeName, 'Resource type name is not empty'); + expect(typeName).toBeTruthy(); const type = specification.ResourceTypes[typeName]; - test.notEqual(type.Documentation, null, `${typeName} is documented`); + expect(type.Documentation).not.toBeNull(); if (type.ScrutinyType) { - test.ok(schema.isResourceScrutinyType(type.ScrutinyType), `${typeName}.ScrutinyType is not a valid ResourceScrutinyType`); + expect(schema.isResourceScrutinyType(type.ScrutinyType)).toBeTruthy(); } - if (type.Properties) { validateProperties(typeName, test, type.Properties, specification); } - if (type.Attributes) { validateAttributes(typeName, test, type.Attributes, specification); } + if (type.Properties) { validateProperties(typeName, type.Properties, specification); } + if (type.Attributes) { validateAttributes(typeName, type.Attributes, specification); } } } -function validatePropertyTypes(test: Test, specification: schema.Specification) { +function validatePropertyTypes(specification: schema.Specification) { for (const typeName of Object.keys(specification.PropertyTypes)) { - test.ok(typeName, 'Property type name is not empty'); + expect(typeName).toBeTruthy(); const type = specification.PropertyTypes[typeName]; if (schema.isRecordType(type)) { - validateProperties(typeName, test, type.Properties, specification); + validateProperties(typeName, type.Properties, specification); } else { - validateProperties(typeName, test, { '': type }, specification); + validateProperties(typeName, { '': type }, specification); } } } function validateProperties( typeName: string, - test: Test, properties: { [name: string]: schema.Property }, specification: schema.Specification) { const expectedKeys = ['Documentation', 'Required', 'UpdateType', 'ScrutinyType']; for (const name of Object.keys(properties)) { const property = properties[name]; - test.notEqual(property.Documentation, '', `${typeName}.Properties.${name} is documented`); - test.ok(!property.UpdateType || schema.isUpdateType(property.UpdateType), `${typeName}.Properties.${name} has valid UpdateType`); + expect(property.Documentation).not.toEqual(''); + expect(!property.UpdateType || schema.isUpdateType(property.UpdateType)).toBeTruthy(); if (property.ScrutinyType !== undefined) { - test.ok(schema.isPropertyScrutinyType(property.ScrutinyType), `${typeName}.Properties.${name} has valid ScrutinyType`); + expect(schema.isPropertyScrutinyType(property.ScrutinyType)).toBeTruthy(); } if (schema.isPrimitiveProperty(property)) { - test.ok(schema.isPrimitiveType(property.PrimitiveType), `${typeName}.Properties.${name} has a valid PrimitiveType`); + expect(schema.isPrimitiveType(property.PrimitiveType)).toBeTruthy(); expectedKeys.push('PrimitiveType'); } else if (schema.isPrimitiveListProperty(property)) { expectedKeys.push('Type', 'DuplicatesAllowed', 'PrimitiveItemType'); - test.ok(schema.isPrimitiveType(property.PrimitiveItemType), `${typeName}.Properties.${name} has a valid PrimitiveItemType`); + expect(schema.isPrimitiveType(property.PrimitiveItemType)).toBeTruthy(); } else if (schema.isPrimitiveMapProperty(property)) { expectedKeys.push('Type', 'DuplicatesAllowed', 'PrimitiveItemType', 'Type'); - test.ok(schema.isPrimitiveType(property.PrimitiveItemType), `${typeName}.Properties.${name} has a valid PrimitiveItemType`); - test.ok(!property.DuplicatesAllowed, `${typeName}.Properties.${name} does not allow duplicates`); + expect(schema.isPrimitiveType(property.PrimitiveItemType)).toBeTruthy(); + expect(property.DuplicatesAllowed).toBeFalsy(); } else if (schema.isComplexListProperty(property)) { expectedKeys.push('Type', 'DuplicatesAllowed', 'ItemType', 'Type'); - test.ok(property.ItemType, `${typeName}.Properties.${name} has a valid ItemType`); + expect(property.ItemType).toBeTruthy(); if (property.ItemType !== 'Tag') { const fqn = `${typeName.split('.')[0]}.${property.ItemType}`; const resolvedType = specification.PropertyTypes && specification.PropertyTypes[fqn]; - test.ok(resolvedType, `${typeName}.Properties.${name} ItemType (${fqn}) resolves`); + expect(resolvedType).toBeTruthy(); } } else if (schema.isMapOfStructsProperty(property)) { expectedKeys.push('Type', 'DuplicatesAllowed', 'ItemType', 'Type'); - test.ok(property.ItemType, `${typeName}.Properties.${name} has a valid ItemType`); + expect(property.ItemType).toBeTruthy(); const fqn = `${typeName.split('.')[0]}.${property.ItemType}`; const resolvedType = specification.PropertyTypes && specification.PropertyTypes[fqn]; - test.ok(resolvedType, `${typeName}.Properties.${name} ItemType (${fqn}) resolves`); - test.ok(!property.DuplicatesAllowed, `${typeName}.Properties.${name} does not allow duplicates`); + expect(resolvedType).toBeTruthy(); + expect(property.DuplicatesAllowed).toBeFalsy(); } else if (schema.isMapOfListsOfPrimitivesProperty(property)) { expectedKeys.push('Type', 'DuplicatesAllowed', 'ItemType', 'PrimitiveItemItemType', 'Type'); - test.ok(schema.isPrimitiveType(property.PrimitiveItemItemType), `${typeName}.Properties.${name} has a valid PrimitiveItemItemType`); - test.ok(!property.DuplicatesAllowed, `${typeName}.Properties.${name} does not allow duplicates`); + expect(schema.isPrimitiveType(property.PrimitiveItemItemType)).toBeTruthy(); + expect(property.DuplicatesAllowed).toBeFalsy(); } else if (schema.isComplexProperty(property)) { expectedKeys.push('Type'); - test.ok(property.Type, `${typeName}.Properties.${name} has a valid type`); + expect(property.Type).toBeTruthy(); const fqn = `${typeName.split('.')[0]}.${property.Type}`; const resolvedType = specification.PropertyTypes && specification.PropertyTypes[fqn]; - test.ok(resolvedType, `${typeName}.Properties.${name} type (${fqn}) resolves`); + expect(resolvedType).toBeTruthy(); } else if (schema.isUnionProperty(property)) { expectedKeys.push('PrimitiveTypes', 'PrimitiveItemTypes', 'ItemTypes', 'Types'); if (property.PrimitiveTypes) { for (const type of property.PrimitiveTypes) { - test.ok(schema.isPrimitiveType(type), `${typeName}.Properties.${name} has only valid PrimitiveTypes`); + expect(schema.isPrimitiveType(type)).toBeTruthy(); } } if (property.ItemTypes) { for (const type of property.ItemTypes) { const fqn = `${typeName.split('.')[0]}.${type}`; const resolvedType = specification.PropertyTypes && specification.PropertyTypes[fqn]; - test.ok(resolvedType, `${typeName}.Properties.${name} type (${fqn}) resolves`); + expect(resolvedType).toBeTruthy(); } } if (property.Types) { for (const type of property.Types) { const fqn = `${typeName.split('.')[0]}.${type}`; const resolvedType = specification.PropertyTypes && specification.PropertyTypes[fqn]; - test.ok(resolvedType, `${typeName}.Properties.${name} type (${fqn}) resolves`); + expect(resolvedType).toBeTruthy(); } } } else { - test.ok(false, `${typeName}.Properties.${name} has known type`); + expect(false).toBeTruthy(); //`${typeName}.Properties.${name} has known type` } - test.deepEqual( - without(Object.keys(property), expectedKeys), [], - `${typeName}.Properties.${name} has no extra properties`); + expect(without(Object.keys(property), expectedKeys)).toEqual([]); } } function validateAttributes( typeName: string, - test: Test, attributes: { [name: string]: schema.Attribute }, specification: schema.Specification) { for (const name of Object.keys(attributes)) { const attribute = attributes[name]; - test.ok(('Type' in attribute) !== ('PrimitiveType' in attribute), 'One of, and only one of, Type or PrimitiveType must be present'); + expect(('Type' in attribute)).not.toEqual(('PrimitiveType' in attribute)); if (schema.isPrimitiveAttribute(attribute)) { - test.ok(!schema.isListAttribute(attribute), `${typeName}.Attributes.${name} is only a Primitive type`); - test.ok(schema.isPrimitiveType(attribute.PrimitiveType), `${typeName}.Attributes.${name} has a valid PrimitiveType`); - test.ok(!('PrimitiveItemType' in attribute), `${typeName}.Attributes.${name} has no PrimitiveItemType`); - test.ok(!('ItemType' in attribute), `${typeName}.Attributes.${name} has no ItemType`); + expect(schema.isListAttribute(attribute)).toBeFalsy(); + expect(schema.isPrimitiveType(attribute.PrimitiveType)).toBeTruthy(); + expect(('PrimitiveItemType' in attribute)).toBeFalsy(); + expect(('ItemType' in attribute)).toBeFalsy(); } else if (schema.isPrimitiveListAttribute(attribute)) { - test.ok(!schema.isComplexListAttribute(attribute), `${typeName}.Attributes.${name} is only a List type`); - test.ok(schema.isPrimitiveType(attribute.PrimitiveItemType), `${typeName}.Attributes.${name} has a valid PrimitiveItemType`); - test.ok(!('ItemType' in attribute), `${typeName}.Attributes.${name} has no ItemType`); + expect(schema.isComplexListAttribute(attribute)).toBeFalsy(); + expect(schema.isPrimitiveType(attribute.PrimitiveItemType)).toBeTruthy(); + expect(('ItemType' in attribute)).toBeFalsy(); } else if (schema.isComplexListAttribute(attribute)) { - test.ok(attribute.ItemType, `${typeName}.Attributes.${name} is a valid List type`); + expect(attribute.ItemType).toBeTruthy(); const fqn = `${typeName.split('.')[0]}.${attribute.ItemType}`; const resolvedType = specification.PropertyTypes && specification.PropertyTypes[fqn]; - test.ok(resolvedType, `${typeName}.Attributes.${name} ItemType (${fqn}) resolves`); - test.ok(!('PrimitiveItemType' in attribute), `${typeName}.Attributes.${name} has no PrimitiveItemType`); + expect(resolvedType).toBeTruthy(); + expect(('PrimitiveItemType' in attribute)).toBeFalsy(); } else if (schema.isPrimitiveMapAttribute(attribute)) { - test.ok(schema.isPrimitiveType(attribute.PrimitiveItemType), `${typeName}.Attributes.${name} has a valid PrimitiveItemType`); - test.ok(!('ItemType' in attribute), `${typeName}.Attributes.${name} has no ItemType`); + expect(schema.isPrimitiveType(attribute.PrimitiveItemType)).toBeTruthy(); + expect(('ItemType' in attribute)).toBeFalsy(); } else { - test.ok(false, `${typeName}.Attributes.${name} has a valid type`); + expect(false).toBeTruthy(); // `${typeName}.Attributes.${name} has a valid type`); } } } diff --git a/packages/@aws-cdk/cfnspec/test/test.augmentation.ts b/packages/@aws-cdk/cfnspec/test/test.augmentation.ts deleted file mode 100644 index 34222c197d867..0000000000000 --- a/packages/@aws-cdk/cfnspec/test/test.augmentation.ts +++ /dev/null @@ -1,29 +0,0 @@ -import * as fs from 'fs'; -import * as path from 'path'; -import { Test } from 'nodeunit'; -import * as cfnspec from '../lib'; -import { MetricType } from '../lib/schema'; - -function resourceAugmentationTest(resource: string) { - return (test: Test) => { - const model = cfnspec.resourceAugmentation(resource); - - if (model.metrics) { - test.ok(typeof(model.metrics.namespace) === 'string', `namespace is invalid: ${model.metrics.namespace}`); - test.ok(typeof(model.metrics.dimensions) === 'object', `dimensions is invalid: ${model.metrics.dimensions}`); - for (const metric of model.metrics.metrics) { - test.ok(typeof metric.name === 'string', `name is invalid: ${metric.name}`); - test.ok(typeof metric.documentation === 'string', `documentation is invalid: ${metric.documentation}`); - test.ok(metric.type === undefined || [MetricType.Attrib, MetricType.Count, MetricType.Gauge].includes(metric.type), - `Metric Type is invalid: ${metric.type}`); - } - } - test.done(); - }; -} - -const files = fs.readdirSync(path.resolve(__dirname, '../lib/augmentations')); -for (const file of files) { - const resource = file.replace(/\.json$/, '').replace(/_/g, '::'); - exports[`Validate augmentation schema for ${resource}`] = resourceAugmentationTest(resource); -} diff --git a/packages/@aws-cdk/cfnspec/test/test.build.ts b/packages/@aws-cdk/cfnspec/test/test.build.ts deleted file mode 100644 index b0638fe3de2a4..0000000000000 --- a/packages/@aws-cdk/cfnspec/test/test.build.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { Test } from 'nodeunit'; -import { massageSpec } from '../build-tools/massage-spec'; -import { schema } from '../lib'; - -export = { - 'dropTypelessAttributes works correctly'(test: Test) { - const spec: schema.Specification = { - Fingerprint: 'some-fingerprint', - PropertyTypes: { - 'CDK::Test::Property': { - Properties: { - Type: ({ - PrimitiveType: 'String', - } as schema.ScalarProperty), // ts is being weird and doesn't correctly match the type - }, - }, - }, - ResourceTypes: { - 'CDK::Test::Resource': { - Attributes: { - Attribute1: ({ - PrimitiveType: 'String', - } as schema.PrimitiveAttribute), // ts is being weird and doesn't correctly match the type - Attribute2: ({} as schema.PrimitiveAttribute), - }, - Documentation: 'https://documentation-url/cdk/test/resource', - Properties: { - ResourceArn: ({ - PrimitiveType: 'String', - } as schema.PrimitiveProperty), // ts is being weird and doesn't correctly match the type - }, - }, - }, - }; - - massageSpec(spec); - - test.deepEqual(spec, { - Fingerprint: 'some-fingerprint', - PropertyTypes: { - 'CDK::Test::Property': { - Properties: { - Type: ({ - PrimitiveType: 'String', - } as schema.ScalarProperty), // ts is being weird and doesn't correctly match the type - }, - }, - }, - ResourceTypes: { - 'CDK::Test::Resource': { - Attributes: { - Attribute1: ({ - PrimitiveType: 'String', - }), - }, - Documentation: 'https://documentation-url/cdk/test/resource', - Properties: { - ResourceArn: { - PrimitiveType: 'String', - }, - }, - }, - }, - }); - - test.done(); - }, -}; diff --git a/packages/@aws-cdk/cfnspec/test/test.canned-metrics.ts b/packages/@aws-cdk/cfnspec/test/test.canned-metrics.ts deleted file mode 100644 index ff14500769c8d..0000000000000 --- a/packages/@aws-cdk/cfnspec/test/test.canned-metrics.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Test } from 'nodeunit'; -import * as cfnspec from '../lib'; - -module.exports = { - 'spot-check DynamoDB metrics'(test: Test) { - const metrics = cfnspec.cannedMetricsForService('AWS::DynamoDB'); - test.ok(metrics.length > 0); - - const resLatency = metrics.find(m => m.metricName === 'SuccessfulRequestLatency'); - test.ok(resLatency); - - test.deepEqual(resLatency?.dimensions, [['Operation', 'TableName']]); - - test.done(); - }, - - 'spot-check MediaStore metrics'(test: Test) { - const metrics = cfnspec.cannedMetricsForService('AWS::MediaStore'); - test.ok(metrics.length > 0); - - test.done(); - }, -}; - -/** - * Test that we can read canned metrics for all namespaces in the spec without throwing an error - */ -for (const _namespace of cfnspec.namespaces()) { - const namespace = _namespace; - module.exports[`Validate canned metrics for ${namespace}`] = (test: Test) => { - const metrics = cfnspec.cannedMetricsForService(namespace); - - // Check that there are no duplicates in these list (duplicates may occur because of duplicate - // dimensions, but those have readly been combined). - const uniqueMetricNames = new Set(metrics.map(m => `${m.namespace}/${m.metricName}`)); - test.equal(uniqueMetricNames.size, metrics.length, 'There are metrics with duplicate names'); - - test.done(); - }; -} \ No newline at end of file diff --git a/packages/@aws-cdk/cfnspec/test/test.cfnlint-annotations.ts b/packages/@aws-cdk/cfnspec/test/test.cfnlint-annotations.ts deleted file mode 100644 index 04e0972893d12..0000000000000 --- a/packages/@aws-cdk/cfnspec/test/test.cfnlint-annotations.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Test } from 'nodeunit'; -import * as cfnspec from '../lib'; - -module.exports = { - 'spot-check Bucket statefulness'(test: Test) { - const anno = cfnspec.cfnLintAnnotations('AWS::S3::Bucket'); - test.equal(anno.stateful, true); - test.equal(anno.mustBeEmptyToDelete, true); - - test.done(); - }, - - 'spot-check Table statefulness'(test: Test) { - const anno = cfnspec.cfnLintAnnotations('AWS::DynamoDB::Table'); - test.equal(anno.stateful, true); - test.equal(anno.mustBeEmptyToDelete, false); - - test.done(); - }, - - 'spot-check MediaStore metrics'(test: Test) { - const anno = cfnspec.cfnLintAnnotations('AWS::MediaStore::Thingy'); - test.equal(anno.stateful, false); - - test.done(); - }, -}; - diff --git a/packages/@aws-cdk/cfnspec/test/test.filtered-specification.ts b/packages/@aws-cdk/cfnspec/test/test.filtered-specification.ts deleted file mode 100644 index 90b56c3001ee6..0000000000000 --- a/packages/@aws-cdk/cfnspec/test/test.filtered-specification.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Test, testCase } from 'nodeunit'; -import { filteredSpecification, resourceTypes, specification } from '../lib/index'; -import { validateSpecification } from './spec-validators'; - -const tests: any = { - 'filteredSpecification(/^AWS::S3::.*/)'(test: Test) { - const filteredSpec = filteredSpecification(/^AWS::S3::.*/); - test.notDeepEqual(filteredSpec, specification, 'The filteredSpecification result is not the whole specification'); - test.notDeepEqual(filteredSpec.ResourceTypes, {}, 'The filtered spec is not empty'); - test.done(); - }, - 'filteredSpecification(s => s.startsWith("AWS::S3::")'(test: Test) { - const filteredSpec = filteredSpecification(s => s.startsWith('AWS::S3::')); - test.notDeepEqual(filteredSpec, specification, 'The filteredSpecification result is not the whole specification'); - test.notDeepEqual(filteredSpec.ResourceTypes, {}, 'The filtered spec is not empty'); - test.done(); - }, -}; - -for (const name of resourceTypes().sort()) { - tests[`filteredSpecification(${JSON.stringify(name)})`] = (test: Test) => { - const filteredSpec = filteredSpecification(name); - test.notDeepEqual(filteredSpec, specification, 'The filteredSpecification result is not the whole specification'); - test.notDeepEqual(filteredSpec.ResourceTypes, {}, 'The filtered spec is not empty'); - // Validate the spec is conform & coherent. - validateSpecification(test, filteredSpec); - test.done(); - }; -} - -export = testCase(tests); diff --git a/packages/@aws-cdk/cfnspec/test/test.namespaces.ts b/packages/@aws-cdk/cfnspec/test/test.namespaces.ts deleted file mode 100644 index fea78b4520ce5..0000000000000 --- a/packages/@aws-cdk/cfnspec/test/test.namespaces.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Test, testCase } from 'nodeunit'; -import { namespaces } from '../lib/index'; - -export = testCase({ - 'namespaces() includes some namespaces'(test: Test) { - test.ok(namespaces().length > 10); - test.done(); - }, -}); diff --git a/packages/@aws-cdk/cfnspec/test/test.scrutiny.ts b/packages/@aws-cdk/cfnspec/test/test.scrutiny.ts deleted file mode 100644 index 8a90a6e21bd4d..0000000000000 --- a/packages/@aws-cdk/cfnspec/test/test.scrutiny.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { Test } from 'nodeunit'; -import { propertySpecification, resourceSpecification } from '../lib'; -import { PropertyScrutinyType, ResourceScrutinyType } from '../lib/schema'; - -export = { - 'spot-check IAM identity tags'(test: Test) { - const prop = propertySpecification('AWS::IAM::Role', 'Policies'); - test.equals(prop.ScrutinyType, PropertyScrutinyType.InlineIdentityPolicies); - - test.done(); - }, - - 'IAM AssumeRolePolicy'(test: Test) { - // AssumeRolePolicyDocument is a resource policy, because it applies to the Role itself! - const prop = propertySpecification('AWS::IAM::Role', 'AssumeRolePolicyDocument'); - test.equals(prop.ScrutinyType, PropertyScrutinyType.InlineResourcePolicy); - - test.done(); - }, - - 'spot-check IAM resource tags'(test: Test) { - const prop = propertySpecification('AWS::KMS::Key', 'KeyPolicy'); - test.equals(prop.ScrutinyType, PropertyScrutinyType.InlineResourcePolicy); - - test.done(); - }, - - 'spot-check resource policy resources'(test: Test) { - test.equals(resourceSpecification('AWS::S3::BucketPolicy').ScrutinyType, ResourceScrutinyType.ResourcePolicyResource); - - test.done(); - }, - - 'spot-check no misclassified tags'(test: Test) { - const prop = propertySpecification('AWS::SNS::Subscription', 'DeliveryPolicy'); - test.equals(prop.ScrutinyType, PropertyScrutinyType.None); - - test.done(); - }, - - 'check Lambda permission resource scrutiny'(test: Test) { - test.equals(resourceSpecification('AWS::Lambda::Permission').ScrutinyType, ResourceScrutinyType.LambdaPermission); - - test.done(); - }, - - 'check role managedpolicyarns'(test: Test) { - const prop = propertySpecification('AWS::IAM::Role', 'ManagedPolicyArns'); - test.equals(prop.ScrutinyType, PropertyScrutinyType.ManagedPolicies); - - test.done(); - }, - - 'check securityGroup scrutinies'(test: Test) { - const inProp = propertySpecification('AWS::EC2::SecurityGroup', 'SecurityGroupIngress'); - test.equals(inProp.ScrutinyType, PropertyScrutinyType.IngressRules); - - const eProp = propertySpecification('AWS::EC2::SecurityGroup', 'SecurityGroupEgress'); - test.equals(eProp.ScrutinyType, PropertyScrutinyType.EgressRules); - - test.done(); - }, - - 'check securityGroupRule scrutinies'(test: Test) { - const inRes = resourceSpecification('AWS::EC2::SecurityGroupIngress'); - test.equals(inRes.ScrutinyType, ResourceScrutinyType.IngressRuleResource); - - const eRes = resourceSpecification('AWS::EC2::SecurityGroupEgress'); - test.equals(eRes.ScrutinyType, ResourceScrutinyType.EgressRuleResource); - - test.done(); - }, -}; \ No newline at end of file diff --git a/packages/@aws-cdk/cloud-assembly-schema/.eslintrc.js b/packages/@aws-cdk/cloud-assembly-schema/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/.eslintrc.js +++ b/packages/@aws-cdk/cloud-assembly-schema/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/cloud-assembly-schema/jest.config.js b/packages/@aws-cdk/cloud-assembly-schema/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/jest.config.js +++ b/packages/@aws-cdk/cloud-assembly-schema/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/cloud-assembly-schema/package.json b/packages/@aws-cdk/cloud-assembly-schema/package.json index 98689e858a5f8..e6aee07a67f09 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/package.json +++ b/packages/@aws-cdk/cloud-assembly-schema/package.json @@ -60,14 +60,14 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", "@types/mock-fs": "^4.13.1", - "@types/semver": "^7.3.7", - "cdk-build-tools": "0.0.0", + "@types/semver": "^7.3.8", "jest": "^26.6.3", "mock-fs": "^4.14.0", - "pkglint": "0.0.0", - "typescript-json-schema": "^0.50.1" + "typescript-json-schema": "^0.51.0" }, "repository": { "url": "https://github.com/aws/aws-cdk.git", @@ -98,9 +98,6 @@ "announce": false }, "maturity": "stable", - "cdk-build": { - "jest": true - }, "publishConfig": { "tag": "latest" } diff --git a/packages/@aws-cdk/cloudformation-diff/.eslintrc.js b/packages/@aws-cdk/cloudformation-diff/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/cloudformation-diff/.eslintrc.js +++ b/packages/@aws-cdk/cloudformation-diff/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/cloudformation-diff/jest.config.js b/packages/@aws-cdk/cloudformation-diff/jest.config.js index 2bf3bec36d750..e49f3262c4d91 100644 --- a/packages/@aws-cdk/cloudformation-diff/jest.config.js +++ b/packages/@aws-cdk/cloudformation-diff/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/cloudformation-diff/package.json b/packages/@aws-cdk/cloudformation-diff/package.json index 1fe5f51e907de..3ce9836319c90 100644 --- a/packages/@aws-cdk/cloudformation-diff/package.json +++ b/packages/@aws-cdk/cloudformation-diff/package.json @@ -28,16 +28,16 @@ "colors": "^1.4.0", "diff": "^5.0.0", "fast-deep-equal": "^3.1.3", - "string-width": "^4.2.2", + "string-width": "^4.2.3", "table": "^6.7.1" }, "devDependencies": { + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", "@types/string-width": "^4.0.1", - "cdk-build-tools": "0.0.0", "fast-check": "^2.17.0", "jest": "^26.6.3", - "pkglint": "0.0.0", "ts-jest": "^26.5.6" }, "repository": { @@ -55,9 +55,6 @@ }, "stability": "stable", "maturity": "stable", - "cdk-build": { - "jest": true - }, "publishConfig": { "tag": "latest" } diff --git a/packages/@aws-cdk/cloudformation-include/.eslintrc.js b/packages/@aws-cdk/cloudformation-include/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/cloudformation-include/.eslintrc.js +++ b/packages/@aws-cdk/cloudformation-include/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/cloudformation-include/jest.config.js b/packages/@aws-cdk/cloudformation-include/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/cloudformation-include/jest.config.js +++ b/packages/@aws-cdk/cloudformation-include/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/cloudformation-include/package.json b/packages/@aws-cdk/cloudformation-include/package.json index 58d67a7fe230e..28c53e5d49c01 100644 --- a/packages/@aws-cdk/cloudformation-include/package.json +++ b/packages/@aws-cdk/cloudformation-include/package.json @@ -55,7 +55,6 @@ "pre": [ "node ./build.js" ], - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -185,6 +184,7 @@ "@aws-cdk/aws-medialive": "0.0.0", "@aws-cdk/aws-mediapackage": "0.0.0", "@aws-cdk/aws-mediastore": "0.0.0", + "@aws-cdk/aws-memorydb": "0.0.0", "@aws-cdk/aws-msk": "0.0.0", "@aws-cdk/aws-mwaa": "0.0.0", "@aws-cdk/aws-neptune": "0.0.0", @@ -358,6 +358,7 @@ "@aws-cdk/aws-medialive": "0.0.0", "@aws-cdk/aws-mediapackage": "0.0.0", "@aws-cdk/aws-mediastore": "0.0.0", + "@aws-cdk/aws-memorydb": "0.0.0", "@aws-cdk/aws-msk": "0.0.0", "@aws-cdk/aws-mwaa": "0.0.0", "@aws-cdk/aws-neptune": "0.0.0", @@ -412,13 +413,13 @@ "constructs": "^3.3.69" }, "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", "jest": "^26.6.3", - "pkglint": "0.0.0", - "ts-jest": "^26.5.6", - "@aws-cdk/assert-internal": "0.0.0" + "ts-jest": "^26.5.6" }, "bundledDependencies": [ "yaml" diff --git a/packages/@aws-cdk/core/.eslintrc.js b/packages/@aws-cdk/core/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/core/.eslintrc.js +++ b/packages/@aws-cdk/core/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/core/jest.config.js b/packages/@aws-cdk/core/jest.config.js index 9dd30a713dd6b..93246ea5102e5 100644 --- a/packages/@aws-cdk/core/jest.config.js +++ b/packages/@aws-cdk/core/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/core/lib/cfn-resource.ts b/packages/@aws-cdk/core/lib/cfn-resource.ts index d6be50b9149fb..f1b4d76a10563 100644 --- a/packages/@aws-cdk/core/lib/cfn-resource.ts +++ b/packages/@aws-cdk/core/lib/cfn-resource.ts @@ -101,6 +101,14 @@ export class CfnResource extends CfnRefElement { /** * Sets the deletion policy of the resource based on the removal policy specified. + * + * The Removal Policy controls what happens to this resource when it stops + * being managed by CloudFormation, either because you've removed it from the + * CDK application or because you've made a change that requires the resource + * to be replaced. + * + * The resource can be deleted (`RemovalPolicy.DESTROY`), or left in your AWS + * account for data recovery and cleanup later (`RemovalPolicy.RETAIN`). */ public applyRemovalPolicy(policy: RemovalPolicy | undefined, options: RemovalPolicyOptions = {}) { policy = policy || options.default || RemovalPolicy.RETAIN; diff --git a/packages/@aws-cdk/core/lib/resource.ts b/packages/@aws-cdk/core/lib/resource.ts index 65fcacd55bf25..c61e9ba69955e 100644 --- a/packages/@aws-cdk/core/lib/resource.ts +++ b/packages/@aws-cdk/core/lib/resource.ts @@ -203,7 +203,7 @@ export abstract class Resource extends CoreConstruct implements IResource { * CDK application or because you've made a change that requires the resource * to be replaced. * - * The resource can be deleted (`RemovalPolicy.DELETE`), or left in your AWS + * The resource can be deleted (`RemovalPolicy.DESTROY`), or left in your AWS * account for data recovery and cleanup later (`RemovalPolicy.RETAIN`). */ public applyRemovalPolicy(policy: RemovalPolicy) { diff --git a/packages/@aws-cdk/core/package.json b/packages/@aws-cdk/core/package.json index e8865fafd3dc2..f2318107d60d3 100644 --- a/packages/@aws-cdk/core/package.json +++ b/packages/@aws-cdk/core/package.json @@ -141,7 +141,6 @@ "cdk-build": { "cloudformation": "AWS::CloudFormation", "cfn2ts-core-import": ".", - "jest": true, "pre": [ "rm -rf test/fs/fixtures", "cd test/fs", @@ -169,19 +168,19 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/aws-lambda": "^8.10.79", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/aws-lambda": "^8.10.83", "@types/fs-extra": "^8.1.2", "@types/jest": "^26.0.24", - "@types/lodash": "^4.14.171", + "@types/lodash": "^4.14.175", "@types/minimatch": "^3.0.5", "@types/node": "^10.17.60", "@types/sinon": "^9.0.11", - "cdk-build-tools": "0.0.0", - "cfn2ts": "0.0.0", "fast-check": "^2.17.0", - "lodash": "^4.17.21", "jest": "^26.6.3", - "pkglint": "0.0.0", + "lodash": "^4.17.21", "sinon": "^9.2.4", "ts-mock-imports": "^1.3.7" }, diff --git a/packages/@aws-cdk/core/test/stack.test.ts b/packages/@aws-cdk/core/test/stack.test.ts index 4473b99e0c2dc..7c67f545d4b87 100644 --- a/packages/@aws-cdk/core/test/stack.test.ts +++ b/packages/@aws-cdk/core/test/stack.test.ts @@ -1,5 +1,5 @@ import * as cxapi from '@aws-cdk/cx-api'; -import { testFutureBehavior, testLegacyBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testFutureBehavior, testLegacyBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import { App, CfnCondition, CfnInclude, CfnOutput, CfnParameter, CfnResource, Construct, Lazy, ScopedAws, Stack, validateString, diff --git a/packages/@aws-cdk/custom-resources/.eslintrc.js b/packages/@aws-cdk/custom-resources/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/custom-resources/.eslintrc.js +++ b/packages/@aws-cdk/custom-resources/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/custom-resources/jest.config.js b/packages/@aws-cdk/custom-resources/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/custom-resources/jest.config.js +++ b/packages/@aws-cdk/custom-resources/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/custom-resources/package.json b/packages/@aws-cdk/custom-resources/package.json index d81b9a11edc0c..d8377c231a06b 100644 --- a/packages/@aws-cdk/custom-resources/package.json +++ b/packages/@aws-cdk/custom-resources/package.json @@ -53,7 +53,6 @@ "build+test+extract": "yarn build+test && yarn rosetta:extract" }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -73,42 +72,42 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/jest": "^26.0.24", + "@aws-cdk/assert-internal": "0.0.0", "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-ssm": "0.0.0", - "@types/aws-lambda": "^8.10.79", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/aws-lambda": "^8.10.83", "@types/fs-extra": "^8.1.2", + "@types/jest": "^26.0.24", "@types/sinon": "^9.0.11", "aws-sdk": "^2.848.0", - "aws-sdk-mock": "^5.2.1", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", + "aws-sdk-mock": "^5.4.0", "fs-extra": "^9.1.0", - "nock": "^13.1.1", - "pkglint": "0.0.0", - "sinon": "^9.2.4", - "@aws-cdk/assert-internal": "0.0.0" + "nock": "^13.1.3", + "sinon": "^9.2.4" }, "dependencies": { "@aws-cdk/aws-cloudformation": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", - "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/aws-cloudformation": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", - "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" }, diff --git a/packages/@aws-cdk/cx-api/.eslintrc.js b/packages/@aws-cdk/cx-api/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/cx-api/.eslintrc.js +++ b/packages/@aws-cdk/cx-api/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/cx-api/jest.config.js b/packages/@aws-cdk/cx-api/jest.config.js index 061fcef9a7451..095efaa522407 100644 --- a/packages/@aws-cdk/cx-api/jest.config.js +++ b/packages/@aws-cdk/cx-api/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/cx-api/package.json b/packages/@aws-cdk/cx-api/package.json index 8dd8ed3b24ff5..8d4293f2b5ee4 100644 --- a/packages/@aws-cdk/cx-api/package.json +++ b/packages/@aws-cdk/cx-api/package.json @@ -66,13 +66,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", "@types/mock-fs": "^4.13.1", - "@types/semver": "^7.3.7", - "cdk-build-tools": "0.0.0", + "@types/semver": "^7.3.8", "jest": "^26.6.3", - "mock-fs": "^4.14.0", - "pkglint": "0.0.0" + "mock-fs": "^4.14.0" }, "repository": { "url": "https://github.com/aws/aws-cdk.git", @@ -156,9 +156,6 @@ "awscdkio": { "announce": false }, - "cdk-build": { - "jest": true - }, "publishConfig": { "tag": "latest" } diff --git a/packages/@aws-cdk/cx-api/test/features.test.ts b/packages/@aws-cdk/cx-api/test/features.test.ts index 81b42773fd292..2aaa774b7b1c5 100644 --- a/packages/@aws-cdk/cx-api/test/features.test.ts +++ b/packages/@aws-cdk/cx-api/test/features.test.ts @@ -1,4 +1,4 @@ -import { testLegacyBehavior } from 'cdk-build-tools/lib/feature-flag'; +import { testLegacyBehavior } from '@aws-cdk/cdk-build-tools/lib/feature-flag'; import * as feats from '../lib/features'; test('all future flags have defaults configured', () => { @@ -9,4 +9,4 @@ test('all future flags have defaults configured', () => { testLegacyBehavior('FUTURE_FLAGS_EXPIRED must be empty in CDKv1', Object, () => { expect(feats.FUTURE_FLAGS_EXPIRED.length).toEqual(0); -}); \ No newline at end of file +}); diff --git a/packages/@aws-cdk/example-construct-library/.eslintrc.js b/packages/@aws-cdk/example-construct-library/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/example-construct-library/.eslintrc.js +++ b/packages/@aws-cdk/example-construct-library/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/example-construct-library/jest.config.js b/packages/@aws-cdk/example-construct-library/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/example-construct-library/jest.config.js +++ b/packages/@aws-cdk/example-construct-library/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/example-construct-library/package.json b/packages/@aws-cdk/example-construct-library/package.json index 7f66f7c22ee55..672ba0e4a50e2 100644 --- a/packages/@aws-cdk/example-construct-library/package.json +++ b/packages/@aws-cdk/example-construct-library/package.json @@ -67,11 +67,11 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-cloudwatch": "0.0.0", @@ -101,7 +101,6 @@ "announce": false }, "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/lambda-layer-awscli/.eslintrc.js b/packages/@aws-cdk/lambda-layer-awscli/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/lambda-layer-awscli/.eslintrc.js +++ b/packages/@aws-cdk/lambda-layer-awscli/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/lambda-layer-awscli/jest.config.js b/packages/@aws-cdk/lambda-layer-awscli/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/lambda-layer-awscli/jest.config.js +++ b/packages/@aws-cdk/lambda-layer-awscli/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/lambda-layer-awscli/package.json b/packages/@aws-cdk/lambda-layer-awscli/package.json index 582ff94d18b4f..773e292d92020 100644 --- a/packages/@aws-cdk/lambda-layer-awscli/package.json +++ b/packages/@aws-cdk/lambda-layer-awscli/package.json @@ -66,12 +66,12 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "dependencies": { "@aws-cdk/aws-lambda": "0.0.0", @@ -96,7 +96,6 @@ "pre": [ "layer/build.sh" ], - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/lambda-layer-kubectl/.eslintrc.js b/packages/@aws-cdk/lambda-layer-kubectl/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/lambda-layer-kubectl/.eslintrc.js +++ b/packages/@aws-cdk/lambda-layer-kubectl/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/lambda-layer-kubectl/jest.config.js b/packages/@aws-cdk/lambda-layer-kubectl/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/lambda-layer-kubectl/jest.config.js +++ b/packages/@aws-cdk/lambda-layer-kubectl/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/lambda-layer-kubectl/package.json b/packages/@aws-cdk/lambda-layer-kubectl/package.json index 514cc7071c299..11e287144b29f 100644 --- a/packages/@aws-cdk/lambda-layer-kubectl/package.json +++ b/packages/@aws-cdk/lambda-layer-kubectl/package.json @@ -66,12 +66,12 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "pkglint": { "attribution": [ @@ -102,7 +102,6 @@ "pre": [ "layer/build.sh" ], - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/tools/cdk-integ-tools/.eslintrc.js b/packages/@aws-cdk/lambda-layer-node-proxy-agent/.eslintrc.js similarity index 56% rename from tools/cdk-integ-tools/.eslintrc.js rename to packages/@aws-cdk/lambda-layer-node-proxy-agent/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/tools/cdk-integ-tools/.eslintrc.js +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/.gitignore b/packages/@aws-cdk/lambda-layer-node-proxy-agent/.gitignore new file mode 100644 index 0000000000000..a86aa21cbaad0 --- /dev/null +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/.gitignore @@ -0,0 +1,20 @@ +*.js +*.js.map +*.d.ts +tsconfig.json +node_modules +*.generated.ts +dist +.jsii + +.LAST_BUILD +.nyc_output +coverage +nyc.config.js +.LAST_PACKAGE +*.snk +!.eslintrc.js +!jest.config.js + +junit.xml +lib/*.zip diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/.npmignore b/packages/@aws-cdk/lambda-layer-node-proxy-agent/.npmignore new file mode 100644 index 0000000000000..8934dbe25655a --- /dev/null +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/.npmignore @@ -0,0 +1,32 @@ +# Don't include original .ts files when doing `npm pack` +*.ts +!*.d.ts +coverage +.nyc_output +*.tgz + +dist +.LAST_PACKAGE +.LAST_BUILD +!*.js + +# Include .jsii +!.jsii + +*.snk + +*.tsbuildinfo + +tsconfig.json +.eslintrc.js +jest.config.js + +# exclude cdk artifacts +**/cdk.out +junit.xml + +test/ + +!*.lit.ts + +layer/node_modules diff --git a/tools/cdk-integ-tools/LICENSE b/packages/@aws-cdk/lambda-layer-node-proxy-agent/LICENSE similarity index 100% rename from tools/cdk-integ-tools/LICENSE rename to packages/@aws-cdk/lambda-layer-node-proxy-agent/LICENSE diff --git a/tools/cdk-integ-tools/NOTICE b/packages/@aws-cdk/lambda-layer-node-proxy-agent/NOTICE similarity index 100% rename from tools/cdk-integ-tools/NOTICE rename to packages/@aws-cdk/lambda-layer-node-proxy-agent/NOTICE diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/README.md b/packages/@aws-cdk/lambda-layer-node-proxy-agent/README.md new file mode 100644 index 0000000000000..45187394cb8b2 --- /dev/null +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/README.md @@ -0,0 +1,23 @@ +# AWS Lambda Layer with the NPM dependency proxy-agent + + +--- + +![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge) + +--- + + + +This module exports a single class called `NodeProxyAgentLayer` which is a `lambda.Layer` that bundles the NPM dependency [`proxy-agent`](https://www.npmjs.com/package/proxy-agent). + +> - proxy-agent Version: 5.0.0 + +Usage: + +```ts +const fn = new lambda.Function(...); +fn.addLayers(new NodeProxyAgentLayer(stack, 'NodeProxyAgentLayer')); +``` + +[`proxy-agent`](https://www.npmjs.com/package/proxy-agent) will be installed under `/opt/nodejs/node_modules`. diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/jest.config.js b/packages/@aws-cdk/lambda-layer-node-proxy-agent/jest.config.js new file mode 100644 index 0000000000000..3a2fd93a1228a --- /dev/null +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/.dockerignore b/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/.dockerignore new file mode 100644 index 0000000000000..69b73f61d249a --- /dev/null +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/.dockerignore @@ -0,0 +1,2 @@ +build.sh +.no-packagejson-validator diff --git a/tools/pkglint/lib/banners/l1.deprecated.md b/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/.no-packagejson-validator similarity index 100% rename from tools/pkglint/lib/banners/l1.deprecated.md rename to packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/.no-packagejson-validator diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/Dockerfile b/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/Dockerfile new file mode 100644 index 0000000000000..8c747a0e2b95f --- /dev/null +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/Dockerfile @@ -0,0 +1,33 @@ +# base lambda image +FROM public.ecr.aws/lambda/nodejs:latest + +USER root +RUN mkdir -p /opt +WORKDIR /tmp + +# +# tools +# + +RUN yum update -y \ + && yum install -y zip + +# +# install nodejs dependencies: proxy-agent +# + +RUN mkdir -p /opt/nodejs +COPY package.json /opt/nodejs +RUN cd /opt/nodejs && npm install + +# +# create the bundle +# + +RUN cd /opt \ + && zip --symlinks -r ../layer.zip * \ + && echo "/layer.zip is ready" \ + && ls -alh /layer.zip; + +WORKDIR / +ENTRYPOINT [ "/bin/bash" ] diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/build.sh b/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/build.sh new file mode 100755 index 0000000000000..6a84896b9d991 --- /dev/null +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/build.sh @@ -0,0 +1,18 @@ +#!/bin/bash +set -euo pipefail + +cd $(dirname $0) + +echo ">> Building AWS Lambda layer inside a docker image..." + +TAG='aws-lambda-node-proxy-agent' + +docker build -t ${TAG} . + +echo ">> Extrating layer.zip from the build container..." +CONTAINER=$(docker run -d ${TAG} false) +docker cp ${CONTAINER}:/layer.zip ../lib/layer.zip + +echo ">> Stopping container..." +docker rm -f ${CONTAINER} +echo ">> lib/layer.zip is ready" diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/package.json b/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/package.json new file mode 100644 index 0000000000000..102dd83c99391 --- /dev/null +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/layer/package.json @@ -0,0 +1,9 @@ +{ + "name": "node-proxy-agent-layer", + "private": true, + "version": "0.0.1", + "license": "Apache-2.0", + "devDependencies": { + "proxy-agent": "^5.0.0" + } +} diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/lib/index.ts b/packages/@aws-cdk/lambda-layer-node-proxy-agent/lib/index.ts new file mode 100644 index 0000000000000..e18d71d317dce --- /dev/null +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/lib/index.ts @@ -0,0 +1 @@ +export * from './node-proxy-agent-layer'; diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/lib/node-proxy-agent-layer.ts b/packages/@aws-cdk/lambda-layer-node-proxy-agent/lib/node-proxy-agent-layer.ts new file mode 100644 index 0000000000000..9e6471a2da2c6 --- /dev/null +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/lib/node-proxy-agent-layer.ts @@ -0,0 +1,27 @@ +import * as crypto from 'crypto'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as lambda from '@aws-cdk/aws-lambda'; +import { Construct } from 'constructs'; + +/** + * An AWS Lambda layer that includes the NPM dependency `proxy-agent`. + */ +export class NodeProxyAgentLayer extends lambda.LayerVersion { + constructor(scope: Construct, id: string) { + super(scope, id, { + code: lambda.Code.fromAsset(path.join(__dirname, 'layer.zip'), { + // we hash the package.json (it contains the tools versions) because hashing the zip is non-deterministic + assetHash: hashFile(path.join(__dirname, '..', 'layer', 'package.json')), + }), + description: '/opt/nodejs/node_modules/proxy-agent', + }); + } +} + +function hashFile(fileName: string) { + return crypto + .createHash('sha256') + .update(fs.readFileSync(fileName)) + .digest('hex'); +} diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/package.json b/packages/@aws-cdk/lambda-layer-node-proxy-agent/package.json new file mode 100644 index 0000000000000..46345afc7f796 --- /dev/null +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/package.json @@ -0,0 +1,115 @@ +{ + "name": "@aws-cdk/lambda-layer-node-proxy-agent", + "private": false, + "version": "0.0.0", + "description": "An AWS Lambda layer that contains the `proxy-agent` NPM dependency", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "jsii": { + "outdir": "dist", + "targets": { + "java": { + "package": "software.amazon.awscdk.lambda.layer.node.proxy.agent", + "maven": { + "groupId": "software.amazon.awscdk", + "artifactId": "cdk-lambda-layer-node-proxy-agent" + } + }, + "dotnet": { + "namespace": "Amazon.CDK.LambdaLayer.NodeProxyAgent", + "packageId": "Amazon.CDK.LambdaLayer.NodeProxyAgent", + "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png" + }, + "python": { + "distName": "aws-cdk.lambda-layer-node-proxy-agent", + "module": "aws_cdk.lambda_layer_node_proxy_agent", + "classifiers": [ + "Framework :: AWS CDK", + "Framework :: AWS CDK :: 1" + ] + } + }, + "projectReferences": true + }, + "repository": { + "type": "git", + "url": "https://github.com/aws/aws-cdk.git", + "directory": "packages/@aws-cdk/lambda-layer-node-proxy-agent" + }, + "scripts": { + "build": "cdk-build", + "watch": "cdk-watch", + "lint": "cdk-lint", + "test": "cdk-test", + "integ": "cdk-integ", + "pkglint": "pkglint -f", + "package": "cdk-package", + "awslint": "cdk-awslint", + "build+test": "yarn build && yarn test", + "build+test+package": "yarn build+test && yarn package", + "compat": "cdk-compat", + "rosetta:extract": "yarn --silent jsii-rosetta extract", + "build+extract": "yarn build && yarn rosetta:extract", + "build+test+extract": "yarn build+test && yarn rosetta:extract" + }, + "keywords": [ + "aws", + "cdk", + "example", + "construct", + "library" + ], + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", + "@types/jest": "^26.0.24", + "jest": "^26.6.3" + }, + "dependencies": { + "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/core": "0.0.0", + "constructs": "^3.3.69" + }, + "homepage": "https://github.com/aws/aws-cdk", + "peerDependencies": { + "@aws-cdk/aws-lambda": "0.0.0", + "@aws-cdk/core": "0.0.0", + "constructs": "^3.3.69" + }, + "engines": { + "node": ">= 10.13.0 <13 || >=13.7.0" + }, + "stability": "stable", + "maturity": "stable", + "awscdkio": { + "announce": false + }, + "cdk-build": { + "pre": [ + "layer/build.sh" + ], + "env": { + "AWSLINT_BASE_CONSTRUCT": true + } + }, + "nozem": { + "ostools": [ + "dirname", + "docker" + ] + }, + "ubergen": { + "exclude": false + }, + "publishConfig": { + "tag": "latest" + } +} diff --git a/packages/@aws-cdk/lambda-layer-node-proxy-agent/test/proxy-agent-layer.test.ts b/packages/@aws-cdk/lambda-layer-node-proxy-agent/test/proxy-agent-layer.test.ts new file mode 100644 index 0000000000000..14264a8d080dc --- /dev/null +++ b/packages/@aws-cdk/lambda-layer-node-proxy-agent/test/proxy-agent-layer.test.ts @@ -0,0 +1,16 @@ +import { Stack } from '@aws-cdk/core'; +import { NodeProxyAgentLayer } from '../lib'; +import '@aws-cdk/assert-internal/jest'; + +test('synthesized to a layer version', () => { + //GIVEN + const stack = new Stack(); + + // WHEN + new NodeProxyAgentLayer(stack, 'MyLayer'); + + // THEN + expect(stack).toHaveResource('AWS::Lambda::LayerVersion', { + Description: '/opt/nodejs/node_modules/proxy-agent', + }); +}); diff --git a/packages/@aws-cdk/pipelines/.eslintrc.js b/packages/@aws-cdk/pipelines/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/pipelines/.eslintrc.js +++ b/packages/@aws-cdk/pipelines/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/pipelines/README.md b/packages/@aws-cdk/pipelines/README.md index 1e0df7a4b2c2a..3013140344bef 100644 --- a/packages/@aws-cdk/pipelines/README.md +++ b/packages/@aws-cdk/pipelines/README.md @@ -1231,8 +1231,8 @@ A hypothetical recovery workflow would look something like this: ```sh $ env CDK_NEW_BOOTSTRAP=1 npx cdk bootstrap \ - --qualifier randchars1234 - --toolkit-stack-name CDKToolkitTemp + --qualifier random1234 \ + --toolkit-stack-name CDKToolkitTemp \ aws://111111111111/us-east-1 ``` diff --git a/packages/@aws-cdk/pipelines/jest.config.js b/packages/@aws-cdk/pipelines/jest.config.js index ad27b218892cb..8ce875da0ea4c 100644 --- a/packages/@aws-cdk/pipelines/jest.config.js +++ b/packages/@aws-cdk/pipelines/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@aws-cdk/pipelines/package.json b/packages/@aws-cdk/pipelines/package.json index 7daeb0589feb0..432dfba00c721 100644 --- a/packages/@aws-cdk/pipelines/package.json +++ b/packages/@aws-cdk/pipelines/package.json @@ -35,14 +35,14 @@ "@aws-cdk/assertions": "0.0.0", "@aws-cdk/aws-apigateway": "0.0.0", "@aws-cdk/aws-ecr-assets": "0.0.0", - "@aws-cdk/aws-sqs": "0.0.0", "@aws-cdk/aws-sns-subscriptions": "0.0.0", + "@aws-cdk/aws-sqs": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-integ-tools": "0.0.0", + "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", - "aws-sdk": "^2.848.0", - "cdk-build-tools": "0.0.0", - "cdk-integ-tools": "0.0.0", - "cfn2ts": "0.0.0", - "pkglint": "0.0.0" + "aws-sdk": "^2.848.0" }, "peerDependencies": { "@aws-cdk/aws-codebuild": "0.0.0", @@ -98,7 +98,6 @@ "stability": "stable", "maturity": "stable", "cdk-build": { - "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/region-info/.eslintrc.js b/packages/@aws-cdk/region-info/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/region-info/.eslintrc.js +++ b/packages/@aws-cdk/region-info/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/region-info/jest.config.js b/packages/@aws-cdk/region-info/jest.config.js index 54e28beb9798b..3a2fd93a1228a 100644 --- a/packages/@aws-cdk/region-info/jest.config.js +++ b/packages/@aws-cdk/region-info/jest.config.js @@ -1,2 +1,2 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = baseConfig; diff --git a/packages/@aws-cdk/region-info/package.json b/packages/@aws-cdk/region-info/package.json index c86fae71c220a..a9e67db6c3be7 100644 --- a/packages/@aws-cdk/region-info/package.json +++ b/packages/@aws-cdk/region-info/package.json @@ -30,9 +30,6 @@ }, "projectReferences": true }, - "cdk-build": { - "jest": true - }, "scripts": { "gen": "bash build-tools/generate.sh", "build": "cdk-build", @@ -56,11 +53,11 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/fs-extra": "^8.1.2", "@types/jest": "^26.0.24", - "cdk-build-tools": "0.0.0", - "fs-extra": "^9.1.0", - "pkglint": "0.0.0" + "fs-extra": "^9.1.0" }, "repository": { "url": "https://github.com/aws/aws-cdk.git", diff --git a/packages/@aws-cdk/yaml-cfn/.eslintrc.js b/packages/@aws-cdk/yaml-cfn/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@aws-cdk/yaml-cfn/.eslintrc.js +++ b/packages/@aws-cdk/yaml-cfn/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@aws-cdk/yaml-cfn/jest.config.js b/packages/@aws-cdk/yaml-cfn/jest.config.js index 19fd4653b47af..315f80405878f 100644 --- a/packages/@aws-cdk/yaml-cfn/jest.config.js +++ b/packages/@aws-cdk/yaml-cfn/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, }; diff --git a/packages/@aws-cdk/yaml-cfn/package.json b/packages/@aws-cdk/yaml-cfn/package.json index ed33f49235536..3a2a674586d84 100644 --- a/packages/@aws-cdk/yaml-cfn/package.json +++ b/packages/@aws-cdk/yaml-cfn/package.json @@ -69,19 +69,16 @@ "yaml": "1.10.2" }, "devDependencies": { + "@aws-cdk/assert-internal": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^26.0.24", "@types/yaml": "^1.9.7", - "cdk-build-tools": "0.0.0", - "jest": "^26.6.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3" }, "bundledDependencies": [ "yaml" ], - "cdk-build": { - "jest": true - }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, diff --git a/packages/@monocdk-experiment/assert/.eslintrc.js b/packages/@monocdk-experiment/assert/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@monocdk-experiment/assert/.eslintrc.js +++ b/packages/@monocdk-experiment/assert/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@monocdk-experiment/assert/jest.config.js b/packages/@monocdk-experiment/assert/jest.config.js index 582b2b3040eb0..06408ea0581b8 100644 --- a/packages/@monocdk-experiment/assert/jest.config.js +++ b/packages/@monocdk-experiment/assert/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@monocdk-experiment/assert/package.json b/packages/@monocdk-experiment/assert/package.json index fa3ae197cad03..4c6bff0534016 100644 --- a/packages/@monocdk-experiment/assert/package.json +++ b/packages/@monocdk-experiment/assert/package.json @@ -36,11 +36,11 @@ "@monocdk-experiment/rewrite-imports": "0.0.0", "@types/jest": "^26.0.24", "@types/node": "^10.17.60", - "cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", "constructs": "^3.3.69", "jest": "^26.6.3", "monocdk": "0.0.0", - "pkglint": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "ts-jest": "^26.5.6" }, "dependencies": { diff --git a/packages/@monocdk-experiment/rewrite-imports/.eslintrc.js b/packages/@monocdk-experiment/rewrite-imports/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/@monocdk-experiment/rewrite-imports/.eslintrc.js +++ b/packages/@monocdk-experiment/rewrite-imports/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/@monocdk-experiment/rewrite-imports/jest.config.js b/packages/@monocdk-experiment/rewrite-imports/jest.config.js index ac8c47076506a..6a8dc8ed67646 100644 --- a/packages/@monocdk-experiment/rewrite-imports/jest.config.js +++ b/packages/@monocdk-experiment/rewrite-imports/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/@monocdk-experiment/rewrite-imports/package.json b/packages/@monocdk-experiment/rewrite-imports/package.json index 71e1e67dbb146..7f602376d551a 100644 --- a/packages/@monocdk-experiment/rewrite-imports/package.json +++ b/packages/@monocdk-experiment/rewrite-imports/package.json @@ -19,9 +19,6 @@ "build+extract": "yarn build", "build+test+extract": "yarn build+test" }, - "cdk-build": { - "jest": true - }, "keywords": [ "aws", "cdk", @@ -34,15 +31,15 @@ }, "license": "Apache-2.0", "dependencies": { - "glob": "^7.1.7", + "glob": "^7.2.0", "typescript": "~3.9.10" }, "devDependencies": { "@types/glob": "^7.1.4", "@types/jest": "^26.0.24", "@types/node": "^10.17.60", - "cdk-build-tools": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0" }, "repository": { "type": "git", diff --git a/packages/aws-cdk-lib/.eslintrc.js b/packages/aws-cdk-lib/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/aws-cdk-lib/.eslintrc.js +++ b/packages/aws-cdk-lib/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/aws-cdk-lib/NOTICE b/packages/aws-cdk-lib/NOTICE index bf88ea022136c..df1053512a80b 100644 --- a/packages/aws-cdk-lib/NOTICE +++ b/packages/aws-cdk-lib/NOTICE @@ -806,4 +806,36 @@ The above copyright notice and this permission notice shall be included in all c THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------- \ No newline at end of file +---------------- + +** kubectl - https://github.com/kubernetes/kubectl +Copyright 2017 The Kubernetes Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +---------------- + +** helm - https://github.com/helm/helm +Copyright 2016 The Kubernetes Authors All Rights Reserved + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/aws-cdk-lib/package.json b/packages/aws-cdk-lib/package.json index bf12c5b3f0d6c..ac9370bacd389 100644 --- a/packages/aws-cdk-lib/package.json +++ b/packages/aws-cdk-lib/package.json @@ -50,6 +50,10 @@ "jsii/java", "jsii/python", "jsii/dotnet" + ], + "attribution": [ + "kubectl", + "helm" ] }, "jsii": { @@ -115,7 +119,7 @@ "minimatch": "^3.0.4", "punycode": "^2.1.1", "semver": "^7.3.5", - "string-width": "^4.2.2", + "string-width": "^4.2.3", "table": "^6.7.1", "yaml": "1.10.2" }, @@ -264,6 +268,7 @@ "@aws-cdk/aws-medialive": "0.0.0", "@aws-cdk/aws-mediapackage": "0.0.0", "@aws-cdk/aws-mediastore": "0.0.0", + "@aws-cdk/aws-memorydb": "0.0.0", "@aws-cdk/aws-msk": "0.0.0", "@aws-cdk/aws-mwaa": "0.0.0", "@aws-cdk/aws-neptune": "0.0.0", @@ -329,17 +334,18 @@ "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/lambda-layer-awscli": "0.0.0", "@aws-cdk/lambda-layer-kubectl": "0.0.0", + "@aws-cdk/lambda-layer-node-proxy-agent": "0.0.0", "@aws-cdk/pipelines": "0.0.0", "@aws-cdk/region-info": "0.0.0", "@types/fs-extra": "^8.1.2", "@types/node": "^10.17.60", - "cdk-build-tools": "0.0.0", + "@aws-cdk/cdk-build-tools": "0.0.0", "constructs": "^3.3.69", "fs-extra": "^9.1.0", - "pkglint": "0.0.0", + "@aws-cdk/pkglint": "0.0.0", "ts-node": "^9.1.1", "typescript": "~3.8.3", - "ubergen": "0.0.0" + "@aws-cdk/ubergen": "0.0.0" }, "peerDependencies": { "constructs": "^3.3.69" diff --git a/packages/aws-cdk-lib/scripts/verify-stripped-exp.ts b/packages/aws-cdk-lib/scripts/verify-stripped-exp.ts index 10e3da07b7f4d..6398852975c05 100644 --- a/packages/aws-cdk-lib/scripts/verify-stripped-exp.ts +++ b/packages/aws-cdk-lib/scripts/verify-stripped-exp.ts @@ -30,7 +30,7 @@ async function main(tempDir: string) { if (pkgJson.stability !== 'experimental') { continue; } - if (pkgJson['cdk-build'].cloudformation) { + if (pkgJson['cdk-build']?.cloudformation) { // if a cfn module, verify only the allowed files exists const files = await listAllFiles(path.join(installedAwsCdkLibPath, module)); const invalidFiles = new Array(); diff --git a/packages/aws-cdk-migration/.eslintrc.js b/packages/aws-cdk-migration/.eslintrc.js index 61dd8dd001f63..2658ee8727166 100644 --- a/packages/aws-cdk-migration/.eslintrc.js +++ b/packages/aws-cdk-migration/.eslintrc.js @@ -1,3 +1,3 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/aws-cdk-migration/jest.config.js b/packages/aws-cdk-migration/jest.config.js index ac8c47076506a..6a8dc8ed67646 100644 --- a/packages/aws-cdk-migration/jest.config.js +++ b/packages/aws-cdk-migration/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/aws-cdk-migration/lib/rewrite.ts b/packages/aws-cdk-migration/lib/rewrite.ts index 970627e361aa2..2e17dfcb08130 100644 --- a/packages/aws-cdk-migration/lib/rewrite.ts +++ b/packages/aws-cdk-migration/lib/rewrite.ts @@ -8,6 +8,21 @@ export interface RewriteOptions { * Optional module names that should result in replacing to something different than just 'aws-cdk-lib'. */ readonly customModules?: { [moduleName: string]: string }; + + /** + * When true, this will rewrite imports of generated L1s to reference aws-cdk-lib. + * + * For example: + * import * as codestar from './codestar.generated';` + * becomes: + * import * as codestar from 'aws-cdk-lib/aws-codestar'; + */ + readonly rewriteCfnImports?: boolean; + + /** + * The unscoped name of the package, e.g. 'aws-kinesisfirehose'. + */ + readonly packageUnscopedName?: string; } /** @@ -38,7 +53,7 @@ export function rewriteImports(sourceText: string, fileName: string = 'index.ts' const visitor = (node: T): ts.VisitResult => { const moduleSpecifier = getModuleSpecifier(node); - const newTarget = moduleSpecifier && updatedLocationOf(moduleSpecifier.text, options); + const newTarget = moduleSpecifier && updatedLocationOf(moduleSpecifier.text, options, getImportedElements(node)); if (moduleSpecifier != null && newTarget != null) { replacements.push({ original: moduleSpecifier, updatedLocation: newTarget }); @@ -60,6 +75,14 @@ export function rewriteImports(sourceText: string, fileName: string = 'index.ts' return updatedSourceText; + /** + * Returns the module specifier (location) of an import statement in one of the following forms: + * import from 'location'; + * import * as name from 'location'; + * import { Type } = require('location'); + * import name = require('location'); + * require('location'); + */ function getModuleSpecifier(node: ts.Node): ts.StringLiteral | undefined { if (ts.isImportDeclaration(node)) { // import style @@ -100,15 +123,40 @@ export function rewriteImports(sourceText: string, fileName: string = 'index.ts' const EXEMPTIONS = new Set([ '@aws-cdk/cloudformation-diff', + // The dev-tools + '@aws-cdk/cdk-build-tools', + '@aws-cdk/cdk-integ-tools', + '@aws-cdk/cfn2ts', + '@aws-cdk/eslint-plugin', + '@aws-cdk/pkglint', ]); -function updatedLocationOf(modulePath: string, options: RewriteOptions): string | undefined { +function updatedLocationOf(modulePath: string, options: RewriteOptions, importedElements?: ts.NodeArray): string | undefined { const customModulePath = options.customModules?.[modulePath]; if (customModulePath) { + let awsCdkLibLocation = undefined; + importedElements?.forEach(e => { + if (e.name.text.startsWith('Cfn') || e.propertyName?.text.startsWith('Cfn')) { + // This is an L1 import, so don't return the customModulePath (which is the alpha module). + // Return the relevant aws-cdk-lib location. + awsCdkLibLocation = `aws-cdk-lib/${modulePath.substring('@aws-cdk/'.length)}`; + } + }); + if (awsCdkLibLocation) { + return awsCdkLibLocation; + } return customModulePath; } - if (!modulePath.startsWith('@aws-cdk/') || EXEMPTIONS.has(modulePath)) { + if (options.rewriteCfnImports && modulePath.endsWith(`${options.packageUnscopedName?.substr('aws-'.length)}.generated`)) { + return `aws-cdk-lib/${options.packageUnscopedName}`; + } + + if ( + !modulePath.startsWith('@aws-cdk/') + || EXEMPTIONS.has(modulePath) + || Array.from(EXEMPTIONS).some((ex) => modulePath.startsWith(`${ex}/`)) + ) { return undefined; } @@ -135,5 +183,22 @@ function updatedLocationOf(modulePath: string, options: RewriteOptions): string return '@aws-cdk/assert/jest'; } - return `aws-cdk-lib/${modulePath.substring(9)}`; + return `aws-cdk-lib/${modulePath.substring('@aws-cdk/'.length)}`; +} + +/** + * Returns the names of all types imported via named imports of the form: + * import { Type } from 'location' + */ +function getImportedElements(node: ts.Node): ts.NodeArray | undefined { + if ( + ts.isImportDeclaration(node) + && ts.isStringLiteral(node.moduleSpecifier) + && node.importClause + && node.importClause.namedBindings + && ts.isNamedImports(node.importClause.namedBindings) + ) { + return node.importClause.namedBindings.elements; + } + return undefined; } diff --git a/packages/aws-cdk-migration/package.json b/packages/aws-cdk-migration/package.json index 714dd26493897..1ce16c5670458 100644 --- a/packages/aws-cdk-migration/package.json +++ b/packages/aws-cdk-migration/package.json @@ -34,15 +34,15 @@ }, "license": "Apache-2.0", "dependencies": { - "glob": "^7.1.7", + "glob": "^7.2.0", "typescript": "~3.9.10" }, "devDependencies": { "@types/glob": "^7.1.4", "@types/jest": "^26.0.24", "@types/node": "^10.17.60", - "cdk-build-tools": "0.0.0", - "pkglint": "0.0.0" + "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/pkglint": "0.0.0" }, "repository": { "type": "git", diff --git a/packages/aws-cdk-migration/test/rewrite.test.ts b/packages/aws-cdk-migration/test/rewrite.test.ts index f9ff8b247d6ce..d4b5c919f5f53 100644 --- a/packages/aws-cdk-migration/test/rewrite.test.ts +++ b/packages/aws-cdk-migration/test/rewrite.test.ts @@ -88,4 +88,52 @@ describe(rewriteImports, () => { console.log('Look! I did something!');`); }); + + test('correctly rewrites Cfn imports', () => { + // Codestar example + const codestar = rewriteImports(` + // something before + import * as codestar from './codestar.generated'; + import { CfnY } from '../codestar.generated'; + import { CfnX } from '../lib/codestar.generated'; + // something after + + console.log('Look! I did something!');`, 'subject.ts', { + rewriteCfnImports: true, + packageUnscopedName: 'aws-codestar', + }); + + expect(codestar).toBe(` + // something before + import * as codestar from 'aws-cdk-lib/aws-codestar'; + import { CfnY } from 'aws-cdk-lib/aws-codestar'; + import { CfnX } from 'aws-cdk-lib/aws-codestar'; + // something after + + console.log('Look! I did something!');`); + }); + + test('correctly rewrites Cfn imports from an alpha module', () => { + const customModules = { + '@aws-cdk/aws-kinesisfirehose': 'aws-kinesisfirehose-alpha', + }; + const output = rewriteImports(` + // something before + import * as firehose from '@aws-cdk/aws-kinesisfirehose'; + import { CfnDeliveryStream } from '@aws-cdk/aws-kinesisfirehose'; + // something after + + console.log('Look! I did something!');`, 'subject.ts', { + rewriteCfnImports: true, + customModules: customModules, + }); + + expect(output).toBe(` + // something before + import * as firehose from 'aws-kinesisfirehose-alpha'; + import { CfnDeliveryStream } from 'aws-cdk-lib/aws-kinesisfirehose'; + // something after + + console.log('Look! I did something!');`); + }); }); diff --git a/packages/aws-cdk/.eslintrc.js b/packages/aws-cdk/.eslintrc.js index b5e0934b9d544..b5ea7218b5f48 100644 --- a/packages/aws-cdk/.eslintrc.js +++ b/packages/aws-cdk/.eslintrc.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/eslintrc'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc'); baseConfig.ignorePatterns.push('lib/init-templates/**/typescript/**/*.ts'); baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; module.exports = baseConfig; diff --git a/packages/aws-cdk/jest.config.js b/packages/aws-cdk/jest.config.js index 72f278bd0ba52..292f68b459252 100644 --- a/packages/aws-cdk/jest.config.js +++ b/packages/aws-cdk/jest.config.js @@ -1,4 +1,4 @@ -const baseConfig = require('cdk-build-tools/config/jest.config'); +const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config'); module.exports = { ...baseConfig, coverageThreshold: { diff --git a/packages/aws-cdk/lib/api/deploy-stack.ts b/packages/aws-cdk/lib/api/deploy-stack.ts index b0770ebdf8ea7..4888d639ff394 100644 --- a/packages/aws-cdk/lib/api/deploy-stack.ts +++ b/packages/aws-cdk/lib/api/deploy-stack.ts @@ -10,6 +10,7 @@ import { publishAssets } from '../util/asset-publishing'; import { contentHash } from '../util/content-hash'; import { ISDK, SdkProvider } from './aws-auth'; import { tryHotswapDeployment } from './hotswap-deployments'; +import { CfnEvaluationException } from './hotswap/evaluate-cloudformation-template'; import { ToolkitInfo } from './toolkit-info'; import { changeSetHasNoChanges, CloudFormationStack, TemplateParameters, waitForChangeSet, @@ -252,12 +253,19 @@ export async function deployStack(options: DeployStackOptions): Promise { - const currentTemplate = await cloudFormationStack.template(); - const stackChanges = cfn_diff.diffTemplate(currentTemplate, stackArtifact.template); - // resolve the environment, so we can substitute things like AWS::Region in CFN expressions const resolvedEnv = await sdkProvider.resolveEnvironment(stackArtifact.environment); - const hotswappableChanges = findAllHotswappableChanges(stackChanges, { - ...assetParams, - 'AWS::Region': resolvedEnv.region, - 'AWS::AccountId': resolvedEnv.account, + // create a new SDK using the CLI credentials, because the default one will not work for new-style synthesis - + // it assumes the bootstrap deploy Role, which doesn't have permissions to update Lambda functions + const sdk = await sdkProvider.forEnvironment(resolvedEnv, Mode.ForWriting); + // The current resources of the Stack. + // We need them to figure out the physical name of a resource in case it wasn't specified by the user. + // We fetch it lazily, to save a service call, in case all hotswapped resources have their physical names set. + const listStackResources = new LazyListStackResources(sdk, stackArtifact.stackName); + const evaluateCfnTemplate = new EvaluateCloudFormationTemplate({ + stackArtifact, + parameters: assetParams, + account: resolvedEnv.account, + region: resolvedEnv.region, + // ToDo make this better: + partition: 'aws', + // ToDo make this better: + urlSuffix: 'amazonaws.com', + listStackResources, }); + + const currentTemplate = await cloudFormationStack.template(); + const stackChanges = cfn_diff.diffTemplate(currentTemplate, stackArtifact.template); + const hotswappableChanges = await findAllHotswappableChanges(stackChanges, evaluateCfnTemplate); if (!hotswappableChanges) { // this means there were changes to the template that cannot be short-circuited return undefined; } - // create a new SDK using the CLI credentials, because the default one will not work for new-style synthesis - - // it assumes the bootstrap deploy Role, which doesn't have permissions to update Lambda functions - const sdk = await sdkProvider.forEnvironment(resolvedEnv, Mode.ForWriting); // apply the short-circuitable changes - await applyAllHotswappableChanges(sdk, stackArtifact, hotswappableChanges); + await applyAllHotswappableChanges(sdk, hotswappableChanges); return { noOp: hotswappableChanges.length === 0, stackArn: cloudFormationStack.stackId, outputs: cloudFormationStack.outputs, stackArtifact }; } -function findAllHotswappableChanges( - stackChanges: cfn_diff.TemplateDiff, assetParamsWithEnv: { [key: string]: string }, -): HotswapOperation[] | undefined { - const hotswappableResources = new Array(); - let foundNonHotswappableChange = false; - stackChanges.resources.forEachDifference((logicalId: string, change: cfn_diff.ResourceDifference) => { - const lambdaFunctionShortCircuitChange = isHotswappableLambdaFunctionChange(logicalId, change, assetParamsWithEnv); - if (lambdaFunctionShortCircuitChange === ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT) { - foundNonHotswappableChange = true; - } else if (lambdaFunctionShortCircuitChange === ChangeHotswapImpact.IRRELEVANT) { - // empty 'if' just for flow-aware typing to kick in... - } else { - hotswappableResources.push(lambdaFunctionShortCircuitChange); +async function findAllHotswappableChanges( + stackChanges: cfn_diff.TemplateDiff, evaluateCfnTemplate: EvaluateCloudFormationTemplate, +): Promise { + const promises = new Array>(); + stackChanges.resources.forEachDifference(async (logicalId: string, change: cfn_diff.ResourceDifference) => { + promises.push(isHotswappableLambdaFunctionChange(logicalId, change, evaluateCfnTemplate)); + }); + return Promise.all(promises).then(hotswapDetectionResults => { + const hotswappableResources = new Array(); + let foundNonHotswappableChange = false; + for (const lambdaFunctionShortCircuitChange of hotswapDetectionResults) { + if (lambdaFunctionShortCircuitChange === ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT) { + foundNonHotswappableChange = true; + } else if (lambdaFunctionShortCircuitChange === ChangeHotswapImpact.IRRELEVANT) { + // empty 'if' just for flow-aware typing to kick in... + } else { + hotswappableResources.push(lambdaFunctionShortCircuitChange); + } } + return foundNonHotswappableChange ? undefined : hotswappableResources; }); - return foundNonHotswappableChange ? undefined : hotswappableResources; } async function applyAllHotswappableChanges( - sdk: ISDK, stackArtifact: cxapi.CloudFormationStackArtifact, hotswappableChanges: HotswapOperation[], + sdk: ISDK, hotswappableChanges: HotswapOperation[], ): Promise { - // The current resources of the Stack. - // We need them to figure out the physical name of a function in case it wasn't specified by the user. - // We fetch it lazily, to save a service call, in case all updated Lambdas have their names set. - const listStackResources = new LazyListStackResources(sdk, stackArtifact.stackName); - - return Promise.all(hotswappableChanges.map(hotswapOperation => hotswapOperation.apply(sdk, listStackResources))); + return Promise.all(hotswappableChanges.map(hotswapOperation => { + return hotswapOperation.apply(sdk); + })); } class LazyListStackResources implements ListStackResources { @@ -79,12 +93,12 @@ class LazyListStackResources implements ListStackResources { async listStackResources(): Promise { if (this.stackResources === undefined) { - this.stackResources = await this.getStackResource(); + this.stackResources = await this.getStackResources(); } return this.stackResources; } - private async getStackResource(): Promise { + private async getStackResources(): Promise { const ret = new Array(); let nextToken: string | undefined; do { diff --git a/packages/aws-cdk/lib/api/hotswap/common.ts b/packages/aws-cdk/lib/api/hotswap/common.ts index d509c32b4c781..c11b29d1d7daa 100644 --- a/packages/aws-cdk/lib/api/hotswap/common.ts +++ b/packages/aws-cdk/lib/api/hotswap/common.ts @@ -1,7 +1,6 @@ import * as cfn_diff from '@aws-cdk/cloudformation-diff'; import { CloudFormation } from 'aws-sdk'; import { ISDK } from '../aws-auth'; -import { evaluateCfn } from '../util/cloudformation/evaluate-cfn'; export interface ListStackResources { listStackResources(): Promise; @@ -11,7 +10,7 @@ export interface ListStackResources { * An interface that represents a change that can be deployed in a short-circuit manner. */ export interface HotswapOperation { - apply(sdk: ISDK, stackResources: ListStackResources): Promise; + apply(sdk: ISDK): Promise; } /** @@ -34,24 +33,6 @@ export enum ChangeHotswapImpact { export type ChangeHotswapResult = HotswapOperation | ChangeHotswapImpact; -/** - * For old-style synthesis which uses CFN Parameters, - * the Code properties can have the values of complex CFN expressions. - * For new-style synthesis of env-agnostic stacks, - * the Fn::Sub expression is used for the Asset bucket. - * Evaluate the CFN expressions to concrete string values which we need for the - * updateFunctionCode() service call. - */ -export function stringifyPotentialCfnExpression(value: any, assetParamsWithEnv: { [key: string]: string }): string { - // if we already have a string, nothing to do - if (value == null || typeof value === 'string') { - return value; - } - - // otherwise, we assume this is a CloudFormation expression that we need to evaluate - return evaluateCfn(value, assetParamsWithEnv); -} - export function assetMetadataChanged(change: cfn_diff.ResourceDifference): boolean { return !!change.newValue?.Metadata['aws:asset:path']; } diff --git a/packages/aws-cdk/lib/api/hotswap/evaluate-cloudformation-template.ts b/packages/aws-cdk/lib/api/hotswap/evaluate-cloudformation-template.ts new file mode 100644 index 0000000000000..dc1541ed74771 --- /dev/null +++ b/packages/aws-cdk/lib/api/hotswap/evaluate-cloudformation-template.ts @@ -0,0 +1,259 @@ +import * as cxapi from '@aws-cdk/cx-api'; +import * as AWS from 'aws-sdk'; +import { ListStackResources } from './common'; + +export class CfnEvaluationException extends Error {} + +export interface EvaluateCloudFormationTemplateProps { + readonly stackArtifact: cxapi.CloudFormationStackArtifact; + readonly parameters: { [parameterName: string]: string }; + readonly account: string; + readonly region: string; + readonly partition: string; + readonly urlSuffix: string; + + readonly listStackResources: ListStackResources; +} + +export class EvaluateCloudFormationTemplate { + private readonly stackResources: ListStackResources; + private readonly context: { [k: string]: string }; + private readonly account: string; + private readonly region: string; + private readonly partition: string; + + constructor(props: EvaluateCloudFormationTemplateProps) { + this.stackResources = props.listStackResources; + this.context = { + 'AWS::AccountId': props.account, + 'AWS::Region': props.region, + 'AWS::Partition': props.partition, + 'AWS::URLSuffix': props.urlSuffix, + ...props.parameters, + }; + this.account = props.account; + this.region = props.region; + this.partition = props.partition; + } + + public async findPhysicalNameFor(logicalId: string): Promise { + const stackResources = await this.stackResources.listStackResources(); + return stackResources.find(sr => sr.LogicalResourceId === logicalId)?.PhysicalResourceId; + } + + public async evaluateCfnExpression(cfnExpression: any): Promise { + const self = this; + class CfnIntrinsics { + public evaluateIntrinsic(intrinsic: Intrinsic): any { + const intrinsicFunc = (this as any)[intrinsic.name]; + if (!intrinsicFunc) { + throw new CfnEvaluationException(`CloudFormation function ${intrinsic.name} is not supported`); + } + + const argsAsArray = Array.isArray(intrinsic.args) ? intrinsic.args : [intrinsic.args]; + + return intrinsicFunc.apply(this, argsAsArray); + } + + async 'Fn::Join'(separator: string, args: any[]): Promise { + const evaluatedArgs = await self.evaluateCfnExpression(args); + return evaluatedArgs.join(separator); + } + + async 'Fn::Split'(separator: string, args: any): Promise { + const evaluatedArgs = await self.evaluateCfnExpression(args); + return evaluatedArgs.split(separator); + } + + async 'Fn::Select'(index: number, args: any[]): Promise { + const evaluatedArgs = await self.evaluateCfnExpression(args); + return evaluatedArgs[index]; + } + + async 'Ref'(logicalId: string): Promise { + const refTarget = await self.findRefTarget(logicalId); + if (refTarget) { + return refTarget; + } else { + throw new CfnEvaluationException(`Parameter or resource '${logicalId}' could not be found for evaluation`); + } + } + + async 'Fn::GetAtt'(logicalId: string, attributeName: string): Promise { + // ToDo handle the 'logicalId.attributeName' form of Fn::GetAtt + const attrValue = await self.findGetAttTarget(logicalId, attributeName); + if (attrValue) { + return attrValue; + } else { + throw new CfnEvaluationException(`Attribute '${attributeName}' of resource '${logicalId}' could not be found for evaluation`); + } + } + + async 'Fn::Sub'(template: string, explicitPlaceholders?: { [variable: string]: string }): Promise { + const placeholders = explicitPlaceholders + ? await self.evaluateCfnExpression(explicitPlaceholders) + : {}; + + return asyncGlobalReplace(template, /\${([^}]*)}/g, key => { + if (key in placeholders) { + return placeholders[key]; + } else { + const splitKey = key.split('.'); + return splitKey.length === 1 + ? this.Ref(key) + : this['Fn::GetAtt'](splitKey[0], splitKey.slice(1).join('.')); + } + }); + } + } + + if (cfnExpression == null) { + return cfnExpression; + } + + if (Array.isArray(cfnExpression)) { + return Promise.all(cfnExpression.map(expr => this.evaluateCfnExpression(expr))); + } + + if (typeof cfnExpression === 'object') { + const intrinsic = this.parseIntrinsic(cfnExpression); + if (intrinsic) { + return new CfnIntrinsics().evaluateIntrinsic(intrinsic); + } else { + const ret: { [key: string]: any } = {}; + for (const [key, val] of Object.entries(cfnExpression)) { + ret[key] = await this.evaluateCfnExpression(val); + } + return ret; + } + } + + return cfnExpression; + } + + private parseIntrinsic(x: any): Intrinsic | undefined { + const keys = Object.keys(x); + if (keys.length === 1 && (keys[0].startsWith('Fn::') || keys[0] === 'Ref')) { + return { + name: keys[0], + args: x[keys[0]], + }; + } + return undefined; + } + + private async findRefTarget(logicalId: string): Promise { + // first, check to see if the Ref is a Parameter who's value we have + const parameterTarget = this.context[logicalId]; + if (parameterTarget) { + return parameterTarget; + } + // if it's not a Parameter, we need to search in the current Stack resources + return this.findGetAttTarget(logicalId); + } + + private async findGetAttTarget(logicalId: string, attribute?: string): Promise { + const stackResources = await this.stackResources.listStackResources(); + const foundResource = stackResources.find(sr => sr.LogicalResourceId === logicalId); + if (!foundResource) { + return undefined; + } + // now, we need to format the appropriate identifier depending on the resource type, + // and the requested attribute name + return this.formatResourceAttribute(foundResource, attribute); + } + + private formatResourceAttribute(resource: AWS.CloudFormation.StackResourceSummary, attribute: string | undefined): string | undefined { + const physicalId = resource.PhysicalResourceId; + + // no attribute means Ref expression, for which we use the physical ID directly + if (!attribute) { + return physicalId; + } + + const resourceTypeFormats = RESOURCE_TYPE_ATTRIBUTES_FORMATS[resource.ResourceType]; + if (!resourceTypeFormats) { + throw new CfnEvaluationException(`We don't support attributes of the '${resource.ResourceType}' resource. This is a CDK limitation. ` + + 'Please report it at https://github.com/aws/aws-cdk/issues/new/choose'); + } + const attributeFmtFunc = resourceTypeFormats[attribute]; + if (!attributeFmtFunc) { + throw new CfnEvaluationException(`We don't support the '${attribute}' attribute of the '${resource.ResourceType}' resource. This is a CDK limitation. ` + + 'Please report it at https://github.com/aws/aws-cdk/issues/new/choose'); + } + const service = this.getServiceOfResource(resource); + const resourceTypeArnPart = this.getResourceTypeArnPartOfResource(resource); + return attributeFmtFunc({ + partition: this.partition, + service, + region: this.region, + account: this.account, + resourceType: resourceTypeArnPart, + resourceName: physicalId!, + }); + } + + private getServiceOfResource(resource: AWS.CloudFormation.StackResourceSummary): string { + return resource.ResourceType.split('::')[1].toLowerCase(); + } + + private getResourceTypeArnPartOfResource(resource: AWS.CloudFormation.StackResourceSummary): string { + return resource.ResourceType.split('::')[2].toLowerCase(); + } +} + +interface ArnParts { + readonly partition: string; + readonly service: string; + readonly region: string; + readonly account: string; + readonly resourceType: string; + readonly resourceName: string; +} + +const RESOURCE_TYPE_ATTRIBUTES_FORMATS: { [type: string]: { [attribute: string]: (parts: ArnParts) => string } } = { + 'AWS::IAM::Role': { Arn: iamArnFmt }, + 'AWS::IAM::User': { Arn: iamArnFmt }, + 'AWS::IAM::Group': { Arn: iamArnFmt }, + 'AWS::S3::Bucket': { Arn: s3ArnFmt }, + 'AWS::Lambda::Function': { Arn: stdColonResourceArnFmt }, +}; + +function iamArnFmt(parts: ArnParts): string { + // we skip region for IAM resources + return `arn:${parts.partition}:${parts.service}::${parts.account}:${parts.resourceType}/${parts.resourceName}`; +} + +function s3ArnFmt(parts: ArnParts): string { + // we skip account, region and resourceType for S3 resources + return `arn:${parts.partition}:${parts.service}:::${parts.resourceName}`; +} + +function stdColonResourceArnFmt(parts: ArnParts): string { + // this is a standard format for ARNs like: arn:aws:service:region:account:resourceType:resourceName + return `arn:${parts.partition}:${parts.service}:${parts.region}:${parts.account}:${parts.resourceType}:${parts.resourceName}`; +} + +interface Intrinsic { + readonly name: string; + readonly args: any; +} + +async function asyncGlobalReplace(str: string, regex: RegExp, cb: (x: string) => Promise): Promise { + if (!regex.global) { throw new Error('Regex must be created with /g flag'); } + + const ret = new Array(); + let start = 0; + while (true) { + const match = regex.exec(str); + if (!match) { break; } + + ret.push(str.substring(start, match.index)); + ret.push(await cb(match[1])); + + start = regex.lastIndex; + } + ret.push(str.substr(start)); + + return ret.join(''); +} diff --git a/packages/aws-cdk/lib/api/hotswap/lambda-functions.ts b/packages/aws-cdk/lib/api/hotswap/lambda-functions.ts index 73b4c529188c5..c110a66b6c9db 100644 --- a/packages/aws-cdk/lib/api/hotswap/lambda-functions.ts +++ b/packages/aws-cdk/lib/api/hotswap/lambda-functions.ts @@ -1,6 +1,7 @@ import * as cfn_diff from '@aws-cdk/cloudformation-diff'; import { ISDK } from '../aws-auth'; -import { assetMetadataChanged, ChangeHotswapImpact, ChangeHotswapResult, HotswapOperation, ListStackResources, stringifyPotentialCfnExpression } from './common'; +import { assetMetadataChanged, ChangeHotswapImpact, ChangeHotswapResult, HotswapOperation } from './common'; +import { CfnEvaluationException, EvaluateCloudFormationTemplate } from './evaluate-cloudformation-template'; /** * Returns `false` if the change cannot be short-circuited, @@ -8,10 +9,10 @@ import { assetMetadataChanged, ChangeHotswapImpact, ChangeHotswapResult, Hotswap * (like a change to CDKMetadata), * or a LambdaFunctionResource if the change can be short-circuited. */ -export function isHotswappableLambdaFunctionChange( - logicalId: string, change: cfn_diff.ResourceDifference, assetParamsWithEnv: { [key: string]: string }, -): ChangeHotswapResult { - const lambdaCodeChange = isLambdaFunctionCodeOnlyChange(change, assetParamsWithEnv); +export async function isHotswappableLambdaFunctionChange( + logicalId: string, change: cfn_diff.ResourceDifference, evaluateCfnTemplate: EvaluateCloudFormationTemplate, +): Promise { + const lambdaCodeChange = await isLambdaFunctionCodeOnlyChange(change, evaluateCfnTemplate); if (typeof lambdaCodeChange === 'string') { return lambdaCodeChange; } else { @@ -23,23 +24,13 @@ export function isHotswappableLambdaFunctionChange( return ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT; } - let functionPhysicalName: string | undefined; - try { - functionPhysicalName = stringifyPotentialCfnExpression(change.newValue?.Properties?.FunctionName, assetParamsWithEnv); - } catch (e) { - // It's possible we can't evaluate the function's name - - // for example, it can use a Ref to a different resource, - // which we wouldn't have in `assetParamsWithEnv`. - // That's fine though - ignore any errors, - // and treat this case the same way as if the name wasn't provided at all, - // which means it will be looked up using the listStackResources() call - // by the later phase (which actually does the Lambda function update) - functionPhysicalName = undefined; + const functionName = await establishFunctionPhysicalName(logicalId, change, evaluateCfnTemplate); + if (!functionName) { + return ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT; } return new LambdaFunctionHotswapOperation({ - logicalId, - physicalName: functionPhysicalName, + physicalName: functionName, code: lambdaCodeChange, }); } @@ -54,9 +45,9 @@ export function isHotswappableLambdaFunctionChange( * or a LambdaFunctionCode if the change is to a AWS::Lambda::Function, * and only affects its Code property. */ -function isLambdaFunctionCodeOnlyChange( - change: cfn_diff.ResourceDifference, assetParamsWithEnv: { [key: string]: string }, -): LambdaFunctionCode | ChangeHotswapImpact { +async function isLambdaFunctionCodeOnlyChange( + change: cfn_diff.ResourceDifference, evaluateCfnTemplate: EvaluateCloudFormationTemplate, +): Promise { if (!change.newValue) { return ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT; } @@ -99,11 +90,11 @@ function isLambdaFunctionCodeOnlyChange( switch (newPropName) { case 'S3Bucket': foundCodeDifference = true; - s3Bucket = stringifyPotentialCfnExpression(updatedProp.newValue[newPropName], assetParamsWithEnv); + s3Bucket = await evaluateCfnTemplate.evaluateCfnExpression(updatedProp.newValue[newPropName]); break; case 'S3Key': foundCodeDifference = true; - s3Key = stringifyPotentialCfnExpression(updatedProp.newValue[newPropName], assetParamsWithEnv); + s3Key = await evaluateCfnTemplate.evaluateCfnExpression(updatedProp.newValue[newPropName]); break; default: return ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT; @@ -125,8 +116,7 @@ interface LambdaFunctionCode { } interface LambdaFunctionResource { - readonly logicalId: string; - readonly physicalName?: string; + readonly physicalName: string; readonly code: LambdaFunctionCode; } @@ -134,26 +124,29 @@ class LambdaFunctionHotswapOperation implements HotswapOperation { constructor(private readonly lambdaFunctionResource: LambdaFunctionResource) { } - public async apply(sdk: ISDK, stackResources: ListStackResources): Promise { - let functionPhysicalName: string; - if (this.lambdaFunctionResource.physicalName) { - functionPhysicalName = this.lambdaFunctionResource.physicalName; - } else { - const stackResourceList = await stackResources.listStackResources(); - const foundFunctionName = stackResourceList - .find(resSummary => resSummary.LogicalResourceId === this.lambdaFunctionResource.logicalId) - ?.PhysicalResourceId; - if (!foundFunctionName) { - // if we couldn't find the function in the current stack, we can't update it - return; - } - functionPhysicalName = foundFunctionName; - } - + public async apply(sdk: ISDK): Promise { return sdk.lambda().updateFunctionCode({ - FunctionName: functionPhysicalName, + FunctionName: this.lambdaFunctionResource.physicalName, S3Bucket: this.lambdaFunctionResource.code.s3Bucket, S3Key: this.lambdaFunctionResource.code.s3Key, }).promise(); } } + +async function establishFunctionPhysicalName( + logicalId: string, change: cfn_diff.ResourceDifference, evaluateCfnTemplate: EvaluateCloudFormationTemplate, +): Promise { + const functionNameInCfnTemplate = change.newValue?.Properties?.FunctionName; + if (functionNameInCfnTemplate != null) { + try { + return await evaluateCfnTemplate.evaluateCfnExpression(functionNameInCfnTemplate); + } catch (e) { + // If we can't evaluate the function's name CloudFormation expression, + // just look it up in the currently deployed Stack + if (!(e instanceof CfnEvaluationException)) { + throw e; + } + } + } + return evaluateCfnTemplate.findPhysicalNameFor(logicalId); +} diff --git a/packages/aws-cdk/lib/api/util/cloudformation/evaluate-cfn.ts b/packages/aws-cdk/lib/api/util/cloudformation/evaluate-cfn.ts deleted file mode 100644 index bdc395df83814..0000000000000 --- a/packages/aws-cdk/lib/api/util/cloudformation/evaluate-cfn.ts +++ /dev/null @@ -1,89 +0,0 @@ -export function evaluateCfn(object: any, context: { [key: string]: string }): any { - const intrinsicFns: any = { - 'Fn::Join'(separator: string, args: string[]): string { - return evaluate(args).map(evaluate).join(separator); - }, - - 'Fn::Split'(separator: string, args: string): string { - return evaluate(args).split(separator); - }, - - 'Fn::Select'(index: number, args: string[]): string { - return evaluate(args).map(evaluate)[index]; - }, - - 'Ref'(logicalId: string): string { - if (logicalId in context) { - return context[logicalId]; - } else { - throw new Error(`Reference target '${logicalId}' was not found`); - } - }, - - 'Fn::Sub'(template: string, explicitPlaceholders?: { [variable: string]: string }): string { - const placeholders = explicitPlaceholders - ? { ...context, ...evaluate(explicitPlaceholders) } - : context; - - return template.replace(/\${([^}]*)}/g, (_: string, key: string) => { - if (key in placeholders) { - return placeholders[key]; - } else { - throw new Error(`Fn::Sub target '${key}' was not found`); - } - }); - }, - }; - - return evaluate(object); - - function evaluate(obj: any): any { - if (Array.isArray(obj)) { - return obj.map(evaluate); - } - - if (typeof obj === 'object') { - const intrinsic = parseIntrinsic(obj); - if (intrinsic) { - return evaluateIntrinsic(intrinsic); - } - - const ret: { [key: string]: any } = {}; - for (const key of Object.keys(obj)) { - ret[key] = evaluate(obj[key]); - } - return ret; - } - - return obj; - } - - function evaluateIntrinsic(intrinsic: Intrinsic) { - if (!(intrinsic.name in intrinsicFns)) { - throw new Error(`Intrinsic ${intrinsic.name} not supported here`); - } - - const argsAsArray = Array.isArray(intrinsic.args) ? intrinsic.args : [intrinsic.args]; - - return intrinsicFns[intrinsic.name].apply(intrinsicFns, argsAsArray); - } -} - -interface Intrinsic { - readonly name: string; - readonly args: any; -} - -function parseIntrinsic(x: any): Intrinsic | undefined { - if (typeof x !== 'object' || x === null) { - return undefined; - } - const keys = Object.keys(x); - if (keys.length === 1 && (keys[0].startsWith('Fn::') || keys[0] === 'Ref')) { - return { - name: keys[0], - args: x[keys[0]], - }; - } - return undefined; -} diff --git a/packages/aws-cdk/lib/api/util/cloudformation/stack-activity-monitor.ts b/packages/aws-cdk/lib/api/util/cloudformation/stack-activity-monitor.ts index 98277d3339fa1..73075a41fee27 100644 --- a/packages/aws-cdk/lib/api/util/cloudformation/stack-activity-monitor.ts +++ b/packages/aws-cdk/lib/api/util/cloudformation/stack-activity-monitor.ts @@ -524,7 +524,7 @@ export class HistoryActivityPrinter extends ActivityPrinterBase { this.stream.write( util.format( ' %s%s | %s | %s | %s %s%s%s\n', - (progress !== false ? ` ${this.progress()} |` : ''), + (progress !== false ? ` ${this.progress()} | ` : ''), new Date(e.Timestamp).toLocaleTimeString(), color(padRight(STATUS_WIDTH, (e.ResourceStatus || '').substr(0, STATUS_WIDTH))), // pad left and trim padRight(this.props.resourceTypeColumnWidth, e.ResourceType || ''), diff --git a/packages/aws-cdk/lib/init-templates/v2/app/csharp/src/%name.PascalCased%/%name.PascalCased%.template.csproj b/packages/aws-cdk/lib/init-templates/v2/app/csharp/src/%name.PascalCased%/%name.PascalCased%.template.csproj index 0ac3cc0a4c6cb..a839c9651027a 100644 --- a/packages/aws-cdk/lib/init-templates/v2/app/csharp/src/%name.PascalCased%/%name.PascalCased%.template.csproj +++ b/packages/aws-cdk/lib/init-templates/v2/app/csharp/src/%name.PascalCased%/%name.PascalCased%.template.csproj @@ -10,6 +10,7 @@ + + + +