├── .devcontainer ├── Dockerfile ├── devcontainer.json └── post-create-command.sh ├── .editorconfig ├── .eslintignore ├── .eslintrc.json ├── .gitattributes ├── .github ├── PULL_REQUEST_TEMPLATE.md ├── semantic.yml └── workflows │ └── pr-auto-merge.yml ├── .gitignore ├── .npmignore ├── .prettierignore ├── .prettierrc.json ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── bin └── cdk-chart-app-sample.ts ├── cdk.json ├── container └── recorder │ ├── Dockerfile │ ├── go.mod │ ├── go.sum │ └── main.go ├── doc └── architecture.jpg ├── jest.config.js ├── lambda └── metrics-handler.ts ├── lib ├── api-stack.ts ├── app-stage.ts ├── backend-stack.ts ├── frontend-stack.ts └── pipeline-stack.ts ├── package-lock.json ├── package.json ├── test ├── __snapshots__ │ └── cdk-chart-app-sample.test.ts.snap └── cdk-chart-app-sample.test.ts ├── tsconfig.json └── webapp └── dashboard ├── .env ├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── index.html ├── logo192.png ├── logo512.png ├── manifest.json └── robots.txt ├── src ├── App.css ├── App.test.tsx ├── App.tsx ├── Chart.tsx ├── index.css ├── index.tsx ├── logo.svg ├── reportWebVitals.ts └── setupTests.ts └── tsconfig.json /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG VARIANT="jammy" 2 | FROM mcr.microsoft.com/vscode/devcontainers/base:0-${VARIANT} 3 | 4 | RUN wget https://go.dev/dl/go1.18.1.linux-amd64.tar.gz \ 5 | && rm -rf /usr/local/go \ 6 | && sudo tar -C /usr/local -xzf go1.18.1.linux-amd64.tar.gz \ 7 | && rm -f go1.18.1.linux-amd64.tar.gz -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Visual Studio Code settings for AWS CDK", 3 | "build": { 4 | "dockerfile": "Dockerfile", 5 | "args": { 6 | "VARIANT": "jammy", 7 | "GOPROXY": "direct" 8 | } 9 | }, 10 | "settings": { 11 | "go.toolsManagement.checkForUpdates": "local", 12 | "go.useLanguageServer": true, 13 | "go.goroot": "/usr/local/go", 14 | "gopls": { 15 | "build.experimentalWorkspaceModule": true 16 | } 17 | }, 18 | "extensions": [ 19 | "dbaeumer.vscode-eslint", 20 | "golang.Go" 21 | ], 22 | "postCreateCommand": "bash .devcontainer/post-create-command.sh", 23 | "remoteUser": "vscode", 24 | "features": { 25 | "docker-in-docker": "latest", 26 | "aws-cli": "latest", 27 | "node": "16" 28 | }, 29 | "containerEnv": { 30 | "GOPROXY": "direct" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /.devcontainer/post-create-command.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -ex 3 | 4 | npm ci 5 | cd webapp/dashboard 6 | npm ci 7 | 8 | curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg 9 | echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null 10 | sudo apt update 11 | sudo apt install gh -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | # base settings 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | # hidden files 13 | [.*] 14 | end_of_line = lf 15 | 16 | # by extensions 17 | [*.sh] 18 | end_of_line = lf 19 | [*.bat] 20 | end_of_line = crlf 21 | [*.md] 22 | trim_trailing_whitespace = false 23 | indent_size = 4 24 | [*.{yml,yaml}] 25 | indent_size = 4 26 | [{Makefile,go.mod,go.sum,*.go}] 27 | indent_style = tab 28 | indent_size = 4 29 | 30 | # by unique files 31 | [package{,-lock}.json] 32 | end_of_line = lf 33 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | **/node_modules/** 2 | **/cdk.out/** 3 | *.js 4 | *.d.ts 5 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"], 3 | "parser": "@typescript-eslint/parser", 4 | "parserOptions": {}, 5 | "plugins": ["@typescript-eslint"], 6 | "rules": {} 7 | } 8 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set the default behavior, in case people don't have core.autocrlf set. 2 | * text=auto 3 | 4 | # Declare files that will always have LF or CRLF line endings on checkout. 5 | *.sln text eol=crlf 6 | *.bat text eol=crlf 7 | *.sh text eol=lf 8 | 9 | # Denote all files that are truly binary and should not be modified. 10 | *.png binary 11 | *.jpg binary 12 | 13 | # Exclude from git archive 14 | .gitkeep export-ignore 15 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | 4 | By submitting this pull request, I confirm that my contribution is made under the terms of the [MIT No Attribution (MIT-0)]. 5 | 6 | [MIT No Attribution (MIT-0)]: https://github.com/aws/mit-0 7 | -------------------------------------------------------------------------------- /.github/semantic.yml: -------------------------------------------------------------------------------- 1 | # Configuration for Semantic Pull Requests 2 | # Always validate the PR title, and ignore the commits 3 | titleOnly: true 4 | 5 | # By default types specified in commitizen/conventional-commit-types is used. 6 | # See: https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json 7 | # You can override the valid types 8 | types: 9 | - feat 10 | - fix 11 | - docs 12 | - style 13 | - refactor 14 | - perf 15 | - test 16 | - build 17 | - ci 18 | - chore 19 | - revert 20 | -------------------------------------------------------------------------------- /.github/workflows/pr-auto-merge.yml: -------------------------------------------------------------------------------- 1 | name: Dependabot auto-merge 2 | on: pull_request 3 | 4 | permissions: 5 | contents: write 6 | pull-requests: write 7 | 8 | jobs: 9 | dependabot: 10 | runs-on: ubuntu-latest 11 | if: ${{ github.actor == 'dependabot[bot]' }} 12 | steps: 13 | - name: Dependabot metadata 14 | id: metadata 15 | uses: dependabot/fetch-metadata@v1.1.1 16 | with: 17 | github-token: '${{ secrets.GITHUB_TOKEN }}' 18 | - name: Approve and enable auto-merge a PR 19 | if: ${{steps.metadata.outputs.update-type == 'version-update:semver-minor' || steps.metadata.outputs.update-type == 'version-update:semver-patch'}} 20 | run: | 21 | gh pr review --approve "$PR_URL" 22 | gh pr merge --auto --merge "$PR_URL" 23 | env: 24 | PR_URL: ${{github.event.pull_request.html_url}} 25 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.js 2 | !jest.config.js 3 | *.d.ts 4 | node_modules 5 | 6 | # CDK asset staging directory 7 | .cdk.staging 8 | cdk.out 9 | 10 | container/recorder/recorder 11 | container/recorder/recorder.exe 12 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | *.ts 2 | !*.d.ts 3 | 4 | # CDK asset staging directory 5 | .cdk.staging 6 | cdk.out 7 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | LICENSE 2 | CHANGELOG.md 3 | CODE_OF_CONDUCT.md 4 | CONTRIBUTING.md 5 | .github/PULL_REQUEST_TEMPLATE.md 6 | 7 | cdk.out 8 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "all", 3 | "semi": true, 4 | "singleQuote": true, 5 | "tabWidth": 2, 6 | "printWidth": 120 7 | } 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | 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. 4 | 5 | ### [1.0.2](https://github.com/aws-samples/cdk-chart-app-sample/compare/v1.0.1...v1.0.2) (2022-06-24) 6 | 7 | 8 | ### Bug Fixes 9 | 10 | * Add webpack in devDependency to solve vulnerability of nth-check ([9ada7a4](https://github.com/aws-samples/cdk-chart-app-sample/commit/9ada7a42c5552879a079a7ddcf436dd73a28a2ef)) 11 | 12 | ### [1.0.1](https://github.com/aws-samples/cdk-chart-app-sample/compare/v1.0.0...v1.0.1) (2022-05-13) 13 | 14 | 15 | ### Bug Fixes 16 | 17 | * **api:** no use try-catch in lambda. fix [#21](https://github.com/aws-samples/cdk-chart-app-sample/issues/21) ([2bd44fc](https://github.com/aws-samples/cdk-chart-app-sample/commit/2bd44fc1660ca28e05c0d58ee92d352fb06e2823)) 18 | * **backend:** Use relative path for container asset. fix [#27](https://github.com/aws-samples/cdk-chart-app-sample/issues/27) ([baa05d5](https://github.com/aws-samples/cdk-chart-app-sample/commit/baa05d5f4eb850b916c76e50749daa424ebf83aa)) 19 | * **frontend:** Build React app without Docker. close [#26](https://github.com/aws-samples/cdk-chart-app-sample/issues/26) ([661b330](https://github.com/aws-samples/cdk-chart-app-sample/commit/661b330703d623ef7e7b350e817c6e586681f49a)) 20 | 21 | ## 1.0.0 (2022-04-24) 22 | 23 | * First release 24 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *main* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 10 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 11 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 12 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 13 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AWS CDK Chart App Sample 2 | 3 | **English follows Japanese** 4 | 5 | AWS CDK (v2) を使用してシンプルな Web アプリケーションを構築するサンプルコードです。次のアーキテクチャ図に示す通り、このアプリケーションは 4 つの CDK スタックによって構成されます。 6 | 7 | ![Architecture](./doc/architecture.jpg) 8 | 9 | それぞれのスタックとその中にデプロイされるアプリケーションは、アプリケーションの機能よりもコード量が最小限になることを優先して設計されています。 10 | 11 | **このサンプルコードはそのまま本番環境に使用されることを意図していません。AWS CDK を活用して簡単なアプリケーションを構築するための例を示したものです。** 12 | 13 | AWS Summit Online Japan 2022 Developer Zone のセッション『AWS CDK で CI/CD つきの Web アプリを作ろう!開発風景を Live Coding でお届けします』でライブコーディングの様子を紹介しました。 14 | 15 | --- 16 | 17 | This is a sample code to build a simple Web application with AWS CDK (v2). As described in the architecture diagram, this application is constructed by 4 CDK stacks. 18 | 19 | Each stacks and applications are designed to minimize the amount of code over the functionality of the application. 20 | 21 | **This sample is not meant to be used as production as-is, but as an inspiration on how to leverage AWS CDK to build a simple application.** 22 | 23 | In AWS Summit Online Japan 2022 Developer Zone session titled "Let's make a Web application with CI/CD by AWS CDK! We will demonstrate daily development process by live coding", we showed live coding with this code. 24 | 25 | ## Requirements 26 | 27 | - [Node.js](https://nodejs.org/) (>= `16.0.0`) 28 | - `npm` (>= `8.1.0`) 29 | - [Go](https://go.dev/) (>= `1.18.0`) 30 | - [Git](https://git-scm.com/) 31 | - [Docker](https://www.docker.com/get-started/) 32 | 33 | ## How to deploy 34 | 35 | ### 1. Create your private Git repository from a copy 36 | 37 | To store [context information](https://docs.aws.amazon.com/cdk/v2/guide/context.html), you can host CDK code in a private Git repository. To achieve this, you can **copy this public repository instead of folking it**. 38 | 39 | First, create your private repository in GitHub. Then, follow those steps: 40 | 41 | ```sh 42 | git clone git@github.com:aws-samples/cdk-chart-app-sample.git 43 | cd cdk-chart-app-sample 44 | git remote set-url origin git@github.com:/.git 45 | git push origin main 46 | ``` 47 | 48 | ### 2. Install dependencies 49 | 50 | ```sh 51 | npm ci 52 | cd webapp/dashboard 53 | npm ci && npm run build 54 | ``` 55 | 56 | ### 3. Create AWS CodeStar connection 57 | 58 | [Create a connection - Developer Tools console](https://docs.aws.amazon.com/dtconsole/latest/userguide/connections-create.html) 59 | 60 | ### 4. Configure your cdk.json 61 | 62 | Replace values with yours: 63 | 64 | ```json 65 | "source-repository": "aws-samples/cdk-chart-app-sample", 66 | "source-branch": "main", 67 | "source-connection-arn": "arn:aws:codestar-connections:ap-northeast-1:123456789012:connection/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" 68 | ``` 69 | 70 | ### 5. Deploy CDK Pipelines 71 | 72 | CDK Pipelines expects the source code has been pushed in connected repository. First time of your deployment, you should `git push` before running `cdk deploy`. 73 | 74 | ```sh 75 | git push origin main 76 | npx cdk deploy --all 77 | ``` 78 | 79 | Once CDK Pipelines is created, changes to the CDK application will be reflected by `git push`. If you want to change the pipeline stack itself, you will need to run `cdk deploy` again from your terminal. 80 | 81 | ### 6. Update `webapp/dashboard/.env` 82 | 83 | Replace the following value in `webapp/dashboard/.env` with your own. This is the time to change the value, as the specific value will not be known until the resource is created. 84 | 85 | ``` 86 | REACT_APP_API_BASE_URL=https://xxx.execute-api.ap-northeast-1.amazonaws.com/prod/ 87 | ``` 88 | 89 | ## Useful commands 90 | 91 | [AWS CDK Toolkit \(cdk command\) \- AWS Cloud Development Kit \(CDK\) v2](https://docs.aws.amazon.com/cdk/v2/guide/cli.html) 92 | 93 | - `npm run test` perform the jest unit tests 94 | - `cdk deploy` deploy this stack to your default AWS account/region 95 | - `cdk diff` compare deployed stack with current state 96 | - `cdk synth` emits the synthesized CloudFormation template 97 | 98 | ## Security issue notifications 99 | 100 | See [Security issue notifications](CONTRIBUTING.md#security-issue-notifications) for more information. 101 | 102 | ## License 103 | 104 | This library is licensed under the [MIT-0](https://github.com/aws/mit-0) License. See the [LICENSE](LICENSE) file. 105 | -------------------------------------------------------------------------------- /bin/cdk-chart-app-sample.ts: -------------------------------------------------------------------------------- 1 | import 'source-map-support/register'; 2 | import * as cdk from 'aws-cdk-lib'; 3 | import { PipelineStack } from '../lib/pipeline-stack'; 4 | 5 | const app = new cdk.App(); 6 | 7 | // We recommend to add prefix to identify stacks deployed by this CDK app 8 | const prefix = 'Summit'; 9 | 10 | const repo = app.node.tryGetContext('source-repository'); 11 | const branch = app.node.tryGetContext('source-branch'); 12 | const connectionArn = app.node.tryGetContext('source-connection-arn'); 13 | 14 | // === Stack naming === 15 | // In CDK Pipeline, you see stack names in `cdk ls` and in CloudFormation console. 16 | // `cdk ls` prints CDK construct ID in following format: 17 | // // 18 | // ex: SummitPipeline/SummitApp/Backend 19 | // CloudFormation stack name is following format: 20 | // - 21 | // ex: SummitApp/Backend 22 | // So we recommend add prefix to and . 23 | // This practice is differ from deployment by `cdk deploy` (not by CDK Pipeline). 24 | // If you use `cdk deploy`, you should add prefix to each . 25 | new PipelineStack(app, `${prefix}Pipeline`, { 26 | prefix, 27 | repo, 28 | branch, 29 | connectionArn, 30 | }); 31 | -------------------------------------------------------------------------------- /cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "npx ts-node --prefer-ts-exts bin/cdk-chart-app-sample.ts", 3 | "watch": { 4 | "include": ["**"], 5 | "exclude": [ 6 | "README.md", 7 | "cdk*.json", 8 | "**/*.d.ts", 9 | "**/*.js", 10 | "tsconfig.json", 11 | "package*.json", 12 | "yarn.lock", 13 | "node_modules", 14 | "test" 15 | ] 16 | }, 17 | "context": { 18 | "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, 19 | "@aws-cdk/core:stackRelativeExports": true, 20 | "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, 21 | "@aws-cdk/aws-lambda:recognizeVersionProps": true, 22 | "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, 23 | "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, 24 | "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, 25 | "@aws-cdk/aws-iam:minimizePolicies": true, 26 | "@aws-cdk/core:target-partitions": ["aws", "aws-cn"], 27 | "source-repository": "aws-samples/cdk-chart-app-sample", 28 | "source-branch": "main", 29 | "source-connection-arn": "arn:aws:codestar-connections:ap-northeast-1:123456789012:connection/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /container/recorder/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/docker/library/golang:1.18 AS builder 2 | WORKDIR /myapp 3 | COPY . /myapp 4 | RUN go env -w GOPROXY=direct \ 5 | && CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o recorder main.go 6 | 7 | FROM public.ecr.aws/docker/library/alpine:3.15 8 | WORKDIR /myapp 9 | RUN adduser -D -H -s /bin/false myuser \ 10 | && chown -R myuser /myapp \ 11 | && apk --no-cache add ca-certificates 12 | COPY --from=builder /myapp/recorder . 13 | USER myuser 14 | ENTRYPOINT ["/myapp/recorder"] 15 | -------------------------------------------------------------------------------- /container/recorder/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/aws-samples/cdk-chart-app-sample/container/recorder 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/aws/aws-sdk-go-v2/config v1.15.4 7 | github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.9.1 8 | github.com/aws/aws-sdk-go-v2/service/dynamodb v1.15.4 9 | ) 10 | 11 | require ( 12 | github.com/aws/aws-sdk-go-v2 v1.16.3 // indirect 13 | github.com/aws/aws-sdk-go-v2/credentials v1.12.0 // indirect 14 | github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.4 // indirect 15 | github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.10 // indirect 16 | github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.4 // indirect 17 | github.com/aws/aws-sdk-go-v2/internal/ini v1.3.11 // indirect 18 | github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.13.4 // indirect 19 | github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.1 // indirect 20 | github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.4 // indirect 21 | github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.4 // indirect 22 | github.com/aws/aws-sdk-go-v2/service/sso v1.11.4 // indirect 23 | github.com/aws/aws-sdk-go-v2/service/sts v1.16.4 // indirect 24 | github.com/aws/smithy-go v1.11.2 // indirect 25 | github.com/jmespath/go-jmespath v0.4.0 // indirect 26 | ) 27 | -------------------------------------------------------------------------------- /container/recorder/go.sum: -------------------------------------------------------------------------------- 1 | github.com/aws/aws-sdk-go-v2 v1.16.2 h1:fqlCk6Iy3bnCumtrLz9r3mJ/2gUT0pJ0wLFVIdWh+JA= 2 | github.com/aws/aws-sdk-go-v2 v1.16.2/go.mod h1:ytwTPBG6fXTZLxxeeCCWj2/EMYp/xDUgX+OET6TLNNU= 3 | github.com/aws/aws-sdk-go-v2 v1.16.3 h1:0W1TSJ7O6OzwuEvIXAtJGvOeQ0SGAhcpxPN2/NK5EhM= 4 | github.com/aws/aws-sdk-go-v2 v1.16.3/go.mod h1:ytwTPBG6fXTZLxxeeCCWj2/EMYp/xDUgX+OET6TLNNU= 5 | github.com/aws/aws-sdk-go-v2/config v1.15.3 h1:5AlQD0jhVXlGzwo+VORKiUuogkG7pQcLJNzIzK7eodw= 6 | github.com/aws/aws-sdk-go-v2/config v1.15.3/go.mod h1:9YL3v07Xc/ohTsxFXzan9ZpFpdTOFl4X65BAKYaz8jg= 7 | github.com/aws/aws-sdk-go-v2/config v1.15.4 h1:P4mesY1hYUxru4f9SU0XxNKXmzfxsD0FtMIPRBjkH7Q= 8 | github.com/aws/aws-sdk-go-v2/config v1.15.4/go.mod h1:ZijHHh0xd/A+ZY53az0qzC5tT46kt4JVCePf2NX9Lk4= 9 | github.com/aws/aws-sdk-go-v2/credentials v1.11.2 h1:RQQ5fzclAKJyY5TvF+fkjJEwzK4hnxQCLOu5JXzDmQo= 10 | github.com/aws/aws-sdk-go-v2/credentials v1.11.2/go.mod h1:j8YsY9TXTm31k4eFhspiQicfXPLZ0gYXA50i4gxPE8g= 11 | github.com/aws/aws-sdk-go-v2/credentials v1.12.0 h1:4R/NqlcRFSkR0wxOhgHi+agGpbEr5qMCjn7VqUIJY+E= 12 | github.com/aws/aws-sdk-go-v2/credentials v1.12.0/go.mod h1:9YWk7VW+eyKsoIL6/CljkTrNVWBSK9pkqOPUuijid4A= 13 | github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.8.4 h1:RFvKYpSTejcSLgtPmfy6jY2vxcAC6y2f+gHD2HH99fg= 14 | github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.8.4/go.mod h1:N7M3jvFFVC8zayueLESAjrsSiak2yYt/b8p4EPsNbaY= 15 | github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.9.1 h1:W5OvMA6XTRXs/voHKPOCSVyzhV07GzHKn5GKTDzjKx0= 16 | github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.9.1/go.mod h1:47xITY/Q+OIf25Z5Z3EbJkG2WxCllBjKxreRmJECDMI= 17 | github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.3 h1:LWPg5zjHV9oz/myQr4wMs0gi4CjnDN/ILmyZUFYXZsU= 18 | github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.3/go.mod h1:uk1vhHHERfSVCUnqSqz8O48LBYDSC+k6brng09jcMOk= 19 | github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.4 h1:FP8gquGeGHHdfY6G5llaMQDF+HAf20VKc8opRwmjf04= 20 | github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.4/go.mod h1:u/s5/Z+ohUQOPXl00m2yJVyioWDECsbpXTQlaqSlufc= 21 | github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.9 h1:onz/VaaxZ7Z4V+WIN9Txly9XLTmoOh1oJ8XcAC3pako= 22 | github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.9/go.mod h1:AnVH5pvai0pAF4lXRq0bmhbes1u9R8wTE+g+183bZNM= 23 | github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.10 h1:uFWgo6mGJI1n17nbcvSc6fxVuR3xLNqvXt12JCnEcT8= 24 | github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.10/go.mod h1:F+EZtuIwjlv35kRJPyBGcsA4f7bnSoz15zOQ2lJq1Z4= 25 | github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.3 h1:9stUQR/u2KXU6HkFJYlqnZEjBnbgrVbG6I5HN09xZh0= 26 | github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.3/go.mod h1:ssOhaLpRlh88H3UmEcsBoVKq309quMvm3Ds8e9d4eJM= 27 | github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.4 h1:cnsvEKSoHN4oAN7spMMr0zhEW2MHnhAVpmqQg8E6UcM= 28 | github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.4/go.mod h1:8glyUqVIM4AmeenIsPo0oVh3+NUwnsQml2OFupfQW+0= 29 | github.com/aws/aws-sdk-go-v2/internal/ini v1.3.10 h1:by9P+oy3P/CwggN4ClnW2D4oL91QV7pBzBICi1chZvQ= 30 | github.com/aws/aws-sdk-go-v2/internal/ini v1.3.10/go.mod h1:8DcYQcz0+ZJaSxANlHIsbbi6S+zMwjwdDqwW3r9AzaE= 31 | github.com/aws/aws-sdk-go-v2/internal/ini v1.3.11 h1:6cZRymlLEIlDTEB0+5+An6Zj1CKt6rSE69tOmFeu1nk= 32 | github.com/aws/aws-sdk-go-v2/internal/ini v1.3.11/go.mod h1:0MR+sS1b/yxsfAPvAESrw8NfwUoxMinDyw6EYR9BS2U= 33 | github.com/aws/aws-sdk-go-v2/service/dynamodb v1.15.3 h1:b5+OInu1LyoF4uhFT453MOhbXXaM0YmQsqkxMjFl1dc= 34 | github.com/aws/aws-sdk-go-v2/service/dynamodb v1.15.3/go.mod h1:SvbsOiwp0L3NvC+XjgS1CU6NQ3TmArV1bNBlugz2hVc= 35 | github.com/aws/aws-sdk-go-v2/service/dynamodb v1.15.4 h1:M65DLU8yF7OT8h66B5ULgCdqDx3aq6KZTB2viHozSyM= 36 | github.com/aws/aws-sdk-go-v2/service/dynamodb v1.15.4/go.mod h1:lBz+dFsiLZcTCnIdWKUmNQLGX4CidaQqb706AIJ652M= 37 | github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.13.3 h1:nPT5ysut/wvhIYyTZ5m6phHS50awx3MVwiB5igAWUH8= 38 | github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.13.3/go.mod h1:y0rhvvclfOoHPdnMyADj6KKydr0+YgaWmDZFqBi9uFc= 39 | github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.13.4 h1:q8C+UWoUI/PWVy/qaA8anr8rNeqdQKmVKN6x8zpj+6o= 40 | github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.13.4/go.mod h1:Ldxp5sLfT8Is7fZOIqTJ8oaVoDo+Rxu0xAYhZqnN6y8= 41 | github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.1 h1:T4pFel53bkHjL2mMo+4DKE6r6AuoZnM0fg7k1/ratr4= 42 | github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.1/go.mod h1:GeUru+8VzrTXV/83XyMJ80KpH8xO89VPoUileyNQ+tc= 43 | github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.3 h1:JUbFrnq5mEeM2anIJ2PUkaHpKPW/D+RYAQVv5HXYQg4= 44 | github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.3/go.mod h1:lgGDXBzoot238KmAAn6zf9lkoxcYtJECnYURSbvNlfc= 45 | github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.4 h1:kkIspXTzCx1Mo8sF/UrzGkb5FmUsAnRy09DCjOKO03g= 46 | github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.4/go.mod h1:EjdPGnmBHOi9ieyuR9ck5Nguyb32/fdjoxDPVrYWYAA= 47 | github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.3 h1:Gh1Gpyh01Yvn7ilO/b/hr01WgNpaszfbKMUgqM186xQ= 48 | github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.3/go.mod h1:wlY6SVjuwvh3TVRpTqdy4I1JpBFLX4UGeKZdWntaocw= 49 | github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.4 h1:b16QW0XWl0jWjLABFc1A+uh145Oqv+xDcObNk0iQgUk= 50 | github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.4/go.mod h1:uKkN7qmSIsNJVyMtxNQoCEYMvFEXbOg9fwCJPdfp2u8= 51 | github.com/aws/aws-sdk-go-v2/service/sso v1.11.3 h1:frW4ikGcxfAEDfmQqWgMLp+F1n4nRo9sF39OcIb5BkQ= 52 | github.com/aws/aws-sdk-go-v2/service/sso v1.11.3/go.mod h1:7UQ/e69kU7LDPtY40OyoHYgRmgfGM4mgsLYtcObdveU= 53 | github.com/aws/aws-sdk-go-v2/service/sso v1.11.4 h1:Uw5wBybFQ1UeA9ts0Y07gbv0ncZnIAyw858tDW0NP2o= 54 | github.com/aws/aws-sdk-go-v2/service/sso v1.11.4/go.mod h1:cPDwJwsP4Kff9mldCXAmddjJL6JGQqtA3Mzer2zyr88= 55 | github.com/aws/aws-sdk-go-v2/service/sts v1.16.3 h1:cJGRyzCSVwZC7zZZ1xbx9m32UnrKydRYhOvcD1NYP9Q= 56 | github.com/aws/aws-sdk-go-v2/service/sts v1.16.3/go.mod h1:bfBj0iVmsUyUg4weDB4NxktD9rDGeKSVWnjTnwbx9b8= 57 | github.com/aws/aws-sdk-go-v2/service/sts v1.16.4 h1:+xtV90n3abQmgzk1pS++FdxZTrPEDgQng6e4/56WR2A= 58 | github.com/aws/aws-sdk-go-v2/service/sts v1.16.4/go.mod h1:lfSYenAXtavyX2A1LsViglqlG9eEFYxNryTZS5rn3QE= 59 | github.com/aws/smithy-go v1.11.2 h1:eG/N+CcUMAvsdffgMvjMKwfyDzIkjM6pfxMJ8Mzc6mE= 60 | github.com/aws/smithy-go v1.11.2/go.mod h1:3xHYmszWVx2c0kIwQeEVf9uSm4fYZt67FBJnwub1bgM= 61 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 62 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 63 | github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= 64 | github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= 65 | github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= 66 | github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= 67 | github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= 68 | github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= 69 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 70 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 71 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 72 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 73 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 74 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 75 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= 76 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 77 | -------------------------------------------------------------------------------- /container/recorder/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "log" 7 | "math" 8 | "os" 9 | "os/signal" 10 | "syscall" 11 | "time" 12 | 13 | "github.com/aws/aws-sdk-go-v2/config" 14 | "github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue" 15 | "github.com/aws/aws-sdk-go-v2/service/dynamodb" 16 | ) 17 | 18 | type record struct { 19 | DeviceID string `dynamodbav:"deviceId"` 20 | Timestamp string `dynamodbav:"timestamp"` 21 | ExpiresAt int64 `dynamodbav:"expiresAt"` 22 | Value float64 `dynamodbav:"value"` 23 | } 24 | 25 | func putItem(ctx context.Context, client *dynamodb.Client, tableName string) error { 26 | now := time.Now() 27 | fmt.Println(now.Format(time.RFC3339)) 28 | 29 | metric := &record{ 30 | DeviceID: "dummy", 31 | Timestamp: now.Format(time.RFC3339), 32 | ExpiresAt: now.Add(1 * time.Hour).Unix(), // TTL 33 | Value: math.Sin(float64(now.Second()) * math.Pi / 30), // -1 ... +1 34 | } 35 | 36 | // marshal struct into attribute value using struct tag 37 | av, err := attributevalue.MarshalMap(metric) 38 | if err != nil { 39 | return err 40 | } 41 | 42 | _, err = client.PutItem(ctx, &dynamodb.PutItemInput{ 43 | TableName: &tableName, 44 | Item: av, 45 | }) 46 | return err 47 | } 48 | 49 | func runRecorder(ctx context.Context, errChan chan error, tableName string) { 50 | // create DynamoDB client 51 | cfg, err := config.LoadDefaultConfig(ctx) 52 | if err != nil { 53 | errChan <- err 54 | return 55 | } 56 | client := dynamodb.NewFromConfig(cfg) 57 | 58 | t := time.NewTicker(10 * time.Second) 59 | defer t.Stop() 60 | 61 | for { 62 | select { 63 | case <-t.C: 64 | // putItem every 10 sec 65 | err = putItem(ctx, client, tableName) 66 | if err != nil { 67 | errChan <- err 68 | return 69 | } 70 | 71 | case <-ctx.Done(): 72 | // catch cancel 73 | return 74 | } 75 | } 76 | } 77 | 78 | func main() { 79 | ctx, cancel := context.WithCancel(context.Background()) 80 | defer cancel() 81 | 82 | // catch SIGTERM for graceful shutdown 83 | // https://aws.amazon.com/jp/blogs/news/graceful-shutdowns-with-ecs/ 84 | sig := make(chan os.Signal, 1) 85 | defer close(sig) 86 | signal.Notify(sig, syscall.SIGTERM) 87 | 88 | // run recorder in goroutine 89 | errChan := make(chan error) 90 | defer close(errChan) 91 | tableName := os.Getenv("DDB_TABLE_NAME") 92 | go runRecorder(ctx, errChan, tableName) 93 | 94 | for { 95 | select { 96 | case err := <-errChan: 97 | if err != nil { 98 | cancel() 99 | log.Fatal(err) 100 | } 101 | return 102 | 103 | case <-sig: 104 | fmt.Println("Caught SIGTERM, shutting down") 105 | return 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /doc/architecture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/cdk-chart-app-sample/9e4f7be203a3dc1badf0af5a7fd00b56f55a9e2d/doc/architecture.jpg -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testEnvironment: 'node', 3 | roots: ['/test'], 4 | testMatch: ['**/*.test.ts'], 5 | transform: { 6 | '^.+\\.tsx?$': 'ts-jest', 7 | }, 8 | }; 9 | -------------------------------------------------------------------------------- /lambda/metrics-handler.ts: -------------------------------------------------------------------------------- 1 | import { APIGatewayProxyHandler } from 'aws-lambda'; 2 | import { DynamoDBClient } from '@aws-sdk/client-dynamodb'; 3 | import { DynamoDBDocumentClient, paginateQuery } from '@aws-sdk/lib-dynamodb'; 4 | import { DateTime } from 'luxon'; 5 | 6 | // get table name from environment variable 7 | const TABLE_NAME = process.env.DDB_TABLE_NAME!; 8 | 9 | // keep SDK client in global scope 10 | const dynamodbClient = new DynamoDBClient({}); 11 | const documentClient = DynamoDBDocumentClient.from(dynamodbClient); 12 | 13 | // CORS headers 14 | const headers = { 15 | 'Content-Type': 'application/json', 16 | 'Access-Control-Allow-Origin': '*', 17 | }; 18 | 19 | // record struct 20 | type Metrics = { 21 | deviceId: string; 22 | timestamp: string; 23 | expiresAt: number; 24 | value: number; 25 | }; 26 | 27 | const timeFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'"; 28 | 29 | export const get: APIGatewayProxyHandler = async (event, context) => { 30 | // TODO: Validate request parameter and return 4xx if invalid 31 | 32 | // expression attribute values for DynamoDB 33 | // fetch the last 10 minutes 34 | const d = DateTime.now().toUTC(); 35 | const d_from = d.minus({ minutes: 10 }).toFormat(timeFormat); 36 | const d_to = d.toFormat(timeFormat); 37 | 38 | const paginator = await paginateQuery( 39 | { 40 | client: documentClient, 41 | pageSize: 30, 42 | }, 43 | { 44 | TableName: TABLE_NAME, 45 | KeyConditionExpression: 'deviceId = :deviceId and #t BETWEEN :from AND :to', 46 | ExpressionAttributeNames: { 47 | '#t': 'timestamp', 48 | }, 49 | 50 | ExpressionAttributeValues: { 51 | ':deviceId': event.queryStringParameters?.deviceId, 52 | ':from': d_from, 53 | ':to': d_to, 54 | }, 55 | }, 56 | ); 57 | 58 | const data = new Array(); 59 | for await (const page of paginator) { 60 | console.log(JSON.stringify({ Count: page.Count })); 61 | page.Items?.forEach((v) => { 62 | data.push(v as Metrics); 63 | }); 64 | } 65 | 66 | return { 67 | statusCode: 200, 68 | body: JSON.stringify(data), 69 | headers, 70 | }; 71 | }; 72 | -------------------------------------------------------------------------------- /lib/api-stack.ts: -------------------------------------------------------------------------------- 1 | import { CfnOutput, Duration, Stack, StackProps } from 'aws-cdk-lib'; 2 | import { Cors, LambdaIntegration, RestApi } from 'aws-cdk-lib/aws-apigateway'; 3 | import { Table } from 'aws-cdk-lib/aws-dynamodb'; 4 | import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs'; 5 | import { Construct } from 'constructs'; 6 | 7 | interface APIStackProps extends StackProps { 8 | currentTable: Table; 9 | } 10 | 11 | export class APIStack extends Stack { 12 | constructor(scope: Construct, id: string, props: APIStackProps) { 13 | super(scope, id, props); 14 | 15 | // Lambda 16 | const getMetricsHandler = new NodejsFunction(this, 'GetMetricsHandler', { 17 | entry: 'lambda/metrics-handler.ts', 18 | handler: 'get', 19 | memorySize: 256, 20 | timeout: Duration.seconds(10), 21 | environment: { 22 | DDB_TABLE_NAME: props.currentTable.tableName, 23 | }, 24 | }); 25 | 26 | props.currentTable.grantReadData(getMetricsHandler); 27 | 28 | // API Gateway 29 | const api = new RestApi(this, 'RestAPI', { 30 | deployOptions: { 31 | tracingEnabled: true, 32 | }, 33 | defaultCorsPreflightOptions: { 34 | allowOrigins: Cors.ALL_ORIGINS, 35 | allowMethods: Cors.ALL_METHODS, 36 | }, 37 | }); 38 | api.root.addResource('metrics').addMethod('GET', new LambdaIntegration(getMetricsHandler)); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/app-stage.ts: -------------------------------------------------------------------------------- 1 | import { Stage, StageProps } from 'aws-cdk-lib'; 2 | import { Construct } from 'constructs'; 3 | import { APIStack } from './api-stack'; 4 | import { BackendStack } from './backend-stack'; 5 | import { FrontendStack } from './frontend-stack'; 6 | 7 | export class AppStage extends Stage { 8 | constructor(scope: Construct, id: string, props?: StageProps) { 9 | super(scope, id, props); 10 | 11 | const backend = new BackendStack(this, `Backend`); 12 | 13 | new APIStack(this, `API`, { 14 | currentTable: backend.currentTable, 15 | }); 16 | 17 | new FrontendStack(this, `Frontend`); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/backend-stack.ts: -------------------------------------------------------------------------------- 1 | import { Stack, StackProps } from 'aws-cdk-lib'; 2 | import { AttributeType, BillingMode, Table } from 'aws-cdk-lib/aws-dynamodb'; 3 | import { 4 | Cluster, 5 | ContainerImage, 6 | CpuArchitecture, 7 | FargateService, 8 | FargateTaskDefinition, 9 | LogDrivers, 10 | OperatingSystemFamily, 11 | } from 'aws-cdk-lib/aws-ecs'; 12 | import { Construct } from 'constructs'; 13 | 14 | export class BackendStack extends Stack { 15 | public readonly currentTable: Table; 16 | 17 | constructor(scope: Construct, id: string, props?: StackProps) { 18 | super(scope, id, props); 19 | 20 | // DynamoDB 21 | const currentTable = new Table(this, 'CurrentMetrics', { 22 | partitionKey: { 23 | name: 'deviceId', 24 | type: AttributeType.STRING, 25 | }, 26 | sortKey: { 27 | name: 'timestamp', 28 | type: AttributeType.STRING, 29 | }, 30 | billingMode: BillingMode.PAY_PER_REQUEST, 31 | timeToLiveAttribute: 'expiresAt', 32 | }); 33 | this.currentTable = currentTable; 34 | 35 | // ECS 36 | const cluster = new Cluster(this, 'BackendCluster'); 37 | 38 | const taskDefinition = new FargateTaskDefinition(this, 'BackendTaskDef', { 39 | cpu: 256, 40 | memoryLimitMiB: 512, 41 | runtimePlatform: { 42 | cpuArchitecture: CpuArchitecture.ARM64, 43 | operatingSystemFamily: OperatingSystemFamily.LINUX, 44 | }, 45 | }); 46 | taskDefinition.addContainer('Recorder', { 47 | logging: LogDrivers.awsLogs({ streamPrefix: 'recorder' }), 48 | image: ContainerImage.fromAsset('container/recorder'), 49 | environment: { 50 | DDB_TABLE_NAME: currentTable.tableName, 51 | }, 52 | }); 53 | 54 | const service = new FargateService(this, 'BackendService', { 55 | cluster, 56 | taskDefinition, 57 | }); 58 | 59 | currentTable.grantWriteData(taskDefinition.taskRole); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /lib/frontend-stack.ts: -------------------------------------------------------------------------------- 1 | import { Stack, StackProps, CfnOutput, DockerImage } from 'aws-cdk-lib'; 2 | import { Construct } from 'constructs'; 3 | import * as cloudfrontS3 from '@aws-solutions-constructs/aws-cloudfront-s3'; 4 | import { BucketDeployment, Source } from 'aws-cdk-lib/aws-s3-deployment'; 5 | 6 | export class FrontendStack extends Stack { 7 | constructor(scope: Construct, id: string, props?: StackProps) { 8 | super(scope, id, props); 9 | 10 | // AWS Solutions Constructs - CloudFront + S3 11 | const { s3Bucket, cloudFrontWebDistribution } = new cloudfrontS3.CloudFrontToS3(this, 'WebAppCloudFrontS3', { 12 | insertHttpSecurityHeaders: false, 13 | }); 14 | 15 | // Deploy webapp by s3deployment 16 | new BucketDeployment(this, 'WebAppDeploy', { 17 | destinationBucket: s3Bucket!, 18 | distribution: cloudFrontWebDistribution, 19 | sources: [ 20 | // Build and deploy a React frontend app 21 | Source.asset('webapp/dashboard/build'), 22 | ], 23 | }); 24 | 25 | // create CFn output but not to be exported - website URL 26 | new CfnOutput(this, 'DistributionDomainName', { 27 | value: cloudFrontWebDistribution!.distributionDomainName, 28 | }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/pipeline-stack.ts: -------------------------------------------------------------------------------- 1 | import { pipelines, Stack, StackProps } from 'aws-cdk-lib'; 2 | import { Construct } from 'constructs'; 3 | import { AppStage } from './app-stage'; 4 | 5 | interface PipelineStackProps extends StackProps { 6 | prefix: string; 7 | repo: string; 8 | branch: string; 9 | connectionArn: string; 10 | } 11 | 12 | export class PipelineStack extends Stack { 13 | constructor(scope: Construct, id: string, props: PipelineStackProps) { 14 | super(scope, id, props); 15 | 16 | const pipeline = new pipelines.CodePipeline(this, 'Pipeline', { 17 | synth: new pipelines.ShellStep('Synth', { 18 | input: pipelines.CodePipelineSource.connection(props.repo, props.branch, { 19 | connectionArn: props.connectionArn, 20 | }), 21 | commands: ['npm ci', 'cd webapp/dashboard && npm ci && npm run build', 'cd - && npx cdk synth'], 22 | }), 23 | // See: https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.pipelines-readme.html#using-docker-in-the-pipeline 24 | // docker is required by: 25 | // * DockerImage.fromAsset() in BackendStack 26 | // * Source.asset() in FrontendStack to build react app 27 | dockerEnabledForSynth: true, 28 | }); 29 | 30 | pipeline.addStage(new AppStage(this, `${props.prefix}App`)); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cdk-chart-app-sample", 3 | "description": "A sample code implements simple web app with AWS CDK.", 4 | "version": "1.0.2", 5 | "license": "MIT-0", 6 | "private": true, 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/aws-samples/cdk-chart-app-sample.git" 10 | }, 11 | "bin": { 12 | "cdk-chart-app-sample": "bin/cdk-chart-app-sample.js" 13 | }, 14 | "scripts": { 15 | "build": "tsc", 16 | "watch": "tsc -w", 17 | "test": "jest", 18 | "cdk": "cdk", 19 | "lint": "eslint --fix .", 20 | "format": "prettier --write .", 21 | "release": "standard-version" 22 | }, 23 | "devDependencies": { 24 | "@aws-solutions-constructs/aws-cloudfront-s3": "^2.5.0", 25 | "@types/aws-lambda": "^8.10.93", 26 | "@types/jest": "^26.0.10", 27 | "@types/node": "^10.17.27", 28 | "@typescript-eslint/eslint-plugin": "^5.19.0", 29 | "@typescript-eslint/parser": "^5.19.0", 30 | "aws-cdk": "2.20.0", 31 | "aws-cdk-lib": "2.20.0", 32 | "constructs": "^10.0.0", 33 | "esbuild": "^0.14.36", 34 | "eslint": "^8.13.0", 35 | "eslint-config-prettier": "^8.5.0", 36 | "eslint-config-react-app": "^7.0.1", 37 | "eslint-plugin-react": "^7.29.4", 38 | "jest": "^26.4.2", 39 | "prettier": "^2.6.2", 40 | "source-map-support": "^0.5.16", 41 | "standard-version": "^9.5.0", 42 | "ts-jest": "^26.2.0", 43 | "ts-node": "^9.0.0", 44 | "typescript": "~3.9.7" 45 | }, 46 | "dependencies": { 47 | "@aws-sdk/client-dynamodb": "^3.351.0", 48 | "@aws-sdk/lib-dynamodb": "^3.67.0", 49 | "luxon": "^2.5.2" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /test/__snapshots__/cdk-chart-app-sample.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`PipelineStack matches snapshot 1`] = ` 4 | Object { 5 | "Parameters": Object { 6 | "BootstrapVersion": Object { 7 | "Default": "/cdk-bootstrap/hnb659fds/version", 8 | "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]", 9 | "Type": "AWS::SSM::Parameter::Value", 10 | }, 11 | }, 12 | "Resources": Object { 13 | "Pipeline9850B417": Object { 14 | "DependsOn": Array [ 15 | "PipelineRoleDefaultPolicy7BDC1ABB", 16 | "PipelineRoleB27FAA37", 17 | ], 18 | "Properties": Object { 19 | "ArtifactStore": Object { 20 | "Location": Object { 21 | "Ref": "PipelineArtifactsBucketAEA9A052", 22 | }, 23 | "Type": "S3", 24 | }, 25 | "RestartExecutionOnUpdate": true, 26 | "RoleArn": Object { 27 | "Fn::GetAtt": Array [ 28 | "PipelineRoleB27FAA37", 29 | "Arn", 30 | ], 31 | }, 32 | "Stages": Array [ 33 | Object { 34 | "Actions": Array [ 35 | Object { 36 | "ActionTypeId": Object { 37 | "Category": "Source", 38 | "Owner": "AWS", 39 | "Provider": "CodeStarSourceConnection", 40 | "Version": "1", 41 | }, 42 | "Configuration": Object { 43 | "BranchName": "main", 44 | "ConnectionArn": "arn:aws:codestar-connections:ap-northeast-1:123456789012:connection/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", 45 | "FullRepositoryId": "aws-samples/cdk-chart-app-sample", 46 | }, 47 | "Name": "aws-samples_cdk-chart-app-sample", 48 | "OutputArtifacts": Array [ 49 | Object { 50 | "Name": "aws_samples_cdk_chart_app_sample_Source", 51 | }, 52 | ], 53 | "RoleArn": Object { 54 | "Fn::GetAtt": Array [ 55 | "PipelineSourceawssamplescdkchartappsampleCodePipelineActionRoleCD4E1688", 56 | "Arn", 57 | ], 58 | }, 59 | "RunOrder": 1, 60 | }, 61 | ], 62 | "Name": "Source", 63 | }, 64 | Object { 65 | "Actions": Array [ 66 | Object { 67 | "ActionTypeId": Object { 68 | "Category": "Build", 69 | "Owner": "AWS", 70 | "Provider": "CodeBuild", 71 | "Version": "1", 72 | }, 73 | "Configuration": Object { 74 | "EnvironmentVariables": "[{\\"name\\":\\"_PROJECT_CONFIG_HASH\\",\\"type\\":\\"PLAINTEXT\\",\\"value\\":\\"164752c0495c3f49c304de0f87ea051e8ef264437b0c98d5147009588f404526\\"}]", 75 | "ProjectName": Object { 76 | "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6", 77 | }, 78 | }, 79 | "InputArtifacts": Array [ 80 | Object { 81 | "Name": "aws_samples_cdk_chart_app_sample_Source", 82 | }, 83 | ], 84 | "Name": "Synth", 85 | "OutputArtifacts": Array [ 86 | Object { 87 | "Name": "Synth_Output", 88 | }, 89 | ], 90 | "RoleArn": Object { 91 | "Fn::GetAtt": Array [ 92 | "PipelineBuildSynthCodePipelineActionRole4E7A6C97", 93 | "Arn", 94 | ], 95 | }, 96 | "RunOrder": 1, 97 | }, 98 | ], 99 | "Name": "Build", 100 | }, 101 | Object { 102 | "Actions": Array [ 103 | Object { 104 | "ActionTypeId": Object { 105 | "Category": "Build", 106 | "Owner": "AWS", 107 | "Provider": "CodeBuild", 108 | "Version": "1", 109 | }, 110 | "Configuration": Object { 111 | "EnvironmentVariables": "[{\\"name\\":\\"_PROJECT_CONFIG_HASH\\",\\"type\\":\\"PLAINTEXT\\",\\"value\\":\\"d9619ebf0d9e05cbc7286d011c7ffa34692e14aa6e2d744ee37050abbaa53aa9\\"}]", 112 | "ProjectName": Object { 113 | "Ref": "PipelineUpdatePipelineSelfMutationDAA41400", 114 | }, 115 | }, 116 | "InputArtifacts": Array [ 117 | Object { 118 | "Name": "Synth_Output", 119 | }, 120 | ], 121 | "Name": "SelfMutate", 122 | "RoleArn": Object { 123 | "Fn::GetAtt": Array [ 124 | "PipelineUpdatePipelineSelfMutateCodePipelineActionRoleD6D4E5CF", 125 | "Arn", 126 | ], 127 | }, 128 | "RunOrder": 1, 129 | }, 130 | ], 131 | "Name": "UpdatePipeline", 132 | }, 133 | Object { 134 | "Actions": Array [ 135 | Object { 136 | "ActionTypeId": Object { 137 | "Category": "Build", 138 | "Owner": "AWS", 139 | "Provider": "CodeBuild", 140 | "Version": "1", 141 | }, 142 | "Configuration": Object { 143 | "ProjectName": Object { 144 | "Ref": "PipelineAssetsDockerAsset1D66D1104", 145 | }, 146 | }, 147 | "InputArtifacts": Array [ 148 | Object { 149 | "Name": "Synth_Output", 150 | }, 151 | ], 152 | "Name": "DockerAsset1", 153 | "RoleArn": Object { 154 | "Fn::GetAtt": Array [ 155 | "PipelineAssetsDockerAsset1CodePipelineActionRole7ED54263", 156 | "Arn", 157 | ], 158 | }, 159 | "RunOrder": 1, 160 | }, 161 | Object { 162 | "ActionTypeId": Object { 163 | "Category": "Build", 164 | "Owner": "AWS", 165 | "Provider": "CodeBuild", 166 | "Version": "1", 167 | }, 168 | "Configuration": Object { 169 | "ProjectName": Object { 170 | "Ref": "PipelineAssetsFileAsset185A67CB4", 171 | }, 172 | }, 173 | "InputArtifacts": Array [ 174 | Object { 175 | "Name": "Synth_Output", 176 | }, 177 | ], 178 | "Name": "FileAsset1", 179 | "RoleArn": Object { 180 | "Fn::GetAtt": Array [ 181 | "PipelineAssetsFileAsset1CodePipelineActionRoleC0EC649A", 182 | "Arn", 183 | ], 184 | }, 185 | "RunOrder": 1, 186 | }, 187 | Object { 188 | "ActionTypeId": Object { 189 | "Category": "Build", 190 | "Owner": "AWS", 191 | "Provider": "CodeBuild", 192 | "Version": "1", 193 | }, 194 | "Configuration": Object { 195 | "ProjectName": Object { 196 | "Ref": "PipelineAssetsFileAsset24D2D639B", 197 | }, 198 | }, 199 | "InputArtifacts": Array [ 200 | Object { 201 | "Name": "Synth_Output", 202 | }, 203 | ], 204 | "Name": "FileAsset2", 205 | "RoleArn": Object { 206 | "Fn::GetAtt": Array [ 207 | "PipelineAssetsFileAsset2CodePipelineActionRole06965A59", 208 | "Arn", 209 | ], 210 | }, 211 | "RunOrder": 1, 212 | }, 213 | Object { 214 | "ActionTypeId": Object { 215 | "Category": "Build", 216 | "Owner": "AWS", 217 | "Provider": "CodeBuild", 218 | "Version": "1", 219 | }, 220 | "Configuration": Object { 221 | "ProjectName": Object { 222 | "Ref": "PipelineAssetsFileAsset3FE71B523", 223 | }, 224 | }, 225 | "InputArtifacts": Array [ 226 | Object { 227 | "Name": "Synth_Output", 228 | }, 229 | ], 230 | "Name": "FileAsset3", 231 | "RoleArn": Object { 232 | "Fn::GetAtt": Array [ 233 | "PipelineAssetsFileAsset3CodePipelineActionRole99229BA9", 234 | "Arn", 235 | ], 236 | }, 237 | "RunOrder": 1, 238 | }, 239 | Object { 240 | "ActionTypeId": Object { 241 | "Category": "Build", 242 | "Owner": "AWS", 243 | "Provider": "CodeBuild", 244 | "Version": "1", 245 | }, 246 | "Configuration": Object { 247 | "ProjectName": Object { 248 | "Ref": "PipelineAssetsFileAsset474303B7D", 249 | }, 250 | }, 251 | "InputArtifacts": Array [ 252 | Object { 253 | "Name": "Synth_Output", 254 | }, 255 | ], 256 | "Name": "FileAsset4", 257 | "RoleArn": Object { 258 | "Fn::GetAtt": Array [ 259 | "PipelineAssetsFileAsset4CodePipelineActionRole492E1DB6", 260 | "Arn", 261 | ], 262 | }, 263 | "RunOrder": 1, 264 | }, 265 | ], 266 | "Name": "Assets", 267 | }, 268 | Object { 269 | "Actions": Array [ 270 | Object { 271 | "ActionTypeId": Object { 272 | "Category": "Deploy", 273 | "Owner": "AWS", 274 | "Provider": "CloudFormation", 275 | "Version": "1", 276 | }, 277 | "Configuration": Object { 278 | "ActionMode": "CHANGE_SET_REPLACE", 279 | "Capabilities": "CAPABILITY_NAMED_IAM,CAPABILITY_AUTO_EXPAND", 280 | "ChangeSetName": "PipelineChange", 281 | "RoleArn": Object { 282 | "Fn::Join": Array [ 283 | "", 284 | Array [ 285 | "arn:", 286 | Object { 287 | "Ref": "AWS::Partition", 288 | }, 289 | ":iam::", 290 | Object { 291 | "Ref": "AWS::AccountId", 292 | }, 293 | ":role/cdk-hnb659fds-cfn-exec-role-", 294 | Object { 295 | "Ref": "AWS::AccountId", 296 | }, 297 | "-", 298 | Object { 299 | "Ref": "AWS::Region", 300 | }, 301 | ], 302 | ], 303 | }, 304 | "StackName": "SummitApp-Backend", 305 | "TemplatePath": "Synth_Output::assembly-Pipeline-SummitApp/PipelineSummitAppBackendED3A4860.template.json", 306 | }, 307 | "InputArtifacts": Array [ 308 | Object { 309 | "Name": "Synth_Output", 310 | }, 311 | ], 312 | "Name": "Backend.Prepare", 313 | "RoleArn": Object { 314 | "Fn::Join": Array [ 315 | "", 316 | Array [ 317 | "arn:", 318 | Object { 319 | "Ref": "AWS::Partition", 320 | }, 321 | ":iam::", 322 | Object { 323 | "Ref": "AWS::AccountId", 324 | }, 325 | ":role/cdk-hnb659fds-deploy-role-", 326 | Object { 327 | "Ref": "AWS::AccountId", 328 | }, 329 | "-", 330 | Object { 331 | "Ref": "AWS::Region", 332 | }, 333 | ], 334 | ], 335 | }, 336 | "RunOrder": 1, 337 | }, 338 | Object { 339 | "ActionTypeId": Object { 340 | "Category": "Deploy", 341 | "Owner": "AWS", 342 | "Provider": "CloudFormation", 343 | "Version": "1", 344 | }, 345 | "Configuration": Object { 346 | "ActionMode": "CHANGE_SET_REPLACE", 347 | "Capabilities": "CAPABILITY_NAMED_IAM,CAPABILITY_AUTO_EXPAND", 348 | "ChangeSetName": "PipelineChange", 349 | "RoleArn": Object { 350 | "Fn::Join": Array [ 351 | "", 352 | Array [ 353 | "arn:", 354 | Object { 355 | "Ref": "AWS::Partition", 356 | }, 357 | ":iam::", 358 | Object { 359 | "Ref": "AWS::AccountId", 360 | }, 361 | ":role/cdk-hnb659fds-cfn-exec-role-", 362 | Object { 363 | "Ref": "AWS::AccountId", 364 | }, 365 | "-", 366 | Object { 367 | "Ref": "AWS::Region", 368 | }, 369 | ], 370 | ], 371 | }, 372 | "StackName": "SummitApp-Frontend", 373 | "TemplatePath": "Synth_Output::assembly-Pipeline-SummitApp/PipelineSummitAppFrontend33FDE9E0.template.json", 374 | }, 375 | "InputArtifacts": Array [ 376 | Object { 377 | "Name": "Synth_Output", 378 | }, 379 | ], 380 | "Name": "Frontend.Prepare", 381 | "RoleArn": Object { 382 | "Fn::Join": Array [ 383 | "", 384 | Array [ 385 | "arn:", 386 | Object { 387 | "Ref": "AWS::Partition", 388 | }, 389 | ":iam::", 390 | Object { 391 | "Ref": "AWS::AccountId", 392 | }, 393 | ":role/cdk-hnb659fds-deploy-role-", 394 | Object { 395 | "Ref": "AWS::AccountId", 396 | }, 397 | "-", 398 | Object { 399 | "Ref": "AWS::Region", 400 | }, 401 | ], 402 | ], 403 | }, 404 | "RunOrder": 1, 405 | }, 406 | Object { 407 | "ActionTypeId": Object { 408 | "Category": "Deploy", 409 | "Owner": "AWS", 410 | "Provider": "CloudFormation", 411 | "Version": "1", 412 | }, 413 | "Configuration": Object { 414 | "ActionMode": "CHANGE_SET_EXECUTE", 415 | "ChangeSetName": "PipelineChange", 416 | "StackName": "SummitApp-Backend", 417 | }, 418 | "Name": "Backend.Deploy", 419 | "RoleArn": Object { 420 | "Fn::Join": Array [ 421 | "", 422 | Array [ 423 | "arn:", 424 | Object { 425 | "Ref": "AWS::Partition", 426 | }, 427 | ":iam::", 428 | Object { 429 | "Ref": "AWS::AccountId", 430 | }, 431 | ":role/cdk-hnb659fds-deploy-role-", 432 | Object { 433 | "Ref": "AWS::AccountId", 434 | }, 435 | "-", 436 | Object { 437 | "Ref": "AWS::Region", 438 | }, 439 | ], 440 | ], 441 | }, 442 | "RunOrder": 2, 443 | }, 444 | Object { 445 | "ActionTypeId": Object { 446 | "Category": "Deploy", 447 | "Owner": "AWS", 448 | "Provider": "CloudFormation", 449 | "Version": "1", 450 | }, 451 | "Configuration": Object { 452 | "ActionMode": "CHANGE_SET_EXECUTE", 453 | "ChangeSetName": "PipelineChange", 454 | "StackName": "SummitApp-Frontend", 455 | }, 456 | "Name": "Frontend.Deploy", 457 | "RoleArn": Object { 458 | "Fn::Join": Array [ 459 | "", 460 | Array [ 461 | "arn:", 462 | Object { 463 | "Ref": "AWS::Partition", 464 | }, 465 | ":iam::", 466 | Object { 467 | "Ref": "AWS::AccountId", 468 | }, 469 | ":role/cdk-hnb659fds-deploy-role-", 470 | Object { 471 | "Ref": "AWS::AccountId", 472 | }, 473 | "-", 474 | Object { 475 | "Ref": "AWS::Region", 476 | }, 477 | ], 478 | ], 479 | }, 480 | "RunOrder": 2, 481 | }, 482 | Object { 483 | "ActionTypeId": Object { 484 | "Category": "Deploy", 485 | "Owner": "AWS", 486 | "Provider": "CloudFormation", 487 | "Version": "1", 488 | }, 489 | "Configuration": Object { 490 | "ActionMode": "CHANGE_SET_REPLACE", 491 | "Capabilities": "CAPABILITY_NAMED_IAM,CAPABILITY_AUTO_EXPAND", 492 | "ChangeSetName": "PipelineChange", 493 | "RoleArn": Object { 494 | "Fn::Join": Array [ 495 | "", 496 | Array [ 497 | "arn:", 498 | Object { 499 | "Ref": "AWS::Partition", 500 | }, 501 | ":iam::", 502 | Object { 503 | "Ref": "AWS::AccountId", 504 | }, 505 | ":role/cdk-hnb659fds-cfn-exec-role-", 506 | Object { 507 | "Ref": "AWS::AccountId", 508 | }, 509 | "-", 510 | Object { 511 | "Ref": "AWS::Region", 512 | }, 513 | ], 514 | ], 515 | }, 516 | "StackName": "SummitApp-API", 517 | "TemplatePath": "Synth_Output::assembly-Pipeline-SummitApp/PipelineSummitAppAPI91B89E1B.template.json", 518 | }, 519 | "InputArtifacts": Array [ 520 | Object { 521 | "Name": "Synth_Output", 522 | }, 523 | ], 524 | "Name": "API.Prepare", 525 | "RoleArn": Object { 526 | "Fn::Join": Array [ 527 | "", 528 | Array [ 529 | "arn:", 530 | Object { 531 | "Ref": "AWS::Partition", 532 | }, 533 | ":iam::", 534 | Object { 535 | "Ref": "AWS::AccountId", 536 | }, 537 | ":role/cdk-hnb659fds-deploy-role-", 538 | Object { 539 | "Ref": "AWS::AccountId", 540 | }, 541 | "-", 542 | Object { 543 | "Ref": "AWS::Region", 544 | }, 545 | ], 546 | ], 547 | }, 548 | "RunOrder": 3, 549 | }, 550 | Object { 551 | "ActionTypeId": Object { 552 | "Category": "Deploy", 553 | "Owner": "AWS", 554 | "Provider": "CloudFormation", 555 | "Version": "1", 556 | }, 557 | "Configuration": Object { 558 | "ActionMode": "CHANGE_SET_EXECUTE", 559 | "ChangeSetName": "PipelineChange", 560 | "StackName": "SummitApp-API", 561 | }, 562 | "Name": "API.Deploy", 563 | "RoleArn": Object { 564 | "Fn::Join": Array [ 565 | "", 566 | Array [ 567 | "arn:", 568 | Object { 569 | "Ref": "AWS::Partition", 570 | }, 571 | ":iam::", 572 | Object { 573 | "Ref": "AWS::AccountId", 574 | }, 575 | ":role/cdk-hnb659fds-deploy-role-", 576 | Object { 577 | "Ref": "AWS::AccountId", 578 | }, 579 | "-", 580 | Object { 581 | "Ref": "AWS::Region", 582 | }, 583 | ], 584 | ], 585 | }, 586 | "RunOrder": 4, 587 | }, 588 | ], 589 | "Name": "SummitApp", 590 | }, 591 | ], 592 | }, 593 | "Type": "AWS::CodePipeline::Pipeline", 594 | }, 595 | "PipelineArtifactsBucketAEA9A052": Object { 596 | "DeletionPolicy": "Retain", 597 | "Properties": Object { 598 | "BucketEncryption": Object { 599 | "ServerSideEncryptionConfiguration": Array [ 600 | Object { 601 | "ServerSideEncryptionByDefault": Object { 602 | "SSEAlgorithm": "aws:kms", 603 | }, 604 | }, 605 | ], 606 | }, 607 | "PublicAccessBlockConfiguration": Object { 608 | "BlockPublicAcls": true, 609 | "BlockPublicPolicy": true, 610 | "IgnorePublicAcls": true, 611 | "RestrictPublicBuckets": true, 612 | }, 613 | }, 614 | "Type": "AWS::S3::Bucket", 615 | "UpdateReplacePolicy": "Retain", 616 | }, 617 | "PipelineArtifactsBucketPolicyF53CCC52": Object { 618 | "Properties": Object { 619 | "Bucket": Object { 620 | "Ref": "PipelineArtifactsBucketAEA9A052", 621 | }, 622 | "PolicyDocument": Object { 623 | "Statement": Array [ 624 | Object { 625 | "Action": "s3:*", 626 | "Condition": Object { 627 | "Bool": Object { 628 | "aws:SecureTransport": "false", 629 | }, 630 | }, 631 | "Effect": "Deny", 632 | "Principal": Object { 633 | "AWS": "*", 634 | }, 635 | "Resource": Array [ 636 | Object { 637 | "Fn::GetAtt": Array [ 638 | "PipelineArtifactsBucketAEA9A052", 639 | "Arn", 640 | ], 641 | }, 642 | Object { 643 | "Fn::Join": Array [ 644 | "", 645 | Array [ 646 | Object { 647 | "Fn::GetAtt": Array [ 648 | "PipelineArtifactsBucketAEA9A052", 649 | "Arn", 650 | ], 651 | }, 652 | "/*", 653 | ], 654 | ], 655 | }, 656 | ], 657 | }, 658 | Object { 659 | "Action": Array [ 660 | "s3:GetObject*", 661 | "s3:GetBucket*", 662 | "s3:List*", 663 | ], 664 | "Effect": "Allow", 665 | "Principal": Object { 666 | "AWS": Object { 667 | "Fn::Join": Array [ 668 | "", 669 | Array [ 670 | "arn:", 671 | Object { 672 | "Ref": "AWS::Partition", 673 | }, 674 | ":iam::", 675 | Object { 676 | "Ref": "AWS::AccountId", 677 | }, 678 | ":role/cdk-hnb659fds-deploy-role-", 679 | Object { 680 | "Ref": "AWS::AccountId", 681 | }, 682 | "-", 683 | Object { 684 | "Ref": "AWS::Region", 685 | }, 686 | ], 687 | ], 688 | }, 689 | }, 690 | "Resource": Array [ 691 | Object { 692 | "Fn::GetAtt": Array [ 693 | "PipelineArtifactsBucketAEA9A052", 694 | "Arn", 695 | ], 696 | }, 697 | Object { 698 | "Fn::Join": Array [ 699 | "", 700 | Array [ 701 | Object { 702 | "Fn::GetAtt": Array [ 703 | "PipelineArtifactsBucketAEA9A052", 704 | "Arn", 705 | ], 706 | }, 707 | "/*", 708 | ], 709 | ], 710 | }, 711 | ], 712 | }, 713 | ], 714 | "Version": "2012-10-17", 715 | }, 716 | }, 717 | "Type": "AWS::S3::BucketPolicy", 718 | }, 719 | "PipelineAssetsDockerAsset1CodePipelineActionRole7ED54263": Object { 720 | "Properties": Object { 721 | "AssumeRolePolicyDocument": Object { 722 | "Statement": Array [ 723 | Object { 724 | "Action": "sts:AssumeRole", 725 | "Effect": "Allow", 726 | "Principal": Object { 727 | "AWS": Object { 728 | "Fn::Join": Array [ 729 | "", 730 | Array [ 731 | "arn:", 732 | Object { 733 | "Ref": "AWS::Partition", 734 | }, 735 | ":iam::", 736 | Object { 737 | "Ref": "AWS::AccountId", 738 | }, 739 | ":root", 740 | ], 741 | ], 742 | }, 743 | }, 744 | }, 745 | ], 746 | "Version": "2012-10-17", 747 | }, 748 | }, 749 | "Type": "AWS::IAM::Role", 750 | }, 751 | "PipelineAssetsDockerAsset1CodePipelineActionRoleDefaultPolicy023CD59D": Object { 752 | "Properties": Object { 753 | "PolicyDocument": Object { 754 | "Statement": Array [ 755 | Object { 756 | "Action": Array [ 757 | "codebuild:BatchGetBuilds", 758 | "codebuild:StartBuild", 759 | "codebuild:StopBuild", 760 | ], 761 | "Effect": "Allow", 762 | "Resource": Object { 763 | "Fn::GetAtt": Array [ 764 | "PipelineAssetsDockerAsset1D66D1104", 765 | "Arn", 766 | ], 767 | }, 768 | }, 769 | ], 770 | "Version": "2012-10-17", 771 | }, 772 | "PolicyName": "PipelineAssetsDockerAsset1CodePipelineActionRoleDefaultPolicy023CD59D", 773 | "Roles": Array [ 774 | Object { 775 | "Ref": "PipelineAssetsDockerAsset1CodePipelineActionRole7ED54263", 776 | }, 777 | ], 778 | }, 779 | "Type": "AWS::IAM::Policy", 780 | }, 781 | "PipelineAssetsDockerAsset1D66D1104": Object { 782 | "Properties": Object { 783 | "Artifacts": Object { 784 | "Type": "CODEPIPELINE", 785 | }, 786 | "Cache": Object { 787 | "Type": "NO_CACHE", 788 | }, 789 | "Description": "Pipeline step Pipeline/Pipeline/Assets/DockerAsset1", 790 | "EncryptionKey": "alias/aws/s3", 791 | "Environment": Object { 792 | "ComputeType": "BUILD_GENERAL1_SMALL", 793 | "Image": "aws/codebuild/standard:5.0", 794 | "ImagePullCredentialsType": "CODEBUILD", 795 | "PrivilegedMode": true, 796 | "Type": "LINUX_CONTAINER", 797 | }, 798 | "ServiceRole": Object { 799 | "Fn::GetAtt": Array [ 800 | "PipelineAssetsDockerRole8BB4542E", 801 | "Arn", 802 | ], 803 | }, 804 | "Source": Object { 805 | "BuildSpec": "{ 806 | \\"version\\": \\"0.2\\", 807 | \\"phases\\": { 808 | \\"install\\": { 809 | \\"commands\\": [ 810 | \\"npm install -g cdk-assets@2\\" 811 | ] 812 | }, 813 | \\"build\\": { 814 | \\"commands\\": [ 815 | \\"cdk-assets --path \\\\\\"assembly-Pipeline-SummitApp/PipelineSummitAppBackendED3A4860.assets.json\\\\\\" --verbose publish \\\\\\"e2bad898212b9aa33917a6664214eaf1faf4f1bcd7c5cdbad4e7aac92448eed3:current_account-current_region\\\\\\"\\" 816 | ] 817 | } 818 | } 819 | }", 820 | "Type": "CODEPIPELINE", 821 | }, 822 | }, 823 | "Type": "AWS::CodeBuild::Project", 824 | }, 825 | "PipelineAssetsDockerRole8BB4542E": Object { 826 | "Properties": Object { 827 | "AssumeRolePolicyDocument": Object { 828 | "Statement": Array [ 829 | Object { 830 | "Action": "sts:AssumeRole", 831 | "Effect": "Allow", 832 | "Principal": Object { 833 | "Service": "codebuild.amazonaws.com", 834 | }, 835 | }, 836 | Object { 837 | "Action": "sts:AssumeRole", 838 | "Effect": "Allow", 839 | "Principal": Object { 840 | "AWS": Object { 841 | "Fn::Join": Array [ 842 | "", 843 | Array [ 844 | "arn:", 845 | Object { 846 | "Ref": "AWS::Partition", 847 | }, 848 | ":iam::", 849 | Object { 850 | "Ref": "AWS::AccountId", 851 | }, 852 | ":root", 853 | ], 854 | ], 855 | }, 856 | }, 857 | }, 858 | ], 859 | "Version": "2012-10-17", 860 | }, 861 | }, 862 | "Type": "AWS::IAM::Role", 863 | }, 864 | "PipelineAssetsDockerRoleDefaultPolicy8B63511D": Object { 865 | "Properties": Object { 866 | "PolicyDocument": Object { 867 | "Statement": Array [ 868 | Object { 869 | "Action": Array [ 870 | "logs:CreateLogGroup", 871 | "logs:CreateLogStream", 872 | "logs:PutLogEvents", 873 | ], 874 | "Effect": "Allow", 875 | "Resource": Object { 876 | "Fn::Join": Array [ 877 | "", 878 | Array [ 879 | "arn:", 880 | Object { 881 | "Ref": "AWS::Partition", 882 | }, 883 | ":logs:", 884 | Object { 885 | "Ref": "AWS::Region", 886 | }, 887 | ":", 888 | Object { 889 | "Ref": "AWS::AccountId", 890 | }, 891 | ":log-group:/aws/codebuild/*", 892 | ], 893 | ], 894 | }, 895 | }, 896 | Object { 897 | "Action": Array [ 898 | "codebuild:CreateReportGroup", 899 | "codebuild:CreateReport", 900 | "codebuild:UpdateReport", 901 | "codebuild:BatchPutTestCases", 902 | "codebuild:BatchPutCodeCoverages", 903 | ], 904 | "Effect": "Allow", 905 | "Resource": Object { 906 | "Fn::Join": Array [ 907 | "", 908 | Array [ 909 | "arn:", 910 | Object { 911 | "Ref": "AWS::Partition", 912 | }, 913 | ":codebuild:", 914 | Object { 915 | "Ref": "AWS::Region", 916 | }, 917 | ":", 918 | Object { 919 | "Ref": "AWS::AccountId", 920 | }, 921 | ":report-group/*", 922 | ], 923 | ], 924 | }, 925 | }, 926 | Object { 927 | "Action": Array [ 928 | "codebuild:BatchGetBuilds", 929 | "codebuild:StartBuild", 930 | "codebuild:StopBuild", 931 | ], 932 | "Effect": "Allow", 933 | "Resource": "*", 934 | }, 935 | Object { 936 | "Action": "sts:AssumeRole", 937 | "Effect": "Allow", 938 | "Resource": Array [ 939 | Object { 940 | "Fn::Sub": "arn:\${AWS::Partition}:iam::\${AWS::AccountId}:role/cdk-hnb659fds-image-publishing-role-\${AWS::AccountId}-\${AWS::Region}", 941 | }, 942 | ], 943 | }, 944 | Object { 945 | "Action": Array [ 946 | "s3:GetObject*", 947 | "s3:GetBucket*", 948 | "s3:List*", 949 | ], 950 | "Effect": "Allow", 951 | "Resource": Array [ 952 | Object { 953 | "Fn::GetAtt": Array [ 954 | "PipelineArtifactsBucketAEA9A052", 955 | "Arn", 956 | ], 957 | }, 958 | Object { 959 | "Fn::Join": Array [ 960 | "", 961 | Array [ 962 | Object { 963 | "Fn::GetAtt": Array [ 964 | "PipelineArtifactsBucketAEA9A052", 965 | "Arn", 966 | ], 967 | }, 968 | "/*", 969 | ], 970 | ], 971 | }, 972 | ], 973 | }, 974 | ], 975 | "Version": "2012-10-17", 976 | }, 977 | "PolicyName": "PipelineAssetsDockerRoleDefaultPolicy8B63511D", 978 | "Roles": Array [ 979 | Object { 980 | "Ref": "PipelineAssetsDockerRole8BB4542E", 981 | }, 982 | ], 983 | }, 984 | "Type": "AWS::IAM::Policy", 985 | }, 986 | "PipelineAssetsFileAsset185A67CB4": Object { 987 | "Properties": Object { 988 | "Artifacts": Object { 989 | "Type": "CODEPIPELINE", 990 | }, 991 | "Cache": Object { 992 | "Type": "NO_CACHE", 993 | }, 994 | "Description": "Pipeline step Pipeline/Pipeline/Assets/FileAsset1", 995 | "EncryptionKey": "alias/aws/s3", 996 | "Environment": Object { 997 | "ComputeType": "BUILD_GENERAL1_SMALL", 998 | "Image": "aws/codebuild/standard:5.0", 999 | "ImagePullCredentialsType": "CODEBUILD", 1000 | "PrivilegedMode": false, 1001 | "Type": "LINUX_CONTAINER", 1002 | }, 1003 | "ServiceRole": Object { 1004 | "Fn::GetAtt": Array [ 1005 | "PipelineAssetsFileRole59943A77", 1006 | "Arn", 1007 | ], 1008 | }, 1009 | "Source": Object { 1010 | "BuildSpec": "{ 1011 | \\"version\\": \\"0.2\\", 1012 | \\"phases\\": { 1013 | \\"install\\": { 1014 | \\"commands\\": [ 1015 | \\"npm install -g cdk-assets@2\\" 1016 | ] 1017 | }, 1018 | \\"build\\": { 1019 | \\"commands\\": [ 1020 | \\"cdk-assets --path \\\\\\"assembly-Pipeline-SummitApp/PipelineSummitAppFrontend33FDE9E0.assets.json\\\\\\" --verbose publish \\\\\\"92c405c4551a308bcdd55823f8b16268bd3c38fd2a011edaaf3ed72a80f557c4:current_account-current_region\\\\\\"\\" 1021 | ] 1022 | } 1023 | } 1024 | }", 1025 | "Type": "CODEPIPELINE", 1026 | }, 1027 | }, 1028 | "Type": "AWS::CodeBuild::Project", 1029 | }, 1030 | "PipelineAssetsFileAsset1CodePipelineActionRoleC0EC649A": Object { 1031 | "Properties": Object { 1032 | "AssumeRolePolicyDocument": Object { 1033 | "Statement": Array [ 1034 | Object { 1035 | "Action": "sts:AssumeRole", 1036 | "Effect": "Allow", 1037 | "Principal": Object { 1038 | "AWS": Object { 1039 | "Fn::Join": Array [ 1040 | "", 1041 | Array [ 1042 | "arn:", 1043 | Object { 1044 | "Ref": "AWS::Partition", 1045 | }, 1046 | ":iam::", 1047 | Object { 1048 | "Ref": "AWS::AccountId", 1049 | }, 1050 | ":root", 1051 | ], 1052 | ], 1053 | }, 1054 | }, 1055 | }, 1056 | ], 1057 | "Version": "2012-10-17", 1058 | }, 1059 | }, 1060 | "Type": "AWS::IAM::Role", 1061 | }, 1062 | "PipelineAssetsFileAsset1CodePipelineActionRoleDefaultPolicy5F0BE7E8": Object { 1063 | "Properties": Object { 1064 | "PolicyDocument": Object { 1065 | "Statement": Array [ 1066 | Object { 1067 | "Action": Array [ 1068 | "codebuild:BatchGetBuilds", 1069 | "codebuild:StartBuild", 1070 | "codebuild:StopBuild", 1071 | ], 1072 | "Effect": "Allow", 1073 | "Resource": Object { 1074 | "Fn::GetAtt": Array [ 1075 | "PipelineAssetsFileAsset185A67CB4", 1076 | "Arn", 1077 | ], 1078 | }, 1079 | }, 1080 | ], 1081 | "Version": "2012-10-17", 1082 | }, 1083 | "PolicyName": "PipelineAssetsFileAsset1CodePipelineActionRoleDefaultPolicy5F0BE7E8", 1084 | "Roles": Array [ 1085 | Object { 1086 | "Ref": "PipelineAssetsFileAsset1CodePipelineActionRoleC0EC649A", 1087 | }, 1088 | ], 1089 | }, 1090 | "Type": "AWS::IAM::Policy", 1091 | }, 1092 | "PipelineAssetsFileAsset24D2D639B": Object { 1093 | "Properties": Object { 1094 | "Artifacts": Object { 1095 | "Type": "CODEPIPELINE", 1096 | }, 1097 | "Cache": Object { 1098 | "Type": "NO_CACHE", 1099 | }, 1100 | "Description": "Pipeline step Pipeline/Pipeline/Assets/FileAsset2", 1101 | "EncryptionKey": "alias/aws/s3", 1102 | "Environment": Object { 1103 | "ComputeType": "BUILD_GENERAL1_SMALL", 1104 | "Image": "aws/codebuild/standard:5.0", 1105 | "ImagePullCredentialsType": "CODEBUILD", 1106 | "PrivilegedMode": false, 1107 | "Type": "LINUX_CONTAINER", 1108 | }, 1109 | "ServiceRole": Object { 1110 | "Fn::GetAtt": Array [ 1111 | "PipelineAssetsFileRole59943A77", 1112 | "Arn", 1113 | ], 1114 | }, 1115 | "Source": Object { 1116 | "BuildSpec": "{ 1117 | \\"version\\": \\"0.2\\", 1118 | \\"phases\\": { 1119 | \\"install\\": { 1120 | \\"commands\\": [ 1121 | \\"npm install -g cdk-assets@2\\" 1122 | ] 1123 | }, 1124 | \\"build\\": { 1125 | \\"commands\\": [ 1126 | \\"cdk-assets --path \\\\\\"assembly-Pipeline-SummitApp/PipelineSummitAppFrontend33FDE9E0.assets.json\\\\\\" --verbose publish \\\\\\"f98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711da:current_account-current_region\\\\\\"\\" 1127 | ] 1128 | } 1129 | } 1130 | }", 1131 | "Type": "CODEPIPELINE", 1132 | }, 1133 | }, 1134 | "Type": "AWS::CodeBuild::Project", 1135 | }, 1136 | "PipelineAssetsFileAsset2CodePipelineActionRole06965A59": Object { 1137 | "Properties": Object { 1138 | "AssumeRolePolicyDocument": Object { 1139 | "Statement": Array [ 1140 | Object { 1141 | "Action": "sts:AssumeRole", 1142 | "Effect": "Allow", 1143 | "Principal": Object { 1144 | "AWS": Object { 1145 | "Fn::Join": Array [ 1146 | "", 1147 | Array [ 1148 | "arn:", 1149 | Object { 1150 | "Ref": "AWS::Partition", 1151 | }, 1152 | ":iam::", 1153 | Object { 1154 | "Ref": "AWS::AccountId", 1155 | }, 1156 | ":root", 1157 | ], 1158 | ], 1159 | }, 1160 | }, 1161 | }, 1162 | ], 1163 | "Version": "2012-10-17", 1164 | }, 1165 | }, 1166 | "Type": "AWS::IAM::Role", 1167 | }, 1168 | "PipelineAssetsFileAsset2CodePipelineActionRoleDefaultPolicy2399F4BC": Object { 1169 | "Properties": Object { 1170 | "PolicyDocument": Object { 1171 | "Statement": Array [ 1172 | Object { 1173 | "Action": Array [ 1174 | "codebuild:BatchGetBuilds", 1175 | "codebuild:StartBuild", 1176 | "codebuild:StopBuild", 1177 | ], 1178 | "Effect": "Allow", 1179 | "Resource": Object { 1180 | "Fn::GetAtt": Array [ 1181 | "PipelineAssetsFileAsset24D2D639B", 1182 | "Arn", 1183 | ], 1184 | }, 1185 | }, 1186 | ], 1187 | "Version": "2012-10-17", 1188 | }, 1189 | "PolicyName": "PipelineAssetsFileAsset2CodePipelineActionRoleDefaultPolicy2399F4BC", 1190 | "Roles": Array [ 1191 | Object { 1192 | "Ref": "PipelineAssetsFileAsset2CodePipelineActionRole06965A59", 1193 | }, 1194 | ], 1195 | }, 1196 | "Type": "AWS::IAM::Policy", 1197 | }, 1198 | "PipelineAssetsFileAsset3CodePipelineActionRole99229BA9": Object { 1199 | "Properties": Object { 1200 | "AssumeRolePolicyDocument": Object { 1201 | "Statement": Array [ 1202 | Object { 1203 | "Action": "sts:AssumeRole", 1204 | "Effect": "Allow", 1205 | "Principal": Object { 1206 | "AWS": Object { 1207 | "Fn::Join": Array [ 1208 | "", 1209 | Array [ 1210 | "arn:", 1211 | Object { 1212 | "Ref": "AWS::Partition", 1213 | }, 1214 | ":iam::", 1215 | Object { 1216 | "Ref": "AWS::AccountId", 1217 | }, 1218 | ":root", 1219 | ], 1220 | ], 1221 | }, 1222 | }, 1223 | }, 1224 | ], 1225 | "Version": "2012-10-17", 1226 | }, 1227 | }, 1228 | "Type": "AWS::IAM::Role", 1229 | }, 1230 | "PipelineAssetsFileAsset3CodePipelineActionRoleDefaultPolicy5C399808": Object { 1231 | "Properties": Object { 1232 | "PolicyDocument": Object { 1233 | "Statement": Array [ 1234 | Object { 1235 | "Action": Array [ 1236 | "codebuild:BatchGetBuilds", 1237 | "codebuild:StartBuild", 1238 | "codebuild:StopBuild", 1239 | ], 1240 | "Effect": "Allow", 1241 | "Resource": Object { 1242 | "Fn::GetAtt": Array [ 1243 | "PipelineAssetsFileAsset3FE71B523", 1244 | "Arn", 1245 | ], 1246 | }, 1247 | }, 1248 | ], 1249 | "Version": "2012-10-17", 1250 | }, 1251 | "PolicyName": "PipelineAssetsFileAsset3CodePipelineActionRoleDefaultPolicy5C399808", 1252 | "Roles": Array [ 1253 | Object { 1254 | "Ref": "PipelineAssetsFileAsset3CodePipelineActionRole99229BA9", 1255 | }, 1256 | ], 1257 | }, 1258 | "Type": "AWS::IAM::Policy", 1259 | }, 1260 | "PipelineAssetsFileAsset3FE71B523": Object { 1261 | "Properties": Object { 1262 | "Artifacts": Object { 1263 | "Type": "CODEPIPELINE", 1264 | }, 1265 | "Cache": Object { 1266 | "Type": "NO_CACHE", 1267 | }, 1268 | "Description": "Pipeline step Pipeline/Pipeline/Assets/FileAsset3", 1269 | "EncryptionKey": "alias/aws/s3", 1270 | "Environment": Object { 1271 | "ComputeType": "BUILD_GENERAL1_SMALL", 1272 | "Image": "aws/codebuild/standard:5.0", 1273 | "ImagePullCredentialsType": "CODEBUILD", 1274 | "PrivilegedMode": false, 1275 | "Type": "LINUX_CONTAINER", 1276 | }, 1277 | "ServiceRole": Object { 1278 | "Fn::GetAtt": Array [ 1279 | "PipelineAssetsFileRole59943A77", 1280 | "Arn", 1281 | ], 1282 | }, 1283 | "Source": Object { 1284 | "BuildSpec": "{ 1285 | \\"version\\": \\"0.2\\", 1286 | \\"phases\\": { 1287 | \\"install\\": { 1288 | \\"commands\\": [ 1289 | \\"npm install -g cdk-assets@2\\" 1290 | ] 1291 | }, 1292 | \\"build\\": { 1293 | \\"commands\\": [ 1294 | \\"cdk-assets --path \\\\\\"assembly-Pipeline-SummitApp/PipelineSummitAppFrontend33FDE9E0.assets.json\\\\\\" --verbose publish \\\\\\"86de1795a40d81a3e75be6193d6b6b11b240488a95bd2618eb233ac7cddd9ee5:current_account-current_region\\\\\\"\\" 1295 | ] 1296 | } 1297 | } 1298 | }", 1299 | "Type": "CODEPIPELINE", 1300 | }, 1301 | }, 1302 | "Type": "AWS::CodeBuild::Project", 1303 | }, 1304 | "PipelineAssetsFileAsset474303B7D": Object { 1305 | "Properties": Object { 1306 | "Artifacts": Object { 1307 | "Type": "CODEPIPELINE", 1308 | }, 1309 | "Cache": Object { 1310 | "Type": "NO_CACHE", 1311 | }, 1312 | "Description": "Pipeline step Pipeline/Pipeline/Assets/FileAsset4", 1313 | "EncryptionKey": "alias/aws/s3", 1314 | "Environment": Object { 1315 | "ComputeType": "BUILD_GENERAL1_SMALL", 1316 | "Image": "aws/codebuild/standard:5.0", 1317 | "ImagePullCredentialsType": "CODEBUILD", 1318 | "PrivilegedMode": false, 1319 | "Type": "LINUX_CONTAINER", 1320 | }, 1321 | "ServiceRole": Object { 1322 | "Fn::GetAtt": Array [ 1323 | "PipelineAssetsFileRole59943A77", 1324 | "Arn", 1325 | ], 1326 | }, 1327 | "Source": Object { 1328 | "BuildSpec": "{ 1329 | \\"version\\": \\"0.2\\", 1330 | \\"phases\\": { 1331 | \\"install\\": { 1332 | \\"commands\\": [ 1333 | \\"npm install -g cdk-assets@2\\" 1334 | ] 1335 | }, 1336 | \\"build\\": { 1337 | \\"commands\\": [ 1338 | \\"cdk-assets --path \\\\\\"assembly-Pipeline-SummitApp/PipelineSummitAppAPI91B89E1B.assets.json\\\\\\" --verbose publish \\\\\\"b438b0e87956f819e7fe6c1ffa18818d22809d2147a5507d907142ae0f250de1:current_account-current_region\\\\\\"\\" 1339 | ] 1340 | } 1341 | } 1342 | }", 1343 | "Type": "CODEPIPELINE", 1344 | }, 1345 | }, 1346 | "Type": "AWS::CodeBuild::Project", 1347 | }, 1348 | "PipelineAssetsFileAsset4CodePipelineActionRole492E1DB6": Object { 1349 | "Properties": Object { 1350 | "AssumeRolePolicyDocument": Object { 1351 | "Statement": Array [ 1352 | Object { 1353 | "Action": "sts:AssumeRole", 1354 | "Effect": "Allow", 1355 | "Principal": Object { 1356 | "AWS": Object { 1357 | "Fn::Join": Array [ 1358 | "", 1359 | Array [ 1360 | "arn:", 1361 | Object { 1362 | "Ref": "AWS::Partition", 1363 | }, 1364 | ":iam::", 1365 | Object { 1366 | "Ref": "AWS::AccountId", 1367 | }, 1368 | ":root", 1369 | ], 1370 | ], 1371 | }, 1372 | }, 1373 | }, 1374 | ], 1375 | "Version": "2012-10-17", 1376 | }, 1377 | }, 1378 | "Type": "AWS::IAM::Role", 1379 | }, 1380 | "PipelineAssetsFileAsset4CodePipelineActionRoleDefaultPolicy7F51ED2C": Object { 1381 | "Properties": Object { 1382 | "PolicyDocument": Object { 1383 | "Statement": Array [ 1384 | Object { 1385 | "Action": Array [ 1386 | "codebuild:BatchGetBuilds", 1387 | "codebuild:StartBuild", 1388 | "codebuild:StopBuild", 1389 | ], 1390 | "Effect": "Allow", 1391 | "Resource": Object { 1392 | "Fn::GetAtt": Array [ 1393 | "PipelineAssetsFileAsset474303B7D", 1394 | "Arn", 1395 | ], 1396 | }, 1397 | }, 1398 | ], 1399 | "Version": "2012-10-17", 1400 | }, 1401 | "PolicyName": "PipelineAssetsFileAsset4CodePipelineActionRoleDefaultPolicy7F51ED2C", 1402 | "Roles": Array [ 1403 | Object { 1404 | "Ref": "PipelineAssetsFileAsset4CodePipelineActionRole492E1DB6", 1405 | }, 1406 | ], 1407 | }, 1408 | "Type": "AWS::IAM::Policy", 1409 | }, 1410 | "PipelineAssetsFileRole59943A77": Object { 1411 | "Properties": Object { 1412 | "AssumeRolePolicyDocument": Object { 1413 | "Statement": Array [ 1414 | Object { 1415 | "Action": "sts:AssumeRole", 1416 | "Effect": "Allow", 1417 | "Principal": Object { 1418 | "Service": "codebuild.amazonaws.com", 1419 | }, 1420 | }, 1421 | Object { 1422 | "Action": "sts:AssumeRole", 1423 | "Effect": "Allow", 1424 | "Principal": Object { 1425 | "AWS": Object { 1426 | "Fn::Join": Array [ 1427 | "", 1428 | Array [ 1429 | "arn:", 1430 | Object { 1431 | "Ref": "AWS::Partition", 1432 | }, 1433 | ":iam::", 1434 | Object { 1435 | "Ref": "AWS::AccountId", 1436 | }, 1437 | ":root", 1438 | ], 1439 | ], 1440 | }, 1441 | }, 1442 | }, 1443 | ], 1444 | "Version": "2012-10-17", 1445 | }, 1446 | }, 1447 | "Type": "AWS::IAM::Role", 1448 | }, 1449 | "PipelineAssetsFileRoleDefaultPolicy14DB8755": Object { 1450 | "Properties": Object { 1451 | "PolicyDocument": Object { 1452 | "Statement": Array [ 1453 | Object { 1454 | "Action": Array [ 1455 | "logs:CreateLogGroup", 1456 | "logs:CreateLogStream", 1457 | "logs:PutLogEvents", 1458 | ], 1459 | "Effect": "Allow", 1460 | "Resource": Object { 1461 | "Fn::Join": Array [ 1462 | "", 1463 | Array [ 1464 | "arn:", 1465 | Object { 1466 | "Ref": "AWS::Partition", 1467 | }, 1468 | ":logs:", 1469 | Object { 1470 | "Ref": "AWS::Region", 1471 | }, 1472 | ":", 1473 | Object { 1474 | "Ref": "AWS::AccountId", 1475 | }, 1476 | ":log-group:/aws/codebuild/*", 1477 | ], 1478 | ], 1479 | }, 1480 | }, 1481 | Object { 1482 | "Action": Array [ 1483 | "codebuild:CreateReportGroup", 1484 | "codebuild:CreateReport", 1485 | "codebuild:UpdateReport", 1486 | "codebuild:BatchPutTestCases", 1487 | "codebuild:BatchPutCodeCoverages", 1488 | ], 1489 | "Effect": "Allow", 1490 | "Resource": Object { 1491 | "Fn::Join": Array [ 1492 | "", 1493 | Array [ 1494 | "arn:", 1495 | Object { 1496 | "Ref": "AWS::Partition", 1497 | }, 1498 | ":codebuild:", 1499 | Object { 1500 | "Ref": "AWS::Region", 1501 | }, 1502 | ":", 1503 | Object { 1504 | "Ref": "AWS::AccountId", 1505 | }, 1506 | ":report-group/*", 1507 | ], 1508 | ], 1509 | }, 1510 | }, 1511 | Object { 1512 | "Action": Array [ 1513 | "codebuild:BatchGetBuilds", 1514 | "codebuild:StartBuild", 1515 | "codebuild:StopBuild", 1516 | ], 1517 | "Effect": "Allow", 1518 | "Resource": "*", 1519 | }, 1520 | Object { 1521 | "Action": "sts:AssumeRole", 1522 | "Effect": "Allow", 1523 | "Resource": Array [ 1524 | Object { 1525 | "Fn::Sub": "arn:\${AWS::Partition}:iam::\${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-\${AWS::AccountId}-\${AWS::Region}", 1526 | }, 1527 | ], 1528 | }, 1529 | Object { 1530 | "Action": Array [ 1531 | "s3:GetObject*", 1532 | "s3:GetBucket*", 1533 | "s3:List*", 1534 | ], 1535 | "Effect": "Allow", 1536 | "Resource": Array [ 1537 | Object { 1538 | "Fn::GetAtt": Array [ 1539 | "PipelineArtifactsBucketAEA9A052", 1540 | "Arn", 1541 | ], 1542 | }, 1543 | Object { 1544 | "Fn::Join": Array [ 1545 | "", 1546 | Array [ 1547 | Object { 1548 | "Fn::GetAtt": Array [ 1549 | "PipelineArtifactsBucketAEA9A052", 1550 | "Arn", 1551 | ], 1552 | }, 1553 | "/*", 1554 | ], 1555 | ], 1556 | }, 1557 | ], 1558 | }, 1559 | ], 1560 | "Version": "2012-10-17", 1561 | }, 1562 | "PolicyName": "PipelineAssetsFileRoleDefaultPolicy14DB8755", 1563 | "Roles": Array [ 1564 | Object { 1565 | "Ref": "PipelineAssetsFileRole59943A77", 1566 | }, 1567 | ], 1568 | }, 1569 | "Type": "AWS::IAM::Policy", 1570 | }, 1571 | "PipelineBuildSynthCdkBuildProject6BEFA8E6": Object { 1572 | "Properties": Object { 1573 | "Artifacts": Object { 1574 | "Type": "CODEPIPELINE", 1575 | }, 1576 | "Cache": Object { 1577 | "Type": "NO_CACHE", 1578 | }, 1579 | "Description": "Pipeline step Pipeline/Pipeline/Build/Synth", 1580 | "EncryptionKey": "alias/aws/s3", 1581 | "Environment": Object { 1582 | "ComputeType": "BUILD_GENERAL1_SMALL", 1583 | "Image": "aws/codebuild/standard:5.0", 1584 | "ImagePullCredentialsType": "CODEBUILD", 1585 | "PrivilegedMode": true, 1586 | "Type": "LINUX_CONTAINER", 1587 | }, 1588 | "ServiceRole": Object { 1589 | "Fn::GetAtt": Array [ 1590 | "PipelineBuildSynthCdkBuildProjectRole231EEA2A", 1591 | "Arn", 1592 | ], 1593 | }, 1594 | "Source": Object { 1595 | "BuildSpec": "{ 1596 | \\"version\\": \\"0.2\\", 1597 | \\"phases\\": { 1598 | \\"build\\": { 1599 | \\"commands\\": [ 1600 | \\"npm ci\\", 1601 | \\"cd webapp/dashboard && npm ci && npm run build\\", 1602 | \\"cd - && npx cdk synth\\" 1603 | ] 1604 | } 1605 | }, 1606 | \\"artifacts\\": { 1607 | \\"base-directory\\": \\"cdk.out\\", 1608 | \\"files\\": \\"**/*\\" 1609 | } 1610 | }", 1611 | "Type": "CODEPIPELINE", 1612 | }, 1613 | }, 1614 | "Type": "AWS::CodeBuild::Project", 1615 | }, 1616 | "PipelineBuildSynthCdkBuildProjectRole231EEA2A": Object { 1617 | "Properties": Object { 1618 | "AssumeRolePolicyDocument": Object { 1619 | "Statement": Array [ 1620 | Object { 1621 | "Action": "sts:AssumeRole", 1622 | "Effect": "Allow", 1623 | "Principal": Object { 1624 | "Service": "codebuild.amazonaws.com", 1625 | }, 1626 | }, 1627 | ], 1628 | "Version": "2012-10-17", 1629 | }, 1630 | }, 1631 | "Type": "AWS::IAM::Role", 1632 | }, 1633 | "PipelineBuildSynthCdkBuildProjectRoleDefaultPolicyFB6C941C": Object { 1634 | "Properties": Object { 1635 | "PolicyDocument": Object { 1636 | "Statement": Array [ 1637 | Object { 1638 | "Action": Array [ 1639 | "logs:CreateLogGroup", 1640 | "logs:CreateLogStream", 1641 | "logs:PutLogEvents", 1642 | ], 1643 | "Effect": "Allow", 1644 | "Resource": Array [ 1645 | Object { 1646 | "Fn::Join": Array [ 1647 | "", 1648 | Array [ 1649 | "arn:", 1650 | Object { 1651 | "Ref": "AWS::Partition", 1652 | }, 1653 | ":logs:", 1654 | Object { 1655 | "Ref": "AWS::Region", 1656 | }, 1657 | ":", 1658 | Object { 1659 | "Ref": "AWS::AccountId", 1660 | }, 1661 | ":log-group:/aws/codebuild/", 1662 | Object { 1663 | "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6", 1664 | }, 1665 | ], 1666 | ], 1667 | }, 1668 | Object { 1669 | "Fn::Join": Array [ 1670 | "", 1671 | Array [ 1672 | "arn:", 1673 | Object { 1674 | "Ref": "AWS::Partition", 1675 | }, 1676 | ":logs:", 1677 | Object { 1678 | "Ref": "AWS::Region", 1679 | }, 1680 | ":", 1681 | Object { 1682 | "Ref": "AWS::AccountId", 1683 | }, 1684 | ":log-group:/aws/codebuild/", 1685 | Object { 1686 | "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6", 1687 | }, 1688 | ":*", 1689 | ], 1690 | ], 1691 | }, 1692 | ], 1693 | }, 1694 | Object { 1695 | "Action": Array [ 1696 | "codebuild:CreateReportGroup", 1697 | "codebuild:CreateReport", 1698 | "codebuild:UpdateReport", 1699 | "codebuild:BatchPutTestCases", 1700 | "codebuild:BatchPutCodeCoverages", 1701 | ], 1702 | "Effect": "Allow", 1703 | "Resource": Object { 1704 | "Fn::Join": Array [ 1705 | "", 1706 | Array [ 1707 | "arn:", 1708 | Object { 1709 | "Ref": "AWS::Partition", 1710 | }, 1711 | ":codebuild:", 1712 | Object { 1713 | "Ref": "AWS::Region", 1714 | }, 1715 | ":", 1716 | Object { 1717 | "Ref": "AWS::AccountId", 1718 | }, 1719 | ":report-group/", 1720 | Object { 1721 | "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6", 1722 | }, 1723 | "-*", 1724 | ], 1725 | ], 1726 | }, 1727 | }, 1728 | Object { 1729 | "Action": Array [ 1730 | "s3:GetObject*", 1731 | "s3:GetBucket*", 1732 | "s3:List*", 1733 | "s3:DeleteObject*", 1734 | "s3:PutObject", 1735 | "s3:PutObjectLegalHold", 1736 | "s3:PutObjectRetention", 1737 | "s3:PutObjectTagging", 1738 | "s3:PutObjectVersionTagging", 1739 | "s3:Abort*", 1740 | ], 1741 | "Effect": "Allow", 1742 | "Resource": Array [ 1743 | Object { 1744 | "Fn::GetAtt": Array [ 1745 | "PipelineArtifactsBucketAEA9A052", 1746 | "Arn", 1747 | ], 1748 | }, 1749 | Object { 1750 | "Fn::Join": Array [ 1751 | "", 1752 | Array [ 1753 | Object { 1754 | "Fn::GetAtt": Array [ 1755 | "PipelineArtifactsBucketAEA9A052", 1756 | "Arn", 1757 | ], 1758 | }, 1759 | "/*", 1760 | ], 1761 | ], 1762 | }, 1763 | ], 1764 | }, 1765 | ], 1766 | "Version": "2012-10-17", 1767 | }, 1768 | "PolicyName": "PipelineBuildSynthCdkBuildProjectRoleDefaultPolicyFB6C941C", 1769 | "Roles": Array [ 1770 | Object { 1771 | "Ref": "PipelineBuildSynthCdkBuildProjectRole231EEA2A", 1772 | }, 1773 | ], 1774 | }, 1775 | "Type": "AWS::IAM::Policy", 1776 | }, 1777 | "PipelineBuildSynthCodePipelineActionRole4E7A6C97": Object { 1778 | "Properties": Object { 1779 | "AssumeRolePolicyDocument": Object { 1780 | "Statement": Array [ 1781 | Object { 1782 | "Action": "sts:AssumeRole", 1783 | "Effect": "Allow", 1784 | "Principal": Object { 1785 | "AWS": Object { 1786 | "Fn::Join": Array [ 1787 | "", 1788 | Array [ 1789 | "arn:", 1790 | Object { 1791 | "Ref": "AWS::Partition", 1792 | }, 1793 | ":iam::", 1794 | Object { 1795 | "Ref": "AWS::AccountId", 1796 | }, 1797 | ":root", 1798 | ], 1799 | ], 1800 | }, 1801 | }, 1802 | }, 1803 | ], 1804 | "Version": "2012-10-17", 1805 | }, 1806 | }, 1807 | "Type": "AWS::IAM::Role", 1808 | }, 1809 | "PipelineBuildSynthCodePipelineActionRoleDefaultPolicy92C90290": Object { 1810 | "Properties": Object { 1811 | "PolicyDocument": Object { 1812 | "Statement": Array [ 1813 | Object { 1814 | "Action": Array [ 1815 | "codebuild:BatchGetBuilds", 1816 | "codebuild:StartBuild", 1817 | "codebuild:StopBuild", 1818 | ], 1819 | "Effect": "Allow", 1820 | "Resource": Object { 1821 | "Fn::GetAtt": Array [ 1822 | "PipelineBuildSynthCdkBuildProject6BEFA8E6", 1823 | "Arn", 1824 | ], 1825 | }, 1826 | }, 1827 | ], 1828 | "Version": "2012-10-17", 1829 | }, 1830 | "PolicyName": "PipelineBuildSynthCodePipelineActionRoleDefaultPolicy92C90290", 1831 | "Roles": Array [ 1832 | Object { 1833 | "Ref": "PipelineBuildSynthCodePipelineActionRole4E7A6C97", 1834 | }, 1835 | ], 1836 | }, 1837 | "Type": "AWS::IAM::Policy", 1838 | }, 1839 | "PipelineRoleB27FAA37": Object { 1840 | "Properties": Object { 1841 | "AssumeRolePolicyDocument": Object { 1842 | "Statement": Array [ 1843 | Object { 1844 | "Action": "sts:AssumeRole", 1845 | "Effect": "Allow", 1846 | "Principal": Object { 1847 | "Service": "codepipeline.amazonaws.com", 1848 | }, 1849 | }, 1850 | ], 1851 | "Version": "2012-10-17", 1852 | }, 1853 | }, 1854 | "Type": "AWS::IAM::Role", 1855 | }, 1856 | "PipelineRoleDefaultPolicy7BDC1ABB": Object { 1857 | "Properties": Object { 1858 | "PolicyDocument": Object { 1859 | "Statement": Array [ 1860 | Object { 1861 | "Action": Array [ 1862 | "s3:GetObject*", 1863 | "s3:GetBucket*", 1864 | "s3:List*", 1865 | "s3:DeleteObject*", 1866 | "s3:PutObject", 1867 | "s3:PutObjectLegalHold", 1868 | "s3:PutObjectRetention", 1869 | "s3:PutObjectTagging", 1870 | "s3:PutObjectVersionTagging", 1871 | "s3:Abort*", 1872 | ], 1873 | "Effect": "Allow", 1874 | "Resource": Array [ 1875 | Object { 1876 | "Fn::GetAtt": Array [ 1877 | "PipelineArtifactsBucketAEA9A052", 1878 | "Arn", 1879 | ], 1880 | }, 1881 | Object { 1882 | "Fn::Join": Array [ 1883 | "", 1884 | Array [ 1885 | Object { 1886 | "Fn::GetAtt": Array [ 1887 | "PipelineArtifactsBucketAEA9A052", 1888 | "Arn", 1889 | ], 1890 | }, 1891 | "/*", 1892 | ], 1893 | ], 1894 | }, 1895 | ], 1896 | }, 1897 | Object { 1898 | "Action": "sts:AssumeRole", 1899 | "Effect": "Allow", 1900 | "Resource": Object { 1901 | "Fn::GetAtt": Array [ 1902 | "PipelineSourceawssamplescdkchartappsampleCodePipelineActionRoleCD4E1688", 1903 | "Arn", 1904 | ], 1905 | }, 1906 | }, 1907 | Object { 1908 | "Action": "sts:AssumeRole", 1909 | "Effect": "Allow", 1910 | "Resource": Object { 1911 | "Fn::GetAtt": Array [ 1912 | "PipelineBuildSynthCodePipelineActionRole4E7A6C97", 1913 | "Arn", 1914 | ], 1915 | }, 1916 | }, 1917 | Object { 1918 | "Action": "sts:AssumeRole", 1919 | "Effect": "Allow", 1920 | "Resource": Object { 1921 | "Fn::GetAtt": Array [ 1922 | "PipelineUpdatePipelineSelfMutateCodePipelineActionRoleD6D4E5CF", 1923 | "Arn", 1924 | ], 1925 | }, 1926 | }, 1927 | Object { 1928 | "Action": "sts:AssumeRole", 1929 | "Effect": "Allow", 1930 | "Resource": Object { 1931 | "Fn::GetAtt": Array [ 1932 | "PipelineAssetsDockerAsset1CodePipelineActionRole7ED54263", 1933 | "Arn", 1934 | ], 1935 | }, 1936 | }, 1937 | Object { 1938 | "Action": "sts:AssumeRole", 1939 | "Effect": "Allow", 1940 | "Resource": Object { 1941 | "Fn::GetAtt": Array [ 1942 | "PipelineAssetsFileAsset1CodePipelineActionRoleC0EC649A", 1943 | "Arn", 1944 | ], 1945 | }, 1946 | }, 1947 | Object { 1948 | "Action": "sts:AssumeRole", 1949 | "Effect": "Allow", 1950 | "Resource": Object { 1951 | "Fn::GetAtt": Array [ 1952 | "PipelineAssetsFileAsset2CodePipelineActionRole06965A59", 1953 | "Arn", 1954 | ], 1955 | }, 1956 | }, 1957 | Object { 1958 | "Action": "sts:AssumeRole", 1959 | "Effect": "Allow", 1960 | "Resource": Object { 1961 | "Fn::GetAtt": Array [ 1962 | "PipelineAssetsFileAsset3CodePipelineActionRole99229BA9", 1963 | "Arn", 1964 | ], 1965 | }, 1966 | }, 1967 | Object { 1968 | "Action": "sts:AssumeRole", 1969 | "Effect": "Allow", 1970 | "Resource": Object { 1971 | "Fn::GetAtt": Array [ 1972 | "PipelineAssetsFileAsset4CodePipelineActionRole492E1DB6", 1973 | "Arn", 1974 | ], 1975 | }, 1976 | }, 1977 | Object { 1978 | "Action": "sts:AssumeRole", 1979 | "Effect": "Allow", 1980 | "Resource": Object { 1981 | "Fn::Join": Array [ 1982 | "", 1983 | Array [ 1984 | "arn:", 1985 | Object { 1986 | "Ref": "AWS::Partition", 1987 | }, 1988 | ":iam::", 1989 | Object { 1990 | "Ref": "AWS::AccountId", 1991 | }, 1992 | ":role/cdk-hnb659fds-deploy-role-", 1993 | Object { 1994 | "Ref": "AWS::AccountId", 1995 | }, 1996 | "-", 1997 | Object { 1998 | "Ref": "AWS::Region", 1999 | }, 2000 | ], 2001 | ], 2002 | }, 2003 | }, 2004 | ], 2005 | "Version": "2012-10-17", 2006 | }, 2007 | "PolicyName": "PipelineRoleDefaultPolicy7BDC1ABB", 2008 | "Roles": Array [ 2009 | Object { 2010 | "Ref": "PipelineRoleB27FAA37", 2011 | }, 2012 | ], 2013 | }, 2014 | "Type": "AWS::IAM::Policy", 2015 | }, 2016 | "PipelineSourceawssamplescdkchartappsampleCodePipelineActionRoleCD4E1688": Object { 2017 | "Properties": Object { 2018 | "AssumeRolePolicyDocument": Object { 2019 | "Statement": Array [ 2020 | Object { 2021 | "Action": "sts:AssumeRole", 2022 | "Effect": "Allow", 2023 | "Principal": Object { 2024 | "AWS": Object { 2025 | "Fn::Join": Array [ 2026 | "", 2027 | Array [ 2028 | "arn:", 2029 | Object { 2030 | "Ref": "AWS::Partition", 2031 | }, 2032 | ":iam::", 2033 | Object { 2034 | "Ref": "AWS::AccountId", 2035 | }, 2036 | ":root", 2037 | ], 2038 | ], 2039 | }, 2040 | }, 2041 | }, 2042 | ], 2043 | "Version": "2012-10-17", 2044 | }, 2045 | }, 2046 | "Type": "AWS::IAM::Role", 2047 | }, 2048 | "PipelineSourceawssamplescdkchartappsampleCodePipelineActionRoleDefaultPolicy9AA5CCD0": Object { 2049 | "Properties": Object { 2050 | "PolicyDocument": Object { 2051 | "Statement": Array [ 2052 | Object { 2053 | "Action": "codestar-connections:UseConnection", 2054 | "Effect": "Allow", 2055 | "Resource": "arn:aws:codestar-connections:ap-northeast-1:123456789012:connection/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", 2056 | }, 2057 | Object { 2058 | "Action": Array [ 2059 | "s3:GetObject*", 2060 | "s3:GetBucket*", 2061 | "s3:List*", 2062 | "s3:DeleteObject*", 2063 | "s3:PutObject", 2064 | "s3:PutObjectLegalHold", 2065 | "s3:PutObjectRetention", 2066 | "s3:PutObjectTagging", 2067 | "s3:PutObjectVersionTagging", 2068 | "s3:Abort*", 2069 | ], 2070 | "Effect": "Allow", 2071 | "Resource": Array [ 2072 | Object { 2073 | "Fn::GetAtt": Array [ 2074 | "PipelineArtifactsBucketAEA9A052", 2075 | "Arn", 2076 | ], 2077 | }, 2078 | Object { 2079 | "Fn::Join": Array [ 2080 | "", 2081 | Array [ 2082 | Object { 2083 | "Fn::GetAtt": Array [ 2084 | "PipelineArtifactsBucketAEA9A052", 2085 | "Arn", 2086 | ], 2087 | }, 2088 | "/*", 2089 | ], 2090 | ], 2091 | }, 2092 | ], 2093 | }, 2094 | Object { 2095 | "Action": Array [ 2096 | "s3:PutObjectAcl", 2097 | "s3:PutObjectVersionAcl", 2098 | ], 2099 | "Effect": "Allow", 2100 | "Resource": Object { 2101 | "Fn::Join": Array [ 2102 | "", 2103 | Array [ 2104 | Object { 2105 | "Fn::GetAtt": Array [ 2106 | "PipelineArtifactsBucketAEA9A052", 2107 | "Arn", 2108 | ], 2109 | }, 2110 | "/*", 2111 | ], 2112 | ], 2113 | }, 2114 | }, 2115 | ], 2116 | "Version": "2012-10-17", 2117 | }, 2118 | "PolicyName": "PipelineSourceawssamplescdkchartappsampleCodePipelineActionRoleDefaultPolicy9AA5CCD0", 2119 | "Roles": Array [ 2120 | Object { 2121 | "Ref": "PipelineSourceawssamplescdkchartappsampleCodePipelineActionRoleCD4E1688", 2122 | }, 2123 | ], 2124 | }, 2125 | "Type": "AWS::IAM::Policy", 2126 | }, 2127 | "PipelineUpdatePipelineSelfMutateCodePipelineActionRoleD6D4E5CF": Object { 2128 | "Properties": Object { 2129 | "AssumeRolePolicyDocument": Object { 2130 | "Statement": Array [ 2131 | Object { 2132 | "Action": "sts:AssumeRole", 2133 | "Effect": "Allow", 2134 | "Principal": Object { 2135 | "AWS": Object { 2136 | "Fn::Join": Array [ 2137 | "", 2138 | Array [ 2139 | "arn:", 2140 | Object { 2141 | "Ref": "AWS::Partition", 2142 | }, 2143 | ":iam::", 2144 | Object { 2145 | "Ref": "AWS::AccountId", 2146 | }, 2147 | ":root", 2148 | ], 2149 | ], 2150 | }, 2151 | }, 2152 | }, 2153 | ], 2154 | "Version": "2012-10-17", 2155 | }, 2156 | }, 2157 | "Type": "AWS::IAM::Role", 2158 | }, 2159 | "PipelineUpdatePipelineSelfMutateCodePipelineActionRoleDefaultPolicyE626265B": Object { 2160 | "Properties": Object { 2161 | "PolicyDocument": Object { 2162 | "Statement": Array [ 2163 | Object { 2164 | "Action": Array [ 2165 | "codebuild:BatchGetBuilds", 2166 | "codebuild:StartBuild", 2167 | "codebuild:StopBuild", 2168 | ], 2169 | "Effect": "Allow", 2170 | "Resource": Object { 2171 | "Fn::GetAtt": Array [ 2172 | "PipelineUpdatePipelineSelfMutationDAA41400", 2173 | "Arn", 2174 | ], 2175 | }, 2176 | }, 2177 | ], 2178 | "Version": "2012-10-17", 2179 | }, 2180 | "PolicyName": "PipelineUpdatePipelineSelfMutateCodePipelineActionRoleDefaultPolicyE626265B", 2181 | "Roles": Array [ 2182 | Object { 2183 | "Ref": "PipelineUpdatePipelineSelfMutateCodePipelineActionRoleD6D4E5CF", 2184 | }, 2185 | ], 2186 | }, 2187 | "Type": "AWS::IAM::Policy", 2188 | }, 2189 | "PipelineUpdatePipelineSelfMutationDAA41400": Object { 2190 | "Properties": Object { 2191 | "Artifacts": Object { 2192 | "Type": "CODEPIPELINE", 2193 | }, 2194 | "Cache": Object { 2195 | "Type": "NO_CACHE", 2196 | }, 2197 | "Description": "Pipeline step Pipeline/Pipeline/UpdatePipeline/SelfMutate", 2198 | "EncryptionKey": "alias/aws/s3", 2199 | "Environment": Object { 2200 | "ComputeType": "BUILD_GENERAL1_SMALL", 2201 | "Image": "aws/codebuild/standard:5.0", 2202 | "ImagePullCredentialsType": "CODEBUILD", 2203 | "PrivilegedMode": false, 2204 | "Type": "LINUX_CONTAINER", 2205 | }, 2206 | "ServiceRole": Object { 2207 | "Fn::GetAtt": Array [ 2208 | "PipelineUpdatePipelineSelfMutationRole57E559E8", 2209 | "Arn", 2210 | ], 2211 | }, 2212 | "Source": Object { 2213 | "BuildSpec": "{ 2214 | \\"version\\": \\"0.2\\", 2215 | \\"phases\\": { 2216 | \\"install\\": { 2217 | \\"commands\\": [ 2218 | \\"npm install -g aws-cdk@2\\" 2219 | ] 2220 | }, 2221 | \\"build\\": { 2222 | \\"commands\\": [ 2223 | \\"cdk -a . deploy Pipeline --require-approval=never --verbose\\" 2224 | ] 2225 | } 2226 | } 2227 | }", 2228 | "Type": "CODEPIPELINE", 2229 | }, 2230 | }, 2231 | "Type": "AWS::CodeBuild::Project", 2232 | }, 2233 | "PipelineUpdatePipelineSelfMutationRole57E559E8": Object { 2234 | "Properties": Object { 2235 | "AssumeRolePolicyDocument": Object { 2236 | "Statement": Array [ 2237 | Object { 2238 | "Action": "sts:AssumeRole", 2239 | "Effect": "Allow", 2240 | "Principal": Object { 2241 | "Service": "codebuild.amazonaws.com", 2242 | }, 2243 | }, 2244 | ], 2245 | "Version": "2012-10-17", 2246 | }, 2247 | }, 2248 | "Type": "AWS::IAM::Role", 2249 | }, 2250 | "PipelineUpdatePipelineSelfMutationRoleDefaultPolicyA225DA4E": Object { 2251 | "Properties": Object { 2252 | "PolicyDocument": Object { 2253 | "Statement": Array [ 2254 | Object { 2255 | "Action": Array [ 2256 | "logs:CreateLogGroup", 2257 | "logs:CreateLogStream", 2258 | "logs:PutLogEvents", 2259 | ], 2260 | "Effect": "Allow", 2261 | "Resource": Array [ 2262 | Object { 2263 | "Fn::Join": Array [ 2264 | "", 2265 | Array [ 2266 | "arn:", 2267 | Object { 2268 | "Ref": "AWS::Partition", 2269 | }, 2270 | ":logs:", 2271 | Object { 2272 | "Ref": "AWS::Region", 2273 | }, 2274 | ":", 2275 | Object { 2276 | "Ref": "AWS::AccountId", 2277 | }, 2278 | ":log-group:/aws/codebuild/", 2279 | Object { 2280 | "Ref": "PipelineUpdatePipelineSelfMutationDAA41400", 2281 | }, 2282 | ], 2283 | ], 2284 | }, 2285 | Object { 2286 | "Fn::Join": Array [ 2287 | "", 2288 | Array [ 2289 | "arn:", 2290 | Object { 2291 | "Ref": "AWS::Partition", 2292 | }, 2293 | ":logs:", 2294 | Object { 2295 | "Ref": "AWS::Region", 2296 | }, 2297 | ":", 2298 | Object { 2299 | "Ref": "AWS::AccountId", 2300 | }, 2301 | ":log-group:/aws/codebuild/", 2302 | Object { 2303 | "Ref": "PipelineUpdatePipelineSelfMutationDAA41400", 2304 | }, 2305 | ":*", 2306 | ], 2307 | ], 2308 | }, 2309 | ], 2310 | }, 2311 | Object { 2312 | "Action": Array [ 2313 | "codebuild:CreateReportGroup", 2314 | "codebuild:CreateReport", 2315 | "codebuild:UpdateReport", 2316 | "codebuild:BatchPutTestCases", 2317 | "codebuild:BatchPutCodeCoverages", 2318 | ], 2319 | "Effect": "Allow", 2320 | "Resource": Object { 2321 | "Fn::Join": Array [ 2322 | "", 2323 | Array [ 2324 | "arn:", 2325 | Object { 2326 | "Ref": "AWS::Partition", 2327 | }, 2328 | ":codebuild:", 2329 | Object { 2330 | "Ref": "AWS::Region", 2331 | }, 2332 | ":", 2333 | Object { 2334 | "Ref": "AWS::AccountId", 2335 | }, 2336 | ":report-group/", 2337 | Object { 2338 | "Ref": "PipelineUpdatePipelineSelfMutationDAA41400", 2339 | }, 2340 | "-*", 2341 | ], 2342 | ], 2343 | }, 2344 | }, 2345 | Object { 2346 | "Action": "sts:AssumeRole", 2347 | "Condition": Object { 2348 | "ForAnyValue:StringEquals": Object { 2349 | "iam:ResourceTag/aws-cdk:bootstrap-role": Array [ 2350 | "image-publishing", 2351 | "file-publishing", 2352 | "deploy", 2353 | ], 2354 | }, 2355 | }, 2356 | "Effect": "Allow", 2357 | "Resource": Object { 2358 | "Fn::Join": Array [ 2359 | "", 2360 | Array [ 2361 | "arn:*:iam::", 2362 | Object { 2363 | "Ref": "AWS::AccountId", 2364 | }, 2365 | ":role/*", 2366 | ], 2367 | ], 2368 | }, 2369 | }, 2370 | Object { 2371 | "Action": "cloudformation:DescribeStacks", 2372 | "Effect": "Allow", 2373 | "Resource": "*", 2374 | }, 2375 | Object { 2376 | "Action": "s3:ListBucket", 2377 | "Effect": "Allow", 2378 | "Resource": "*", 2379 | }, 2380 | Object { 2381 | "Action": Array [ 2382 | "s3:GetObject*", 2383 | "s3:GetBucket*", 2384 | "s3:List*", 2385 | ], 2386 | "Effect": "Allow", 2387 | "Resource": Array [ 2388 | Object { 2389 | "Fn::GetAtt": Array [ 2390 | "PipelineArtifactsBucketAEA9A052", 2391 | "Arn", 2392 | ], 2393 | }, 2394 | Object { 2395 | "Fn::Join": Array [ 2396 | "", 2397 | Array [ 2398 | Object { 2399 | "Fn::GetAtt": Array [ 2400 | "PipelineArtifactsBucketAEA9A052", 2401 | "Arn", 2402 | ], 2403 | }, 2404 | "/*", 2405 | ], 2406 | ], 2407 | }, 2408 | ], 2409 | }, 2410 | ], 2411 | "Version": "2012-10-17", 2412 | }, 2413 | "PolicyName": "PipelineUpdatePipelineSelfMutationRoleDefaultPolicyA225DA4E", 2414 | "Roles": Array [ 2415 | Object { 2416 | "Ref": "PipelineUpdatePipelineSelfMutationRole57E559E8", 2417 | }, 2418 | ], 2419 | }, 2420 | "Type": "AWS::IAM::Policy", 2421 | }, 2422 | }, 2423 | "Rules": Object { 2424 | "CheckBootstrapVersion": Object { 2425 | "Assertions": Array [ 2426 | Object { 2427 | "Assert": Object { 2428 | "Fn::Not": Array [ 2429 | Object { 2430 | "Fn::Contains": Array [ 2431 | Array [ 2432 | "1", 2433 | "2", 2434 | "3", 2435 | "4", 2436 | "5", 2437 | ], 2438 | Object { 2439 | "Ref": "BootstrapVersion", 2440 | }, 2441 | ], 2442 | }, 2443 | ], 2444 | }, 2445 | "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.", 2446 | }, 2447 | ], 2448 | }, 2449 | }, 2450 | } 2451 | `; 2452 | 2453 | exports[`Stacks match snapshots APIStack matches snapshot 1`] = ` 2454 | Object { 2455 | "Outputs": Object { 2456 | "RestAPIEndpointB14C3C54": Object { 2457 | "Value": Object { 2458 | "Fn::Join": Array [ 2459 | "", 2460 | Array [ 2461 | "https://", 2462 | Object { 2463 | "Ref": "RestAPI1CC12F26", 2464 | }, 2465 | ".execute-api.", 2466 | Object { 2467 | "Ref": "AWS::Region", 2468 | }, 2469 | ".", 2470 | Object { 2471 | "Ref": "AWS::URLSuffix", 2472 | }, 2473 | "/", 2474 | Object { 2475 | "Ref": "RestAPIDeploymentStageprod21CF62B9", 2476 | }, 2477 | "/", 2478 | ], 2479 | ], 2480 | }, 2481 | }, 2482 | }, 2483 | "Parameters": Object { 2484 | "BootstrapVersion": Object { 2485 | "Default": "/cdk-bootstrap/hnb659fds/version", 2486 | "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]", 2487 | "Type": "AWS::SSM::Parameter::Value", 2488 | }, 2489 | }, 2490 | "Resources": Object { 2491 | "GetMetricsHandler9056C484": Object { 2492 | "DependsOn": Array [ 2493 | "GetMetricsHandlerServiceRoleDefaultPolicyF6EF0E46", 2494 | "GetMetricsHandlerServiceRoleDA3A8822", 2495 | ], 2496 | "Properties": Object { 2497 | "Code": Object { 2498 | "S3Bucket": Object { 2499 | "Fn::Sub": "cdk-hnb659fds-assets-\${AWS::AccountId}-\${AWS::Region}", 2500 | }, 2501 | "S3Key": "b438b0e87956f819e7fe6c1ffa18818d22809d2147a5507d907142ae0f250de1.zip", 2502 | }, 2503 | "Environment": Object { 2504 | "Variables": Object { 2505 | "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", 2506 | "DDB_TABLE_NAME": Object { 2507 | "Fn::ImportValue": "Backend:ExportsOutputRefCurrentMetrics6C060EB01E69F74A", 2508 | }, 2509 | }, 2510 | }, 2511 | "Handler": "index.get", 2512 | "MemorySize": 256, 2513 | "Role": Object { 2514 | "Fn::GetAtt": Array [ 2515 | "GetMetricsHandlerServiceRoleDA3A8822", 2516 | "Arn", 2517 | ], 2518 | }, 2519 | "Runtime": "nodejs14.x", 2520 | "Timeout": 10, 2521 | }, 2522 | "Type": "AWS::Lambda::Function", 2523 | }, 2524 | "GetMetricsHandlerServiceRoleDA3A8822": Object { 2525 | "Properties": Object { 2526 | "AssumeRolePolicyDocument": Object { 2527 | "Statement": Array [ 2528 | Object { 2529 | "Action": "sts:AssumeRole", 2530 | "Effect": "Allow", 2531 | "Principal": Object { 2532 | "Service": "lambda.amazonaws.com", 2533 | }, 2534 | }, 2535 | ], 2536 | "Version": "2012-10-17", 2537 | }, 2538 | "ManagedPolicyArns": Array [ 2539 | Object { 2540 | "Fn::Join": Array [ 2541 | "", 2542 | Array [ 2543 | "arn:", 2544 | Object { 2545 | "Ref": "AWS::Partition", 2546 | }, 2547 | ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", 2548 | ], 2549 | ], 2550 | }, 2551 | ], 2552 | }, 2553 | "Type": "AWS::IAM::Role", 2554 | }, 2555 | "GetMetricsHandlerServiceRoleDefaultPolicyF6EF0E46": Object { 2556 | "Properties": Object { 2557 | "PolicyDocument": Object { 2558 | "Statement": Array [ 2559 | Object { 2560 | "Action": Array [ 2561 | "dynamodb:BatchGetItem", 2562 | "dynamodb:GetRecords", 2563 | "dynamodb:GetShardIterator", 2564 | "dynamodb:Query", 2565 | "dynamodb:GetItem", 2566 | "dynamodb:Scan", 2567 | "dynamodb:ConditionCheckItem", 2568 | "dynamodb:DescribeTable", 2569 | ], 2570 | "Effect": "Allow", 2571 | "Resource": Array [ 2572 | Object { 2573 | "Fn::ImportValue": "Backend:ExportsOutputFnGetAttCurrentMetrics6C060EB0ArnBA728C6F", 2574 | }, 2575 | Object { 2576 | "Ref": "AWS::NoValue", 2577 | }, 2578 | ], 2579 | }, 2580 | ], 2581 | "Version": "2012-10-17", 2582 | }, 2583 | "PolicyName": "GetMetricsHandlerServiceRoleDefaultPolicyF6EF0E46", 2584 | "Roles": Array [ 2585 | Object { 2586 | "Ref": "GetMetricsHandlerServiceRoleDA3A8822", 2587 | }, 2588 | ], 2589 | }, 2590 | "Type": "AWS::IAM::Policy", 2591 | }, 2592 | "RestAPI1CC12F26": Object { 2593 | "Properties": Object { 2594 | "Name": "RestAPI", 2595 | }, 2596 | "Type": "AWS::ApiGateway::RestApi", 2597 | }, 2598 | "RestAPIAccountB5481627": Object { 2599 | "DependsOn": Array [ 2600 | "RestAPI1CC12F26", 2601 | ], 2602 | "Properties": Object { 2603 | "CloudWatchRoleArn": Object { 2604 | "Fn::GetAtt": Array [ 2605 | "RestAPICloudWatchRole025FE33D", 2606 | "Arn", 2607 | ], 2608 | }, 2609 | }, 2610 | "Type": "AWS::ApiGateway::Account", 2611 | }, 2612 | "RestAPICloudWatchRole025FE33D": Object { 2613 | "Properties": Object { 2614 | "AssumeRolePolicyDocument": Object { 2615 | "Statement": Array [ 2616 | Object { 2617 | "Action": "sts:AssumeRole", 2618 | "Effect": "Allow", 2619 | "Principal": Object { 2620 | "Service": "apigateway.amazonaws.com", 2621 | }, 2622 | }, 2623 | ], 2624 | "Version": "2012-10-17", 2625 | }, 2626 | "ManagedPolicyArns": Array [ 2627 | Object { 2628 | "Fn::Join": Array [ 2629 | "", 2630 | Array [ 2631 | "arn:", 2632 | Object { 2633 | "Ref": "AWS::Partition", 2634 | }, 2635 | ":iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs", 2636 | ], 2637 | ], 2638 | }, 2639 | ], 2640 | }, 2641 | "Type": "AWS::IAM::Role", 2642 | }, 2643 | "RestAPIDeploymentD35A5380235061c3acfccf23d6d23c0a19f56793": Object { 2644 | "DependsOn": Array [ 2645 | "RestAPImetricsGET0B7D5000", 2646 | "RestAPImetricsOPTIONSB6AB5946", 2647 | "RestAPImetricsDC2DDE7F", 2648 | "RestAPIOPTIONS3271A002", 2649 | ], 2650 | "Properties": Object { 2651 | "Description": "Automatically created by the RestApi construct", 2652 | "RestApiId": Object { 2653 | "Ref": "RestAPI1CC12F26", 2654 | }, 2655 | }, 2656 | "Type": "AWS::ApiGateway::Deployment", 2657 | }, 2658 | "RestAPIDeploymentStageprod21CF62B9": Object { 2659 | "DependsOn": Array [ 2660 | "RestAPIAccountB5481627", 2661 | ], 2662 | "Properties": Object { 2663 | "DeploymentId": Object { 2664 | "Ref": "RestAPIDeploymentD35A5380235061c3acfccf23d6d23c0a19f56793", 2665 | }, 2666 | "RestApiId": Object { 2667 | "Ref": "RestAPI1CC12F26", 2668 | }, 2669 | "StageName": "prod", 2670 | "TracingEnabled": true, 2671 | }, 2672 | "Type": "AWS::ApiGateway::Stage", 2673 | }, 2674 | "RestAPIOPTIONS3271A002": Object { 2675 | "Properties": Object { 2676 | "AuthorizationType": "NONE", 2677 | "HttpMethod": "OPTIONS", 2678 | "Integration": Object { 2679 | "IntegrationResponses": Array [ 2680 | Object { 2681 | "ResponseParameters": Object { 2682 | "method.response.header.Access-Control-Allow-Headers": "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent'", 2683 | "method.response.header.Access-Control-Allow-Methods": "'OPTIONS,GET,PUT,POST,DELETE,PATCH,HEAD'", 2684 | "method.response.header.Access-Control-Allow-Origin": "'*'", 2685 | }, 2686 | "StatusCode": "204", 2687 | }, 2688 | ], 2689 | "RequestTemplates": Object { 2690 | "application/json": "{ statusCode: 200 }", 2691 | }, 2692 | "Type": "MOCK", 2693 | }, 2694 | "MethodResponses": Array [ 2695 | Object { 2696 | "ResponseParameters": Object { 2697 | "method.response.header.Access-Control-Allow-Headers": true, 2698 | "method.response.header.Access-Control-Allow-Methods": true, 2699 | "method.response.header.Access-Control-Allow-Origin": true, 2700 | }, 2701 | "StatusCode": "204", 2702 | }, 2703 | ], 2704 | "ResourceId": Object { 2705 | "Fn::GetAtt": Array [ 2706 | "RestAPI1CC12F26", 2707 | "RootResourceId", 2708 | ], 2709 | }, 2710 | "RestApiId": Object { 2711 | "Ref": "RestAPI1CC12F26", 2712 | }, 2713 | }, 2714 | "Type": "AWS::ApiGateway::Method", 2715 | }, 2716 | "RestAPImetricsDC2DDE7F": Object { 2717 | "Properties": Object { 2718 | "ParentId": Object { 2719 | "Fn::GetAtt": Array [ 2720 | "RestAPI1CC12F26", 2721 | "RootResourceId", 2722 | ], 2723 | }, 2724 | "PathPart": "metrics", 2725 | "RestApiId": Object { 2726 | "Ref": "RestAPI1CC12F26", 2727 | }, 2728 | }, 2729 | "Type": "AWS::ApiGateway::Resource", 2730 | }, 2731 | "RestAPImetricsGET0B7D5000": Object { 2732 | "Properties": Object { 2733 | "AuthorizationType": "NONE", 2734 | "HttpMethod": "GET", 2735 | "Integration": Object { 2736 | "IntegrationHttpMethod": "POST", 2737 | "Type": "AWS_PROXY", 2738 | "Uri": Object { 2739 | "Fn::Join": Array [ 2740 | "", 2741 | Array [ 2742 | "arn:", 2743 | Object { 2744 | "Ref": "AWS::Partition", 2745 | }, 2746 | ":apigateway:", 2747 | Object { 2748 | "Ref": "AWS::Region", 2749 | }, 2750 | ":lambda:path/2015-03-31/functions/", 2751 | Object { 2752 | "Fn::GetAtt": Array [ 2753 | "GetMetricsHandler9056C484", 2754 | "Arn", 2755 | ], 2756 | }, 2757 | "/invocations", 2758 | ], 2759 | ], 2760 | }, 2761 | }, 2762 | "ResourceId": Object { 2763 | "Ref": "RestAPImetricsDC2DDE7F", 2764 | }, 2765 | "RestApiId": Object { 2766 | "Ref": "RestAPI1CC12F26", 2767 | }, 2768 | }, 2769 | "Type": "AWS::ApiGateway::Method", 2770 | }, 2771 | "RestAPImetricsGETApiPermissionAPIRestAPI3747843CGETmetricsAD7709DE": Object { 2772 | "Properties": Object { 2773 | "Action": "lambda:InvokeFunction", 2774 | "FunctionName": Object { 2775 | "Fn::GetAtt": Array [ 2776 | "GetMetricsHandler9056C484", 2777 | "Arn", 2778 | ], 2779 | }, 2780 | "Principal": "apigateway.amazonaws.com", 2781 | "SourceArn": Object { 2782 | "Fn::Join": Array [ 2783 | "", 2784 | Array [ 2785 | "arn:", 2786 | Object { 2787 | "Ref": "AWS::Partition", 2788 | }, 2789 | ":execute-api:", 2790 | Object { 2791 | "Ref": "AWS::Region", 2792 | }, 2793 | ":", 2794 | Object { 2795 | "Ref": "AWS::AccountId", 2796 | }, 2797 | ":", 2798 | Object { 2799 | "Ref": "RestAPI1CC12F26", 2800 | }, 2801 | "/", 2802 | Object { 2803 | "Ref": "RestAPIDeploymentStageprod21CF62B9", 2804 | }, 2805 | "/GET/metrics", 2806 | ], 2807 | ], 2808 | }, 2809 | }, 2810 | "Type": "AWS::Lambda::Permission", 2811 | }, 2812 | "RestAPImetricsGETApiPermissionTestAPIRestAPI3747843CGETmetrics8305EC0F": Object { 2813 | "Properties": Object { 2814 | "Action": "lambda:InvokeFunction", 2815 | "FunctionName": Object { 2816 | "Fn::GetAtt": Array [ 2817 | "GetMetricsHandler9056C484", 2818 | "Arn", 2819 | ], 2820 | }, 2821 | "Principal": "apigateway.amazonaws.com", 2822 | "SourceArn": Object { 2823 | "Fn::Join": Array [ 2824 | "", 2825 | Array [ 2826 | "arn:", 2827 | Object { 2828 | "Ref": "AWS::Partition", 2829 | }, 2830 | ":execute-api:", 2831 | Object { 2832 | "Ref": "AWS::Region", 2833 | }, 2834 | ":", 2835 | Object { 2836 | "Ref": "AWS::AccountId", 2837 | }, 2838 | ":", 2839 | Object { 2840 | "Ref": "RestAPI1CC12F26", 2841 | }, 2842 | "/test-invoke-stage/GET/metrics", 2843 | ], 2844 | ], 2845 | }, 2846 | }, 2847 | "Type": "AWS::Lambda::Permission", 2848 | }, 2849 | "RestAPImetricsOPTIONSB6AB5946": Object { 2850 | "Properties": Object { 2851 | "AuthorizationType": "NONE", 2852 | "HttpMethod": "OPTIONS", 2853 | "Integration": Object { 2854 | "IntegrationResponses": Array [ 2855 | Object { 2856 | "ResponseParameters": Object { 2857 | "method.response.header.Access-Control-Allow-Headers": "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent'", 2858 | "method.response.header.Access-Control-Allow-Methods": "'OPTIONS,GET,PUT,POST,DELETE,PATCH,HEAD'", 2859 | "method.response.header.Access-Control-Allow-Origin": "'*'", 2860 | }, 2861 | "StatusCode": "204", 2862 | }, 2863 | ], 2864 | "RequestTemplates": Object { 2865 | "application/json": "{ statusCode: 200 }", 2866 | }, 2867 | "Type": "MOCK", 2868 | }, 2869 | "MethodResponses": Array [ 2870 | Object { 2871 | "ResponseParameters": Object { 2872 | "method.response.header.Access-Control-Allow-Headers": true, 2873 | "method.response.header.Access-Control-Allow-Methods": true, 2874 | "method.response.header.Access-Control-Allow-Origin": true, 2875 | }, 2876 | "StatusCode": "204", 2877 | }, 2878 | ], 2879 | "ResourceId": Object { 2880 | "Ref": "RestAPImetricsDC2DDE7F", 2881 | }, 2882 | "RestApiId": Object { 2883 | "Ref": "RestAPI1CC12F26", 2884 | }, 2885 | }, 2886 | "Type": "AWS::ApiGateway::Method", 2887 | }, 2888 | }, 2889 | "Rules": Object { 2890 | "CheckBootstrapVersion": Object { 2891 | "Assertions": Array [ 2892 | Object { 2893 | "Assert": Object { 2894 | "Fn::Not": Array [ 2895 | Object { 2896 | "Fn::Contains": Array [ 2897 | Array [ 2898 | "1", 2899 | "2", 2900 | "3", 2901 | "4", 2902 | "5", 2903 | ], 2904 | Object { 2905 | "Ref": "BootstrapVersion", 2906 | }, 2907 | ], 2908 | }, 2909 | ], 2910 | }, 2911 | "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.", 2912 | }, 2913 | ], 2914 | }, 2915 | }, 2916 | } 2917 | `; 2918 | 2919 | exports[`Stacks match snapshots BackendStack matches snapshot 1`] = ` 2920 | Object { 2921 | "Outputs": Object { 2922 | "ExportsOutputFnGetAttCurrentMetrics6C060EB0ArnBA728C6F": Object { 2923 | "Export": Object { 2924 | "Name": "Backend:ExportsOutputFnGetAttCurrentMetrics6C060EB0ArnBA728C6F", 2925 | }, 2926 | "Value": Object { 2927 | "Fn::GetAtt": Array [ 2928 | "CurrentMetrics6C060EB0", 2929 | "Arn", 2930 | ], 2931 | }, 2932 | }, 2933 | "ExportsOutputRefCurrentMetrics6C060EB01E69F74A": Object { 2934 | "Export": Object { 2935 | "Name": "Backend:ExportsOutputRefCurrentMetrics6C060EB01E69F74A", 2936 | }, 2937 | "Value": Object { 2938 | "Ref": "CurrentMetrics6C060EB0", 2939 | }, 2940 | }, 2941 | }, 2942 | "Parameters": Object { 2943 | "BootstrapVersion": Object { 2944 | "Default": "/cdk-bootstrap/hnb659fds/version", 2945 | "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]", 2946 | "Type": "AWS::SSM::Parameter::Value", 2947 | }, 2948 | }, 2949 | "Resources": Object { 2950 | "BackendCluster5086059C": Object { 2951 | "Type": "AWS::ECS::Cluster", 2952 | }, 2953 | "BackendClusterVpcC58EF45A": Object { 2954 | "Properties": Object { 2955 | "CidrBlock": "10.0.0.0/16", 2956 | "EnableDnsHostnames": true, 2957 | "EnableDnsSupport": true, 2958 | "InstanceTenancy": "default", 2959 | "Tags": Array [ 2960 | Object { 2961 | "Key": "Name", 2962 | "Value": "Backend/BackendCluster/Vpc", 2963 | }, 2964 | ], 2965 | }, 2966 | "Type": "AWS::EC2::VPC", 2967 | }, 2968 | "BackendClusterVpcIGW26870C5D": Object { 2969 | "Properties": Object { 2970 | "Tags": Array [ 2971 | Object { 2972 | "Key": "Name", 2973 | "Value": "Backend/BackendCluster/Vpc", 2974 | }, 2975 | ], 2976 | }, 2977 | "Type": "AWS::EC2::InternetGateway", 2978 | }, 2979 | "BackendClusterVpcPrivateSubnet1DefaultRouteE292E5B2": Object { 2980 | "Properties": Object { 2981 | "DestinationCidrBlock": "0.0.0.0/0", 2982 | "NatGatewayId": Object { 2983 | "Ref": "BackendClusterVpcPublicSubnet1NATGateway901701DA", 2984 | }, 2985 | "RouteTableId": Object { 2986 | "Ref": "BackendClusterVpcPrivateSubnet1RouteTable5DEED5FE", 2987 | }, 2988 | }, 2989 | "Type": "AWS::EC2::Route", 2990 | }, 2991 | "BackendClusterVpcPrivateSubnet1RouteTable5DEED5FE": Object { 2992 | "Properties": Object { 2993 | "Tags": Array [ 2994 | Object { 2995 | "Key": "Name", 2996 | "Value": "Backend/BackendCluster/Vpc/PrivateSubnet1", 2997 | }, 2998 | ], 2999 | "VpcId": Object { 3000 | "Ref": "BackendClusterVpcC58EF45A", 3001 | }, 3002 | }, 3003 | "Type": "AWS::EC2::RouteTable", 3004 | }, 3005 | "BackendClusterVpcPrivateSubnet1RouteTableAssociation680FA35F": Object { 3006 | "Properties": Object { 3007 | "RouteTableId": Object { 3008 | "Ref": "BackendClusterVpcPrivateSubnet1RouteTable5DEED5FE", 3009 | }, 3010 | "SubnetId": Object { 3011 | "Ref": "BackendClusterVpcPrivateSubnet1Subnet820DA3AD", 3012 | }, 3013 | }, 3014 | "Type": "AWS::EC2::SubnetRouteTableAssociation", 3015 | }, 3016 | "BackendClusterVpcPrivateSubnet1Subnet820DA3AD": Object { 3017 | "Properties": Object { 3018 | "AvailabilityZone": Object { 3019 | "Fn::Select": Array [ 3020 | 0, 3021 | Object { 3022 | "Fn::GetAZs": "", 3023 | }, 3024 | ], 3025 | }, 3026 | "CidrBlock": "10.0.128.0/18", 3027 | "MapPublicIpOnLaunch": false, 3028 | "Tags": Array [ 3029 | Object { 3030 | "Key": "aws-cdk:subnet-name", 3031 | "Value": "Private", 3032 | }, 3033 | Object { 3034 | "Key": "aws-cdk:subnet-type", 3035 | "Value": "Private", 3036 | }, 3037 | Object { 3038 | "Key": "Name", 3039 | "Value": "Backend/BackendCluster/Vpc/PrivateSubnet1", 3040 | }, 3041 | ], 3042 | "VpcId": Object { 3043 | "Ref": "BackendClusterVpcC58EF45A", 3044 | }, 3045 | }, 3046 | "Type": "AWS::EC2::Subnet", 3047 | }, 3048 | "BackendClusterVpcPrivateSubnet2DefaultRouteB1196619": Object { 3049 | "Properties": Object { 3050 | "DestinationCidrBlock": "0.0.0.0/0", 3051 | "NatGatewayId": Object { 3052 | "Ref": "BackendClusterVpcPublicSubnet2NATGatewayCF09ACCB", 3053 | }, 3054 | "RouteTableId": Object { 3055 | "Ref": "BackendClusterVpcPrivateSubnet2RouteTable78289E13", 3056 | }, 3057 | }, 3058 | "Type": "AWS::EC2::Route", 3059 | }, 3060 | "BackendClusterVpcPrivateSubnet2RouteTable78289E13": Object { 3061 | "Properties": Object { 3062 | "Tags": Array [ 3063 | Object { 3064 | "Key": "Name", 3065 | "Value": "Backend/BackendCluster/Vpc/PrivateSubnet2", 3066 | }, 3067 | ], 3068 | "VpcId": Object { 3069 | "Ref": "BackendClusterVpcC58EF45A", 3070 | }, 3071 | }, 3072 | "Type": "AWS::EC2::RouteTable", 3073 | }, 3074 | "BackendClusterVpcPrivateSubnet2RouteTableAssociationD4F65E17": Object { 3075 | "Properties": Object { 3076 | "RouteTableId": Object { 3077 | "Ref": "BackendClusterVpcPrivateSubnet2RouteTable78289E13", 3078 | }, 3079 | "SubnetId": Object { 3080 | "Ref": "BackendClusterVpcPrivateSubnet2Subnet34675548", 3081 | }, 3082 | }, 3083 | "Type": "AWS::EC2::SubnetRouteTableAssociation", 3084 | }, 3085 | "BackendClusterVpcPrivateSubnet2Subnet34675548": Object { 3086 | "Properties": Object { 3087 | "AvailabilityZone": Object { 3088 | "Fn::Select": Array [ 3089 | 1, 3090 | Object { 3091 | "Fn::GetAZs": "", 3092 | }, 3093 | ], 3094 | }, 3095 | "CidrBlock": "10.0.192.0/18", 3096 | "MapPublicIpOnLaunch": false, 3097 | "Tags": Array [ 3098 | Object { 3099 | "Key": "aws-cdk:subnet-name", 3100 | "Value": "Private", 3101 | }, 3102 | Object { 3103 | "Key": "aws-cdk:subnet-type", 3104 | "Value": "Private", 3105 | }, 3106 | Object { 3107 | "Key": "Name", 3108 | "Value": "Backend/BackendCluster/Vpc/PrivateSubnet2", 3109 | }, 3110 | ], 3111 | "VpcId": Object { 3112 | "Ref": "BackendClusterVpcC58EF45A", 3113 | }, 3114 | }, 3115 | "Type": "AWS::EC2::Subnet", 3116 | }, 3117 | "BackendClusterVpcPublicSubnet1DefaultRoute8518EDC8": Object { 3118 | "DependsOn": Array [ 3119 | "BackendClusterVpcVPCGWC47F352C", 3120 | ], 3121 | "Properties": Object { 3122 | "DestinationCidrBlock": "0.0.0.0/0", 3123 | "GatewayId": Object { 3124 | "Ref": "BackendClusterVpcIGW26870C5D", 3125 | }, 3126 | "RouteTableId": Object { 3127 | "Ref": "BackendClusterVpcPublicSubnet1RouteTable9589C5CA", 3128 | }, 3129 | }, 3130 | "Type": "AWS::EC2::Route", 3131 | }, 3132 | "BackendClusterVpcPublicSubnet1EIPD9D06FB5": Object { 3133 | "Properties": Object { 3134 | "Domain": "vpc", 3135 | "Tags": Array [ 3136 | Object { 3137 | "Key": "Name", 3138 | "Value": "Backend/BackendCluster/Vpc/PublicSubnet1", 3139 | }, 3140 | ], 3141 | }, 3142 | "Type": "AWS::EC2::EIP", 3143 | }, 3144 | "BackendClusterVpcPublicSubnet1NATGateway901701DA": Object { 3145 | "Properties": Object { 3146 | "AllocationId": Object { 3147 | "Fn::GetAtt": Array [ 3148 | "BackendClusterVpcPublicSubnet1EIPD9D06FB5", 3149 | "AllocationId", 3150 | ], 3151 | }, 3152 | "SubnetId": Object { 3153 | "Ref": "BackendClusterVpcPublicSubnet1Subnet43B50817", 3154 | }, 3155 | "Tags": Array [ 3156 | Object { 3157 | "Key": "Name", 3158 | "Value": "Backend/BackendCluster/Vpc/PublicSubnet1", 3159 | }, 3160 | ], 3161 | }, 3162 | "Type": "AWS::EC2::NatGateway", 3163 | }, 3164 | "BackendClusterVpcPublicSubnet1RouteTable9589C5CA": Object { 3165 | "Properties": Object { 3166 | "Tags": Array [ 3167 | Object { 3168 | "Key": "Name", 3169 | "Value": "Backend/BackendCluster/Vpc/PublicSubnet1", 3170 | }, 3171 | ], 3172 | "VpcId": Object { 3173 | "Ref": "BackendClusterVpcC58EF45A", 3174 | }, 3175 | }, 3176 | "Type": "AWS::EC2::RouteTable", 3177 | }, 3178 | "BackendClusterVpcPublicSubnet1RouteTableAssociation0CDAC697": Object { 3179 | "Properties": Object { 3180 | "RouteTableId": Object { 3181 | "Ref": "BackendClusterVpcPublicSubnet1RouteTable9589C5CA", 3182 | }, 3183 | "SubnetId": Object { 3184 | "Ref": "BackendClusterVpcPublicSubnet1Subnet43B50817", 3185 | }, 3186 | }, 3187 | "Type": "AWS::EC2::SubnetRouteTableAssociation", 3188 | }, 3189 | "BackendClusterVpcPublicSubnet1Subnet43B50817": Object { 3190 | "Properties": Object { 3191 | "AvailabilityZone": Object { 3192 | "Fn::Select": Array [ 3193 | 0, 3194 | Object { 3195 | "Fn::GetAZs": "", 3196 | }, 3197 | ], 3198 | }, 3199 | "CidrBlock": "10.0.0.0/18", 3200 | "MapPublicIpOnLaunch": true, 3201 | "Tags": Array [ 3202 | Object { 3203 | "Key": "aws-cdk:subnet-name", 3204 | "Value": "Public", 3205 | }, 3206 | Object { 3207 | "Key": "aws-cdk:subnet-type", 3208 | "Value": "Public", 3209 | }, 3210 | Object { 3211 | "Key": "Name", 3212 | "Value": "Backend/BackendCluster/Vpc/PublicSubnet1", 3213 | }, 3214 | ], 3215 | "VpcId": Object { 3216 | "Ref": "BackendClusterVpcC58EF45A", 3217 | }, 3218 | }, 3219 | "Type": "AWS::EC2::Subnet", 3220 | }, 3221 | "BackendClusterVpcPublicSubnet2DefaultRoute85C5B5D0": Object { 3222 | "DependsOn": Array [ 3223 | "BackendClusterVpcVPCGWC47F352C", 3224 | ], 3225 | "Properties": Object { 3226 | "DestinationCidrBlock": "0.0.0.0/0", 3227 | "GatewayId": Object { 3228 | "Ref": "BackendClusterVpcIGW26870C5D", 3229 | }, 3230 | "RouteTableId": Object { 3231 | "Ref": "BackendClusterVpcPublicSubnet2RouteTable97919F69", 3232 | }, 3233 | }, 3234 | "Type": "AWS::EC2::Route", 3235 | }, 3236 | "BackendClusterVpcPublicSubnet2EIPD79B0E2A": Object { 3237 | "Properties": Object { 3238 | "Domain": "vpc", 3239 | "Tags": Array [ 3240 | Object { 3241 | "Key": "Name", 3242 | "Value": "Backend/BackendCluster/Vpc/PublicSubnet2", 3243 | }, 3244 | ], 3245 | }, 3246 | "Type": "AWS::EC2::EIP", 3247 | }, 3248 | "BackendClusterVpcPublicSubnet2NATGatewayCF09ACCB": Object { 3249 | "Properties": Object { 3250 | "AllocationId": Object { 3251 | "Fn::GetAtt": Array [ 3252 | "BackendClusterVpcPublicSubnet2EIPD79B0E2A", 3253 | "AllocationId", 3254 | ], 3255 | }, 3256 | "SubnetId": Object { 3257 | "Ref": "BackendClusterVpcPublicSubnet2Subnet06EA30BD", 3258 | }, 3259 | "Tags": Array [ 3260 | Object { 3261 | "Key": "Name", 3262 | "Value": "Backend/BackendCluster/Vpc/PublicSubnet2", 3263 | }, 3264 | ], 3265 | }, 3266 | "Type": "AWS::EC2::NatGateway", 3267 | }, 3268 | "BackendClusterVpcPublicSubnet2RouteTable97919F69": Object { 3269 | "Properties": Object { 3270 | "Tags": Array [ 3271 | Object { 3272 | "Key": "Name", 3273 | "Value": "Backend/BackendCluster/Vpc/PublicSubnet2", 3274 | }, 3275 | ], 3276 | "VpcId": Object { 3277 | "Ref": "BackendClusterVpcC58EF45A", 3278 | }, 3279 | }, 3280 | "Type": "AWS::EC2::RouteTable", 3281 | }, 3282 | "BackendClusterVpcPublicSubnet2RouteTableAssociationD6EFC0E7": Object { 3283 | "Properties": Object { 3284 | "RouteTableId": Object { 3285 | "Ref": "BackendClusterVpcPublicSubnet2RouteTable97919F69", 3286 | }, 3287 | "SubnetId": Object { 3288 | "Ref": "BackendClusterVpcPublicSubnet2Subnet06EA30BD", 3289 | }, 3290 | }, 3291 | "Type": "AWS::EC2::SubnetRouteTableAssociation", 3292 | }, 3293 | "BackendClusterVpcPublicSubnet2Subnet06EA30BD": Object { 3294 | "Properties": Object { 3295 | "AvailabilityZone": Object { 3296 | "Fn::Select": Array [ 3297 | 1, 3298 | Object { 3299 | "Fn::GetAZs": "", 3300 | }, 3301 | ], 3302 | }, 3303 | "CidrBlock": "10.0.64.0/18", 3304 | "MapPublicIpOnLaunch": true, 3305 | "Tags": Array [ 3306 | Object { 3307 | "Key": "aws-cdk:subnet-name", 3308 | "Value": "Public", 3309 | }, 3310 | Object { 3311 | "Key": "aws-cdk:subnet-type", 3312 | "Value": "Public", 3313 | }, 3314 | Object { 3315 | "Key": "Name", 3316 | "Value": "Backend/BackendCluster/Vpc/PublicSubnet2", 3317 | }, 3318 | ], 3319 | "VpcId": Object { 3320 | "Ref": "BackendClusterVpcC58EF45A", 3321 | }, 3322 | }, 3323 | "Type": "AWS::EC2::Subnet", 3324 | }, 3325 | "BackendClusterVpcVPCGWC47F352C": Object { 3326 | "Properties": Object { 3327 | "InternetGatewayId": Object { 3328 | "Ref": "BackendClusterVpcIGW26870C5D", 3329 | }, 3330 | "VpcId": Object { 3331 | "Ref": "BackendClusterVpcC58EF45A", 3332 | }, 3333 | }, 3334 | "Type": "AWS::EC2::VPCGatewayAttachment", 3335 | }, 3336 | "BackendService7A4224EE": Object { 3337 | "Properties": Object { 3338 | "Cluster": Object { 3339 | "Ref": "BackendCluster5086059C", 3340 | }, 3341 | "DeploymentConfiguration": Object { 3342 | "MaximumPercent": 200, 3343 | "MinimumHealthyPercent": 50, 3344 | }, 3345 | "EnableECSManagedTags": false, 3346 | "LaunchType": "FARGATE", 3347 | "NetworkConfiguration": Object { 3348 | "AwsvpcConfiguration": Object { 3349 | "AssignPublicIp": "DISABLED", 3350 | "SecurityGroups": Array [ 3351 | Object { 3352 | "Fn::GetAtt": Array [ 3353 | "BackendServiceSecurityGroup0865F57D", 3354 | "GroupId", 3355 | ], 3356 | }, 3357 | ], 3358 | "Subnets": Array [ 3359 | Object { 3360 | "Ref": "BackendClusterVpcPrivateSubnet1Subnet820DA3AD", 3361 | }, 3362 | Object { 3363 | "Ref": "BackendClusterVpcPrivateSubnet2Subnet34675548", 3364 | }, 3365 | ], 3366 | }, 3367 | }, 3368 | "TaskDefinition": Object { 3369 | "Ref": "BackendTaskDef6ECE986E", 3370 | }, 3371 | }, 3372 | "Type": "AWS::ECS::Service", 3373 | }, 3374 | "BackendServiceSecurityGroup0865F57D": Object { 3375 | "Properties": Object { 3376 | "GroupDescription": "Backend/BackendService/SecurityGroup", 3377 | "SecurityGroupEgress": Array [ 3378 | Object { 3379 | "CidrIp": "0.0.0.0/0", 3380 | "Description": "Allow all outbound traffic by default", 3381 | "IpProtocol": "-1", 3382 | }, 3383 | ], 3384 | "VpcId": Object { 3385 | "Ref": "BackendClusterVpcC58EF45A", 3386 | }, 3387 | }, 3388 | "Type": "AWS::EC2::SecurityGroup", 3389 | }, 3390 | "BackendTaskDef6ECE986E": Object { 3391 | "Properties": Object { 3392 | "ContainerDefinitions": Array [ 3393 | Object { 3394 | "Environment": Array [ 3395 | Object { 3396 | "Name": "DDB_TABLE_NAME", 3397 | "Value": Object { 3398 | "Ref": "CurrentMetrics6C060EB0", 3399 | }, 3400 | }, 3401 | ], 3402 | "Essential": true, 3403 | "Image": Object { 3404 | "Fn::Sub": "\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.\${AWS::URLSuffix}/cdk-hnb659fds-container-assets-\${AWS::AccountId}-\${AWS::Region}:e2bad898212b9aa33917a6664214eaf1faf4f1bcd7c5cdbad4e7aac92448eed3", 3405 | }, 3406 | "LogConfiguration": Object { 3407 | "LogDriver": "awslogs", 3408 | "Options": Object { 3409 | "awslogs-group": Object { 3410 | "Ref": "BackendTaskDefRecorderLogGroup7ADD08BD", 3411 | }, 3412 | "awslogs-region": Object { 3413 | "Ref": "AWS::Region", 3414 | }, 3415 | "awslogs-stream-prefix": "recorder", 3416 | }, 3417 | }, 3418 | "Name": "Recorder", 3419 | }, 3420 | ], 3421 | "Cpu": "256", 3422 | "ExecutionRoleArn": Object { 3423 | "Fn::GetAtt": Array [ 3424 | "BackendTaskDefExecutionRoleC5A001DB", 3425 | "Arn", 3426 | ], 3427 | }, 3428 | "Family": "BackendBackendTaskDef7DB6A109", 3429 | "Memory": "512", 3430 | "NetworkMode": "awsvpc", 3431 | "RequiresCompatibilities": Array [ 3432 | "FARGATE", 3433 | ], 3434 | "RuntimePlatform": Object { 3435 | "CpuArchitecture": "ARM64", 3436 | "OperatingSystemFamily": "LINUX", 3437 | }, 3438 | "TaskRoleArn": Object { 3439 | "Fn::GetAtt": Array [ 3440 | "BackendTaskDefTaskRoleBA953A3B", 3441 | "Arn", 3442 | ], 3443 | }, 3444 | }, 3445 | "Type": "AWS::ECS::TaskDefinition", 3446 | }, 3447 | "BackendTaskDefExecutionRoleC5A001DB": Object { 3448 | "Properties": Object { 3449 | "AssumeRolePolicyDocument": Object { 3450 | "Statement": Array [ 3451 | Object { 3452 | "Action": "sts:AssumeRole", 3453 | "Effect": "Allow", 3454 | "Principal": Object { 3455 | "Service": "ecs-tasks.amazonaws.com", 3456 | }, 3457 | }, 3458 | ], 3459 | "Version": "2012-10-17", 3460 | }, 3461 | }, 3462 | "Type": "AWS::IAM::Role", 3463 | }, 3464 | "BackendTaskDefExecutionRoleDefaultPolicyAA625660": Object { 3465 | "Properties": Object { 3466 | "PolicyDocument": Object { 3467 | "Statement": Array [ 3468 | Object { 3469 | "Action": Array [ 3470 | "ecr:BatchCheckLayerAvailability", 3471 | "ecr:GetDownloadUrlForLayer", 3472 | "ecr:BatchGetImage", 3473 | ], 3474 | "Effect": "Allow", 3475 | "Resource": Object { 3476 | "Fn::Join": Array [ 3477 | "", 3478 | Array [ 3479 | "arn:", 3480 | Object { 3481 | "Ref": "AWS::Partition", 3482 | }, 3483 | ":ecr:", 3484 | Object { 3485 | "Ref": "AWS::Region", 3486 | }, 3487 | ":", 3488 | Object { 3489 | "Ref": "AWS::AccountId", 3490 | }, 3491 | ":repository/", 3492 | Object { 3493 | "Fn::Sub": "cdk-hnb659fds-container-assets-\${AWS::AccountId}-\${AWS::Region}", 3494 | }, 3495 | ], 3496 | ], 3497 | }, 3498 | }, 3499 | Object { 3500 | "Action": "ecr:GetAuthorizationToken", 3501 | "Effect": "Allow", 3502 | "Resource": "*", 3503 | }, 3504 | Object { 3505 | "Action": Array [ 3506 | "logs:CreateLogStream", 3507 | "logs:PutLogEvents", 3508 | ], 3509 | "Effect": "Allow", 3510 | "Resource": Object { 3511 | "Fn::GetAtt": Array [ 3512 | "BackendTaskDefRecorderLogGroup7ADD08BD", 3513 | "Arn", 3514 | ], 3515 | }, 3516 | }, 3517 | ], 3518 | "Version": "2012-10-17", 3519 | }, 3520 | "PolicyName": "BackendTaskDefExecutionRoleDefaultPolicyAA625660", 3521 | "Roles": Array [ 3522 | Object { 3523 | "Ref": "BackendTaskDefExecutionRoleC5A001DB", 3524 | }, 3525 | ], 3526 | }, 3527 | "Type": "AWS::IAM::Policy", 3528 | }, 3529 | "BackendTaskDefRecorderLogGroup7ADD08BD": Object { 3530 | "DeletionPolicy": "Retain", 3531 | "Type": "AWS::Logs::LogGroup", 3532 | "UpdateReplacePolicy": "Retain", 3533 | }, 3534 | "BackendTaskDefTaskRoleBA953A3B": Object { 3535 | "Properties": Object { 3536 | "AssumeRolePolicyDocument": Object { 3537 | "Statement": Array [ 3538 | Object { 3539 | "Action": "sts:AssumeRole", 3540 | "Effect": "Allow", 3541 | "Principal": Object { 3542 | "Service": "ecs-tasks.amazonaws.com", 3543 | }, 3544 | }, 3545 | ], 3546 | "Version": "2012-10-17", 3547 | }, 3548 | }, 3549 | "Type": "AWS::IAM::Role", 3550 | }, 3551 | "BackendTaskDefTaskRoleDefaultPolicy2C657A56": Object { 3552 | "Properties": Object { 3553 | "PolicyDocument": Object { 3554 | "Statement": Array [ 3555 | Object { 3556 | "Action": Array [ 3557 | "dynamodb:BatchWriteItem", 3558 | "dynamodb:PutItem", 3559 | "dynamodb:UpdateItem", 3560 | "dynamodb:DeleteItem", 3561 | "dynamodb:DescribeTable", 3562 | ], 3563 | "Effect": "Allow", 3564 | "Resource": Array [ 3565 | Object { 3566 | "Fn::GetAtt": Array [ 3567 | "CurrentMetrics6C060EB0", 3568 | "Arn", 3569 | ], 3570 | }, 3571 | Object { 3572 | "Ref": "AWS::NoValue", 3573 | }, 3574 | ], 3575 | }, 3576 | ], 3577 | "Version": "2012-10-17", 3578 | }, 3579 | "PolicyName": "BackendTaskDefTaskRoleDefaultPolicy2C657A56", 3580 | "Roles": Array [ 3581 | Object { 3582 | "Ref": "BackendTaskDefTaskRoleBA953A3B", 3583 | }, 3584 | ], 3585 | }, 3586 | "Type": "AWS::IAM::Policy", 3587 | }, 3588 | "CurrentMetrics6C060EB0": Object { 3589 | "DeletionPolicy": "Retain", 3590 | "Properties": Object { 3591 | "AttributeDefinitions": Array [ 3592 | Object { 3593 | "AttributeName": "deviceId", 3594 | "AttributeType": "S", 3595 | }, 3596 | Object { 3597 | "AttributeName": "timestamp", 3598 | "AttributeType": "S", 3599 | }, 3600 | ], 3601 | "BillingMode": "PAY_PER_REQUEST", 3602 | "KeySchema": Array [ 3603 | Object { 3604 | "AttributeName": "deviceId", 3605 | "KeyType": "HASH", 3606 | }, 3607 | Object { 3608 | "AttributeName": "timestamp", 3609 | "KeyType": "RANGE", 3610 | }, 3611 | ], 3612 | "TimeToLiveSpecification": Object { 3613 | "AttributeName": "expiresAt", 3614 | "Enabled": true, 3615 | }, 3616 | }, 3617 | "Type": "AWS::DynamoDB::Table", 3618 | "UpdateReplacePolicy": "Retain", 3619 | }, 3620 | }, 3621 | "Rules": Object { 3622 | "CheckBootstrapVersion": Object { 3623 | "Assertions": Array [ 3624 | Object { 3625 | "Assert": Object { 3626 | "Fn::Not": Array [ 3627 | Object { 3628 | "Fn::Contains": Array [ 3629 | Array [ 3630 | "1", 3631 | "2", 3632 | "3", 3633 | "4", 3634 | "5", 3635 | ], 3636 | Object { 3637 | "Ref": "BootstrapVersion", 3638 | }, 3639 | ], 3640 | }, 3641 | ], 3642 | }, 3643 | "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.", 3644 | }, 3645 | ], 3646 | }, 3647 | }, 3648 | } 3649 | `; 3650 | 3651 | exports[`Stacks match snapshots FrontendStack matches snapshot 1`] = ` 3652 | Object { 3653 | "Outputs": Object { 3654 | "DistributionDomainName": Object { 3655 | "Value": Object { 3656 | "Fn::GetAtt": Array [ 3657 | "WebAppCloudFrontS3CloudFrontDistribution5EB6A455", 3658 | "DomainName", 3659 | ], 3660 | }, 3661 | }, 3662 | }, 3663 | "Parameters": Object { 3664 | "BootstrapVersion": Object { 3665 | "Default": "/cdk-bootstrap/hnb659fds/version", 3666 | "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]", 3667 | "Type": "AWS::SSM::Parameter::Value", 3668 | }, 3669 | }, 3670 | "Resources": Object { 3671 | "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C81C01536": Object { 3672 | "DependsOn": Array [ 3673 | "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRoleDefaultPolicy88902FDF", 3674 | "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265", 3675 | ], 3676 | "Properties": Object { 3677 | "Code": Object { 3678 | "S3Bucket": Object { 3679 | "Fn::Sub": "cdk-hnb659fds-assets-\${AWS::AccountId}-\${AWS::Region}", 3680 | }, 3681 | "S3Key": "f98b78092dcdd31f5e6d47489beb5f804d4835ef86a8085d0a2053cb9ae711da.zip", 3682 | }, 3683 | "Handler": "index.handler", 3684 | "Layers": Array [ 3685 | Object { 3686 | "Ref": "WebAppDeployAwsCliLayer11329AB7", 3687 | }, 3688 | ], 3689 | "Role": Object { 3690 | "Fn::GetAtt": Array [ 3691 | "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265", 3692 | "Arn", 3693 | ], 3694 | }, 3695 | "Runtime": "python3.7", 3696 | "Timeout": 900, 3697 | }, 3698 | "Type": "AWS::Lambda::Function", 3699 | }, 3700 | "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265": Object { 3701 | "Properties": Object { 3702 | "AssumeRolePolicyDocument": Object { 3703 | "Statement": Array [ 3704 | Object { 3705 | "Action": "sts:AssumeRole", 3706 | "Effect": "Allow", 3707 | "Principal": Object { 3708 | "Service": "lambda.amazonaws.com", 3709 | }, 3710 | }, 3711 | ], 3712 | "Version": "2012-10-17", 3713 | }, 3714 | "ManagedPolicyArns": Array [ 3715 | Object { 3716 | "Fn::Join": Array [ 3717 | "", 3718 | Array [ 3719 | "arn:", 3720 | Object { 3721 | "Ref": "AWS::Partition", 3722 | }, 3723 | ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", 3724 | ], 3725 | ], 3726 | }, 3727 | ], 3728 | }, 3729 | "Type": "AWS::IAM::Role", 3730 | }, 3731 | "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRoleDefaultPolicy88902FDF": Object { 3732 | "Properties": Object { 3733 | "PolicyDocument": Object { 3734 | "Statement": Array [ 3735 | Object { 3736 | "Action": Array [ 3737 | "s3:GetObject*", 3738 | "s3:GetBucket*", 3739 | "s3:List*", 3740 | ], 3741 | "Effect": "Allow", 3742 | "Resource": Array [ 3743 | Object { 3744 | "Fn::Join": Array [ 3745 | "", 3746 | Array [ 3747 | "arn:", 3748 | Object { 3749 | "Ref": "AWS::Partition", 3750 | }, 3751 | ":s3:::", 3752 | Object { 3753 | "Fn::Sub": "cdk-hnb659fds-assets-\${AWS::AccountId}-\${AWS::Region}", 3754 | }, 3755 | ], 3756 | ], 3757 | }, 3758 | Object { 3759 | "Fn::Join": Array [ 3760 | "", 3761 | Array [ 3762 | "arn:", 3763 | Object { 3764 | "Ref": "AWS::Partition", 3765 | }, 3766 | ":s3:::", 3767 | Object { 3768 | "Fn::Sub": "cdk-hnb659fds-assets-\${AWS::AccountId}-\${AWS::Region}", 3769 | }, 3770 | "/*", 3771 | ], 3772 | ], 3773 | }, 3774 | ], 3775 | }, 3776 | Object { 3777 | "Action": Array [ 3778 | "s3:GetObject*", 3779 | "s3:GetBucket*", 3780 | "s3:List*", 3781 | "s3:DeleteObject*", 3782 | "s3:PutObject", 3783 | "s3:PutObjectLegalHold", 3784 | "s3:PutObjectRetention", 3785 | "s3:PutObjectTagging", 3786 | "s3:PutObjectVersionTagging", 3787 | "s3:Abort*", 3788 | ], 3789 | "Effect": "Allow", 3790 | "Resource": Array [ 3791 | Object { 3792 | "Fn::GetAtt": Array [ 3793 | "WebAppCloudFrontS3S3BucketE5B829B9", 3794 | "Arn", 3795 | ], 3796 | }, 3797 | Object { 3798 | "Fn::Join": Array [ 3799 | "", 3800 | Array [ 3801 | Object { 3802 | "Fn::GetAtt": Array [ 3803 | "WebAppCloudFrontS3S3BucketE5B829B9", 3804 | "Arn", 3805 | ], 3806 | }, 3807 | "/*", 3808 | ], 3809 | ], 3810 | }, 3811 | ], 3812 | }, 3813 | Object { 3814 | "Action": Array [ 3815 | "cloudfront:GetInvalidation", 3816 | "cloudfront:CreateInvalidation", 3817 | ], 3818 | "Effect": "Allow", 3819 | "Resource": "*", 3820 | }, 3821 | ], 3822 | "Version": "2012-10-17", 3823 | }, 3824 | "PolicyName": "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRoleDefaultPolicy88902FDF", 3825 | "Roles": Array [ 3826 | Object { 3827 | "Ref": "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265", 3828 | }, 3829 | ], 3830 | }, 3831 | "Type": "AWS::IAM::Policy", 3832 | }, 3833 | "WebAppCloudFrontS3CloudFrontDistribution5EB6A455": Object { 3834 | "Metadata": Object { 3835 | "cfn_nag": Object { 3836 | "rules_to_suppress": Array [ 3837 | Object { 3838 | "id": "W70", 3839 | "reason": "Since the distribution uses the CloudFront domain name, CloudFront automatically sets the security policy to TLSv1 regardless of the value of MinimumProtocolVersion", 3840 | }, 3841 | ], 3842 | }, 3843 | }, 3844 | "Properties": Object { 3845 | "DistributionConfig": Object { 3846 | "DefaultCacheBehavior": Object { 3847 | "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", 3848 | "Compress": true, 3849 | "TargetOriginId": "FrontendWebAppCloudFrontS3CloudFrontDistributionOrigin168B6A819", 3850 | "ViewerProtocolPolicy": "redirect-to-https", 3851 | }, 3852 | "DefaultRootObject": "index.html", 3853 | "Enabled": true, 3854 | "HttpVersion": "http2", 3855 | "IPV6Enabled": true, 3856 | "Logging": Object { 3857 | "Bucket": Object { 3858 | "Fn::GetAtt": Array [ 3859 | "WebAppCloudFrontS3CloudfrontLoggingBucketED71F089", 3860 | "RegionalDomainName", 3861 | ], 3862 | }, 3863 | }, 3864 | "Origins": Array [ 3865 | Object { 3866 | "DomainName": Object { 3867 | "Fn::GetAtt": Array [ 3868 | "WebAppCloudFrontS3S3BucketE5B829B9", 3869 | "RegionalDomainName", 3870 | ], 3871 | }, 3872 | "Id": "FrontendWebAppCloudFrontS3CloudFrontDistributionOrigin168B6A819", 3873 | "S3OriginConfig": Object { 3874 | "OriginAccessIdentity": Object { 3875 | "Fn::Join": Array [ 3876 | "", 3877 | Array [ 3878 | "origin-access-identity/cloudfront/", 3879 | Object { 3880 | "Ref": "WebAppCloudFrontS3CloudFrontDistributionOrigin1S3OriginAD5F58BE", 3881 | }, 3882 | ], 3883 | ], 3884 | }, 3885 | }, 3886 | }, 3887 | ], 3888 | }, 3889 | }, 3890 | "Type": "AWS::CloudFront::Distribution", 3891 | }, 3892 | "WebAppCloudFrontS3CloudFrontDistributionOrigin1S3OriginAD5F58BE": Object { 3893 | "Properties": Object { 3894 | "CloudFrontOriginAccessIdentityConfig": Object { 3895 | "Comment": "Identity for FrontendWebAppCloudFrontS3CloudFrontDistributionOrigin168B6A819", 3896 | }, 3897 | }, 3898 | "Type": "AWS::CloudFront::CloudFrontOriginAccessIdentity", 3899 | }, 3900 | "WebAppCloudFrontS3CloudfrontLoggingBucketED71F089": Object { 3901 | "DeletionPolicy": "Retain", 3902 | "Metadata": Object { 3903 | "cfn_nag": Object { 3904 | "rules_to_suppress": Array [ 3905 | Object { 3906 | "id": "W35", 3907 | "reason": "This S3 bucket is used as the access logging bucket for CloudFront Distribution", 3908 | }, 3909 | ], 3910 | }, 3911 | }, 3912 | "Properties": Object { 3913 | "AccessControl": "LogDeliveryWrite", 3914 | "BucketEncryption": Object { 3915 | "ServerSideEncryptionConfiguration": Array [ 3916 | Object { 3917 | "ServerSideEncryptionByDefault": Object { 3918 | "SSEAlgorithm": "AES256", 3919 | }, 3920 | }, 3921 | ], 3922 | }, 3923 | "PublicAccessBlockConfiguration": Object { 3924 | "BlockPublicAcls": true, 3925 | "BlockPublicPolicy": true, 3926 | "IgnorePublicAcls": true, 3927 | "RestrictPublicBuckets": true, 3928 | }, 3929 | "VersioningConfiguration": Object { 3930 | "Status": "Enabled", 3931 | }, 3932 | }, 3933 | "Type": "AWS::S3::Bucket", 3934 | "UpdateReplacePolicy": "Retain", 3935 | }, 3936 | "WebAppCloudFrontS3CloudfrontLoggingBucketPolicy2F5CFA37": Object { 3937 | "Properties": Object { 3938 | "Bucket": Object { 3939 | "Ref": "WebAppCloudFrontS3CloudfrontLoggingBucketED71F089", 3940 | }, 3941 | "PolicyDocument": Object { 3942 | "Statement": Array [ 3943 | Object { 3944 | "Action": "s3:*", 3945 | "Condition": Object { 3946 | "Bool": Object { 3947 | "aws:SecureTransport": "false", 3948 | }, 3949 | }, 3950 | "Effect": "Deny", 3951 | "Principal": Object { 3952 | "AWS": "*", 3953 | }, 3954 | "Resource": Array [ 3955 | Object { 3956 | "Fn::GetAtt": Array [ 3957 | "WebAppCloudFrontS3CloudfrontLoggingBucketED71F089", 3958 | "Arn", 3959 | ], 3960 | }, 3961 | Object { 3962 | "Fn::Join": Array [ 3963 | "", 3964 | Array [ 3965 | Object { 3966 | "Fn::GetAtt": Array [ 3967 | "WebAppCloudFrontS3CloudfrontLoggingBucketED71F089", 3968 | "Arn", 3969 | ], 3970 | }, 3971 | "/*", 3972 | ], 3973 | ], 3974 | }, 3975 | ], 3976 | }, 3977 | ], 3978 | "Version": "2012-10-17", 3979 | }, 3980 | }, 3981 | "Type": "AWS::S3::BucketPolicy", 3982 | }, 3983 | "WebAppCloudFrontS3S3BucketE5B829B9": Object { 3984 | "DeletionPolicy": "Retain", 3985 | "Properties": Object { 3986 | "BucketEncryption": Object { 3987 | "ServerSideEncryptionConfiguration": Array [ 3988 | Object { 3989 | "ServerSideEncryptionByDefault": Object { 3990 | "SSEAlgorithm": "AES256", 3991 | }, 3992 | }, 3993 | ], 3994 | }, 3995 | "LifecycleConfiguration": Object { 3996 | "Rules": Array [ 3997 | Object { 3998 | "NoncurrentVersionTransitions": Array [ 3999 | Object { 4000 | "StorageClass": "GLACIER", 4001 | "TransitionInDays": 90, 4002 | }, 4003 | ], 4004 | "Status": "Enabled", 4005 | }, 4006 | ], 4007 | }, 4008 | "LoggingConfiguration": Object { 4009 | "DestinationBucketName": Object { 4010 | "Ref": "WebAppCloudFrontS3S3LoggingBucketE71DE76E", 4011 | }, 4012 | }, 4013 | "PublicAccessBlockConfiguration": Object { 4014 | "BlockPublicAcls": true, 4015 | "BlockPublicPolicy": true, 4016 | "IgnorePublicAcls": true, 4017 | "RestrictPublicBuckets": true, 4018 | }, 4019 | "Tags": Array [ 4020 | Object { 4021 | "Key": "aws-cdk:cr-owned:479bdc94", 4022 | "Value": "true", 4023 | }, 4024 | ], 4025 | "VersioningConfiguration": Object { 4026 | "Status": "Enabled", 4027 | }, 4028 | }, 4029 | "Type": "AWS::S3::Bucket", 4030 | "UpdateReplacePolicy": "Retain", 4031 | }, 4032 | "WebAppCloudFrontS3S3BucketPolicyB47EE26D": Object { 4033 | "Metadata": Object { 4034 | "cfn_nag": Object { 4035 | "rules_to_suppress": Array [ 4036 | Object { 4037 | "id": "F16", 4038 | "reason": "Public website bucket policy requires a wildcard principal", 4039 | }, 4040 | ], 4041 | }, 4042 | }, 4043 | "Properties": Object { 4044 | "Bucket": Object { 4045 | "Ref": "WebAppCloudFrontS3S3BucketE5B829B9", 4046 | }, 4047 | "PolicyDocument": Object { 4048 | "Statement": Array [ 4049 | Object { 4050 | "Action": "s3:*", 4051 | "Condition": Object { 4052 | "Bool": Object { 4053 | "aws:SecureTransport": "false", 4054 | }, 4055 | }, 4056 | "Effect": "Deny", 4057 | "Principal": Object { 4058 | "AWS": "*", 4059 | }, 4060 | "Resource": Array [ 4061 | Object { 4062 | "Fn::GetAtt": Array [ 4063 | "WebAppCloudFrontS3S3BucketE5B829B9", 4064 | "Arn", 4065 | ], 4066 | }, 4067 | Object { 4068 | "Fn::Join": Array [ 4069 | "", 4070 | Array [ 4071 | Object { 4072 | "Fn::GetAtt": Array [ 4073 | "WebAppCloudFrontS3S3BucketE5B829B9", 4074 | "Arn", 4075 | ], 4076 | }, 4077 | "/*", 4078 | ], 4079 | ], 4080 | }, 4081 | ], 4082 | }, 4083 | Object { 4084 | "Action": "s3:GetObject", 4085 | "Effect": "Allow", 4086 | "Principal": Object { 4087 | "CanonicalUser": Object { 4088 | "Fn::GetAtt": Array [ 4089 | "WebAppCloudFrontS3CloudFrontDistributionOrigin1S3OriginAD5F58BE", 4090 | "S3CanonicalUserId", 4091 | ], 4092 | }, 4093 | }, 4094 | "Resource": Object { 4095 | "Fn::Join": Array [ 4096 | "", 4097 | Array [ 4098 | Object { 4099 | "Fn::GetAtt": Array [ 4100 | "WebAppCloudFrontS3S3BucketE5B829B9", 4101 | "Arn", 4102 | ], 4103 | }, 4104 | "/*", 4105 | ], 4106 | ], 4107 | }, 4108 | }, 4109 | ], 4110 | "Version": "2012-10-17", 4111 | }, 4112 | }, 4113 | "Type": "AWS::S3::BucketPolicy", 4114 | }, 4115 | "WebAppCloudFrontS3S3LoggingBucketE71DE76E": Object { 4116 | "DeletionPolicy": "Retain", 4117 | "Metadata": Object { 4118 | "cfn_nag": Object { 4119 | "rules_to_suppress": Array [ 4120 | Object { 4121 | "id": "W35", 4122 | "reason": "This S3 bucket is used as the access logging bucket for another bucket", 4123 | }, 4124 | ], 4125 | }, 4126 | }, 4127 | "Properties": Object { 4128 | "AccessControl": "LogDeliveryWrite", 4129 | "BucketEncryption": Object { 4130 | "ServerSideEncryptionConfiguration": Array [ 4131 | Object { 4132 | "ServerSideEncryptionByDefault": Object { 4133 | "SSEAlgorithm": "AES256", 4134 | }, 4135 | }, 4136 | ], 4137 | }, 4138 | "PublicAccessBlockConfiguration": Object { 4139 | "BlockPublicAcls": true, 4140 | "BlockPublicPolicy": true, 4141 | "IgnorePublicAcls": true, 4142 | "RestrictPublicBuckets": true, 4143 | }, 4144 | "VersioningConfiguration": Object { 4145 | "Status": "Enabled", 4146 | }, 4147 | }, 4148 | "Type": "AWS::S3::Bucket", 4149 | "UpdateReplacePolicy": "Retain", 4150 | }, 4151 | "WebAppCloudFrontS3S3LoggingBucketPolicyDE63F05B": Object { 4152 | "Properties": Object { 4153 | "Bucket": Object { 4154 | "Ref": "WebAppCloudFrontS3S3LoggingBucketE71DE76E", 4155 | }, 4156 | "PolicyDocument": Object { 4157 | "Statement": Array [ 4158 | Object { 4159 | "Action": "s3:*", 4160 | "Condition": Object { 4161 | "Bool": Object { 4162 | "aws:SecureTransport": "false", 4163 | }, 4164 | }, 4165 | "Effect": "Deny", 4166 | "Principal": Object { 4167 | "AWS": "*", 4168 | }, 4169 | "Resource": Array [ 4170 | Object { 4171 | "Fn::GetAtt": Array [ 4172 | "WebAppCloudFrontS3S3LoggingBucketE71DE76E", 4173 | "Arn", 4174 | ], 4175 | }, 4176 | Object { 4177 | "Fn::Join": Array [ 4178 | "", 4179 | Array [ 4180 | Object { 4181 | "Fn::GetAtt": Array [ 4182 | "WebAppCloudFrontS3S3LoggingBucketE71DE76E", 4183 | "Arn", 4184 | ], 4185 | }, 4186 | "/*", 4187 | ], 4188 | ], 4189 | }, 4190 | ], 4191 | }, 4192 | ], 4193 | "Version": "2012-10-17", 4194 | }, 4195 | }, 4196 | "Type": "AWS::S3::BucketPolicy", 4197 | }, 4198 | "WebAppDeployAwsCliLayer11329AB7": Object { 4199 | "Properties": Object { 4200 | "Content": Object { 4201 | "S3Bucket": Object { 4202 | "Fn::Sub": "cdk-hnb659fds-assets-\${AWS::AccountId}-\${AWS::Region}", 4203 | }, 4204 | "S3Key": "92c405c4551a308bcdd55823f8b16268bd3c38fd2a011edaaf3ed72a80f557c4.zip", 4205 | }, 4206 | "Description": "/opt/awscli/aws", 4207 | }, 4208 | "Type": "AWS::Lambda::LayerVersion", 4209 | }, 4210 | "WebAppDeployCustomResource97DAE47A": Object { 4211 | "DeletionPolicy": "Delete", 4212 | "Properties": Object { 4213 | "DestinationBucketName": Object { 4214 | "Ref": "WebAppCloudFrontS3S3BucketE5B829B9", 4215 | }, 4216 | "DistributionId": Object { 4217 | "Ref": "WebAppCloudFrontS3CloudFrontDistribution5EB6A455", 4218 | }, 4219 | "Prune": true, 4220 | "ServiceToken": Object { 4221 | "Fn::GetAtt": Array [ 4222 | "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C81C01536", 4223 | "Arn", 4224 | ], 4225 | }, 4226 | "SourceBucketNames": Array [ 4227 | Object { 4228 | "Fn::Sub": "cdk-hnb659fds-assets-\${AWS::AccountId}-\${AWS::Region}", 4229 | }, 4230 | ], 4231 | "SourceObjectKeys": Array [ 4232 | "86de1795a40d81a3e75be6193d6b6b11b240488a95bd2618eb233ac7cddd9ee5.zip", 4233 | ], 4234 | }, 4235 | "Type": "Custom::CDKBucketDeployment", 4236 | "UpdateReplacePolicy": "Delete", 4237 | }, 4238 | }, 4239 | "Rules": Object { 4240 | "CheckBootstrapVersion": Object { 4241 | "Assertions": Array [ 4242 | Object { 4243 | "Assert": Object { 4244 | "Fn::Not": Array [ 4245 | Object { 4246 | "Fn::Contains": Array [ 4247 | Array [ 4248 | "1", 4249 | "2", 4250 | "3", 4251 | "4", 4252 | "5", 4253 | ], 4254 | Object { 4255 | "Ref": "BootstrapVersion", 4256 | }, 4257 | ], 4258 | }, 4259 | ], 4260 | }, 4261 | "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.", 4262 | }, 4263 | ], 4264 | }, 4265 | }, 4266 | } 4267 | `; 4268 | -------------------------------------------------------------------------------- /test/cdk-chart-app-sample.test.ts: -------------------------------------------------------------------------------- 1 | import * as cdk from 'aws-cdk-lib'; 2 | import { Template } from 'aws-cdk-lib/assertions'; 3 | import { PipelineStack } from '../lib/pipeline-stack'; 4 | import { BackendStack } from '../lib/backend-stack'; 5 | import { FrontendStack } from '../lib/frontend-stack'; 6 | import { APIStack } from '../lib/api-stack'; 7 | 8 | test('PipelineStack matches snapshot', () => { 9 | const app = new cdk.App(); 10 | // WHEN 11 | const stack = new PipelineStack(app, 'Pipeline', { 12 | prefix: 'Summit', 13 | repo: 'aws-samples/cdk-chart-app-sample', 14 | branch: 'main', 15 | connectionArn: 16 | 'arn:aws:codestar-connections:ap-northeast-1:123456789012:connection/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', 17 | }); 18 | // THEN 19 | const template = Template.fromStack(stack); 20 | expect(template.toJSON()).toMatchSnapshot(); 21 | }); 22 | 23 | describe('Stacks match snapshots', () => { 24 | const app = new cdk.App(); 25 | // WHEN 26 | const backend = new BackendStack(app, `Backend`); 27 | 28 | const api = new APIStack(app, `API`, { 29 | currentTable: backend.currentTable, 30 | }); 31 | 32 | const frontend = new FrontendStack(app, `Frontend`); 33 | 34 | test('BackendStack matches snapshot', () => { 35 | expect(Template.fromStack(backend).toJSON()).toMatchSnapshot(); 36 | }); 37 | 38 | test('APIStack matches snapshot', () => { 39 | expect(Template.fromStack(api).toJSON()).toMatchSnapshot(); 40 | }); 41 | 42 | test('FrontendStack matches snapshot', () => { 43 | expect(Template.fromStack(frontend).toJSON()).toMatchSnapshot(); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2018", 4 | "module": "commonjs", 5 | "lib": ["es2018"], 6 | "declaration": true, 7 | "strict": true, 8 | "noImplicitAny": true, 9 | "strictNullChecks": true, 10 | "noImplicitThis": true, 11 | "alwaysStrict": true, 12 | "noUnusedLocals": false, 13 | "noUnusedParameters": false, 14 | "noImplicitReturns": true, 15 | "noFallthroughCasesInSwitch": false, 16 | "inlineSourceMap": true, 17 | "inlineSources": true, 18 | "experimentalDecorators": true, 19 | "strictPropertyInitialization": false, 20 | "typeRoots": ["./node_modules/@types"] 21 | }, 22 | "exclude": ["node_modules", "cdk.out"], 23 | "include": ["bin", "lib"] 24 | } 25 | -------------------------------------------------------------------------------- /webapp/dashboard/.env: -------------------------------------------------------------------------------- 1 | REACT_APP_API_BASE_URL=https://example.com/ 2 | -------------------------------------------------------------------------------- /webapp/dashboard/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /webapp/dashboard/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Create React App 2 | 3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 4 | 5 | ## Available Scripts 6 | 7 | In the project directory, you can run: 8 | 9 | ### `npm start` 10 | 11 | Runs the app in the development mode.\ 12 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 13 | 14 | The page will reload if you make edits.\ 15 | You will also see any lint errors in the console. 16 | 17 | ### `npm test` 18 | 19 | Launches the test runner in the interactive watch mode.\ 20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 21 | 22 | ### `npm run build` 23 | 24 | Builds the app for production to the `build` folder.\ 25 | It correctly bundles React in production mode and optimizes the build for the best performance. 26 | 27 | The build is minified and the filenames include the hashes.\ 28 | Your app is ready to be deployed! 29 | 30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 31 | 32 | ### `npm run eject` 33 | 34 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 35 | 36 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 37 | 38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 39 | 40 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 41 | 42 | ## Learn More 43 | 44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 45 | 46 | To learn React, check out the [React documentation](https://reactjs.org/). 47 | -------------------------------------------------------------------------------- /webapp/dashboard/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dashboard", 3 | "version": "0.1.0", 4 | "private": true, 5 | "devDependencies": { 6 | "@svgr/webpack": "^6.2.1", 7 | "@testing-library/jest-dom": "^5.16.4", 8 | "@testing-library/react": "^13.3.0", 9 | "@testing-library/user-event": "^13.5.0", 10 | "@types/jest": "^27.5.2", 11 | "@types/luxon": "^2.3.2", 12 | "@types/node": "^16.11.41", 13 | "@types/react": "^18.0.14", 14 | "@types/react-dom": "^18.0.5", 15 | "@types/url-join": "^4.0.1", 16 | "react-scripts": "5.0.1", 17 | "typescript": "^4.7.4" 18 | }, 19 | "overrides": { 20 | "@svgr/webpack": "$@svgr/webpack" 21 | }, 22 | "dependencies": { 23 | "chart.js": "^3.8.0", 24 | "luxon": "^2.5.2", 25 | "react": "^18.2.0", 26 | "react-chartjs-2": "^4.2.0", 27 | "react-dom": "^18.2.0", 28 | "url-join": "^5.0.0", 29 | "web-vitals": "^2.1.4" 30 | }, 31 | "scripts": { 32 | "start": "react-scripts start", 33 | "build": "react-scripts build", 34 | "test": "react-scripts test", 35 | "eject": "react-scripts eject" 36 | }, 37 | "eslintConfig": { 38 | "extends": [ 39 | "react-app", 40 | "react-app/jest" 41 | ] 42 | }, 43 | "browserslist": { 44 | "production": [ 45 | ">0.2%", 46 | "not dead", 47 | "not op_mini all" 48 | ], 49 | "development": [ 50 | "last 1 chrome version", 51 | "last 1 firefox version", 52 | "last 1 safari version" 53 | ] 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /webapp/dashboard/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/cdk-chart-app-sample/9e4f7be203a3dc1badf0af5a7fd00b56f55a9e2d/webapp/dashboard/public/favicon.ico -------------------------------------------------------------------------------- /webapp/dashboard/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 14 | 15 | 24 | React App 25 | 26 | 27 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /webapp/dashboard/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/cdk-chart-app-sample/9e4f7be203a3dc1badf0af5a7fd00b56f55a9e2d/webapp/dashboard/public/logo192.png -------------------------------------------------------------------------------- /webapp/dashboard/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/cdk-chart-app-sample/9e4f7be203a3dc1badf0af5a7fd00b56f55a9e2d/webapp/dashboard/public/logo512.png -------------------------------------------------------------------------------- /webapp/dashboard/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /webapp/dashboard/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /webapp/dashboard/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /webapp/dashboard/src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, screen } from '@testing-library/react'; 3 | import App from './App'; 4 | 5 | test('renders learn react link', () => { 6 | render(); 7 | const linkElement = screen.getByText(/learn react/i); 8 | expect(linkElement).toBeInTheDocument(); 9 | }); 10 | -------------------------------------------------------------------------------- /webapp/dashboard/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './App.css'; 3 | import { MyChart } from './Chart'; 4 | 5 | function App() { 6 | return ( 7 |
8 |

AWS CDK Chart App Sample

9 | 10 |
11 | ); 12 | } 13 | 14 | export default App; 15 | -------------------------------------------------------------------------------- /webapp/dashboard/src/Chart.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react'; 2 | import { Chart as ChartJS, registerables, ChartData } from 'chart.js'; 3 | import { Chart, ChartProps } from 'react-chartjs-2'; 4 | import { DateTime } from 'luxon'; 5 | import urljoin from 'url-join'; 6 | 7 | ChartJS.register(...registerables); 8 | 9 | type MyChartProps = { 10 | deviceId: string; 11 | }; 12 | 13 | type Metric = { 14 | timestamp: string; 15 | value: number; 16 | }; 17 | 18 | const timeFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'"; 19 | 20 | const getMetrics = async (props: MyChartProps): Promise => { 21 | const params = { 22 | deviceId: props.deviceId, 23 | }; 24 | const query = new URLSearchParams(params); 25 | const res = await fetch(urljoin(process.env.REACT_APP_API_BASE_URL!, `metrics?${query}`)); 26 | 27 | return res.json(); 28 | }; 29 | 30 | export const MyChart = (props: MyChartProps): JSX.Element => { 31 | const [metrics, setMetrics] = useState([]); 32 | 33 | useEffect(() => { 34 | getMetrics(props) 35 | .then((m) => { 36 | setMetrics(m); 37 | }) 38 | .catch((e) => { 39 | console.log(e); 40 | }); 41 | }, [props]); 42 | 43 | const data: ChartData<'line', number[], string> = { 44 | labels: metrics.map((m) => 45 | DateTime.fromFormat(m.timestamp, timeFormat, { zone: 'UTC' }) 46 | .toLocal() 47 | .toLocaleString(DateTime.TIME_24_WITH_SECONDS), 48 | ), 49 | datasets: [ 50 | { 51 | type: 'line', 52 | label: 'value', 53 | data: metrics.map((m) => m.value), 54 | borderColor: 'rgba(245, 195, 66, 0.9)', 55 | }, 56 | ], 57 | }; 58 | 59 | const options: ChartProps['options'] = { 60 | responsive: true, 61 | }; 62 | 63 | return ; 64 | }; 65 | -------------------------------------------------------------------------------- /webapp/dashboard/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 4 | 'Droid Sans', 'Helvetica Neue', sans-serif; 5 | -webkit-font-smoothing: antialiased; 6 | -moz-osx-font-smoothing: grayscale; 7 | } 8 | 9 | code { 10 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; 11 | } 12 | -------------------------------------------------------------------------------- /webapp/dashboard/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement); 8 | root.render( 9 | 10 | 11 | , 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /webapp/dashboard/src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /webapp/dashboard/src/reportWebVitals.ts: -------------------------------------------------------------------------------- 1 | import { ReportHandler } from 'web-vitals'; 2 | 3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => { 4 | if (onPerfEntry && onPerfEntry instanceof Function) { 5 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 6 | getCLS(onPerfEntry); 7 | getFID(onPerfEntry); 8 | getFCP(onPerfEntry); 9 | getLCP(onPerfEntry); 10 | getTTFB(onPerfEntry); 11 | }); 12 | } 13 | }; 14 | 15 | export default reportWebVitals; 16 | -------------------------------------------------------------------------------- /webapp/dashboard/src/setupTests.ts: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /webapp/dashboard/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "module": "esnext", 13 | "moduleResolution": "node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src"] 20 | } 21 | --------------------------------------------------------------------------------