├── .DS_Store ├── .github └── PULL_REQUEST_TEMPLATE.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── NOTICE ├── README.md ├── images ├── 00-cf-create.png ├── 00-cloud9-select.png ├── 00-cloud9-welcome.png ├── cfn-iam-capabilities.png ├── deploy-to-aws.png └── mysfits-welcome.png ├── workshop-1 ├── .DS_Store ├── README.md ├── app │ ├── .DS_Store │ ├── buildspec.yml │ ├── like-service │ │ ├── Dockerfile │ │ └── service │ │ │ ├── mysfits_like.py │ │ │ └── requirements.txt │ └── monolith-service │ │ ├── Dockerfile.draft │ │ └── service │ │ ├── mysfitsTableClient.py │ │ ├── mythicalMysfitsService.py │ │ └── requirements.txt ├── core.yml ├── images │ ├── 00-cf-create.png │ ├── 00-cloud9-select.png │ ├── 00-cloud9-welcome.png │ ├── 00-website.png │ ├── 01-arch.png │ ├── 01-container-image.png │ ├── 01-ecr-push-complete.png │ ├── 01-ecr-repo-uri.png │ ├── 01-ecr-repo.png │ ├── 02-arch.png │ ├── 02-awslogs.png │ ├── 02-cloudwatch-logs.png │ ├── 02-public-IP.png │ ├── 02-run-task.png │ ├── 02-task-def-edit-container.png │ ├── 02-task-pending.png │ ├── 02-task-running.png │ ├── 03-arch.png │ ├── 03-deployment.png │ ├── 03-fully-deployed.png │ ├── 03-like-count.png │ ├── 03-like-processed.png │ ├── 03-nginx.png │ ├── 03-update-service.png │ ├── 03-website.png │ ├── 04-arch.png │ ├── 04-containerdef.png │ ├── 04-ecr-like.png │ ├── 04-ecr-nolike2.png │ ├── 04-ecs-service-alb-detail.png │ ├── 04-ecs-service-alb.png │ ├── 04-ecs-service-step1.png │ ├── 04-ecs-service-vpc.png │ ├── 04-env-var.png │ ├── 04-logging.png │ ├── 04-taskdef.png │ ├── aws_mythical_banner.png │ ├── chimera_hover.png │ ├── chimera_thumb.png │ ├── cyclops_hover.png │ ├── cyclops_thumb.png │ ├── dragon_hover.png │ ├── dragon_thumb.png │ ├── gorgon_hover.png │ ├── gorgon_thumb.png │ ├── haetae_hover.png │ ├── haetae_thumb.png │ ├── kraken_hover.png │ ├── kraken_thumb.png │ ├── like_icon_false.png │ ├── like_icon_true.png │ ├── mandrake_hover.png │ ├── mandrake_thumb.png │ ├── mysfits_banner.gif │ ├── nessie_hover.png │ ├── nessie_thumb.png │ ├── pegasus_hover.png │ ├── pegasus_thumb.png │ ├── phoenix_hover.png │ ├── phoenix_thumb.png │ ├── troll_hover.png │ ├── troll_thumb.png │ ├── yeti_hover.png │ └── yeti_thumb.png ├── pipeline.temp ├── script │ ├── associate-profile │ ├── credhelper │ ├── fetch-outputs │ ├── load-ddb │ ├── resize │ ├── setup │ └── upload-site └── web │ ├── confirm.html │ ├── images │ ├── aws_mythical_banner.png │ ├── chimera_hover.png │ ├── chimera_thumb.png │ ├── cyclops_hover.png │ ├── cyclops_thumb.png │ ├── dragon_hover.png │ ├── dragon_thumb.png │ ├── gorgon_hover.png │ ├── gorgon_thumb.png │ ├── haetae_hover.png │ ├── haetae_thumb.png │ ├── kraken_hover.png │ ├── kraken_thumb.png │ ├── like_icon_false.png │ ├── like_icon_true.png │ ├── mandrake_hover.png │ ├── mandrake_thumb.png │ ├── mysfits_banner.gif │ ├── nessie_hover.png │ ├── nessie_thumb.png │ ├── pegasus_hover.png │ ├── pegasus_thumb.png │ ├── phoenix_hover.png │ ├── phoenix_thumb.png │ ├── troll_hover.png │ ├── troll_thumb.png │ ├── yeti_hover.png │ └── yeti_thumb.png │ ├── index.html │ ├── js │ ├── amazon-cognito-identity.min.js │ ├── aws-cognito-sdk.min.js │ └── aws-sdk-2.246.1.min.js │ └── register.html ├── workshop-2 ├── .DS_Store ├── Lab-0 │ ├── .DS_Store │ ├── README.md │ └── images │ │ ├── arch-starthere.png │ │ ├── cfn-create-complete.png │ │ ├── cfn-createstack-1.png │ │ ├── cfn-createstack-2.png │ │ ├── cfn-iam-capabilities.png │ │ ├── cloud9-environment.png │ │ ├── cloud9-list.png │ │ ├── cloud9.png │ │ ├── ecr-list-repos.png │ │ ├── ecs-taskdef-change-image.png │ │ ├── ecs-taskdef-describe.png │ │ └── ecs-taskdef-update-success.png ├── Lab-1 │ └── README.md ├── Lab-2 │ ├── .DS_Store │ ├── README.md │ ├── hints │ │ ├── buildspec_dev.yml.draft │ │ └── hintspec_dev.yml │ └── images │ │ ├── .DS_Store │ │ ├── arch-codebuild.png │ │ ├── cb-create-1-old.png │ │ ├── cb-create-1-old2.png │ │ ├── cb-create-1.png │ │ ├── cb-create-project-1-2.png │ │ ├── cb-create-project-1.png │ │ ├── cb-create-project-2.png │ │ ├── cb-create-project-envvar.png │ │ ├── cb-success.png │ │ ├── ecr-get-like-commands.png │ │ └── ecr-new-image.png ├── Lab-3 │ ├── .DS_Store │ ├── README.md │ ├── hints │ │ └── buildspec_prod.yml │ ├── images │ │ ├── cp-add-source.png │ │ ├── cp-create-cb-1.png │ │ ├── cp-create-cb-complete.png │ │ ├── cp-create-name-old.png │ │ ├── cp-create-name.png.png │ │ ├── cp-create-source.png │ │ ├── cp-deploy-step-old.png │ │ ├── cp-deploy-step.png │ │ └── cp-deploy-success.png │ └── mysfits_like_v2.py ├── Lab-4 │ ├── README.md │ ├── hints │ │ └── buildspec_clair.yml │ └── images │ │ ├── arch-codebuild.png │ │ ├── cb-create-1.png │ │ ├── cb-create-project-1-2.png │ │ ├── cb-create-project-1.png │ │ ├── cb-create-project-2.png │ │ ├── cb-create-project-envvar.png │ │ ├── cb-create-test-project-1.png │ │ ├── cb-create-test-project-2.png │ │ ├── cb-success.png │ │ ├── clair-action.png │ │ ├── cloud9.png │ │ ├── cp-create-action.png │ │ ├── ecr-get-like-commands.png │ │ ├── ecr-new-image.png │ │ ├── edit-pipeline.png │ │ └── klar-logs.png ├── README.md ├── app │ ├── buildspec.yml │ ├── like-service │ │ ├── Dockerfile │ │ └── service │ │ │ ├── mysfits_like.py │ │ │ └── requirements.txt │ └── monolith-service │ │ ├── Dockerfile │ │ └── service │ │ ├── mysfitsTableClient.py │ │ ├── mythicalMysfitsService.py │ │ └── requirements.txt ├── core.yml ├── script │ ├── fetch-outputs │ ├── load-ddb │ ├── populate-dynamodb.json │ ├── setup │ ├── setup_ws1_end │ ├── upload-site │ ├── ws2 │ │ ├── bootstrap_ws2 │ │ ├── build-containers │ │ ├── create-fargate-services │ │ ├── service-template.json │ │ └── update-service-json │ └── ws3 │ │ ├── bootstrap_ws3 │ │ ├── clone │ │ └── populate ├── slides │ └── CON321.pdf ├── web │ ├── confirm.html │ ├── index.html │ ├── js │ │ ├── amazon-cognito-identity.min.js │ │ ├── aws-cognito-sdk.min.js │ │ └── aws-sdk-2.246.1.min.js │ └── register.html └── ws3-start │ ├── app │ ├── like-service │ │ ├── Dockerfile │ │ ├── buildspec_prod.yml │ │ └── service │ │ │ ├── mysfits_like.py │ │ │ └── requirements.txt │ └── monolith-service │ │ ├── Dockerfile │ │ └── service │ │ ├── mysfitsTableClient.py │ │ ├── mythicalMysfitsService.py │ │ └── requirements.txt │ └── core.yml └── workshop-3 ├── README.md ├── app ├── like-service │ ├── .DS_Store │ ├── Dockerfile │ ├── buildspec_prod.yml │ └── service │ │ ├── mmchaos.py │ │ ├── mysfits_like.py │ │ └── requirements.txt ├── monolith-service │ ├── Dockerfile │ └── service │ │ ├── mysfitsTableClient.py │ │ ├── mythicalMysfitsService.py │ │ └── requirements.txt └── xray │ └── Dockerfile ├── cfn-templates └── load-gen-lab4.yml ├── core.yml ├── images ├── .DS_Store ├── 02-03-ESProcessing.png ├── 02-03-cwlLikes.png ├── 02-03-cwlStreamES.png ├── 02-03-cwlStreamESConfig.png ├── 02-03-cwlSubscription.png ├── 02-03-enableKibanaCognitoAuth.png ├── 02-03-kibanaIndexPattern.png ├── 02-03-kibanaTimeFilter.png ├── 02-03-logLevelDebug.png ├── 02-03-serviceUpdate.png ├── 02-03-startStreaming.png ├── 02-03-userPoolDomain.png ├── 03-JSconsole.png ├── 03-commitInstrumented.png ├── 03-elbHealthCheckTrace.png ├── 03-filterGroup.png ├── 03-likeInstrumented.png ├── 03-pipeline.png ├── 03-requirements.png ├── 03-serviceMap.png ├── 03-updateLikeService.png ├── 03-xraySidecar.png ├── architecture-diagram-aws-developer-center_mythical-mysfits-application-architecture.png ├── architecture_diagram_ws3_lab_1.png ├── architecture_diagram_ws3_starting_point.png ├── lab1.3.task-network-ip.png └── mysfits-welcome.png ├── script ├── fetch-outputs ├── load-ddb ├── populate-dynamodb.json ├── setup ├── setup_ws1_end ├── upload-site ├── ws2 │ ├── bootstrap_ws2 │ ├── build-containers │ ├── create-fargate-services │ ├── service-template.json │ └── update-service-json └── ws3 │ ├── bootstrap_ws3 │ ├── clone │ └── populate └── web ├── confirm.html ├── index.html ├── js ├── amazon-cognito-identity.min.js ├── aws-cognito-sdk.min.js └── aws-sdk-2.246.1.min.js └── register.html /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/.DS_Store -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | *Issue #, if available:* 2 | 3 | *Description of changes:* 4 | 5 | 6 | By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license. 7 | -------------------------------------------------------------------------------- /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](https://github.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/issues), or [recently closed](https://github.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), 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 *master* 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'](https://github.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/labels/help%20wanted) 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](https://github.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/blob/master/LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | 61 | We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. 62 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | AWS Modern Application Development Workshop 2 | Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Mythical Mysfits: A tale of love, loss, and cuddles 2 | 3 | ![mysfits-welcome](/images/mysfits-welcome.png) 4 | 5 | # Will you help us find their forever homes? 6 | 7 | **Mythical Mysfits** is a (fictional) pet adoption non-profit dedicated to helping abandoned, and often misunderstood, mythical creatures find a new forever family! Mythical Mysfits believes that all creatures deserve a second chance, even if they spent their first chance hiding under bridges and unapologetically robbing helpless travelers. 8 | 9 | Our business has been thriving with only a single Mysfits adoption center, located inside Devils Tower National Monument. Speak, friend, and enter should you ever come to visit. 10 | 11 | We've just had a surge of new mysfits arrive at our door with nowhere else to go! They're all pretty distraught after not only being driven from their homes... but an immensely grumpy ogre has also denied them all entry at a swamp they've used for refuge in the past. 12 | 13 | That's why we've hired you to be our first Full Stack Engineer. We need a more scalable way to show off our inventory of mysfits and let families adopt them. We'd like you to build the first Mythical Mysfits adoption website to help introduce these lovable, magical, often mischievous creatures to the world! 14 | 15 | ### Requirements: 16 | * AWS account - if you don't have one, it's easy and free to [create one](https://aws.amazon.com/) 17 | * AWS IAM account with elevated privileges allowing you to interact with various AWS Services 18 | * Familiarity with Python, vim/emacs/nano, [Docker](https://www.docker.com/), AWS and microservices - not required but a bonus 19 | 20 | ### Learning Paths 21 | 22 | This is a 3-part workshop series running at AWS re:Invent 2018 (CON214/CON321/CON322): 23 | 24 | * [CON214: Monolith to Microservices with Docker and AWS Fargate](workshop-1/) 25 | * [CON321: DevSecOps with Docker and AWS Fargate](workshop-2/) 26 | * [CON322: Management and Operations with AWS Fargate](workshop-3) 27 | 28 | ### Session Times 29 | 30 | These session times and locations are provided as a reference. Check your session guide for the latest details. 31 | 32 | **CON214-R: Monolith to Microservices with Docker and AWS Fargate** 33 | - Monday, Nov 26, 10:45 AM - 1:00 PM 34 | - MGM, Level 3, Premier Ballroom 320 35 | 36 | **CON214-R1: Monolith to Microservices with Docker and AWS Fargate** 37 | - Tuesday, Nov 27, 9:15 AM - 11:30 AM 38 | - Venetian, Level 4, Lando 4205 39 | 40 | **CON321-R: DevSecOps with Docker and AWS Fargate** 41 | - Monday, Nov 26, 10:45 AM - 1:00 PM 42 | - MGM, Level 3, Premier Ballroom 311 43 | 44 | **CON321-R1: DevSecOps with Docker and AWS Fargate** 45 | - Tuesday, Nov 27, 12:15 PM - 2:30 PM 46 | - MGM, Level 3, Premier Ballroom 320 47 | 48 | **CON321-R2: DevSecOps with Docker and AWS Fargate** 49 | - Friday, Nov 30, 8:30 AM - 10:45 AM 50 | - Venetian, Level 2, Veronese 2404 51 | 52 | **CON322-R: Management and Operations with AWS Fargate** 53 | - Wednesday, Nov 28, 11:30 AM - 1:45 PM 54 | - Mirage, Mirage Event Center C1 55 | 56 | **CON322-R1: Management and Operations with AWS Fargate** 57 | - Friday, Nov 30, 8:30 AM - 10:45 AM 58 | - Mirage, Bermuda A 59 | 60 | -------------------------------------------------------------------------------- /images/00-cf-create.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/images/00-cf-create.png -------------------------------------------------------------------------------- /images/00-cloud9-select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/images/00-cloud9-select.png -------------------------------------------------------------------------------- /images/00-cloud9-welcome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/images/00-cloud9-welcome.png -------------------------------------------------------------------------------- /images/cfn-iam-capabilities.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/images/cfn-iam-capabilities.png -------------------------------------------------------------------------------- /images/deploy-to-aws.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/images/deploy-to-aws.png -------------------------------------------------------------------------------- /images/mysfits-welcome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/images/mysfits-welcome.png -------------------------------------------------------------------------------- /workshop-1/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/.DS_Store -------------------------------------------------------------------------------- /workshop-1/app/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/app/.DS_Store -------------------------------------------------------------------------------- /workshop-1/app/buildspec.yml: -------------------------------------------------------------------------------- 1 | # A buildspec.yml file informs AWS CodeBuild of all the actions that should be 2 | # taken during a build execution for our application. We are able to divide the 3 | # build execution in separate pre-defined phases for logical organization, and 4 | # list the commands that will be executed on the provisioned build server 5 | # performing a build execution job. 6 | version: 0.2 7 | 8 | phases: 9 | pre_build: 10 | commands: 11 | - echo Logging in to Amazon ECR... 12 | # Retrieves docker credentials so that the subsequent docker push command is 13 | # authorized. Authentication is performed automatically by the AWS CLI 14 | # using the AWS credentials associated with the IAM role assigned to the 15 | # instances in your AWS CodeBuild project. 16 | - $(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION) 17 | build: 18 | commands: 19 | - echo Build started on `date` 20 | - echo Building the Docker image... 21 | - docker build -t mythicalmysfits/service:latest . 22 | # Tag the built docker image using the appropriate Amazon ECR endpoint and relevant 23 | # repository for our service container. This ensures that when the docker push 24 | # command is executed later, it will be pushed to the appropriate repository. 25 | - docker tag mythicalmysfits/service:latest $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/mythicalmysfits/service:latest 26 | post_build: 27 | commands: 28 | - echo Build completed on `date` 29 | - echo Pushing the Docker image.. 30 | # Push the image to ECR. 31 | - docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/mythicalmysfits/service:latest 32 | - echo Completed pushing Docker image. Deploying Docker image to AWS Fargate on `date` 33 | # Create a artifacts file that contains the name and location of the image 34 | # pushed to ECR. This will be used by AWS CodePipeline to automate 35 | # deployment of this specific container to Amazon ECS. 36 | - printf '[{"name":"MythicalMysfits-Service","imageUri":"%s"}]' $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/mythicalmysfits/service:latest > imagedefinitions.json 37 | artifacts: 38 | # Indicate that the created imagedefinitions.json file created on the previous 39 | # line is to be referenceable as an artifact of the build execution job. 40 | files: imagedefinitions.json 41 | -------------------------------------------------------------------------------- /workshop-1/app/like-service/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | RUN echo Updating existing packages, installing and upgrading python and pip. 3 | RUN apt-get update -y 4 | RUN apt-get install -y python3-pip python-dev build-essential 5 | RUN pip3 install --upgrade pip 6 | RUN echo Copying the Mythical Mysfits Flask service into a service directory. 7 | COPY ./service /MythicalMysfitsService 8 | WORKDIR /MythicalMysfitsService 9 | RUN echo Installing Python packages listed in requirements.txt 10 | RUN pip3 install -r ./requirements.txt 11 | RUN echo Starting python and starting the Flask service... 12 | ENTRYPOINT ["python3"] 13 | CMD ["mysfits_like.py"] 14 | -------------------------------------------------------------------------------- /workshop-1/app/like-service/service/mysfits_like.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | import os 4 | import sys 5 | import requests 6 | from urllib.parse import urlparse 7 | from flask import Flask, jsonify, json, Response, request 8 | from flask_cors import CORS 9 | 10 | app = Flask(__name__) 11 | CORS(app) 12 | 13 | # The service basepath has a short response just to ensure that healthchecks 14 | # sent to the service root will receive a healthy response. 15 | @app.route("/") 16 | def health_check_response(): 17 | return jsonify({'message' : 'Nothing here, used for health check.'}) 18 | # indicate that the provided mysfit should be marked as liked. 19 | 20 | def process_like_request(): 21 | print('Like processed.', file=sys.stderr) 22 | 23 | def fulfill_like(mysfit_id): 24 | url = urlparse('http://{}/mysfits/{}/fulfill-like'.format(os.environ['MONOLITH_URL'], mysfit_id)) 25 | return requests.post(url=url.geturl()) 26 | 27 | 28 | @app.route("/mysfits//like", methods=['POST']) 29 | def like_mysfit(mysfit_id): 30 | process_like_request() 31 | service_response = fulfill_like(mysfit_id) 32 | 33 | flask_response = Response(service_response) 34 | flask_response.headers["Content-Type"] = "application/json" 35 | 36 | return flask_response 37 | 38 | # Run the service on the local server it has been deployed to, 39 | # listening on port 8080. 40 | if __name__ == "__main__": 41 | app.run(host="0.0.0.0", port=80) 42 | -------------------------------------------------------------------------------- /workshop-1/app/like-service/service/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==2.2.5 2 | flask-cors==3.0.10 3 | requests==2.31.0 4 | markupsafe==2.1.3 -------------------------------------------------------------------------------- /workshop-1/app/monolith-service/Dockerfile.draft: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | RUN apt-get update -y 3 | RUN apt-get install -y python3-pip python-dev build-essential 4 | RUN pip3 install --upgrade pip 5 | #[TODO]: Copy python source files and requirements file into container image 6 | 7 | #[TODO]: Install dependencies listed in the requirements.txt file using pip3 8 | 9 | #[TODO]: Specify a listening port for the container 10 | 11 | #[TODO]: Run mythicalMysfitsService.py as the final step. We want this container to run as an executable. Looking at ENTRYPOINT and CMD for this? 12 | -------------------------------------------------------------------------------- /workshop-1/app/monolith-service/service/mysfitsTableClient.py: -------------------------------------------------------------------------------- 1 | import boto3 2 | import json 3 | import logging 4 | import os 5 | from collections import defaultdict 6 | 7 | # create a DynamoDB client using boto3. The boto3 library will automatically 8 | # use the credentials associated with our ECS task role to communicate with 9 | # DynamoDB, so no credentials need to be stored/managed at all by our code! 10 | client = boto3.client('dynamodb') 11 | table_name = os.environ['DDB_TABLE_NAME'] 12 | 13 | def getAllMysfits(): 14 | 15 | # Retrieve all Mysfits from DynamoDB using the DynamoDB scan operation. 16 | # Note: The scan API can be expensive in terms of latency when a DynamoDB 17 | # table contains a high number of records and filters are applied to the 18 | # operation that require a large amount of data to be scanned in the table 19 | # before a response is returned by DynamoDB. For high-volume tables that 20 | # receive many requests, it is common to store the result of frequent/common 21 | # scan operations in an in-memory cache. DynamoDB Accelerator (DAX) or 22 | # use of ElastiCache can provide these benefits. But, because out Mythical 23 | # Mysfits API is low traffic and the table is very small, the scan operation 24 | # will suit our needs for this workshop. 25 | response = client.scan( 26 | TableName=table_name 27 | ) 28 | 29 | logging.info(response["Items"]) 30 | 31 | # loop through the returned mysfits and add their attributes to a new dict 32 | # that matches the JSON response structure expected by the frontend. 33 | mysfitList = defaultdict(list) 34 | for item in response["Items"]: 35 | mysfit = {} 36 | mysfit["mysfitId"] = item["MysfitId"]["S"] 37 | mysfit["name"] = item["Name"]["S"] 38 | mysfit["goodevil"] = item["GoodEvil"]["S"] 39 | mysfit["lawchaos"] = item["LawChaos"]["S"] 40 | mysfit["species"] = item["Species"]["S"] 41 | mysfit["thumbImageUri"] = item["ThumbImageUri"]["S"] 42 | mysfitList["mysfits"].append(mysfit) 43 | 44 | # convert the create list of dicts in to JSON 45 | return json.dumps(mysfitList) 46 | 47 | def queryMysfits(queryParam): 48 | 49 | logging.info(json.dumps(queryParam)) 50 | 51 | # Use the DynamoDB API Query to retrieve mysfits from the table that are 52 | # equal to the selected filter values. 53 | response = client.query( 54 | TableName=table_name, 55 | IndexName=queryParam['filter']+'Index', 56 | KeyConditions={ 57 | queryParam['filter']: { 58 | 'AttributeValueList': [ 59 | { 60 | 'S': queryParam['value'] 61 | } 62 | ], 63 | 'ComparisonOperator': "EQ" 64 | } 65 | } 66 | ) 67 | 68 | mysfitList = defaultdict(list) 69 | for item in response["Items"]: 70 | mysfit = {} 71 | mysfit["mysfitId"] = item["MysfitId"]["S"] 72 | mysfit["name"] = item["Name"]["S"] 73 | mysfit["goodevil"] = item["GoodEvil"]["S"] 74 | mysfit["lawchaos"] = item["LawChaos"]["S"] 75 | mysfit["species"] = item["Species"]["S"] 76 | mysfit["thumbImageUri"] = item["ThumbImageUri"]["S"] 77 | mysfitList["mysfits"].append(mysfit) 78 | 79 | return json.dumps(mysfitList) 80 | 81 | # Retrive a single mysfit from DynamoDB using their unique mysfitId 82 | def getMysfit(mysfitId): 83 | 84 | # use the DynamoDB API GetItem, which gives you the ability to retrieve 85 | # a single item from a DynamoDB table using its unique key with super 86 | # low latency. 87 | response = client.get_item( 88 | TableName=table_name, 89 | Key={ 90 | 'MysfitId': { 91 | 'S': mysfitId 92 | } 93 | } 94 | ) 95 | 96 | item = response["Item"] 97 | 98 | mysfit = {} 99 | mysfit["mysfitId"] = item["MysfitId"]["S"] 100 | mysfit["name"] = item["Name"]["S"] 101 | mysfit["age"] = int(item["Age"]["N"]) 102 | mysfit["goodevil"] = item["GoodEvil"]["S"] 103 | mysfit["lawchaos"] = item["LawChaos"]["S"] 104 | mysfit["species"] = item["Species"]["S"] 105 | mysfit["description"] = item["Description"]["S"] 106 | mysfit["thumbImageUri"] = item["ThumbImageUri"]["S"] 107 | mysfit["profileImageUri"] = item["ProfileImageUri"]["S"] 108 | mysfit["likes"] = item["Likes"]["N"] 109 | mysfit["adopted"] = item["Adopted"]["BOOL"] 110 | 111 | return json.dumps(mysfit) 112 | 113 | # increment the number of likes for a mysfit by 1 114 | def likeMysfit(mysfitId): 115 | 116 | # Use the DynamoDB API UpdateItem to increment the number of Likes 117 | # the mysfit has by 1 using an UpdateExpression. 118 | response = client.update_item( 119 | TableName=table_name, 120 | Key={ 121 | 'MysfitId': { 122 | 'S': mysfitId 123 | } 124 | }, 125 | UpdateExpression="SET Likes = Likes + :n", 126 | ExpressionAttributeValues={':n': {'N': '1'}} 127 | ) 128 | 129 | response = {} 130 | response["Update"] = "Success"; 131 | 132 | return json.dumps(response) 133 | 134 | # mark a mysfit as adopted 135 | def adoptMysfit(mysfitId): 136 | 137 | # Use the DynamoDB API UpdateItem to set the value of the mysfit's 138 | # Adopted attribute to True using an UpdateExpression. 139 | response = client.update_item( 140 | TableName=table_name, 141 | Key={ 142 | 'MysfitId': { 143 | 'S': mysfitId 144 | } 145 | }, 146 | UpdateExpression="SET Adopted = :b", 147 | ExpressionAttributeValues={':b': {'BOOL': True}} 148 | ) 149 | 150 | response = {} 151 | response["Update"] = "Success"; 152 | 153 | return json.dumps(response) 154 | -------------------------------------------------------------------------------- /workshop-1/app/monolith-service/service/mythicalMysfitsService.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | from flask import Flask, jsonify, json, Response, request 4 | from flask_cors import CORS 5 | import mysfitsTableClient 6 | import os 7 | import sys 8 | 9 | app = Flask(__name__) 10 | CORS(app) 11 | 12 | # The service basepath has a short response just to ensure that healthchecks 13 | # sent to the service root will receive a healthy response. 14 | @app.route("/") 15 | def healthCheckResponse(): 16 | return jsonify({'message' : 'Nothing here, used for health check.'}) 17 | 18 | # Retrive mysfits from DynamoDB based on provided querystring params, or all 19 | # mysfits if no querystring is present. 20 | @app.route("/mysfits", methods=['GET']) 21 | def getMysfits(): 22 | 23 | filterCategory = request.args.get('filter') 24 | if filterCategory: 25 | filterValue = request.args.get('value') 26 | queryParam = { 27 | 'filter': filterCategory, 28 | 'value': filterValue 29 | } 30 | serviceResponse = mysfitsTableClient.queryMysfits(queryParam) 31 | else: 32 | serviceResponse = mysfitsTableClient.getAllMysfits() 33 | 34 | flaskResponse = Response(serviceResponse) 35 | flaskResponse.headers["Content-Type"] = "application/json" 36 | 37 | return flaskResponse 38 | 39 | def process_like_request(): 40 | print('Like processed.', file=sys.stderr) 41 | 42 | # retrieve the full details for a specific mysfit with their provided path 43 | # parameter as their ID. 44 | @app.route("/mysfits/", methods=['GET']) 45 | def getMysfit(mysfit_id): 46 | serviceResponse = mysfitsTableClient.getMysfit(mysfit_id) 47 | 48 | flaskResponse = Response(serviceResponse) 49 | flaskResponse.headers["Content-Type"] = "application/json" 50 | 51 | return flaskResponse 52 | 53 | # increment the number of likes for the provided mysfit. 54 | @app.route("/mysfits//like", methods=['POST']) 55 | def likeMysfit(mysfit_id): 56 | serviceResponse = mysfitsTableClient.likeMysfit(mysfit_id) 57 | process_like_request() 58 | flaskResponse = Response(serviceResponse) 59 | flaskResponse.headers["Content-Type"] = "application/json" 60 | return flaskResponse 61 | 62 | # @app.route("/mysfits//fulfill-like", methods=['POST']) 63 | # def fulfillLikeMysfit(mysfit_id): 64 | # serviceResponse = mysfitsTableClient.likeMysfit(mysfit_id) 65 | # flaskResponse = Response(serviceResponse) 66 | # flaskResponse.headers["Content-Type"] = "application/json" 67 | # return flaskResponse 68 | 69 | # indicate that the provided mysfit should be marked as adopted. 70 | @app.route("/mysfits//adopt", methods=['POST']) 71 | def adoptMysfit(mysfit_id): 72 | serviceResponse = mysfitsTableClient.adoptMysfit(mysfit_id) 73 | 74 | flaskResponse = Response(serviceResponse) 75 | flaskResponse.headers["Content-Type"] = "application/json" 76 | 77 | return flaskResponse 78 | 79 | # Run the service on the local server it has been deployed to, 80 | # listening on port 8080. 81 | if __name__ == "__main__": 82 | app.run(host="0.0.0.0", port=80) 83 | -------------------------------------------------------------------------------- /workshop-1/app/monolith-service/service/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==2.2.5 2 | flask-cors==3.0.10 3 | boto3==1.26.148 4 | markupsafe==2.1.3 -------------------------------------------------------------------------------- /workshop-1/images/00-cf-create.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/00-cf-create.png -------------------------------------------------------------------------------- /workshop-1/images/00-cloud9-select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/00-cloud9-select.png -------------------------------------------------------------------------------- /workshop-1/images/00-cloud9-welcome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/00-cloud9-welcome.png -------------------------------------------------------------------------------- /workshop-1/images/00-website.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/00-website.png -------------------------------------------------------------------------------- /workshop-1/images/01-arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/01-arch.png -------------------------------------------------------------------------------- /workshop-1/images/01-container-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/01-container-image.png -------------------------------------------------------------------------------- /workshop-1/images/01-ecr-push-complete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/01-ecr-push-complete.png -------------------------------------------------------------------------------- /workshop-1/images/01-ecr-repo-uri.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/01-ecr-repo-uri.png -------------------------------------------------------------------------------- /workshop-1/images/01-ecr-repo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/01-ecr-repo.png -------------------------------------------------------------------------------- /workshop-1/images/02-arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/02-arch.png -------------------------------------------------------------------------------- /workshop-1/images/02-awslogs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/02-awslogs.png -------------------------------------------------------------------------------- /workshop-1/images/02-cloudwatch-logs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/02-cloudwatch-logs.png -------------------------------------------------------------------------------- /workshop-1/images/02-public-IP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/02-public-IP.png -------------------------------------------------------------------------------- /workshop-1/images/02-run-task.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/02-run-task.png -------------------------------------------------------------------------------- /workshop-1/images/02-task-def-edit-container.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/02-task-def-edit-container.png -------------------------------------------------------------------------------- /workshop-1/images/02-task-pending.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/02-task-pending.png -------------------------------------------------------------------------------- /workshop-1/images/02-task-running.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/02-task-running.png -------------------------------------------------------------------------------- /workshop-1/images/03-arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/03-arch.png -------------------------------------------------------------------------------- /workshop-1/images/03-deployment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/03-deployment.png -------------------------------------------------------------------------------- /workshop-1/images/03-fully-deployed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/03-fully-deployed.png -------------------------------------------------------------------------------- /workshop-1/images/03-like-count.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/03-like-count.png -------------------------------------------------------------------------------- /workshop-1/images/03-like-processed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/03-like-processed.png -------------------------------------------------------------------------------- /workshop-1/images/03-nginx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/03-nginx.png -------------------------------------------------------------------------------- /workshop-1/images/03-update-service.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/03-update-service.png -------------------------------------------------------------------------------- /workshop-1/images/03-website.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/03-website.png -------------------------------------------------------------------------------- /workshop-1/images/04-arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/04-arch.png -------------------------------------------------------------------------------- /workshop-1/images/04-containerdef.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/04-containerdef.png -------------------------------------------------------------------------------- /workshop-1/images/04-ecr-like.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/04-ecr-like.png -------------------------------------------------------------------------------- /workshop-1/images/04-ecr-nolike2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/04-ecr-nolike2.png -------------------------------------------------------------------------------- /workshop-1/images/04-ecs-service-alb-detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/04-ecs-service-alb-detail.png -------------------------------------------------------------------------------- /workshop-1/images/04-ecs-service-alb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/04-ecs-service-alb.png -------------------------------------------------------------------------------- /workshop-1/images/04-ecs-service-step1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/04-ecs-service-step1.png -------------------------------------------------------------------------------- /workshop-1/images/04-ecs-service-vpc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/04-ecs-service-vpc.png -------------------------------------------------------------------------------- /workshop-1/images/04-env-var.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/04-env-var.png -------------------------------------------------------------------------------- /workshop-1/images/04-logging.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/04-logging.png -------------------------------------------------------------------------------- /workshop-1/images/04-taskdef.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/04-taskdef.png -------------------------------------------------------------------------------- /workshop-1/images/aws_mythical_banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/aws_mythical_banner.png -------------------------------------------------------------------------------- /workshop-1/images/chimera_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/chimera_hover.png -------------------------------------------------------------------------------- /workshop-1/images/chimera_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/chimera_thumb.png -------------------------------------------------------------------------------- /workshop-1/images/cyclops_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/cyclops_hover.png -------------------------------------------------------------------------------- /workshop-1/images/cyclops_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/cyclops_thumb.png -------------------------------------------------------------------------------- /workshop-1/images/dragon_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/dragon_hover.png -------------------------------------------------------------------------------- /workshop-1/images/dragon_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/dragon_thumb.png -------------------------------------------------------------------------------- /workshop-1/images/gorgon_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/gorgon_hover.png -------------------------------------------------------------------------------- /workshop-1/images/gorgon_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/gorgon_thumb.png -------------------------------------------------------------------------------- /workshop-1/images/haetae_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/haetae_hover.png -------------------------------------------------------------------------------- /workshop-1/images/haetae_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/haetae_thumb.png -------------------------------------------------------------------------------- /workshop-1/images/kraken_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/kraken_hover.png -------------------------------------------------------------------------------- /workshop-1/images/kraken_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/kraken_thumb.png -------------------------------------------------------------------------------- /workshop-1/images/like_icon_false.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/like_icon_false.png -------------------------------------------------------------------------------- /workshop-1/images/like_icon_true.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/like_icon_true.png -------------------------------------------------------------------------------- /workshop-1/images/mandrake_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/mandrake_hover.png -------------------------------------------------------------------------------- /workshop-1/images/mandrake_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/mandrake_thumb.png -------------------------------------------------------------------------------- /workshop-1/images/mysfits_banner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/mysfits_banner.gif -------------------------------------------------------------------------------- /workshop-1/images/nessie_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/nessie_hover.png -------------------------------------------------------------------------------- /workshop-1/images/nessie_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/nessie_thumb.png -------------------------------------------------------------------------------- /workshop-1/images/pegasus_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/pegasus_hover.png -------------------------------------------------------------------------------- /workshop-1/images/pegasus_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/pegasus_thumb.png -------------------------------------------------------------------------------- /workshop-1/images/phoenix_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/phoenix_hover.png -------------------------------------------------------------------------------- /workshop-1/images/phoenix_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/phoenix_thumb.png -------------------------------------------------------------------------------- /workshop-1/images/troll_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/troll_hover.png -------------------------------------------------------------------------------- /workshop-1/images/troll_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/troll_thumb.png -------------------------------------------------------------------------------- /workshop-1/images/yeti_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/yeti_hover.png -------------------------------------------------------------------------------- /workshop-1/images/yeti_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/images/yeti_thumb.png -------------------------------------------------------------------------------- /workshop-1/pipeline.temp: -------------------------------------------------------------------------------- 1 | 2 | # An IAM role that allows the AWS CodePipeline service to perform it's 3 | # necessary actions. We have intentionally left permissions on this role 4 | # that will not be used by the CodePipeline service during this workshop. 5 | # This will allow you to more simply use CodePipeline in the future should 6 | # you want to use the service for Pipelines that interact with different 7 | # AWS services than the ones used in this workshop. 8 | MythicalMysfitsServiceCodePipelineServiceRole: 9 | Type: AWS::IAM::Role 10 | Properties: 11 | RoleName: !Sub CodePipelineServiceRole_${AWS::StackName} 12 | AssumeRolePolicyDocument: 13 | Statement: 14 | - Effect: Allow 15 | Principal: 16 | Service: 17 | - codepipeline.amazonaws.com 18 | Action: 19 | - sts:AssumeRole 20 | Path: "/" 21 | Policies: 22 | - PolicyName: MythicalMysfitsService-codepipeline-service-policy 23 | PolicyDocument: 24 | Statement: 25 | - Action: 26 | - codecommit:GetBranch 27 | - codecommit:GetCommit 28 | - codecommit:UploadArchive 29 | - codecommit:GetUploadArchiveStatus 30 | - codecommit:CancelUploadArchive 31 | Resource: "*" 32 | Effect: Allow 33 | - Action: 34 | - s3:GetObject 35 | - s3:GetObjectVersion 36 | - s3:GetBucketVersioning 37 | Resource: "*" 38 | Effect: Allow 39 | - Action: 40 | - s3:PutObject 41 | Resource: 42 | - arn:aws:s3:::* 43 | Effect: Allow 44 | - Action: 45 | - elasticloadbalancing:* 46 | - autoscaling:* 47 | - cloudwatch:* 48 | - ecs:* 49 | - codebuild:* 50 | - iam:PassRole 51 | Resource: "*" 52 | Effect: Allow 53 | Version: "2012-10-17" 54 | 55 | # An IAM role that allows the AWS CodeBuild service to perform the actions 56 | # required to complete a build of our source code retrieved from CodeCommit, 57 | # and push the created image to ECR. 58 | MythicalMysfitsServiceCodeBuildServiceRole: 59 | Type: AWS::IAM::Role 60 | Properties: 61 | RoleName: !Sub CodeBuildServiceRole_${AWS::StackName} 62 | AssumeRolePolicyDocument: 63 | Version: "2012-10-17" 64 | Statement: 65 | Effect: Allow 66 | Principal: 67 | Service: codebuild.amazonaws.com 68 | Action: sts:AssumeRole 69 | Policies: 70 | - PolicyName: "MythicalMysfitsService-CodeBuildServicePolicy" 71 | PolicyDocument: 72 | Version: "2012-10-17" 73 | Statement: 74 | - Effect: "Allow" 75 | Action: 76 | - "codecommit:ListBranches" 77 | - "codecommit:ListRepositories" 78 | - "codecommit:BatchGetRepositories" 79 | - "codecommit:Get*" 80 | - "codecommit:GitPull" 81 | Resource: 82 | - !GetAtt MythicalImageRepository.Arn 83 | - Effect: "Allow" 84 | Action: 85 | - "logs:CreateLogGroup" 86 | - "logs:CreateLogStream" 87 | - "logs:PutLogEvents" 88 | Resource: "*" 89 | - Effect: "Allow" 90 | Action: 91 | - "s3:PutObject" 92 | - "s3:GetObject" 93 | - "s3:GetObjectVersion" 94 | - "s3:ListBucket" 95 | Resource: "*" 96 | - Effect: "Allow" 97 | Action: 98 | - "ecr:InitiateLayerUpload" 99 | - "ecr:GetAuthorizationToken" 100 | Resource: "*" 101 | 102 | 103 | -------------------------------------------------------------------------------- /workshop-1/script/associate-profile: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | instance_id=$(curl -sS http://169.254.169.254/latest/meta-data/instance-id) 4 | profile_name="$(jq < cfn-output.json -r '.ProfileName')" 5 | 6 | if aws ec2 associate-iam-instance-profile --iam-instance-profile "Name=$profile_name" --instance-id $instance_id; then 7 | echo "Profile associated successfully." 8 | else 9 | echo "WARNING: Encountered error associating instance profile with Cloud9 environment" 10 | fi 11 | -------------------------------------------------------------------------------- /workshop-1/script/credhelper: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | set -eu 4 | 5 | mkdir -p /home/ec2-user/.docker 6 | cat << EOF > /home/ec2-user/.docker/config.json 7 | { 8 | "credsStore": "ecr-login" 9 | } 10 | EOF 11 | chown -R ec2-user. /home/ec2-user/.docker 12 | rm -rf amazon-ecr-credential-helper 13 | git clone https://github.com/awslabs/amazon-ecr-credential-helper.git 14 | cd amazon-ecr-credential-helper && make docker && cp bin/local/docker-credential-ecr-login /usr/local/bin/ 15 | -------------------------------------------------------------------------------- /workshop-1/script/fetch-outputs: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | set -eu 4 | 5 | if [[ $# -eq 1 ]]; then 6 | STACK_NAME=$1 7 | else 8 | STACK_NAME="$(echo $C9_PROJECT | sed 's/^Project-//')" 9 | fi 10 | 11 | aws cloudformation describe-stacks --stack-name "$STACK_NAME" | jq -r '[.Stacks[0].Outputs[] | {key: .OutputKey, value: .OutputValue}] | from_entries' > cfn-output.json 12 | -------------------------------------------------------------------------------- /workshop-1/script/resize: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # Specify the desired volume size in GiB as a command line argument. If not specified, default to 20 GiB. 4 | SIZE=${1:-20} 5 | # Get the ID of the environment host Amazon EC2 instance. 6 | TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 60") 7 | INSTANCEID=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" -v http://169.254.169.254/latest/meta-data/instance-id 2> /dev/null) 8 | REGION=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" -v http://169.254.169.254/latest/meta-data/placement/region 2> /dev/null) 9 | # Get the ID of the Amazon EBS volume associated with the instance. 10 | VOLUMEID=$(aws ec2 describe-instances \ 11 | --instance-id $INSTANCEID \ 12 | --query "Reservations[0].Instances[0].BlockDeviceMappings[0].Ebs.VolumeId" \ 13 | --output text \ 14 | --region $REGION) 15 | # Resize the EBS volume. 16 | aws ec2 modify-volume --volume-id $VOLUMEID --size $SIZE 17 | # Wait for the resize to finish. 18 | while [ \ 19 | "$(aws ec2 describe-volumes-modifications \ 20 | --volume-id $VOLUMEID \ 21 | --filters Name=modification-state,Values="optimizing","completed" \ 22 | --query "length(VolumesModifications)"\ 23 | --output text)" != "1" ]; do 24 | sleep 1 25 | done 26 | # Check if we're on an NVMe filesystem 27 | if [[ -e "/dev/xvda" && $(readlink -f /dev/xvda) = "/dev/xvda" ]] 28 | then 29 | # Rewrite the partition table so that the partition takes up all the space that it can. 30 | sudo growpart /dev/xvda 1 31 | # Expand the size of the file system. 32 | # Check if we're on AL2 33 | STR=$(cat /etc/os-release) 34 | SUB="VERSION_ID=\"2\"" 35 | if [[ "$STR" == *"$SUB"* ]] 36 | then 37 | sudo xfs_growfs -d / 38 | else 39 | sudo resize2fs /dev/xvda1 40 | fi 41 | else 42 | # Rewrite the partition table so that the partition takes up all the space that it can. 43 | sudo growpart /dev/nvme0n1 1 44 | # Expand the size of the file system. 45 | # Check if we're on AL2 46 | STR=$(cat /etc/os-release) 47 | SUB="VERSION_ID=\"2\"" 48 | if [[ "$STR" == *"$SUB"* ]] 49 | then 50 | sudo xfs_growfs -d / 51 | else 52 | sudo resize2fs /dev/nvme0n1p1 53 | fi 54 | fi -------------------------------------------------------------------------------- /workshop-1/script/setup: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | set -eu 4 | 5 | echo "Removing unneeded docker images..." 6 | docker images -q | xargs docker rmi || true 7 | 8 | echo "Installing dependencies..." 9 | sudo yum install -y jq 10 | 11 | echo "Fetching CloudFormation outputs..." 12 | script/fetch-outputs 13 | 14 | echo "Populating DynamoDB table..." 15 | script/load-ddb 16 | 17 | echo "Uploading static site to S3..." 18 | if [[ $# -eq 1 ]]; then 19 | script/upload-site $1 20 | else 21 | script/upload-site 22 | fi 23 | 24 | echo "Installing ECR Cred Helper..." 25 | sudo script/credhelper 26 | 27 | echo "Attaching Instance Profile to Cloud9..." 28 | script/associate-profile 29 | 30 | echo "Resizing Cloud9 root volume..." 31 | script/resize 32 | 33 | echo "Success!" 34 | -------------------------------------------------------------------------------- /workshop-1/script/upload-site: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | set -eu 4 | 5 | if [[ $# -eq 1 ]]; then 6 | BUCKET_NAME="$1" 7 | else 8 | BUCKET_NAME=$(jq < cfn-output.json -r '.SiteBucket // empty') 9 | fi 10 | 11 | if [[ -z $BUCKET_NAME ]]; then 12 | echo "Unable to determine S3 bucket to use. Ensure that it is returned as an output from CloudFormation or passed as the first argument to the script." 13 | exit 1 14 | fi 15 | 16 | API_ENDPOINT=$(jq < cfn-output.json -er '.LoadBalancerDNS') 17 | # For auth, not used now 18 | #USER_POOL_ID=$(jq < cfn-output.json -er '.UserPoolId') 19 | #CLIENT_ID=$(jq < cfn-output.json -er '.ClientId') 20 | REGION=$(aws configure get region) 21 | 22 | TEMP_DIR=$(mktemp -d) 23 | 24 | cp -R web/. $TEMP_DIR/. 25 | 26 | if which gsed; then 27 | sed_cmd=gsed 28 | else 29 | sed_cmd=sed 30 | fi 31 | 32 | sed_prog="s|REPLACE_ME_API_ENDPOINT|http://$API_ENDPOINT|;" 33 | $sed_cmd -i $sed_prog $TEMP_DIR/index.html 34 | $sed_cmd -i $sed_prog $TEMP_DIR/register.html 35 | $sed_cmd -i $sed_prog $TEMP_DIR/confirm.html 36 | 37 | #update endpoint for banner and like/no-like 38 | sed_prog="s|REPLACE_ME_WEB_ENDPOINT|$BUCKET_NAME.s3.amazonaws.com|;" 39 | $sed_cmd -i $sed_prog $TEMP_DIR/index.html 40 | $sed_cmd -i $sed_prog $TEMP_DIR/register.html 41 | $sed_cmd -i $sed_prog $TEMP_DIR/confirm.html 42 | 43 | aws s3 sync $TEMP_DIR s3://$BUCKET_NAME 44 | aws s3 cp web/images s3://$BUCKET_NAME/web/images --recursive 45 | -------------------------------------------------------------------------------- /workshop-1/web/confirm.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | Mythical Mysfits Registration 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 |
22 | 23 |
24 |
25 |

Enter the code sent to the email you provided.
Then, login again on the home page.

26 |
27 |
28 | 29 | 30 |
31 | 32 |
33 |

34 | 35 | 36 | 37 | 71 | 72 | -------------------------------------------------------------------------------- /workshop-1/web/images/aws_mythical_banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/web/images/aws_mythical_banner.png -------------------------------------------------------------------------------- /workshop-1/web/images/chimera_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/web/images/chimera_hover.png -------------------------------------------------------------------------------- /workshop-1/web/images/chimera_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/web/images/chimera_thumb.png -------------------------------------------------------------------------------- /workshop-1/web/images/cyclops_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/web/images/cyclops_hover.png -------------------------------------------------------------------------------- /workshop-1/web/images/cyclops_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/web/images/cyclops_thumb.png -------------------------------------------------------------------------------- /workshop-1/web/images/dragon_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/web/images/dragon_hover.png -------------------------------------------------------------------------------- /workshop-1/web/images/dragon_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/web/images/dragon_thumb.png -------------------------------------------------------------------------------- /workshop-1/web/images/gorgon_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/web/images/gorgon_hover.png -------------------------------------------------------------------------------- /workshop-1/web/images/gorgon_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/web/images/gorgon_thumb.png -------------------------------------------------------------------------------- /workshop-1/web/images/haetae_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/web/images/haetae_hover.png -------------------------------------------------------------------------------- /workshop-1/web/images/haetae_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/web/images/haetae_thumb.png -------------------------------------------------------------------------------- /workshop-1/web/images/kraken_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/web/images/kraken_hover.png -------------------------------------------------------------------------------- /workshop-1/web/images/kraken_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/web/images/kraken_thumb.png -------------------------------------------------------------------------------- /workshop-1/web/images/like_icon_false.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/web/images/like_icon_false.png -------------------------------------------------------------------------------- /workshop-1/web/images/like_icon_true.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/web/images/like_icon_true.png -------------------------------------------------------------------------------- /workshop-1/web/images/mandrake_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/web/images/mandrake_hover.png -------------------------------------------------------------------------------- /workshop-1/web/images/mandrake_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/web/images/mandrake_thumb.png -------------------------------------------------------------------------------- /workshop-1/web/images/mysfits_banner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/web/images/mysfits_banner.gif -------------------------------------------------------------------------------- /workshop-1/web/images/nessie_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/web/images/nessie_hover.png -------------------------------------------------------------------------------- /workshop-1/web/images/nessie_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/web/images/nessie_thumb.png -------------------------------------------------------------------------------- /workshop-1/web/images/pegasus_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/web/images/pegasus_hover.png -------------------------------------------------------------------------------- /workshop-1/web/images/pegasus_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/web/images/pegasus_thumb.png -------------------------------------------------------------------------------- /workshop-1/web/images/phoenix_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/web/images/phoenix_hover.png -------------------------------------------------------------------------------- /workshop-1/web/images/phoenix_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/web/images/phoenix_thumb.png -------------------------------------------------------------------------------- /workshop-1/web/images/troll_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/web/images/troll_hover.png -------------------------------------------------------------------------------- /workshop-1/web/images/troll_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/web/images/troll_thumb.png -------------------------------------------------------------------------------- /workshop-1/web/images/yeti_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/web/images/yeti_hover.png -------------------------------------------------------------------------------- /workshop-1/web/images/yeti_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-1/web/images/yeti_thumb.png -------------------------------------------------------------------------------- /workshop-1/web/register.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | Register for Mythical Mysfits 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |
21 | 22 |
23 |
24 |

Register for Mythical Mysfits!

25 |
26 |
27 | 28 | 29 |
30 |
31 | 32 | 33 |
34 |
35 | 36 | 37 |
38 | 39 |
40 |
41 | 42 | 43 | 44 | 90 | 91 | -------------------------------------------------------------------------------- /workshop-2/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/.DS_Store -------------------------------------------------------------------------------- /workshop-2/Lab-0/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-0/.DS_Store -------------------------------------------------------------------------------- /workshop-2/Lab-0/images/arch-starthere.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-0/images/arch-starthere.png -------------------------------------------------------------------------------- /workshop-2/Lab-0/images/cfn-create-complete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-0/images/cfn-create-complete.png -------------------------------------------------------------------------------- /workshop-2/Lab-0/images/cfn-createstack-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-0/images/cfn-createstack-1.png -------------------------------------------------------------------------------- /workshop-2/Lab-0/images/cfn-createstack-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-0/images/cfn-createstack-2.png -------------------------------------------------------------------------------- /workshop-2/Lab-0/images/cfn-iam-capabilities.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-0/images/cfn-iam-capabilities.png -------------------------------------------------------------------------------- /workshop-2/Lab-0/images/cloud9-environment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-0/images/cloud9-environment.png -------------------------------------------------------------------------------- /workshop-2/Lab-0/images/cloud9-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-0/images/cloud9-list.png -------------------------------------------------------------------------------- /workshop-2/Lab-0/images/cloud9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-0/images/cloud9.png -------------------------------------------------------------------------------- /workshop-2/Lab-0/images/ecr-list-repos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-0/images/ecr-list-repos.png -------------------------------------------------------------------------------- /workshop-2/Lab-0/images/ecs-taskdef-change-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-0/images/ecs-taskdef-change-image.png -------------------------------------------------------------------------------- /workshop-2/Lab-0/images/ecs-taskdef-describe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-0/images/ecs-taskdef-describe.png -------------------------------------------------------------------------------- /workshop-2/Lab-0/images/ecs-taskdef-update-success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-0/images/ecs-taskdef-update-success.png -------------------------------------------------------------------------------- /workshop-2/Lab-1/README.md: -------------------------------------------------------------------------------- 1 | # Mythical Mysfits: DevSecOps with Docker and AWS Fargate 2 | 3 | ## Lab 1 - Starting the DevSecOps Journey 4 | 5 | In this lab, we are going to start building in DevSecOps. Security is everyone's responsibility and in today, you will ensure that you aren't checking in any AWS secrets like AWS Access and Secret Keys. 6 | 7 | Here's what you'll be doing: 8 | 9 | * [Set up repos](#set-up-repos) 10 | * [Build security right into git commits](#build-security-right-into-git-commits) 11 | * [Remediation](#rsemediation) 12 | 13 | ### Set up repos 14 | 15 | 1\. Clone all repos 16 | 17 | Up until now, Mythical Mysfits hasn't really been doing anything with source repos, so let's start checking things into repos like we're supposed to. First, you'll have to clone the pre-created repositories. You can get the git clone URLs from either the console or CLI. We'll do it from the CLI today. 18 | 19 | First, list your repositories: 20 | 21 |
 22 | $ aws codecommit list-repositories
 23 | {
 24 |     "repositories": [
 25 |         {
 26 |             "repositoryName": "mythical-mysfits-devsecops-like-service",
 27 |             "repositoryId": "54763f98-c295-4189-a91a-7830ea085aae"
 28 |         },
 29 |         {
 30 |             "repositoryName": "mythical-mysfits-devsecops-monolith-service",
 31 |             "repositoryId": "c8aa761e-3ed1-4033-b830-4d9465b51087"
 32 |         }
 33 |     ]
 34 | }
 35 | 
36 | 37 | Next, use the batch-get-repositories command to get the clone URLs for both repositories, substituting the names you got from the previous CLI command: 38 | 39 |
 40 | $ aws codecommit batch-get-repositories --repository-names mythical-mysfits-devsecops-monolith-service mythical-mysfits-devsecops-like-service
 41 | {
 42 |     "repositories": [
 43 |         {
 44 |             "repositoryName": "mythical-mysfits-devsecops-monolith-service",
 45 |             "cloneUrlSsh": "ssh://git-codecommit.eu-west-1.amazonaws.com/v1/repos/mythical-mysfits-devsecops-monolith-service",
 46 |             "lastModifiedDate": 1542588318.447,
 47 |             "repositoryDescription": "Repository for the Mythical Mysfits monolith service",
 48 |             "cloneUrlHttp": "https://git-codecommit.eu-west-1.amazonaws.com/v1/repos/mythical-mysfits-devsecops-monolith-service",
 49 |             "creationDate": 1542588318.447,
 50 |             "repositoryId": "c8aa761e-3ed1-4033-b830-4d9465b51087",
 51 |             "Arn": "arn:aws:codecommit:eu-west-1:123456789012:mythical-mysfits-devsecops-monolith-service",
 52 |             "accountId": "123456789012"
 53 |         },
 54 |         {
 55 |             "repositoryName": "mythical-mysfits-devsecops-like-service",
 56 |             "cloneUrlSsh": "ssh://git-codecommit.eu-west-1.amazonaws.com/v1/repos/mythical-mysfits-devsecops-like-service",
 57 |             "lastModifiedDate": 1542500073.535,
 58 |             "repositoryDescription": "Repository for the Mythical Mysfits like service",
 59 |             "cloneUrlHttp": "https://git-codecommit.eu-west-1.amazonaws.com/v1/repos/mythical-mysfits-devsecops-like-service",
 60 |             "creationDate": 1542500073.535,
 61 |             "repositoryId": "54763f98-c295-4189-a91a-7830ea085aae",
 62 |             "Arn": "arn:aws:codecommit:eu-west-1:123456789012:mythical-mysfits-devsecops-like-service",
 63 |             "accountId": "123456789012"
 64 |         }
 65 |     ],
 66 |     "repositoriesNotFound": []
 67 | }
 68 | 
69 | 70 | 2\. Clone repos and copy in app code 71 | 72 | Earlier in the workshop, we set up the CodeCommit credential helper, so for today, we'll use the HTTPS clone URLs instead of SSH. 73 | 74 |
 75 | $ cd ~/environment/
 76 | $ git clone REPLACEME_LIKE_REPOSITORY_CLONEURL
 77 | $ git clone REPLACEME_MONOLITH_REPOSITORY_CLONEURL
 78 | $ cp -R ~/environment/amazon-ecs-mythicalmysfits-workshop/workshop-2/app/like-service/* REPLACEME_LIKE_REPOSITORY_NAME
 79 | $ cp -R ~/environment/amazon-ecs-mythicalmysfits-workshop/workshop-2/app/monolith-service/* REPLACEME_MONOLITH_REPOSITORY_NAME
 80 | 
81 | 82 | ### Build security right into git commits 83 | 84 | Now that we have our repos cloned and are ready to start checking in, let's stop to think about security. Exposed access and secret keys are often very costly for companies and that's what we're going to try and avoid. To achieve this, we're going to use a project called [git-secrets](https://github.com/awslabs/git-secrets). 85 | 86 | Git-Secrets scans commits, commit messages, and --no-ff merges to prevent adding secrets into your git repositories. If a commit, commit message, or any commit in a --no-ff merge history matches one of your configured prohibited regular expression patterns, then the commit is rejected. 87 | 88 | 1\. Install git-secrets 89 | 90 | First thing's first. We have to install git-secrets and set it up. Clone the git-secrets repo: 91 | 92 |
 93 | $ cd ~/environment/
 94 | $ git clone https://github.com/awslabs/git-secrets.git
 95 | 
96 | 97 | Install it as per the instructions on the [git-secrets GitHub page](https://github.com/awslabs/git-secrets#installing-git-secrets): 98 | 99 |
100 | $ cd ~/environment/git-secrets/
101 | $ sudo make install
102 | $ git secrets --install
103 | ✓ Installed commit-msg hook to .git/hooks/commit-msg
104 | ✓ Installed pre-commit hook to .git/hooks/pre-commit
105 | ✓ Installed prepare-commit-msg hook to .git/hooks/prepare-commit-msg
106 | 
107 | 108 | 2\. Configure git-secrets 109 | 110 | Git-secrets uses hooks within git to catch whether or not you're committing something you're not supposed to. We will install it into both the repos we cloned: 111 | 112 |
113 | $ git secrets --register-aws --global
114 | OK
115 | $ cd ~/environment/REPLACEME_MONOLITH_REPOSITORY_NAME
116 | $ git secrets --install
117 | $ cd ~/environment/REPLACEME_LIKE_REPOSITORY_NAME
118 | $ git secrets --install
119 | 
120 | 121 | 3\. Check in code 122 |
123 | $ cd REPLACEME_LIKE_REPOSITORY_NAME
124 | $ git add -A
125 | $ git commit -m "Initial Commit of like-service repo"
126 | 
127 | 128 | Did you run into any issues? **If not, go back to Lab 1 and make sure git secrets is working.** 129 | 130 | ### Remediation 131 | 132 | 1\. Stop following anti-patterns! 133 | 134 | Looks like someone put in some secrets to our application. We should never have any sort of secrets directly built into the application. We have to fix this. This is the output you should have seen: 135 | 136 |
137 | service/mysfits_like.py:19:    # Boy I hope someone finds me: AKIAIOSFODNN7EXAMPLS
138 | 
139 | [ERROR] Matched one or more prohibited patterns
140 | 
141 | Possible mitigations:
142 | - Mark false positives as allowed using: git config --add secrets.allowed ...
143 | - Mark false positives as allowed by adding regular expressions to .gitallowed at repository's root directory
144 | - List your configured patterns: git config --get-all secrets.patterns
145 | - List your configured allowed patterns: git config --get-all secrets.allowed
146 | - List your configured allowed patterns in .gitallowed at repository's root directory
147 | - Use --no-verify if this is a one-time false positive
148 | 
149 | 150 | If you see the above output, git-secrets is working. If not, go back to the [Build security right into git commits](#build-security-right-into-git-commits) section. 151 | 152 | Open up the file and remove the line. This time, someone just left a commented access key in there so it's not being used, but it could have been bad. 153 | 154 | 2\. Check in the code again 155 | 156 | Now that we've fixed the issue, let's try again. 157 |
158 | $ git add -A
159 | $ git commit -m "Initial Commit of like-service repo"
160 | $ git push origin master
161 | 
162 | 163 | 3\. Check the rest of the repos for AWS Credentials 164 | 165 | Now let's make sure the rest of the repos don't have any access and secret keys checked in. 166 | 167 |
168 | $ cd ~/environment/REPLACEME_MONOLITH_REPOSITORY_NAME
169 | $ git secrets --scan
170 | $ cd ~/environment/REPLACEME_LIKE_REPOSITORY_NAME
171 | $ git secrets --scan
172 | 
173 | 174 | If there were no errors, looks like we're ok. 175 | 176 | # Checkpoint 177 | 178 | This short lab taught you how to start building in security right from the beginning before we even hit any sort of infrastructure. Now we can really get started. 179 | 180 | Proceed to [Lab 2](../Lab-2) 181 | 182 | -------------------------------------------------------------------------------- /workshop-2/Lab-2/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-2/.DS_Store -------------------------------------------------------------------------------- /workshop-2/Lab-2/hints/buildspec_dev.yml.draft: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | 3 | phases: 4 | pre_build: 5 | commands: 6 | - echo Logging in to Amazon ECR... 7 | - REPOSITORY_URI=REPLACEME_REPO_URI # This was started. Just replace REPLACEME_REPO_URI with your ECR Repo URI 8 | - #[TODO]: Command to log into ECR. Remember, it has to be executed $(maybe like this?) 9 | build: 10 | commands: 11 | - echo Build started on `date` 12 | - echo Building the Docker image... 13 | - #[TODO]: Build the actual image using the current commit ID as the tag 14 | - #[TODO]: Tag the newly built Docker image so that we can push the image to ECR. See the instructions in your ECR console to find out how to do this. Make sure you use the current commit ID as the tag! 15 | post_build: 16 | commands: 17 | - echo Build completed on `date` 18 | - echo Pushing the Docker image... 19 | - #[TODO]: Push the Docker image up to ECR 20 | -------------------------------------------------------------------------------- /workshop-2/Lab-2/hints/hintspec_dev.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | 3 | phases: 4 | pre_build: 5 | commands: 6 | - echo Logging in to Amazon ECR... 7 | - REPOSITORY_URI=REPLACEME_REPO_URI # This was started. Just replace REPLACEME_REPO_URI with your ECR Repo URI 8 | - $(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION) 9 | build: 10 | commands: 11 | - echo Build started on `date` 12 | - echo Building the Docker image... 13 | - docker build -t $REPOSITORY_URI:$CODEBUILD_RESOLVED_SOURCE_VERSION . 14 | - docker tag $REPOSITORY_URI:$CODEBUILD_RESOLVED_SOURCE_VERSION $REPOSITORY_URI:$CODEBUILD_RESOLVED_SOURCE_VERSION 15 | post_build: 16 | commands: 17 | - echo Build completed on `date` 18 | - echo Pushing the Docker image... 19 | - docker push $REPOSITORY_URI:$CODEBUILD_RESOLVED_SOURCE_VERSION 20 | -------------------------------------------------------------------------------- /workshop-2/Lab-2/images/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-2/images/.DS_Store -------------------------------------------------------------------------------- /workshop-2/Lab-2/images/arch-codebuild.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-2/images/arch-codebuild.png -------------------------------------------------------------------------------- /workshop-2/Lab-2/images/cb-create-1-old.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-2/images/cb-create-1-old.png -------------------------------------------------------------------------------- /workshop-2/Lab-2/images/cb-create-1-old2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-2/images/cb-create-1-old2.png -------------------------------------------------------------------------------- /workshop-2/Lab-2/images/cb-create-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-2/images/cb-create-1.png -------------------------------------------------------------------------------- /workshop-2/Lab-2/images/cb-create-project-1-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-2/images/cb-create-project-1-2.png -------------------------------------------------------------------------------- /workshop-2/Lab-2/images/cb-create-project-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-2/images/cb-create-project-1.png -------------------------------------------------------------------------------- /workshop-2/Lab-2/images/cb-create-project-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-2/images/cb-create-project-2.png -------------------------------------------------------------------------------- /workshop-2/Lab-2/images/cb-create-project-envvar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-2/images/cb-create-project-envvar.png -------------------------------------------------------------------------------- /workshop-2/Lab-2/images/cb-success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-2/images/cb-success.png -------------------------------------------------------------------------------- /workshop-2/Lab-2/images/ecr-get-like-commands.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-2/images/ecr-get-like-commands.png -------------------------------------------------------------------------------- /workshop-2/Lab-2/images/ecr-new-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-2/images/ecr-new-image.png -------------------------------------------------------------------------------- /workshop-2/Lab-3/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-3/.DS_Store -------------------------------------------------------------------------------- /workshop-2/Lab-3/README.md: -------------------------------------------------------------------------------- 1 | # Mythical Mysfits: DevSecOps with Docker and AWS Fargate 2 | 3 | ## Lab 3 - Automating End to End Deployments for AWS Fargate 4 | 5 | In this lab, you will implement the end to end deployment and testing process for your like service. This lab is where it all comes together. By the end, you will be able to check in new code and have your application automatically updated. 6 | 7 | Here's what you'll be doing: 8 | 9 | * Create new buildspec and merge feature branch 10 | * Create Pipeline for deployments 11 | * Deploy new version of Project Cuddle 12 | 13 | ### Create new buildspec and merge feature branch 14 | 15 | 1\. Create the buildspec_prod.yml file 16 | 17 | In Lab 2, we created a buildspec for dev named buildspec_dev. That was used when CodeBuild was run directly on source code in CodeCommit, but now for production we want to build a full pipeline that will automatically deploy our environment, so we'll use CodePipeline to orchestrate that. 18 | 19 | Ideally, we want to keep production and development branches as similar as possible, but want to control differences between dev and prod build stages. To start, we can basically copy over what we created for Lab 2, but there will be a few minor changes. We will name the new buildspec buildspec_prod.yml instead of buildspec_dev.yml. 20 | 21 | Make sure you're in the like repository folder, which should be named something like **CFNStackName-like-service**. 22 | 23 |
 24 | $ cd ~/environment/REPLACE_ME_LIKE_REPOSITORY_NAME
 25 | $ cp buildspec_dev.yml buildspec_prod.yml
 26 | 
27 | 28 | Next, in order for CodePipeline to deploy to Fargate, we need to have an `imagedefinitions.json` file that includes the name of the container we want to replace as well as the imageUri. Then we have to surface the file to CodePipeline in an Artifacts section. The end of your buildspec_prod.yml file will look like this: 29 | 30 |
 31 | ...
 32 |     post_build:
 33 |       commands:
 34 |         - echo Build completed on `date`
 35 |         - echo Pushing the Docker image...
 36 |         - docker push $REPOSITORY_URI:$CODEBUILD_RESOLVED_SOURCE_VERSION
 37 |         - printf '[{"name":"REPLACEME_CONTAINERNAME","imageUri":"%s"}]' $REPOSITORY_URI:$CODEBUILD_RESOLVED_SOURCE_VERSION > imagedefinitions.json
 38 | artifacts:
 39 |   files: imagedefinitions.json
 40 | 
41 | 42 | Replace the container name with the name of your service, which should be `like-service`. 43 | 44 |
45 | HINT: There's also completed file in hints/hintspec_prod.yml. Click here to see how to copy it in. 46 | Make sure you change REPLACEME_REPO_URI to your ECR repository URI! 47 |
 48 |   $ cp ~/environment/amazon-ecs-mythicalmysfits-workshop/workshop-2/Lab-3/hints/buildspec_prod.yml ~/environment/REPLACEME_REPO_NAME/buildspec_prod.yml
 49 |   
50 |
51 | 52 | 2\. Check in and push to dev 53 | 54 | Add, commit, and push the new file to your repo. You can try to build the app again, but CodeBuild will just do the same thing because it's still looking at buildspec_dev.yml. 55 | 56 |
 57 |   $ git add buildspec_prod.yml
 58 |   $ git commit -m "Adding a buildspec for prod"
 59 |   $ git push origin dev
 60 | 
61 | 62 | 3\. Merge into master branch 63 | 64 | Now that we're ready with all the code let's merge with our master branch. The master branch is what we're going to use to trigger all CodePipeline deployments 65 | 66 | First switch back to your master branch: 67 |
 68 |   $ git checkout master
 69 | 
70 | 71 | Next, merge in all your changes: 72 | 73 |
 74 |   $ git merge dev
 75 |   $ git push origin master
 76 | 
77 | 78 | ### Create Pipeline for deployments 79 | 80 | 1\. Create an AWS CodePipeline Pipeline and set it up to listen to AWS CodeCommit. 81 | 82 | Now it's time to hook everything together. In the AWS Management Console, navigate to the [AWS CodePipeline](https://console.aws.amazon.com/codepipeline/home#/) dashboard. Click on **Create Pipeline**. 83 | 84 | On the following pages, enter the following details: 85 | 86 | **Choose pipeline settings:** 87 | 88 | - Pipeline name: `prod-like-service` - *This is a production pipeline, so we'll prefix with prod* 89 | - Service role: **Existing service role** - *A service role was automatically created for you via CFN* 90 | - Role name: Choose **CFNStackName-CodePipelineServiceRole** - *Look for the service role that has the name of the CFN stack you created previously* 91 | 92 | **Click Advanced Settings** 93 | 94 | - Artifact store: Choose **Custom location** - *An artifact bucket was created for you via CFN* 95 | - Bucket: Choose **CFNStackName-mythicalartifactbucket** - *Look for the artifact bucket that has the name of the CFN stack you created previously. Note that there are two buckets that were created for you. Look for the one that says mythicalartifactbucket* 96 | 97 | Click **Next** 98 | 99 | ![CodePipeline Choose pipeline settings](images/cp-create-name.png) 100 | 101 | **Add source stage:** 102 | 103 | - Source provider: **AWS CodeCommit** - *We checked in our code to CodeCommit, so that's where we'll start. CodePipeline also supports a variety of different source providers. Try them out later!* 104 | - Repository name: **CFNStackName-like-service** - *Name of your CodeCommit repo for the like-service* 105 | - Branch name: **master** - *We want this to automatically trigger when we push to the master branch in our repo* 106 | - Change detection options: **Amazon CloudWatch Events (recommended)** - *You have the option of using CodePipeline to poll CodeCommit for changes every minute, but using CloudWatch Events will trigger CodePipeline executions based on events, so it's much faster* 107 | 108 | Click **Next**. 109 | 110 | ![CodePipeline Add source stage](images/cp-add-source.png) 111 | 112 | **Add build stage:** 113 | 114 | - Build provider: **AWS CodeBuild** 115 | - Region: **Choose the region you are in. It will say in the top right hand corner of the console** 116 | - Project name: Click **Create a new build project** 117 | 118 | A new window should appear. The values here are almost identical to that of Lab-2 when you created your dev CodeBuild project, with the exception that the name is now prod-like-service-build and the buildspec will be buildspec_prod.yml. See Lab-2 instructions for detailed screenshots. 119 | 120 | **Create build project:** 121 | 122 | - Project name: `prod-like-service-build` 123 | - Environment Image: Select **Managed Image** - *There are two options. You can either use a predefined Docker container that is curated by CodeBuild, or you can upload your own if you want to customize dependencies etc. to speed up build time* 124 | - Operating System: Select **Ubuntu** - *This is the OS that will run your build* 125 | - Runtime: Select **Standard** - *Each image has specific versions of software installed. See [Docker Images Provided by AWS CodeBuild](https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-available.html)* 126 | - Image: **aws/codebuild/standard:1.0** 127 | - Image version: **Leave as is** 128 | - Privileged: **Ensure Checked** - *In order for to run Docker inside a Docker container, you need to have elevated privileges* 129 | - Service role: **Existing service role** - *A service role was automatically created for you via CFN* 130 | - Role name: Choose **CFNStackName-CodeBuildServiceRole** - *Look for the service role that has the name of the CFN stack you created previously. It will be in the form of **CFNStackName**-CodeBuildServiceRole* 131 | 132 | - Uncheck **Allow AWS CodeBuild to modify this service role so it can be used with this build project** 133 | 134 | Expand the **Additional Information** and enter the following in Environment Variables: 135 | 136 | - Name: `AWS_ACCOUNT_ID` - *Enter this string* 137 | - Value: ***`REPLACEME_YOUR_ACCOUNT_ID`*** - *This is YOUR account ID* 138 | 139 | **Buildspec:** 140 | 141 | - Build Specification: Select **Use a buildspec file** - *We are going to provide CodeBuild with a buildspec file* 142 | - Buildspec name: Enter `buildspec_prod.yml` - *Using our new buildspec* 143 | 144 | Once confirmed, click **Continue to CodePipeline**. This should close out the popup and tell you that it **successfully created prod-like-service-build in CodeBuild.** 145 | 146 | - Project Name: **prod-like-service-build** 147 | 148 | Click **Next**. 149 | 150 | ![CodePipeline Created Build Project](images/cp-create-cb-complete.png) 151 | 152 | **Add deploy stage:** 153 | 154 | - Deployment provider: Select **Amazon ECS** - *This is the mechanism we're choosing to deploy with. CodePipeline also supports several other deployment options, but we're using ECS directly in this case.* 155 | - Region: **Select the region you're in** 156 | - Cluster Name: Select your ECS Cluster. In my case, **Cluster-mythical-mysfits-devsecops** - *This is the cluster that CodePipeline will deploy into.* 157 | - Service Name: Enter `CFNStackName-Mythical-Like-Service` - *Name the CloudFormation stack that you're going to create/update* 158 | - Image definitions file - *optional*: Enter `imagedefinitions.json` - *This is the file we created within the buildspec_prod.yml file earlier* 159 | 160 | ![CodePipeline ECS](images/cp-deploy-step.png) 161 | 162 | Click **Next**. 163 | 164 | Review your details and click **Create Pipeline**. 165 | 166 | 5\. Test your pipeline. 167 | 168 | By default, when you create your pipeline, CodePipeline will automatically run through and try to deploy your application. If you see it go through all three stages with all GREEN, you're good to go. Otherwise, click into the links it gives you and troubleshoot the deployment. 169 | 170 | ![CodePipeline ECS](images/cp-deploy-success.png) 171 | 172 | ## Deploy new version of Project Cuddle 173 | 174 | Now that you have your application deploying automatically, let's deploy a new version! We've upgraded the health check for our like service to make sure it can connect to the monolith service for the fulfillment method. 175 | 176 |
177 | $ cd ~/environment/REPLACEME_LIKE_REPO
178 | $ cp ~/environment/amazon-ecs-mythicalmysfits-workshop/workshop-2/Lab-3/mysfits_like_v2.py service/mysfits_like.py
179 | $ git add service/mysfits_like.py
180 | $ git commit -m "Cuddles v2"
181 | $ git push origin master
182 | 
183 | 184 | Now sit back, relax, and watch the deployment. When it's done, congratulations! You've unlocked the automated build and deploy achievement! Next up, head on over to [Lab 4](../Lab-4) for the "Sec" in DevSecOps. 185 | -------------------------------------------------------------------------------- /workshop-2/Lab-3/hints/buildspec_prod.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | 3 | phases: 4 | pre_build: 5 | commands: 6 | - echo Logging in to Amazon ECR... 7 | - REPOSITORY_URI=REPLACEME_REPO_URI 8 | - $(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION) 9 | build: 10 | commands: 11 | - echo Build started on `date` 12 | - echo Building the Docker image... 13 | - docker build -t $REPOSITORY_URI:$CODEBUILD_RESOLVED_SOURCE_VERSION . # Here, we are using the environment variable passed in via CodeBuild IMAGE_REPO_NAME 14 | - docker tag $REPOSITORY_URI:$CODEBUILD_RESOLVED_SOURCE_VERSION $REPOSITORY_URI:$CODEBUILD_RESOLVED_SOURCE_VERSION 15 | post_build: 16 | commands: 17 | - echo Build completed on `date` 18 | - echo Pushing the Docker image... 19 | - docker push $REPOSITORY_URI:$CODEBUILD_RESOLVED_SOURCE_VERSION 20 | - printf '[{"name":"like-service","imageUri":"%s"}]' $REPOSITORY_URI:$CODEBUILD_RESOLVED_SOURCE_VERSION > imagedefinitions.json 21 | artifacts: 22 | files: imagedefinitions.json 23 | -------------------------------------------------------------------------------- /workshop-2/Lab-3/images/cp-add-source.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-3/images/cp-add-source.png -------------------------------------------------------------------------------- /workshop-2/Lab-3/images/cp-create-cb-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-3/images/cp-create-cb-1.png -------------------------------------------------------------------------------- /workshop-2/Lab-3/images/cp-create-cb-complete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-3/images/cp-create-cb-complete.png -------------------------------------------------------------------------------- /workshop-2/Lab-3/images/cp-create-name-old.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-3/images/cp-create-name-old.png -------------------------------------------------------------------------------- /workshop-2/Lab-3/images/cp-create-name.png.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-3/images/cp-create-name.png.png -------------------------------------------------------------------------------- /workshop-2/Lab-3/images/cp-create-source.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-3/images/cp-create-source.png -------------------------------------------------------------------------------- /workshop-2/Lab-3/images/cp-deploy-step-old.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-3/images/cp-deploy-step-old.png -------------------------------------------------------------------------------- /workshop-2/Lab-3/images/cp-deploy-step.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-3/images/cp-deploy-step.png -------------------------------------------------------------------------------- /workshop-2/Lab-3/images/cp-deploy-success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-3/images/cp-deploy-success.png -------------------------------------------------------------------------------- /workshop-2/Lab-3/mysfits_like_v2.py: -------------------------------------------------------------------------------- 1 | import os 2 | import requests 3 | from urlparse import urlparse 4 | from flask import Flask, jsonify, json, Response, request 5 | from flask_cors import CORS 6 | 7 | app = Flask(__name__) 8 | CORS(app) 9 | 10 | # The service basepath has a short response just to ensure that healthchecks 11 | # sent to the service root will receive a healthy response. 12 | @app.route("/") 13 | def health_check_response(): 14 | url = urlparse('http://{}/'.format(os.environ['MONOLITH_URL'])) 15 | response = requests.get(url=url.geturl()) 16 | 17 | flask_response = jsonify({"message" : "Health check, monolith service available."}) 18 | flask_response.status_code = response.status_code 19 | return flask_response 20 | 21 | # indicate that the provided mysfit should be marked as liked. 22 | def process_like_request(): 23 | print('Like processed.') 24 | 25 | def fulfill_like(mysfit_id): 26 | url = urlparse('http://{}/mysfits/{}/fulfill-like'.format(os.environ['MONOLITH_URL'], mysfit_id)) 27 | return requests.post(url=url.geturl()) 28 | 29 | 30 | @app.route("/mysfits//like", methods=['POST']) 31 | def like_mysfit(mysfit_id): 32 | process_like_request() 33 | service_response = fulfill_like(mysfit_id) 34 | 35 | flask_response = Response(service_response) 36 | flask_response.headers["Content-Type"] = "application/json" 37 | 38 | return flask_response 39 | 40 | # Run the service on the local server it has been deployed to 41 | if __name__ == "__main__": 42 | app.run(host="0.0.0.0", port=80) 43 | -------------------------------------------------------------------------------- /workshop-2/Lab-4/README.md: -------------------------------------------------------------------------------- 1 | # Mythical Mysfits: DevSecOps with Docker and AWS Fargate 2 | 3 | ## Lab 4: Implement Container Image scanning 4 | 5 | In this lab we will really put the Sec in DevSecOps by including Clair, a static vulnerability scanner for container images. Clair is a service that requires a Postgres DB and a running container. Because we know you already know how to stand up ECS services we've already stood up the Clair service for you in the core.yml CloudFormation template. Now we're going to add another CodeBuild project to run Clair via a tool called Klar, add a test phase to the pipeline we created in Lab 3, then run our CodeBuild project in that test phase. Klar is a wrapper around the Clair APIs that makes it easier to use integration piplines like this one. Check out the [Klar GitHub repo](https://github.com/optiopay/klar)) for more info. 6 | 7 | Why would we use Clair? Injecting automated security into the pipeline gives you the same benefit as automated test - the ability to move quickly with confidence that you haven't regressed on security. 8 | 9 | Here's what you'll be doing: 10 | 11 | * [Create AWS CodeBuild Project](#create-aws-codebuild-project) 12 | * [Create Buildspec and Test the Pipeline](#create-buildspec-and-test-the-pipeline) 13 | 14 | ### Create AWS CodeBuild Project 15 | 1\. Create the new CodeBuild project. 16 | 17 | In the AWS Management Console, navigate to the [AWS CodePipeline](https://console.aws.amazon.com/codepipeline/home#/) dashboard. Choose the pipeline you created in Lab 3, which should be named prod-like-service, then choose Edit in the upper right. 18 | 19 | ![Edit Pipeline](images/edit-pipeline.png) 20 | 21 | We're going to add a new stage, "Test", between the "Build" and "Deploy" stages. Scroll down and choose "Add Stage" between "Build" and "Deploy". Name the stage "Test" then choose "Add stage". Choose "Add action group" inside of our new stage. Name the new action "Clair" and choose CodeBuild from the dropdown. New fields will appear - choose "Create project" similar to what we did in Lab 3. 22 | 23 | ![Clair Action](images/clair-action.png) 24 | 25 | - Project Name: Enter `prod-like-service-test` 26 | 27 | **Environment:** 28 | 29 | - Environment Image: Select **Managed Image** - *There are two options. You can either use a predefined Docker container that is curated by CodeBuild, or you can upload your own if you want to customize dependencies etc. to speed up build time* 30 | - Operating System: Select **Ubuntu** - *This is the OS that will run your build* 31 | - Runtime: Select **Standard** - *Each image has specific versions of software installed. See [Docker Images Provided by AWS CodeBuild](https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-available.html)* 32 | - Image: **aws/codebuild/standard:1.0** 33 | - Image version: **Leave as is** 34 | - Privileged: **Leave as is** - *You can't actually change anything here. In order for to run Docker inside a Docker container, you need to have elevated privileges* 35 | - Service role: **Existing service role** - *A service role was automatically created for you via CFN* 36 | - Role name: Choose **CFNStackName-CodeBuildServiceRole** - *Look for the service role that has the name of the CFN stack you created previously* 37 | 38 | - Uncheck **Allow AWS CodeBuild to modify this service role so it can be used with this build project** 39 | 40 | ![CodeBuild Create Project Part 1](images/cb-create-test-project-1.png) 41 | 42 | Expand the **Additional configuration** and enter the following in Environment Variables: 43 | 44 | - Name: `CLAIR_URL` - *Enter this string* 45 | - Value: ***`REPLACE_ME_LoadBalancerDNS`*** - *This is an output from your CloudFormation stack - LoadBalancerDNS.* 46 | 47 | 48 | 49 | **Buildspec:** 50 | 51 | - Build Specification: Select **Use a buildspec file** - *We are going to provide CodeBuild with a buildspec file* 52 | - Buildspec name: Enter `buildspec_clair.yml` - *we'll be using the same repo, but different buildspecs* 53 | 54 | Choose **Continue to CodePipeline**. 55 | 56 | ![CodeBuild Create Project Part 1](images/cb-create-test-project-2.png) 57 | 58 | You will now be back at the CodePipeline console. In the Input Artifacts section we're going to do something different than before - we're going to use multiple artifacts. Select SourceArtifact from the dropdown, then choose add, then choose BuildArtifact. Another dropdown will appear above, Primary Artifact. Select SourceArtifact here. Finally leave your output artifacts empty. What we've done here is inject the source artifact from CodeCommit as well as the build artifact (imagedefinitions.json) from the build phase. The source artifact is our primary input artifact because it's where our buildspec is. 59 | 60 | ![CodePipeline Create Action](images/cp-create-action.png) 61 | 62 | Save the action, choose "Done" to finish editing the stage, then choose "Save" to save the entire pipeline. 63 | 64 | ### Create Buildspec and Test the Pipeline 65 | 66 | 1\. Create BuildSpec and Test the Pipeline 67 | 68 | Just like in Lab 2 and Lab 3, we're going to create a buildspec for running Clair. See [Build Specification Reference for AWS CodeBuild](http://docs.aws.amazon.com/codebuild/latest/userguide/build-spec-ref.html) for more details on the buildspec format. 69 | 70 | Our intern from last summer got started with Clair but didn't finish before she went back to school. Her buildspec is ready to rock, it just needs to get copied into your source repository. 71 | 72 |
73 | $ cd ~/environment/REPLACEME_LIKE_REPO_NAME
74 | $ git checkout master
75 | $ cp ~/environment/amazon-ecs-mythicalmysfits-workshop/workshop-2/Lab-4/hints/buildspec_clair.yml buildspec_clair.yml
76 | 
77 | 78 | 2\. Check in your new file into the AWS CodeCommit repository. 79 | 80 | Make sure the name of the file is buildspec_clair.yml and then run these commands: 81 | 82 |
83 | $ git add buildspec_clair.yml
84 | $ git commit -m "Adding in support for Clair."
85 | $ git push origin master
86 | 
87 | 88 | If all goes well, you should see that Clair inspected your image and didn't find anything wrong. Choose "AWS CodeBuild" in the Clair action to go to the CodeBuild project. Inspect the **Build Log** to see if there was a failure. You'll also see these same logs in the CloudWatch Logs console. It make take a few minutes before anything shows up. 89 | 90 | ![Klar logs](images/klar-logs.png) 91 | 92 | From here, any run of the pipeline will include an automated security check to look for CVEs and other vulnerabilities. Congratulations! You've finished the second workshop in this track. If you're heading on to the last workshop in the series, feel free to leave everything as is. 93 | 94 | Whether you move on to the next workshop or wrap up here, make sure you [clean everything up](../README.md#workshop-cleanup) when you're done! 95 | -------------------------------------------------------------------------------- /workshop-2/Lab-4/hints/buildspec_clair.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | 3 | phases: 4 | pre_build: 5 | commands: 6 | # Grabbing Klar, our integration tool. 7 | - echo Grabbing Klar 8 | - wget https://github.com/optiopay/klar/releases/download/v2.3.0/klar-2.3.0-linux-amd64 9 | - chmod +x ./klar-2.3.0-linux-amd64 10 | - mv ./klar-2.3.0-linux-amd64 ./klar 11 | 12 | # Getting the image URI 13 | - cd $CODEBUILD_SRC_DIR_BuildArtifact 14 | - wget https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64 -O jq 15 | - chmod +x jq 16 | - IMAGE_URI=$(./jq -r '.[0] | .imageUri' imagedefinitions.json) 17 | - cd $CODEBUILD_SRC_DIR 18 | 19 | # Getting our Docker registry (ECR) login info for Klar and Clair to use 20 | - echo Getting Docker registry login info 21 | - DOCKER_LOGIN=`aws ecr get-login --region $AWS_DEFAULT_REGION` 22 | - PASSWORD=`echo $DOCKER_LOGIN | cut -d' ' -f6` 23 | build: 24 | commands: 25 | - echo Calling Clair with Klar 26 | - DOCKER_USER=AWS DOCKER_PASSWORD=${PASSWORD} CLAIR_ADDR=$CLAIR_URL ./klar $IMAGE_URI 27 | post_build: 28 | commands: 29 | - echo Finished 30 | -------------------------------------------------------------------------------- /workshop-2/Lab-4/images/arch-codebuild.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-4/images/arch-codebuild.png -------------------------------------------------------------------------------- /workshop-2/Lab-4/images/cb-create-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-4/images/cb-create-1.png -------------------------------------------------------------------------------- /workshop-2/Lab-4/images/cb-create-project-1-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-4/images/cb-create-project-1-2.png -------------------------------------------------------------------------------- /workshop-2/Lab-4/images/cb-create-project-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-4/images/cb-create-project-1.png -------------------------------------------------------------------------------- /workshop-2/Lab-4/images/cb-create-project-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-4/images/cb-create-project-2.png -------------------------------------------------------------------------------- /workshop-2/Lab-4/images/cb-create-project-envvar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-4/images/cb-create-project-envvar.png -------------------------------------------------------------------------------- /workshop-2/Lab-4/images/cb-create-test-project-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-4/images/cb-create-test-project-1.png -------------------------------------------------------------------------------- /workshop-2/Lab-4/images/cb-create-test-project-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-4/images/cb-create-test-project-2.png -------------------------------------------------------------------------------- /workshop-2/Lab-4/images/cb-success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-4/images/cb-success.png -------------------------------------------------------------------------------- /workshop-2/Lab-4/images/clair-action.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-4/images/clair-action.png -------------------------------------------------------------------------------- /workshop-2/Lab-4/images/cloud9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-4/images/cloud9.png -------------------------------------------------------------------------------- /workshop-2/Lab-4/images/cp-create-action.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-4/images/cp-create-action.png -------------------------------------------------------------------------------- /workshop-2/Lab-4/images/ecr-get-like-commands.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-4/images/ecr-get-like-commands.png -------------------------------------------------------------------------------- /workshop-2/Lab-4/images/ecr-new-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-4/images/ecr-new-image.png -------------------------------------------------------------------------------- /workshop-2/Lab-4/images/edit-pipeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-4/images/edit-pipeline.png -------------------------------------------------------------------------------- /workshop-2/Lab-4/images/klar-logs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/Lab-4/images/klar-logs.png -------------------------------------------------------------------------------- /workshop-2/README.md: -------------------------------------------------------------------------------- 1 | # Mythical Mysfits: DevSecOps with Docker and AWS Fargate 2 | 3 | ## Overview 4 | ![mysfits-welcome](/images/mysfits-welcome.png) 5 | 6 | **Mythical Mysfits** is a (fictional) pet adoption non-profit dedicated to helping abandoned, and often misunderstood, mythical creatures find a new forever family! Mythical Mysfits believes that all creatures deserve a second chance, even if they spent their first chance hiding under bridges and unapologetically robbing helpless travelers. 7 | 8 | Our business has been thriving with only a single Mysfits adoption center, located inside Devils Tower National Monument. Speak, friend, and enter should you ever come to visit. 9 | 10 | We've just had a surge of new mysfits arrive at our door with nowhere else to go! They're all pretty distraught after not only being driven from their homes... but an immensely grumpy ogre has also denied them all entry at a swamp they've used for refuge in the past. 11 | 12 | That's why we've hired you to be our first Full Stack Engineer. We need a more scalable way to show off our inventory of mysfits and let families adopt them. We'd like you to build the first Mythical Mysfits adoption website to help introduce these lovable, magical, often mischievous creatures to the world! 13 | 14 | We're growing, but we're struggling to keep up with our new mysfits mainly due to our legacy inventory platform. We heard about the benefits of containers, especially in the context of microservices and devsecops. We've already taken some steps in that direction, but can you help us take this to the next level? 15 | 16 | We've already moved to a microservice based model, but are still not able to develop quickly. We want to be able to deploy to our microservices as quickly as possible while maintaining a certain level of confidence that our code will work well. This is where you come in. 17 | 18 | If you are not familiar with DevOps, there are multiple facets to the the word. One focuses on organizational values, such as small, well rounded agile teams focusing on owning a particular service, whereas one focuses on automating the software delivery process as much as possible to shorten the time between code check in and customers testing and providing feedback. This allows us to shorten the feedback loop and iterate based on customer requirements at a much quicker rate. 19 | 20 | In this workshop, you will take our Mythical stack and apply concepts of CI/CD to their environment. To do this, you will create a pipeline to automate all deployments using AWS CodeCommit or GitHub, AWS CodeBuild, AWS CodePipeline, and AWS Fargate. Today, the Mythical stack runs on AWS Fargate following a microservice architecture, meaning that there are very strict API contracts that are in place. As part of the move to a more continuous delivery model, they would like to make sure these contracts are always maintained. 21 | 22 | The tools that we use in this workshop are part of the AWS Dev Tools stack, but are by no means an end all be all. What you should focus on is the idea of CI/CD and how you can apply it to your environments. 23 | 24 | ### Requirements: 25 | * AWS account - if you don't have one, it's easy and free to [create one](https://aws.amazon.com/) 26 | * AWS IAM account with elevated privileges allowing you to interact with CloudFormation, IAM, EC2, ECS, ECR, ALB, VPC, SNS, CloudWatch, AWS CodeCommit, AWS CodeBuild, AWS CodePipeline 27 | * Familiarity with Python, vim/emacs/nano, [Docker](https://www.docker.com/), AWS and microservices - not required but a bonus 28 | 29 | ### What you'll do: 30 | 31 | These labs are designed to be completed in sequence, and the full set of instructions are documented below. Read and follow along to complete the labs. If you're at a live AWS event, the workshop attendants will give you a high level run down of the labs and help answer any questions. Don't worry if you get stuck, we provide hints along the way. 32 | 33 | * **[Lab 0](Lab-0):** Deploy Existing Mythical Stack 34 | * **[Lab 1](Lab-1):** Integrating Security Right from the Get Go 35 | * **[Lab 2](Lab-2):** Offloading Builds to AWS CodeBuild 36 | * **[Lab 3](Lab-3):** Automating End to End Deployments for AWS Fargate 37 | * **[Lab 4](Lab-4):** Moar Security! Implementing Container Image scanning 38 | * **Workshop Cleanup** [Cleanup working environment](#workshop-cleanup) 39 | 40 | ### Conventions: 41 | Throughout this workshop, we will provide commands for you to run in the terminal. These commands will look like this: 42 | 43 |
44 | $ ssh -i PRIVATE_KEY.PEM ec2-user@EC2_PUBLIC_DNS_NAME
45 | 
46 | 47 | The command starts after the $. Text that is ***UPPER_ITALIC_BOLD*** indicates a value that is unique to your environment. For example, the ***PRIVATE\_KEY.PEM*** refers to the private key of an SSH key pair that you've created, and the ***EC2\_PUBLIC\_DNS\_NAME*** is a value that is specific to an EC2 instance launched in your account. You can find these unique values either in the CloudFormation outputs or by going to the specific service dashboard in the [AWS management console](https://console.aws.amazon.com). 48 | 49 | If you are asked to enter a specific value in a text field, the value will look like `VALUE`. 50 | 51 | Hints are also provided along the way and will look like this: 52 | 53 |
54 | HINT 55 | 56 | **Nice work, you just revealed a hint!** 57 |
58 | 59 | 60 | *Click on the arrow to show the contents of the hint.* 61 | 62 | ### IMPORTANT: Workshop Cleanup 63 | 64 | You will be deploying infrastructure on AWS which will have an associated cost. If you're attending an AWS event, credits will be provided. When you're done with the workshop, [follow the steps at the very end of the instructions](#workshop-cleanup) to make sure everything is cleaned up and avoid unnecessary charges. 65 | 66 | * * * 67 | 68 | ## Let's Begin! 69 | 70 | [Go to Lab-0 to set up your environment](Lab-0) 71 | 72 | ### Workshop Cleanup 73 | 74 | This is really important because if you leave stuff running in your account, it will continue to generate charges. Certain things were created by CloudFormation and certain things were created manually throughout the workshop. Follow the steps below to make sure you clean up properly. 75 | 76 | 1. Delete any manually created resources throughout the labs, e.g. CodePipeline Pipelines and CodeBuild projects. Certain things like task definitions do not have a cost associated, so you don't have to worry about that. If you're not sure what has a cost, you can always look it up on our website. All of our pricing is publicly available, or feel free to ask one of the workshop attendants when you're done. 77 | 2. Go to the CodePipeline console and delete prod-like-service. Hit Edit and then Delete. 78 | 3. Delete any container images stored in ECR, delete CloudWatch logs groups, and empty/delete S3 buckets 79 | 4. In your ECS Cluster, edit all services to have 0 tasks and delete all services 80 | 5. Delete log groups in CloudWatch Logs 81 | 6. Finally, delete the CloudFormation stack launched at the beginning of the workshop to clean up the rest. If the stack deletion process encountered errors, look at the Events tab in the CloudFormation dashboard, and you'll see what steps failed. It might just be a case where you need to clean up a manually created asset that is tied to a resource goverened by CloudFormation. 82 | 83 | -------------------------------------------------------------------------------- /workshop-2/app/buildspec.yml: -------------------------------------------------------------------------------- 1 | # A buildspec.yml file informs AWS CodeBuild of all the actions that should be 2 | # taken during a build execution for our application. We are able to divide the 3 | # build execution in separate pre-defined phases for logical organization, and 4 | # list the commands that will be executed on the provisioned build server 5 | # performing a build execution job. 6 | version: 0.2 7 | 8 | phases: 9 | pre_build: 10 | commands: 11 | - echo Logging in to Amazon ECR... 12 | # Retrieves docker credentials so that the subsequent docker push command is 13 | # authorized. Authentication is performed automatically by the AWS CLI 14 | # using the AWS credentials associated with the IAM role assigned to the 15 | # instances in your AWS CodeBuild project. 16 | - $(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION) 17 | build: 18 | commands: 19 | - echo Build started on `date` 20 | - echo Building the Docker image... 21 | - docker build -t mythicalmysfits/service:latest . 22 | # Tag the built docker image using the appropriate Amazon ECR endpoint and relevant 23 | # repository for our service container. This ensures that when the docker push 24 | # command is executed later, it will be pushed to the appropriate repository. 25 | - docker tag mythicalmysfits/service:latest $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/mythicalmysfits/service:latest 26 | post_build: 27 | commands: 28 | - echo Build completed on `date` 29 | - echo Pushing the Docker image.. 30 | # Push the image to ECR. 31 | - docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/mythicalmysfits/service:latest 32 | - echo Completed pushing Docker image. Deploying Docker image to AWS Fargate on `date` 33 | # Create a artifacts file that contains the name and location of the image 34 | # pushed to ECR. This will be used by AWS CodePipeline to automate 35 | # deployment of this specific container to Amazon ECS. 36 | - printf '[{"name":"MythicalMysfits-Service","imageUri":"%s"}]' $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/mythicalmysfits/service:latest > imagedefinitions.json 37 | artifacts: 38 | # Indicate that the created imagedefinitions.json file created on the previous 39 | # line is to be referenceable as an artifact of the build execution job. 40 | files: imagedefinitions.json 41 | -------------------------------------------------------------------------------- /workshop-2/app/like-service/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | RUN echo Updating existing packages, installing and upgrading python and pip. 3 | RUN apt-get update -y 4 | RUN apt-get install -y python-pip python-dev build-essential 5 | RUN pip install --upgrade pip 6 | RUN echo Copying the Mythical Mysfits Flask service into a service directory. 7 | COPY ./service /MythicalMysfitsService 8 | WORKDIR /MythicalMysfitsService 9 | RUN echo Installing Python packages listed in requirements.txt 10 | RUN pip install -r ./requirements.txt 11 | RUN echo Starting python and starting the Flask service... 12 | ENTRYPOINT ["python"] 13 | CMD ["mysfits_like.py"] 14 | -------------------------------------------------------------------------------- /workshop-2/app/like-service/service/mysfits_like.py: -------------------------------------------------------------------------------- 1 | import os 2 | import requests 3 | from urlparse import urlparse 4 | from flask import Flask, jsonify, json, Response, request 5 | from flask_cors import CORS 6 | 7 | app = Flask(__name__) 8 | CORS(app) 9 | 10 | # The service basepath has a short response just to ensure that healthchecks 11 | # sent to the service root will receive a healthy response. 12 | @app.route("/") 13 | def health_check_response(): 14 | return jsonify({'message' : 'Nothing here, used for health check.'}) 15 | # indicate that the provided mysfit should be marked as liked. 16 | 17 | def process_like_request(): 18 | print('Like processed.') 19 | # Boy I hope someone finds me: AKIAIOSFODNN7EXAMPLS 20 | 21 | def fulfill_like(mysfit_id): 22 | url = urlparse('http://{}/mysfits/{}/fulfill-like'.format(os.environ['MONOLITH_URL'], mysfit_id)) 23 | return requests.post(url=url.geturl()) 24 | 25 | 26 | @app.route("/mysfits//like", methods=['POST']) 27 | def like_mysfit(mysfit_id): 28 | process_like_request() 29 | service_response = fulfill_like(mysfit_id) 30 | 31 | flask_response = Response(service_response) 32 | flask_response.headers["Content-Type"] = "application/json" 33 | 34 | return flask_response 35 | 36 | # Run the service on the local server it has been deployed to, 37 | # listening on port 8080. 38 | if __name__ == "__main__": 39 | app.run(host="0.0.0.0", port=80) 40 | -------------------------------------------------------------------------------- /workshop-2/app/like-service/service/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==2.2.5 2 | flask-cors==3.0.10 3 | requests==2.31.0 4 | markupsafe==2.1.3 -------------------------------------------------------------------------------- /workshop-2/app/monolith-service/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | RUN echo Updating existing packages, installing and upgrading python and pip. 3 | RUN apt-get update -y 4 | RUN apt-get install -y python-pip python-dev build-essential 5 | RUN pip install --upgrade pip 6 | RUN echo Copying the Mythical Mysfits Flask service into a service directory. 7 | COPY ./service /MythicalMysfitsService 8 | WORKDIR /MythicalMysfitsService 9 | RUN echo Installing Python packages listed in requirements.txt 10 | RUN pip install -r ./requirements.txt 11 | RUN echo Starting python and starting the Flask service... 12 | ENTRYPOINT ["python"] 13 | CMD ["mythicalMysfitsService.py"] 14 | -------------------------------------------------------------------------------- /workshop-2/app/monolith-service/service/mysfitsTableClient.py: -------------------------------------------------------------------------------- 1 | import boto3 2 | import json 3 | import logging 4 | import os 5 | from collections import defaultdict 6 | 7 | # create a DynamoDB client using boto3. The boto3 library will automatically 8 | # use the credentials associated with our ECS task role to communicate with 9 | # DynamoDB, so no credentials need to be stored/managed at all by our code! 10 | client = boto3.client('dynamodb') 11 | table_name = os.environ['DDB_TABLE_NAME'] 12 | 13 | def getAllMysfits(): 14 | 15 | # Retrieve all Mysfits from DynamoDB using the DynamoDB scan operation. 16 | # Note: The scan API can be expensive in terms of latency when a DynamoDB 17 | # table contains a high number of records and filters are applied to the 18 | # operation that require a large amount of data to be scanned in the table 19 | # before a response is returned by DynamoDB. For high-volume tables that 20 | # receive many requests, it is common to store the result of frequent/common 21 | # scan operations in an in-memory cache. DynamoDB Accelerator (DAX) or 22 | # use of ElastiCache can provide these benefits. But, because out Mythical 23 | # Mysfits API is low traffic and the table is very small, the scan operation 24 | # will suit our needs for this workshop. 25 | response = client.scan( 26 | TableName=table_name 27 | ) 28 | 29 | logging.info(response["Items"]) 30 | 31 | # loop through the returned mysfits and add their attributes to a new dict 32 | # that matches the JSON response structure expected by the frontend. 33 | mysfitList = defaultdict(list) 34 | for item in response["Items"]: 35 | mysfit = {} 36 | mysfit["mysfitId"] = item["MysfitId"]["S"] 37 | mysfit["name"] = item["Name"]["S"] 38 | mysfit["goodevil"] = item["GoodEvil"]["S"] 39 | mysfit["lawchaos"] = item["LawChaos"]["S"] 40 | mysfit["species"] = item["Species"]["S"] 41 | mysfit["thumbImageUri"] = item["ThumbImageUri"]["S"] 42 | mysfitList["mysfits"].append(mysfit) 43 | 44 | # convert the create list of dicts in to JSON 45 | return json.dumps(mysfitList) 46 | 47 | def queryMysfits(queryParam): 48 | 49 | logging.info(json.dumps(queryParam)) 50 | 51 | # Use the DynamoDB API Query to retrieve mysfits from the table that are 52 | # equal to the selected filter values. 53 | response = client.query( 54 | TableName=table_name, 55 | IndexName=queryParam['filter']+'Index', 56 | KeyConditions={ 57 | queryParam['filter']: { 58 | 'AttributeValueList': [ 59 | { 60 | 'S': queryParam['value'] 61 | } 62 | ], 63 | 'ComparisonOperator': "EQ" 64 | } 65 | } 66 | ) 67 | 68 | mysfitList = defaultdict(list) 69 | for item in response["Items"]: 70 | mysfit = {} 71 | mysfit["mysfitId"] = item["MysfitId"]["S"] 72 | mysfit["name"] = item["Name"]["S"] 73 | mysfit["goodevil"] = item["GoodEvil"]["S"] 74 | mysfit["lawchaos"] = item["LawChaos"]["S"] 75 | mysfit["species"] = item["Species"]["S"] 76 | mysfit["thumbImageUri"] = item["ThumbImageUri"]["S"] 77 | mysfitList["mysfits"].append(mysfit) 78 | 79 | return json.dumps(mysfitList) 80 | 81 | # Retrive a single mysfit from DynamoDB using their unique mysfitId 82 | def getMysfit(mysfitId): 83 | 84 | # use the DynamoDB API GetItem, which gives you the ability to retrieve 85 | # a single item from a DynamoDB table using its unique key with super 86 | # low latency. 87 | response = client.get_item( 88 | TableName=table_name, 89 | Key={ 90 | 'MysfitId': { 91 | 'S': mysfitId 92 | } 93 | } 94 | ) 95 | 96 | item = response["Item"] 97 | 98 | mysfit = {} 99 | mysfit["mysfitId"] = item["MysfitId"]["S"] 100 | mysfit["name"] = item["Name"]["S"] 101 | mysfit["age"] = int(item["Age"]["N"]) 102 | mysfit["goodevil"] = item["GoodEvil"]["S"] 103 | mysfit["lawchaos"] = item["LawChaos"]["S"] 104 | mysfit["species"] = item["Species"]["S"] 105 | mysfit["description"] = item["Description"]["S"] 106 | mysfit["thumbImageUri"] = item["ThumbImageUri"]["S"] 107 | mysfit["profileImageUri"] = item["ProfileImageUri"]["S"] 108 | mysfit["likes"] = item["Likes"]["N"] 109 | mysfit["adopted"] = item["Adopted"]["BOOL"] 110 | 111 | return json.dumps(mysfit) 112 | 113 | # increment the number of likes for a mysfit by 1 114 | def likeMysfit(mysfitId): 115 | 116 | # Use the DynamoDB API UpdateItem to increment the number of Likes 117 | # the mysfit has by 1 using an UpdateExpression. 118 | response = client.update_item( 119 | TableName=table_name, 120 | Key={ 121 | 'MysfitId': { 122 | 'S': mysfitId 123 | } 124 | }, 125 | UpdateExpression="SET Likes = Likes + :n", 126 | ExpressionAttributeValues={':n': {'N': '1'}} 127 | ) 128 | 129 | response = {} 130 | response["Update"] = "Success"; 131 | 132 | return json.dumps(response) 133 | 134 | # mark a mysfit as adopted 135 | def adoptMysfit(mysfitId): 136 | 137 | # Use the DynamoDB API UpdateItem to set the value of the mysfit's 138 | # Adopted attribute to True using an UpdateExpression. 139 | response = client.update_item( 140 | TableName=table_name, 141 | Key={ 142 | 'MysfitId': { 143 | 'S': mysfitId 144 | } 145 | }, 146 | UpdateExpression="SET Adopted = :b", 147 | ExpressionAttributeValues={':b': {'BOOL': True}} 148 | ) 149 | 150 | response = {} 151 | response["Update"] = "Success"; 152 | 153 | return json.dumps(response) 154 | -------------------------------------------------------------------------------- /workshop-2/app/monolith-service/service/mythicalMysfitsService.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, jsonify, json, Response, request 2 | from flask_cors import CORS 3 | import mysfitsTableClient 4 | import os 5 | 6 | app = Flask(__name__) 7 | CORS(app) 8 | 9 | # The service basepath has a short response just to ensure that healthchecks 10 | # sent to the service root will receive a healthy response. 11 | @app.route("/") 12 | def healthCheckResponse(): 13 | return jsonify({'message' : 'Nothing here, used for health check. Try /mysfits instead.'}) 14 | 15 | # Retrive mysfits from DynamoDB based on provided querystring params, or all 16 | # mysfits if no querystring is present. 17 | @app.route("/mysfits", methods=['GET']) 18 | def getMysfits(): 19 | 20 | filterCategory = request.args.get('filter') 21 | if filterCategory: 22 | filterValue = request.args.get('value') 23 | queryParam = { 24 | 'filter': filterCategory, 25 | 'value': filterValue 26 | } 27 | serviceResponse = mysfitsTableClient.queryMysfits(queryParam) 28 | else: 29 | serviceResponse = mysfitsTableClient.getAllMysfits() 30 | 31 | flaskResponse = Response(serviceResponse) 32 | flaskResponse.headers["Content-Type"] = "application/json" 33 | 34 | return flaskResponse 35 | 36 | def process_like_request(): 37 | print('Like processed.') 38 | 39 | # retrieve the full details for a specific mysfit with their provided path 40 | # parameter as their ID. 41 | @app.route("/mysfits/", methods=['GET']) 42 | def getMysfit(mysfit_id): 43 | serviceResponse = mysfitsTableClient.getMysfit(mysfit_id) 44 | 45 | flaskResponse = Response(serviceResponse) 46 | flaskResponse.headers["Content-Type"] = "application/json" 47 | 48 | return flaskResponse 49 | 50 | # increment the number of likes for the provided mysfit. 51 | @app.route("/mysfits//like", methods=['POST']) 52 | def likeMysfit(mysfit_id): 53 | serviceResponse = mysfitsTableClient.likeMysfit(mysfit_id) 54 | process_like_request() 55 | flaskResponse = Response(serviceResponse) 56 | flaskResponse.headers["Content-Type"] = "application/json" 57 | return flaskResponse 58 | 59 | # @app.route("/mysfits//fulfill-like", methods=['POST']) 60 | # def likeMysfit(mysfit_id): 61 | # serviceResponse = mysfitsTableClient.likeMysfit(mysfit_id) 62 | # flaskResponse = Response(serviceResponse) 63 | # flaskResponse.headers["Content-Type"] = "application/json" 64 | # return flaskResponse 65 | 66 | # indicate that the provided mysfit should be marked as adopted. 67 | @app.route("/mysfits//adopt", methods=['POST']) 68 | def adoptMysfit(mysfit_id): 69 | serviceResponse = mysfitsTableClient.adoptMysfit(mysfit_id) 70 | 71 | flaskResponse = Response(serviceResponse) 72 | flaskResponse.headers["Content-Type"] = "application/json" 73 | 74 | return flaskResponse 75 | 76 | # Run the service on the local server it has been deployed to, 77 | # listening on port 8080. 78 | if __name__ == "__main__": 79 | app.run(host="0.0.0.0", port=80) 80 | -------------------------------------------------------------------------------- /workshop-2/app/monolith-service/service/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==2.2.5 2 | flask-cors==3.0.10 3 | boto3==1.26.148 4 | markupsafe==2.1.3 -------------------------------------------------------------------------------- /workshop-2/script/fetch-outputs: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | set -eu 4 | 5 | if [[ $# -eq 1 ]]; then 6 | STACK_NAME=$1 7 | else 8 | STACK_NAME="$(echo $C9_PROJECT | sed 's/^Project-//')" 9 | fi 10 | 11 | aws cloudformation describe-stacks --stack-name "$STACK_NAME" | jq -r '[.Stacks[0].Outputs[] | {key: .OutputKey, value: .OutputValue}] | from_entries' > cfn-output.json 12 | -------------------------------------------------------------------------------- /workshop-2/script/setup: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | set -eu 4 | 5 | echo "Installing dependencies..." 6 | sudo yum install -y jq 7 | echo "Fetching CloudFormation outputs..." 8 | script/fetch-outputs 9 | echo "Populating DynamoDB table..." 10 | script/load-ddb 11 | #echo "Cloning Repos" 12 | #script/clone 13 | #echo "Populating and pushing Repos" 14 | #script/populate 15 | echo "Uploading static site to S3..." 16 | if [[ $# -eq 1 ]]; then 17 | script/upload-site $1 18 | else 19 | script/upload-site 20 | fi 21 | echo "Bootstrapping for crash course" 22 | script/ws2/update-service-json 23 | #echo "Bootstrapping for WS2" 24 | #script/ws2/bootstrap_ws2 25 | #echo "Bootstrapping for WS3" 26 | #script/ws3/bootstrap_ws3 27 | echo "Success!" 28 | -------------------------------------------------------------------------------- /workshop-2/script/setup_ws1_end: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | set -eu 4 | 5 | #echo "Installing dependencies..." 6 | #sudo yum install -y jq 7 | #echo "Fetching CloudFormation outputs..." 8 | #script/fetch-outputs 9 | #echo "Populating DynamoDB table..." 10 | #script/load-ddb 11 | #echo "Cloning Repos" 12 | #script/clone 13 | #echo "Populating and pushing Repos" 14 | #script/populate 15 | #echo "Uploading static site to S3..." 16 | #if [[ $# -eq 1 ]]; then 17 | # script/upload-site $1 18 | #else 19 | # script/upload-site 20 | #fi 21 | echo "Bootstrapping for WS2" 22 | script/ws2/bootstrap_ws2 23 | #echo "Bootstrapping for WS3" 24 | #script/ws3/bootstrap_ws3 25 | echo "Success!" 26 | -------------------------------------------------------------------------------- /workshop-2/script/upload-site: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | set -eu 4 | 5 | if [[ $# -eq 1 ]]; then 6 | BUCKET_NAME="$1" 7 | else 8 | BUCKET_NAME=$(jq < cfn-output.json -er '.SiteBucket') 9 | fi 10 | 11 | API_ENDPOINT=$(jq < cfn-output.json -er '.LoadBalancerDNS') 12 | # For auth, not used now 13 | #USER_POOL_ID=$(jq < cfn-output.json -er '.UserPoolId') 14 | #CLIENT_ID=$(jq < cfn-output.json -er '.ClientId') 15 | REGION=$(aws configure get region) 16 | 17 | TEMP_DIR=$(mktemp -d) 18 | 19 | cp -R web/. $TEMP_DIR/. 20 | 21 | if which gsed; then 22 | sed_cmd=gsed 23 | else 24 | sed_cmd=sed 25 | fi 26 | 27 | sed_prog="s|REPLACE_ME_API_ENDPOINT|http://$API_ENDPOINT|;" 28 | $sed_cmd -i $sed_prog $TEMP_DIR/index.html 29 | $sed_cmd -i $sed_prog $TEMP_DIR/register.html 30 | $sed_cmd -i $sed_prog $TEMP_DIR/confirm.html 31 | aws s3 sync $TEMP_DIR s3://$BUCKET_NAME --acl public-read 32 | -------------------------------------------------------------------------------- /workshop-2/script/ws2/bootstrap_ws2: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | echo "Building Docker Containers" 4 | script/ws2/build-containers 5 | echo "Creating Fargate service JSONs" 6 | script/ws2/update-service-json 7 | echo "Creating Fargate Services for Like/Monolith" 8 | script/ws2/create-fargate-services 9 | -------------------------------------------------------------------------------- /workshop-2/script/ws2/build-containers: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | LIKE_ECR_REPO=$(jq < cfn-output.json -r '.LikeEcrRepo') 4 | MONO_ECR_REPO=$(jq < cfn-output.json -r '.MonoEcrRepo') 5 | 6 | $(aws ecr get-login --no-include-email) 7 | 8 | docker build -t like-service app/like-service 9 | docker tag like-service:latest $LIKE_ECR_REPO:latest 10 | docker push $LIKE_ECR_REPO:latest 11 | 12 | docker build -t monolith-service app/monolith-service 13 | docker tag monolith-service:latest $MONO_ECR_REPO:latest 14 | docker push $MONO_ECR_REPO:latest 15 | -------------------------------------------------------------------------------- /workshop-2/script/ws2/create-fargate-services: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | LIKE_TASK_DEF=$(jq < cfn-output.json -r '.LikeTaskDefinition') 4 | MONOLITH_TASK_DEF=$(jq < cfn-output.json -r '.MonolithTaskDefinition') 5 | 6 | aws ecs create-service --cli-input-json file://Lab-0/like-service.json --task-definition $LIKE_TASK_DEF 7 | aws ecs create-service --cli-input-json file://Lab-0/monolith-service.json --task-definition $MONOLITH_TASK_DEF 8 | -------------------------------------------------------------------------------- /workshop-2/script/ws2/service-template.json: -------------------------------------------------------------------------------- 1 | { 2 | "cluster": "CLUSTER_NAME", 3 | "serviceName": "STACK_NAME_Mythical-SERVICE_NAME-Service", 4 | "loadBalancers": [ 5 | { 6 | "targetGroupArn": "TARGET_GROUP_ARN", 7 | "containerName": "CONTAINER_NAME", 8 | "containerPort": 80 9 | } 10 | ], 11 | "desiredCount": 1, 12 | "launchType": "FARGATE", 13 | "deploymentConfiguration": { 14 | "maximumPercent": 200, 15 | "minimumHealthyPercent": 0 16 | }, 17 | "networkConfiguration": { 18 | "awsvpcConfiguration": { 19 | "subnets": [ 20 | "PRIVATE_SUBNET_ONE", 21 | "PRIVATE_SUBNET_TWO" 22 | ], 23 | "securityGroups": [ 24 | "FARGATE_CONTAINER_SECURITY_GROUP" 25 | ], 26 | "assignPublicIp": "DISABLED" 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /workshop-2/script/ws2/update-service-json: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | set -eu 4 | 5 | # declare an associative array, the -A defines the array of this type 6 | declare -A cfnOutputs 7 | 8 | # The output of jq is separated by '|' so that we have a valid delimiter 9 | # to read our keys and values. The read command processes one line at a 10 | # time and puts the values in the variables 'key' and 'value' 11 | while IFS='|' read -r key value; do 12 | # Strip out the text until the last occurrence of '/' 13 | strippedKey="${key##*/}" 14 | # Putting the key/value pair in the array 15 | cfnOutputs["$strippedKey"]="$value" 16 | done< <(jq -r 'keys[] as $k | "\($k)|\(.[$k])"' cfn-output.json) 17 | 18 | # Print the array using the '-p' or do one by one 19 | #declare -p cfnOutputs 20 | 21 | cp script/ws2/service-template.json Lab-0/monolith-service.json 22 | cp script/ws2/service-template.json Lab-0/like-service.json 23 | 24 | sed -i -e 's/CLUSTER_NAME/'"${cfnOutputs[EcsClusterName]}"'/' \ 25 | -e 's/STACK_NAME/'"${cfnOutputs[StackName]}"'/' \ 26 | -e 's/SERVICE_NAME/Monolith/' \ 27 | -e 's~TARGET_GROUP_ARN~'"${cfnOutputs[MonolithTargetGroupArn]}"'~' \ 28 | -e 's/CONTAINER_NAME/monolith-service/' \ 29 | -e 's/PRIVATE_SUBNET_ONE/'"${cfnOutputs[PrivateSubnetOne]}"'/' \ 30 | -e 's/PRIVATE_SUBNET_TWO/'"${cfnOutputs[PrivateSubnetTwo]}"'/' \ 31 | -e 's/FARGATE_CONTAINER_SECURITY_GROUP/'"${cfnOutputs[FargateContainerSecurityGroup]}"'/' Lab-0/monolith-service.json 32 | 33 | sed -i -e 's/CLUSTER_NAME/'"${cfnOutputs[EcsClusterName]}"'/' \ 34 | -e 's/STACK_NAME/'"${cfnOutputs[StackName]}"'/' \ 35 | -e 's/SERVICE_NAME/Like/' \ 36 | -e 's~TARGET_GROUP_ARN~'"${cfnOutputs[LikeTargetGroupArn]}"'~' \ 37 | -e 's/CONTAINER_NAME/like-service/' \ 38 | -e 's/PRIVATE_SUBNET_ONE/'"${cfnOutputs[PrivateSubnetOne]}"'/' \ 39 | -e 's/PRIVATE_SUBNET_TWO/'"${cfnOutputs[PrivateSubnetTwo]}"'/' \ 40 | -e 's/FARGATE_CONTAINER_SECURITY_GROUP/'"${cfnOutputs[FargateContainerSecurityGroup]}"'/' Lab-0/like-service.json 41 | -------------------------------------------------------------------------------- /workshop-2/script/ws3/bootstrap_ws3: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "Cloning Git Repos" 3 | script/ws3/clone 4 | echo "Populating and pushing Git Repos" 5 | script/ws3/populate 6 | -------------------------------------------------------------------------------- /workshop-2/script/ws3/clone: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | git config --global credential.helper "cache --timeout=7200" 4 | git config --global user.email "REPLACEME" 5 | git config --global user.name "ws3-user" 6 | git config --global credential.helper '!aws codecommit credential-helper $@' 7 | git config --global credential.UseHttpPath true 8 | 9 | LIKE_REPO=$(jq < cfn-output.json -r '.MythicalLikeGitRepositoryCloneUrl') 10 | MONOLITH_REPO=$(jq < cfn-output.json -r '.MythicalMonolithGitRepositoryCloneUrl') 11 | 12 | LIKE_REPO_NAME==$(jq < cfn-output.json -r '.MythicalLikeGitRepositoryName') 13 | MONOLITH_REPO_NAME==$(jq < cfn-output.json -r '.MythicalMonolithGitRepositoryName') 14 | 15 | cd ~/environment/ 16 | 17 | git clone $LIKE_REPO 18 | git clone $MONOLITH_REPO 19 | -------------------------------------------------------------------------------- /workshop-2/script/ws3/populate: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | LIKE_REPO_NAME=$(jq < cfn-output.json -r '.MythicalLikeGitRepositoryName') 4 | MONOLITH_REPO_NAME=$(jq < cfn-output.json -r '.MythicalMonolithGitRepositoryName') 5 | 6 | LIKE_ECR_REPO_URI=$(jq < cfn-output.json -r '.LikeEcrRepo') 7 | 8 | cp -R app/like-service/* ~/environment/$LIKE_REPO_NAME/ 9 | sed -i -e 's;REPLACEME_REPO_URI;'"$LIKE_ECR_REPO_URI"';' ~/environment/$LIKE_REPO_NAME/buildspec_prod.yml 10 | cp -R app/monolith-service/* ~/environment/$MONOLITH_REPO_NAME/ 11 | 12 | cd ~/environment/$LIKE_REPO_NAME/ 13 | git add -A 14 | git commit -m "Initial Commit of Like Service" 15 | git push origin master 16 | 17 | cd ~/environment/$MONOLITH_REPO_NAME/ 18 | git add -A 19 | git commit -m "Initial Commit of Monolith Service" 20 | git push origin master 21 | -------------------------------------------------------------------------------- /workshop-2/slides/CON321.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-2/slides/CON321.pdf -------------------------------------------------------------------------------- /workshop-2/web/confirm.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | Mythical Mysfits Registration 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 |
22 | 23 |
24 |
25 |

Enter the code sent to the email you provided.
Then, login again on the home page.

26 |
27 |
28 | 29 | 30 |
31 | 32 |
33 |

34 | 35 | 36 | 37 | 71 | 72 | -------------------------------------------------------------------------------- /workshop-2/web/register.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | Register for Mythical Mysfits 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |
21 | 22 |
23 |
24 |

Register for Mythical Mysfits!

25 |
26 |
27 | 28 | 29 |
30 |
31 | 32 | 33 |
34 |
35 | 36 | 37 |
38 | 39 |
40 |
41 | 42 | 43 | 44 | 90 | 91 | -------------------------------------------------------------------------------- /workshop-2/ws3-start/app/like-service/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:latest 2 | RUN echo Updating existing packages, installing and upgrading python and pip. 3 | RUN apt-get update -y 4 | RUN apt-get install -y python-pip python-dev build-essential 5 | RUN pip install --upgrade pip 6 | RUN echo Copying the Mythical Mysfits Flask service into a service directory. 7 | COPY ./service /MythicalMysfitsService 8 | WORKDIR /MythicalMysfitsService 9 | RUN echo Installing Python packages listed in requirements.txt 10 | RUN pip install -r ./requirements.txt 11 | RUN echo Starting python and starting the Flask service... 12 | ENTRYPOINT ["python"] 13 | CMD ["mysfits_like.py"] 14 | -------------------------------------------------------------------------------- /workshop-2/ws3-start/app/like-service/buildspec_prod.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | 3 | phases: 4 | pre_build: 5 | commands: 6 | - echo Logging in to Amazon ECR... 7 | - REPOSITORY_URI=REPLACEME_REPO_URI 8 | - $(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION) 9 | build: 10 | commands: 11 | - echo Build started on `date` 12 | - echo Building the Docker image... 13 | - docker build -t $REPOSITORY_URI:$CODEBUILD_RESOLVED_SOURCE_VERSION . # Here, we are using the environment variable passed in via CodeBuild IMAGE_REPO_NAME 14 | - docker tag $REPOSITORY_URI:$CODEBUILD_RESOLVED_SOURCE_VERSION $REPOSITORY_URI:$CODEBUILD_RESOLVED_SOURCE_VERSION 15 | post_build: 16 | commands: 17 | - echo Build completed on `date` 18 | - echo Pushing the Docker image... 19 | - docker push $REPOSITORY_URI:$CODEBUILD_RESOLVED_SOURCE_VERSION 20 | # Printing the container name (in taskdef) and passing it a new Docker image. 21 | - printf '[{"name":"like-service","imageUri":"%s"}]' $REPOSITORY_URI:$CODEBUILD_RESOLVED_SOURCE_VERSION > imagedefinitions.json 22 | artifacts: 23 | files: imagedefinitions.json 24 | -------------------------------------------------------------------------------- /workshop-2/ws3-start/app/like-service/service/mysfits_like.py: -------------------------------------------------------------------------------- 1 | import os 2 | import requests 3 | from urlparse import urlparse 4 | from flask import Flask, jsonify, json, Response, request 5 | from flask_cors import CORS 6 | 7 | app = Flask(__name__) 8 | CORS(app) 9 | 10 | # The service basepath has a short response just to ensure that healthchecks 11 | # sent to the service root will receive a healthy response. 12 | @app.route("/") 13 | def health_check_response(): 14 | url = urlparse('http://{}/'.format(os.environ['MONOLITH_URL'])) 15 | response = requests.get(url=url.geturl()) 16 | 17 | flask_response = jsonify({"message" : "Health check, monolith service available."}) 18 | flask_response.status_code = response.status_code 19 | return flask_response 20 | 21 | # indicate that the provided mysfit should be marked as liked. 22 | def process_like_request(): 23 | print('Like processed.') 24 | 25 | def fulfill_like(mysfit_id): 26 | url = urlparse('http://{}/mysfits/{}/fulfill-like'.format(os.environ['MONOLITH_URL'], mysfit_id)) 27 | return requests.post(url=url.geturl()) 28 | 29 | 30 | @app.route("/mysfits//like", methods=['POST']) 31 | def like_mysfit(mysfit_id): 32 | process_like_request() 33 | service_response = fulfill_like(mysfit_id) 34 | 35 | flask_response = Response(service_response) 36 | flask_response.headers["Content-Type"] = "application/json" 37 | 38 | return flask_response 39 | 40 | # Run the service on the local server it has been deployed to 41 | if __name__ == "__main__": 42 | app.run(host="0.0.0.0", port=80) 43 | -------------------------------------------------------------------------------- /workshop-2/ws3-start/app/like-service/service/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==2.2.5 2 | flask-cors==3.0.10 3 | requests==2.31.0 4 | markupsafe==2.1.3 -------------------------------------------------------------------------------- /workshop-2/ws3-start/app/monolith-service/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:latest 2 | RUN echo Updating existing packages, installing and upgrading python and pip. 3 | RUN apt-get update -y 4 | RUN apt-get install -y python-pip python-dev build-essential 5 | RUN pip install --upgrade pip 6 | RUN echo Copying the Mythical Mysfits Flask service into a service directory. 7 | COPY ./service /MythicalMysfitsService 8 | WORKDIR /MythicalMysfitsService 9 | RUN echo Installing Python packages listed in requirements.txt 10 | RUN pip install -r ./requirements.txt 11 | RUN echo Starting python and starting the Flask service... 12 | ENTRYPOINT ["python"] 13 | CMD ["mythicalMysfitsService.py"] 14 | -------------------------------------------------------------------------------- /workshop-2/ws3-start/app/monolith-service/service/mysfitsTableClient.py: -------------------------------------------------------------------------------- 1 | import boto3 2 | import json 3 | import logging 4 | import os 5 | from collections import defaultdict 6 | 7 | # create a DynamoDB client using boto3. The boto3 library will automatically 8 | # use the credentials associated with our ECS task role to communicate with 9 | # DynamoDB, so no credentials need to be stored/managed at all by our code! 10 | client = boto3.client('dynamodb') 11 | table_name = os.environ['DDB_TABLE_NAME'] 12 | 13 | def getAllMysfits(): 14 | 15 | # Retrieve all Mysfits from DynamoDB using the DynamoDB scan operation. 16 | # Note: The scan API can be expensive in terms of latency when a DynamoDB 17 | # table contains a high number of records and filters are applied to the 18 | # operation that require a large amount of data to be scanned in the table 19 | # before a response is returned by DynamoDB. For high-volume tables that 20 | # receive many requests, it is common to store the result of frequent/common 21 | # scan operations in an in-memory cache. DynamoDB Accelerator (DAX) or 22 | # use of ElastiCache can provide these benefits. But, because out Mythical 23 | # Mysfits API is low traffic and the table is very small, the scan operation 24 | # will suit our needs for this workshop. 25 | response = client.scan( 26 | TableName=table_name 27 | ) 28 | 29 | logging.info(response["Items"]) 30 | 31 | # loop through the returned mysfits and add their attributes to a new dict 32 | # that matches the JSON response structure expected by the frontend. 33 | mysfitList = defaultdict(list) 34 | for item in response["Items"]: 35 | mysfit = {} 36 | mysfit["mysfitId"] = item["MysfitId"]["S"] 37 | mysfit["name"] = item["Name"]["S"] 38 | mysfit["goodevil"] = item["GoodEvil"]["S"] 39 | mysfit["lawchaos"] = item["LawChaos"]["S"] 40 | mysfit["species"] = item["Species"]["S"] 41 | mysfit["thumbImageUri"] = item["ThumbImageUri"]["S"] 42 | mysfitList["mysfits"].append(mysfit) 43 | 44 | # convert the create list of dicts in to JSON 45 | return json.dumps(mysfitList) 46 | 47 | def queryMysfits(queryParam): 48 | 49 | logging.info(json.dumps(queryParam)) 50 | 51 | # Use the DynamoDB API Query to retrieve mysfits from the table that are 52 | # equal to the selected filter values. 53 | response = client.query( 54 | TableName=table_name, 55 | IndexName=queryParam['filter']+'Index', 56 | KeyConditions={ 57 | queryParam['filter']: { 58 | 'AttributeValueList': [ 59 | { 60 | 'S': queryParam['value'] 61 | } 62 | ], 63 | 'ComparisonOperator': "EQ" 64 | } 65 | } 66 | ) 67 | 68 | mysfitList = defaultdict(list) 69 | for item in response["Items"]: 70 | mysfit = {} 71 | mysfit["mysfitId"] = item["MysfitId"]["S"] 72 | mysfit["name"] = item["Name"]["S"] 73 | mysfit["goodevil"] = item["GoodEvil"]["S"] 74 | mysfit["lawchaos"] = item["LawChaos"]["S"] 75 | mysfit["species"] = item["Species"]["S"] 76 | mysfit["thumbImageUri"] = item["ThumbImageUri"]["S"] 77 | mysfitList["mysfits"].append(mysfit) 78 | 79 | return json.dumps(mysfitList) 80 | 81 | # Retrive a single mysfit from DynamoDB using their unique mysfitId 82 | def getMysfit(mysfitId): 83 | 84 | # use the DynamoDB API GetItem, which gives you the ability to retrieve 85 | # a single item from a DynamoDB table using its unique key with super 86 | # low latency. 87 | response = client.get_item( 88 | TableName=table_name, 89 | Key={ 90 | 'MysfitId': { 91 | 'S': mysfitId 92 | } 93 | } 94 | ) 95 | 96 | item = response["Item"] 97 | 98 | mysfit = {} 99 | mysfit["mysfitId"] = item["MysfitId"]["S"] 100 | mysfit["name"] = item["Name"]["S"] 101 | mysfit["age"] = int(item["Age"]["N"]) 102 | mysfit["goodevil"] = item["GoodEvil"]["S"] 103 | mysfit["lawchaos"] = item["LawChaos"]["S"] 104 | mysfit["species"] = item["Species"]["S"] 105 | mysfit["description"] = item["Description"]["S"] 106 | mysfit["thumbImageUri"] = item["ThumbImageUri"]["S"] 107 | mysfit["profileImageUri"] = item["ProfileImageUri"]["S"] 108 | mysfit["likes"] = item["Likes"]["N"] 109 | mysfit["adopted"] = item["Adopted"]["BOOL"] 110 | 111 | return json.dumps(mysfit) 112 | 113 | # increment the number of likes for a mysfit by 1 114 | def likeMysfit(mysfitId): 115 | 116 | # Use the DynamoDB API UpdateItem to increment the number of Likes 117 | # the mysfit has by 1 using an UpdateExpression. 118 | response = client.update_item( 119 | TableName=table_name, 120 | Key={ 121 | 'MysfitId': { 122 | 'S': mysfitId 123 | } 124 | }, 125 | UpdateExpression="SET Likes = Likes + :n", 126 | ExpressionAttributeValues={':n': {'N': '1'}} 127 | ) 128 | 129 | response = {} 130 | response["Update"] = "Success"; 131 | 132 | return json.dumps(response) 133 | 134 | # mark a mysfit as adopted 135 | def adoptMysfit(mysfitId): 136 | 137 | # Use the DynamoDB API UpdateItem to set the value of the mysfit's 138 | # Adopted attribute to True using an UpdateExpression. 139 | response = client.update_item( 140 | TableName=table_name, 141 | Key={ 142 | 'MysfitId': { 143 | 'S': mysfitId 144 | } 145 | }, 146 | UpdateExpression="SET Adopted = :b", 147 | ExpressionAttributeValues={':b': {'BOOL': True}} 148 | ) 149 | 150 | response = {} 151 | response["Update"] = "Success"; 152 | 153 | return json.dumps(response) 154 | -------------------------------------------------------------------------------- /workshop-2/ws3-start/app/monolith-service/service/mythicalMysfitsService.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, jsonify, json, Response, request 2 | from flask_cors import CORS 3 | import mysfitsTableClient 4 | import os 5 | 6 | app = Flask(__name__) 7 | CORS(app) 8 | 9 | # The service basepath has a short response just to ensure that healthchecks 10 | # sent to the service root will receive a healthy response. 11 | @app.route("/") 12 | def healthCheckResponse(): 13 | return jsonify({"message" : "Nothing here, used for health check. Try /mysfits instead."}) 14 | 15 | # Retrive mysfits from DynamoDB based on provided querystring params, or all 16 | # mysfits if no querystring is present. 17 | @app.route("/mysfits", methods=['GET']) 18 | def getMysfits(): 19 | 20 | filterCategory = request.args.get('filter') 21 | if filterCategory: 22 | filterValue = request.args.get('value') 23 | queryParam = { 24 | 'filter': filterCategory, 25 | 'value': filterValue 26 | } 27 | serviceResponse = mysfitsTableClient.queryMysfits(queryParam) 28 | else: 29 | serviceResponse = mysfitsTableClient.getAllMysfits() 30 | 31 | flaskResponse = Response(serviceResponse) 32 | flaskResponse.headers["Content-Type"] = "application/json" 33 | 34 | return flaskResponse 35 | 36 | def process_like_request(): 37 | print('Like processed.') 38 | 39 | # retrieve the full details for a specific mysfit with their provided path 40 | # parameter as their ID. 41 | @app.route("/mysfits/", methods=['GET']) 42 | def getMysfit(mysfit_id): 43 | serviceResponse = mysfitsTableClient.getMysfit(mysfit_id) 44 | 45 | flaskResponse = Response(serviceResponse) 46 | flaskResponse.headers["Content-Type"] = "application/json" 47 | 48 | return flaskResponse 49 | 50 | # increment the number of likes for the provided mysfit. 51 | @app.route("/mysfits//like", methods=['POST']) 52 | def likeMysfit(mysfit_id): 53 | serviceResponse = mysfitsTableClient.likeMysfit(mysfit_id) 54 | process_like_request() 55 | flaskResponse = Response(serviceResponse) 56 | flaskResponse.headers["Content-Type"] = "application/json" 57 | return flaskResponse 58 | 59 | # @app.route("/mysfits//fulfill-like", methods=['POST']) 60 | # def likeMysfit(mysfit_id): 61 | # serviceResponse = mysfitsTableClient.likeMysfit(mysfit_id) 62 | # flaskResponse = Response(serviceResponse) 63 | # flaskResponse.headers["Content-Type"] = "application/json" 64 | # return flaskResponse 65 | 66 | # indicate that the provided mysfit should be marked as adopted. 67 | @app.route("/mysfits//adopt", methods=['POST']) 68 | def adoptMysfit(mysfit_id): 69 | serviceResponse = mysfitsTableClient.adoptMysfit(mysfit_id) 70 | 71 | flaskResponse = Response(serviceResponse) 72 | flaskResponse.headers["Content-Type"] = "application/json" 73 | 74 | return flaskResponse 75 | 76 | # Run the service on the local server it has been deployed to, 77 | # listening on port 8080. 78 | if __name__ == "__main__": 79 | app.run(host="0.0.0.0", port=80) 80 | -------------------------------------------------------------------------------- /workshop-2/ws3-start/app/monolith-service/service/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==2.2.5 2 | flask-cors==3.0.10 3 | boto3==1.26.148 4 | markupsafe==2.1.3 -------------------------------------------------------------------------------- /workshop-3/app/like-service/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-3/app/like-service/.DS_Store -------------------------------------------------------------------------------- /workshop-3/app/like-service/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | RUN echo Updating existing packages, installing and upgrading python and pip. 3 | RUN apt-get update -y 4 | RUN apt-get install -y python3-pip python-dev build-essential 5 | RUN pip3 install --upgrade pip 6 | RUN echo Copying the Mythical Mysfits Flask service into a service directory. 7 | COPY ./service /MythicalMysfitsService 8 | WORKDIR /MythicalMysfitsService 9 | RUN echo Installing Python packages listed in requirements.txt 10 | RUN pip3 install -r ./requirements.txt 11 | RUN echo Starting python and starting the Flask service... 12 | ENTRYPOINT ["python3"] 13 | CMD ["mysfits_like.py"] 14 | -------------------------------------------------------------------------------- /workshop-3/app/like-service/buildspec_prod.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | 3 | phases: 4 | pre_build: 5 | commands: 6 | - echo Logging in to Amazon ECR... 7 | - REPOSITORY_URI=REPLACEME_REPO_URI 8 | - $(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION) 9 | build: 10 | commands: 11 | - echo Build started on `date` 12 | - echo Building the Docker image... 13 | - docker build -t $REPOSITORY_URI:$CODEBUILD_RESOLVED_SOURCE_VERSION . # Here, we are using the environment variable passed in via CodeBuild IMAGE_REPO_NAME 14 | - docker tag $REPOSITORY_URI:$CODEBUILD_RESOLVED_SOURCE_VERSION $REPOSITORY_URI:$CODEBUILD_RESOLVED_SOURCE_VERSION 15 | post_build: 16 | commands: 17 | - echo Build completed on `date` 18 | - echo Pushing the Docker image... 19 | - docker push $REPOSITORY_URI:$CODEBUILD_RESOLVED_SOURCE_VERSION 20 | # Printing the container name (in taskdef) and passing it a new Docker image. 21 | - printf '[{"name":"like-service","imageUri":"%s"}]' $REPOSITORY_URI:$CODEBUILD_RESOLVED_SOURCE_VERSION > imagedefinitions.json 22 | artifacts: 23 | files: imagedefinitions.json 24 | -------------------------------------------------------------------------------- /workshop-3/app/like-service/service/mmchaos.py: -------------------------------------------------------------------------------- 1 | #import time 2 | import random 3 | import os 4 | 5 | # CREDIT for pi code: 6 | # Dan Anderson - http://blog.recursiveprocess.com/2013/03/14/calculate-pi-with-python/ 7 | 8 | from decimal import * 9 | 10 | def factorial(n): 11 | if n<1: 12 | return 1 13 | else: 14 | return n * factorial(n-1) 15 | 16 | def chudnovskyBig(n): # http://en.wikipedia.org/wiki/Chudnovsky_algorithm 17 | pi = Decimal(0) 18 | k = 0 19 | while k < n: 20 | pi += (Decimal(-1)**k)*(Decimal(factorial(6*k))/((factorial(k)**3)*(factorial(3*k)))* (13591409+545140134*k)/(640320**(3*k))) 21 | k += 1 22 | pi = pi * Decimal(10005).sqrt()/4270934400 23 | pi = pi**(-1) 24 | return pi 25 | 26 | def stress(): 27 | ran = False 28 | temp = 0 29 | #start = time.time() 30 | n = random.randint(2500,3500) 31 | #print "RUNNING for %d" % n 32 | getcontext().prec = n 33 | temp = chudnovskyBig(10) 34 | ran = True 35 | #end = time.time() 36 | #print "Duration: %r seconds" % (end-start) 37 | #print temp 38 | return ran 39 | -------------------------------------------------------------------------------- /workshop-3/app/like-service/service/mysfits_like.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | from __future__ import print_function 3 | import os 4 | import requests 5 | import mmchaos 6 | import sys 7 | import logging 8 | import random 9 | from urllib.parse import urlparse 10 | from flask import Flask, jsonify, json, Response, request, abort 11 | from flask_cors import CORS 12 | 13 | # [TODO] load x-ray recorder module 14 | # [TODO] load middleware module for incoming requests 15 | 16 | loglevel = os.environ['LOGLEVEL'].upper() 17 | 18 | app = Flask(__name__) 19 | CORS(app) 20 | app.config['DEBUG'] = True 21 | app.logger 22 | 23 | # [TODO] x-ray recorder config to label segments as 'like service' 24 | # [TODO] initialize the x-ray middleware 25 | 26 | # The service basepath has a short response just to ensure that healthchecks 27 | # sent to the service root will receive a healthy response. 28 | @app.route("/") 29 | def health_check_response(): 30 | url = urlparse('http://{}/'.format(os.environ['MONOLITH_URL'])) 31 | response = requests.get(url=url.geturl()) 32 | 33 | flask_response = jsonify({"message" : "Health check, monolith service available."}) 34 | flask_response.status_code = response.status_code 35 | return flask_response 36 | 37 | # indicate that the provided mysfit should be marked as liked. 38 | def process_like_request(): 39 | #print('Like processed.', file=sys.stderr) 40 | app.logger.info('Like processed.') 41 | 42 | def fulfill_like(mysfit_id): 43 | url = urlparse('http://{}/mysfits/{}/fulfill-like'.format(os.environ['MONOLITH_URL'], mysfit_id)) 44 | app.logger.info('Fulfill processed.') 45 | return requests.post(url=url.geturl()) 46 | 47 | @app.route("/mysfits//like", methods=['POST']) 48 | def like_mysfit(mysfit_id): 49 | app.logger.info('Like received.') 50 | if os.environ['CHAOSMODE'] == "on": 51 | n = random.randint(1,100) 52 | if n < 65: 53 | app.logger.warn('WARN: stress function activated') 54 | mmchaos.stress() 55 | elif n < 90: 56 | app.logger.warn('WARN: simulated 404 activated') 57 | abort(404) 58 | app.logger.warn('WARN: This thing should NOT be left on..') 59 | 60 | process_like_request() 61 | service_response = fulfill_like(mysfit_id) 62 | 63 | flask_response = Response(service_response) 64 | flask_response.headers["Content-Type"] = "application/json" 65 | 66 | return flask_response 67 | 68 | # Run the service on the local server it has been deployed to 69 | if __name__ == "__main__": 70 | app.run(host="0.0.0.0", port=80) 71 | -------------------------------------------------------------------------------- /workshop-3/app/like-service/service/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==2.2.5 2 | flask-cors==3.0.10 3 | requests==2.31.0 4 | markupsafe==2.1.3 -------------------------------------------------------------------------------- /workshop-3/app/monolith-service/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | RUN echo Updating existing packages, installing and upgrading python and pip. 3 | RUN apt-get update -y 4 | RUN apt-get install -y python3-pip python-dev build-essential 5 | RUN pip3 install --upgrade pip 6 | RUN echo Copying the Mythical Mysfits Flask service into a service directory. 7 | COPY ./service /MythicalMysfitsService 8 | WORKDIR /MythicalMysfitsService 9 | RUN echo Installing Python packages listed in requirements.txt 10 | RUN pip3 install -r ./requirements.txt 11 | RUN echo Starting python and starting the Flask service... 12 | ENTRYPOINT ["python3"] 13 | CMD ["mythicalMysfitsService.py"] 14 | -------------------------------------------------------------------------------- /workshop-3/app/monolith-service/service/mysfitsTableClient.py: -------------------------------------------------------------------------------- 1 | import boto3 2 | import json 3 | import logging 4 | import os 5 | from collections import defaultdict 6 | 7 | # create a DynamoDB client using boto3. The boto3 library will automatically 8 | # use the credentials associated with our ECS task role to communicate with 9 | # DynamoDB, so no credentials need to be stored/managed at all by our code! 10 | client = boto3.client('dynamodb') 11 | table_name = os.environ['DDB_TABLE_NAME'] 12 | 13 | def getAllMysfits(): 14 | 15 | # Retrieve all Mysfits from DynamoDB using the DynamoDB scan operation. 16 | # Note: The scan API can be expensive in terms of latency when a DynamoDB 17 | # table contains a high number of records and filters are applied to the 18 | # operation that require a large amount of data to be scanned in the table 19 | # before a response is returned by DynamoDB. For high-volume tables that 20 | # receive many requests, it is common to store the result of frequent/common 21 | # scan operations in an in-memory cache. DynamoDB Accelerator (DAX) or 22 | # use of ElastiCache can provide these benefits. But, because out Mythical 23 | # Mysfits API is low traffic and the table is very small, the scan operation 24 | # will suit our needs for this workshop. 25 | response = client.scan( 26 | TableName=table_name 27 | ) 28 | 29 | logging.info(response["Items"]) 30 | 31 | # loop through the returned mysfits and add their attributes to a new dict 32 | # that matches the JSON response structure expected by the frontend. 33 | mysfitList = defaultdict(list) 34 | for item in response["Items"]: 35 | mysfit = {} 36 | mysfit["mysfitId"] = item["MysfitId"]["S"] 37 | mysfit["name"] = item["Name"]["S"] 38 | mysfit["goodevil"] = item["GoodEvil"]["S"] 39 | mysfit["lawchaos"] = item["LawChaos"]["S"] 40 | mysfit["species"] = item["Species"]["S"] 41 | mysfit["thumbImageUri"] = item["ThumbImageUri"]["S"] 42 | mysfitList["mysfits"].append(mysfit) 43 | 44 | # convert the create list of dicts in to JSON 45 | return json.dumps(mysfitList) 46 | 47 | def queryMysfits(queryParam): 48 | 49 | logging.info(json.dumps(queryParam)) 50 | 51 | # Use the DynamoDB API Query to retrieve mysfits from the table that are 52 | # equal to the selected filter values. 53 | response = client.query( 54 | TableName=table_name, 55 | IndexName=queryParam['filter']+'Index', 56 | KeyConditions={ 57 | queryParam['filter']: { 58 | 'AttributeValueList': [ 59 | { 60 | 'S': queryParam['value'] 61 | } 62 | ], 63 | 'ComparisonOperator': "EQ" 64 | } 65 | } 66 | ) 67 | 68 | mysfitList = defaultdict(list) 69 | for item in response["Items"]: 70 | mysfit = {} 71 | mysfit["mysfitId"] = item["MysfitId"]["S"] 72 | mysfit["name"] = item["Name"]["S"] 73 | mysfit["goodevil"] = item["GoodEvil"]["S"] 74 | mysfit["lawchaos"] = item["LawChaos"]["S"] 75 | mysfit["species"] = item["Species"]["S"] 76 | mysfit["thumbImageUri"] = item["ThumbImageUri"]["S"] 77 | mysfitList["mysfits"].append(mysfit) 78 | 79 | return json.dumps(mysfitList) 80 | 81 | # Retrive a single mysfit from DynamoDB using their unique mysfitId 82 | def getMysfit(mysfitId): 83 | 84 | # use the DynamoDB API GetItem, which gives you the ability to retrieve 85 | # a single item from a DynamoDB table using its unique key with super 86 | # low latency. 87 | response = client.get_item( 88 | TableName=table_name, 89 | Key={ 90 | 'MysfitId': { 91 | 'S': mysfitId 92 | } 93 | } 94 | ) 95 | 96 | item = response["Item"] 97 | 98 | mysfit = {} 99 | mysfit["mysfitId"] = item["MysfitId"]["S"] 100 | mysfit["name"] = item["Name"]["S"] 101 | mysfit["age"] = int(item["Age"]["N"]) 102 | mysfit["goodevil"] = item["GoodEvil"]["S"] 103 | mysfit["lawchaos"] = item["LawChaos"]["S"] 104 | mysfit["species"] = item["Species"]["S"] 105 | mysfit["description"] = item["Description"]["S"] 106 | mysfit["thumbImageUri"] = item["ThumbImageUri"]["S"] 107 | mysfit["profileImageUri"] = item["ProfileImageUri"]["S"] 108 | mysfit["likes"] = item["Likes"]["N"] 109 | mysfit["adopted"] = item["Adopted"]["BOOL"] 110 | 111 | return json.dumps(mysfit) 112 | 113 | # increment the number of likes for a mysfit by 1 114 | def likeMysfit(mysfitId): 115 | 116 | # Use the DynamoDB API UpdateItem to increment the number of Likes 117 | # the mysfit has by 1 using an UpdateExpression. 118 | response = client.update_item( 119 | TableName=table_name, 120 | Key={ 121 | 'MysfitId': { 122 | 'S': mysfitId 123 | } 124 | }, 125 | UpdateExpression="SET Likes = Likes + :n", 126 | ExpressionAttributeValues={':n': {'N': '1'}} 127 | ) 128 | 129 | response = {} 130 | response["Update"] = "Success"; 131 | 132 | return json.dumps(response) 133 | 134 | # mark a mysfit as adopted 135 | def adoptMysfit(mysfitId): 136 | 137 | # Use the DynamoDB API UpdateItem to set the value of the mysfit's 138 | # Adopted attribute to True using an UpdateExpression. 139 | response = client.update_item( 140 | TableName=table_name, 141 | Key={ 142 | 'MysfitId': { 143 | 'S': mysfitId 144 | } 145 | }, 146 | UpdateExpression="SET Adopted = :b", 147 | ExpressionAttributeValues={':b': {'BOOL': True}} 148 | ) 149 | 150 | response = {} 151 | response["Update"] = "Success"; 152 | 153 | return json.dumps(response) 154 | -------------------------------------------------------------------------------- /workshop-3/app/monolith-service/service/mythicalMysfitsService.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, jsonify, json, Response, request 2 | from flask_cors import CORS 3 | import mysfitsTableClient 4 | import os 5 | 6 | app = Flask(__name__) 7 | CORS(app) 8 | 9 | # The service basepath has a short response just to ensure that healthchecks 10 | # sent to the service root will receive a healthy response. 11 | @app.route("/") 12 | def healthCheckResponse(): 13 | return jsonify({'message' : 'Nothing here, used for health check. Try /mysfits instead.'}) 14 | 15 | # Retrive mysfits from DynamoDB based on provided querystring params, or all 16 | # mysfits if no querystring is present. 17 | @app.route("/mysfits", methods=['GET']) 18 | def getMysfits(): 19 | 20 | filterCategory = request.args.get('filter') 21 | if filterCategory: 22 | filterValue = request.args.get('value') 23 | queryParam = { 24 | 'filter': filterCategory, 25 | 'value': filterValue 26 | } 27 | serviceResponse = mysfitsTableClient.queryMysfits(queryParam) 28 | else: 29 | serviceResponse = mysfitsTableClient.getAllMysfits() 30 | 31 | flaskResponse = Response(serviceResponse) 32 | flaskResponse.headers["Content-Type"] = "application/json" 33 | 34 | return flaskResponse 35 | 36 | def process_like_request(): 37 | print('Like processed.') 38 | 39 | # retrieve the full details for a specific mysfit with their provided path 40 | # parameter as their ID. 41 | @app.route("/mysfits/", methods=['GET']) 42 | def getMysfit(mysfit_id): 43 | serviceResponse = mysfitsTableClient.getMysfit(mysfit_id) 44 | 45 | flaskResponse = Response(serviceResponse) 46 | flaskResponse.headers["Content-Type"] = "application/json" 47 | 48 | return flaskResponse 49 | 50 | # increment the number of likes for the provided mysfit. 51 | # @app.route("/mysfits//like", methods=['POST']) 52 | # def likeMysfit(mysfit_id): 53 | # serviceResponse = mysfitsTableClient.likeMysfit(mysfit_id) 54 | # process_like_request() 55 | # flaskResponse = Response(serviceResponse) 56 | # flaskResponse.headers["Content-Type"] = "application/json" 57 | # return flaskResponse 58 | 59 | @app.route("/mysfits//fulfill-like", methods=['POST']) 60 | def likeMysfit(mysfit_id): 61 | serviceResponse = mysfitsTableClient.likeMysfit(mysfit_id) 62 | flaskResponse = Response(serviceResponse) 63 | flaskResponse.headers["Content-Type"] = "application/json" 64 | return flaskResponse 65 | 66 | # indicate that the provided mysfit should be marked as adopted. 67 | @app.route("/mysfits//adopt", methods=['POST']) 68 | def adoptMysfit(mysfit_id): 69 | serviceResponse = mysfitsTableClient.adoptMysfit(mysfit_id) 70 | 71 | flaskResponse = Response(serviceResponse) 72 | flaskResponse.headers["Content-Type"] = "application/json" 73 | 74 | return flaskResponse 75 | 76 | # Run the service on the local server it has been deployed to, 77 | # listening on port 8080. 78 | if __name__ == "__main__": 79 | app.run(host="0.0.0.0", port=80) 80 | -------------------------------------------------------------------------------- /workshop-3/app/monolith-service/service/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==2.2.5 2 | flask-cors==3.0.10 3 | boto3==1.26.148 4 | markupsafe==2.1.3 -------------------------------------------------------------------------------- /workshop-3/app/xray/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). 4 | # You may not use this file except in compliance with the License. 5 | # A copy of the License is located at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # or in the "license" file accompanying this file. This file is distributed 10 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing 12 | # permissions and limitations under the License. 13 | 14 | FROM amazonlinux:1 15 | 16 | # Download latest 2.x release of X-Ray daemon 17 | # Unpack archive, by default unzip is not installed so do that beforehand 18 | RUN yum install -y unzip && \ 19 | cd /tmp/ && \ 20 | curl https://s3.dualstack.us-east-2.amazonaws.com/aws-xray-assets.us-east-2/xray-daemon/aws-xray-daemon-linux-2.x.zip > aws-xray-daemon-linux-2.x.zip && \ 21 | unzip aws-xray-daemon-linux-2.x.zip && \ 22 | cp xray /usr/bin/xray && \ 23 | rm aws-xray-daemon-linux-2.x.zip && \ 24 | rm cfg.yaml 25 | 26 | # Expose port 2000 on udp 27 | EXPOSE 2000/udp 28 | 29 | ENTRYPOINT ["/usr/bin/xray", "-b", "0.0.0.0:2000"] 30 | 31 | # No cmd line parameters, use default configuration 32 | CMD [''] 33 | -------------------------------------------------------------------------------- /workshop-3/cfn-templates/load-gen-lab4.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: Mythical Misfits workshop lab4. Deploys a load generator. 3 | Parameters: 4 | ALBDNSName: 5 | Type: String 6 | Description: "DNS Name of the Mysfits ALB" 7 | MysfitID: 8 | Type: String 9 | Description: "ID of one of the Mysfits" 10 | Default: "0e37d916-f960-4772-a25a-01b762b5c1b" 11 | Mappings: 12 | AWSRegionToAMZNLinuxAMI: 13 | us-east-1: 14 | AMIID: ami-a4c7edb2 15 | us-east-2: 16 | AMIID: ami-8a7859ef 17 | us-west-1: 18 | AMIID: ami-327f5352 19 | us-west-2: 20 | AMIID: ami-6df1e514 21 | eu-central-1: 22 | AMIID: ami-82be18ed 23 | eu-west-1: 24 | AMIID: ami-d7b9a2b1 25 | eu-west-2: 26 | AMIID: ami-ed100689 27 | ap-northeast-1: 28 | AMIID: ami-3bd3c45c 29 | ap-southeast-2: 30 | AMIID: ami-10918173 31 | ap-southeast-1: 32 | AMIID: ami-77af2014 33 | ca-central-1: 34 | AMIID: ami-a7aa15c3 35 | Resources: 36 | LoadGeneratorInstance: 37 | Type: AWS::EC2::Instance 38 | Metadata: 39 | AWS::CloudFormation::Init: 40 | config: 41 | files: 42 | /home/ec2-user/targets: 43 | content: !Join ['', ['POST http://', !Ref 'ALBDNSName' , '/mysfits/', !Ref 'MysfitID','/like']] 44 | mode: '000777' 45 | owner: root 46 | group: root 47 | /home/ec2-user/load.sh: 48 | content: !Join ['', [ '#! /bin/bash', ' 49 | 50 | ', 'cd /home/ec2-user 51 | 52 | ', '/home/ec2-user/vegeta attack -targets targets -timeout 15m -output results.txt 53 | 54 | ']] 55 | mode: '000777' 56 | owner: root 57 | group: root 58 | Properties: 59 | ImageId: !FindInMap [AWSRegionToAMZNLinuxAMI, !Ref 'AWS::Region', AMIID] 60 | InstanceType: m4.large 61 | Tags: 62 | - 63 | Key: Name 64 | Value: LoadGenerator 65 | UserData: !Base64 66 | Fn::Join: 67 | - '' 68 | - ['#!/bin/bash 69 | 70 | ', '/opt/aws/bin/cfn-init -s ', !Ref 'AWS::StackName', ' -r LoadGeneratorInstance --region ', !Ref 'AWS::Region', ' 71 | 72 | ', 'wget http://catsndogs-assets.s3.amazonaws.com/vegeta -P /home/ec2-user/ 73 | 74 | ', 'chmod +x /home/ec2-user/vegeta 75 | 76 | ', 'sleep 10', ' 77 | 78 | ', '/home/ec2-user/load.sh',' 79 | 80 | '] 81 | -------------------------------------------------------------------------------- /workshop-3/images/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-3/images/.DS_Store -------------------------------------------------------------------------------- /workshop-3/images/02-03-ESProcessing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-3/images/02-03-ESProcessing.png -------------------------------------------------------------------------------- /workshop-3/images/02-03-cwlLikes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-3/images/02-03-cwlLikes.png -------------------------------------------------------------------------------- /workshop-3/images/02-03-cwlStreamES.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-3/images/02-03-cwlStreamES.png -------------------------------------------------------------------------------- /workshop-3/images/02-03-cwlStreamESConfig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-3/images/02-03-cwlStreamESConfig.png -------------------------------------------------------------------------------- /workshop-3/images/02-03-cwlSubscription.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-3/images/02-03-cwlSubscription.png -------------------------------------------------------------------------------- /workshop-3/images/02-03-enableKibanaCognitoAuth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-3/images/02-03-enableKibanaCognitoAuth.png -------------------------------------------------------------------------------- /workshop-3/images/02-03-kibanaIndexPattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-3/images/02-03-kibanaIndexPattern.png -------------------------------------------------------------------------------- /workshop-3/images/02-03-kibanaTimeFilter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-3/images/02-03-kibanaTimeFilter.png -------------------------------------------------------------------------------- /workshop-3/images/02-03-logLevelDebug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-3/images/02-03-logLevelDebug.png -------------------------------------------------------------------------------- /workshop-3/images/02-03-serviceUpdate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-3/images/02-03-serviceUpdate.png -------------------------------------------------------------------------------- /workshop-3/images/02-03-startStreaming.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-3/images/02-03-startStreaming.png -------------------------------------------------------------------------------- /workshop-3/images/02-03-userPoolDomain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-3/images/02-03-userPoolDomain.png -------------------------------------------------------------------------------- /workshop-3/images/03-JSconsole.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-3/images/03-JSconsole.png -------------------------------------------------------------------------------- /workshop-3/images/03-commitInstrumented.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-3/images/03-commitInstrumented.png -------------------------------------------------------------------------------- /workshop-3/images/03-elbHealthCheckTrace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-3/images/03-elbHealthCheckTrace.png -------------------------------------------------------------------------------- /workshop-3/images/03-filterGroup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-3/images/03-filterGroup.png -------------------------------------------------------------------------------- /workshop-3/images/03-likeInstrumented.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-3/images/03-likeInstrumented.png -------------------------------------------------------------------------------- /workshop-3/images/03-pipeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-3/images/03-pipeline.png -------------------------------------------------------------------------------- /workshop-3/images/03-requirements.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-3/images/03-requirements.png -------------------------------------------------------------------------------- /workshop-3/images/03-serviceMap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-3/images/03-serviceMap.png -------------------------------------------------------------------------------- /workshop-3/images/03-updateLikeService.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-3/images/03-updateLikeService.png -------------------------------------------------------------------------------- /workshop-3/images/03-xraySidecar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-3/images/03-xraySidecar.png -------------------------------------------------------------------------------- /workshop-3/images/architecture-diagram-aws-developer-center_mythical-mysfits-application-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-3/images/architecture-diagram-aws-developer-center_mythical-mysfits-application-architecture.png -------------------------------------------------------------------------------- /workshop-3/images/architecture_diagram_ws3_lab_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-3/images/architecture_diagram_ws3_lab_1.png -------------------------------------------------------------------------------- /workshop-3/images/architecture_diagram_ws3_starting_point.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-3/images/architecture_diagram_ws3_starting_point.png -------------------------------------------------------------------------------- /workshop-3/images/lab1.3.task-network-ip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-3/images/lab1.3.task-network-ip.png -------------------------------------------------------------------------------- /workshop-3/images/mysfits-welcome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-ecs-mythicalmysfits-workshop/8ab2b33e9003f6b8745867d7bd6955a281c629d4/workshop-3/images/mysfits-welcome.png -------------------------------------------------------------------------------- /workshop-3/script/fetch-outputs: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | set -eu 4 | 5 | if [[ $# -eq 1 ]]; then 6 | STACK_NAME=$1 7 | else 8 | STACK_NAME="$(echo $C9_PROJECT | sed 's/^Project-//')" 9 | fi 10 | 11 | aws cloudformation describe-stacks --stack-name "$STACK_NAME" | jq -r '[.Stacks[0].Outputs[] | {key: .OutputKey, value: .OutputValue}] | from_entries' > cfn-output.json 12 | -------------------------------------------------------------------------------- /workshop-3/script/setup: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | set -eu 4 | 5 | echo "Installing dependencies..." 6 | sudo yum install -y jq 7 | echo "Fetching CloudFormation outputs..." 8 | script/fetch-outputs 9 | echo "Populating DynamoDB table..." 10 | script/load-ddb 11 | #echo "Cloning Repos" 12 | #script/clone 13 | #echo "Populating and pushing Repos" 14 | #script/populate 15 | echo "Uploading static site to S3..." 16 | if [[ $# -eq 1 ]]; then 17 | script/upload-site $1 18 | else 19 | script/upload-site 20 | fi 21 | #echo "Bootstrapping for crash course" 22 | #script/ws2/update-service-json 23 | echo "Bootstrapping for WS2" 24 | script/ws2/bootstrap_ws2 25 | echo "Bootstrapping for WS3" 26 | script/ws3/bootstrap_ws3 27 | echo "Success!" 28 | -------------------------------------------------------------------------------- /workshop-3/script/setup_ws1_end: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | set -eu 4 | 5 | echo "Installing dependencies..." 6 | sudo yum install -y jq 7 | echo "Fetching CloudFormation outputs..." 8 | script/fetch-outputs 9 | echo "Populating DynamoDB table..." 10 | script/load-ddb 11 | #echo "Cloning Repos" 12 | #script/clone 13 | #echo "Populating and pushing Repos" 14 | #script/populate 15 | echo "Uploading static site to S3..." 16 | if [[ $# -eq 1 ]]; then 17 | script/upload-site $1 18 | else 19 | script/upload-site 20 | fi 21 | echo "Bootstrapping for WS2" 22 | script/ws2/bootstrap_ws2 23 | #echo "Bootstrapping for WS3" 24 | #script/ws3/bootstrap_ws3 25 | echo "Success!" 26 | -------------------------------------------------------------------------------- /workshop-3/script/upload-site: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | set -eu 4 | 5 | if [[ $# -eq 1 ]]; then 6 | BUCKET_NAME="$1" 7 | else 8 | BUCKET_NAME=$(jq < cfn-output.json -er '.SiteBucket') 9 | fi 10 | 11 | API_ENDPOINT=$(jq < cfn-output.json -er '.LoadBalancerDNS') 12 | # For auth, not used now 13 | #USER_POOL_ID=$(jq < cfn-output.json -er '.UserPoolId') 14 | #CLIENT_ID=$(jq < cfn-output.json -er '.ClientId') 15 | REGION=$(aws configure get region) 16 | 17 | TEMP_DIR=$(mktemp -d) 18 | 19 | cp -R web/. $TEMP_DIR/. 20 | 21 | if which gsed; then 22 | sed_cmd=gsed 23 | else 24 | sed_cmd=sed 25 | fi 26 | 27 | sed_prog="s|REPLACE_ME_API_ENDPOINT|http://$API_ENDPOINT|;" 28 | $sed_cmd -i $sed_prog $TEMP_DIR/index.html 29 | $sed_cmd -i $sed_prog $TEMP_DIR/register.html 30 | $sed_cmd -i $sed_prog $TEMP_DIR/confirm.html 31 | aws s3 sync $TEMP_DIR s3://$BUCKET_NAME --acl public-read 32 | -------------------------------------------------------------------------------- /workshop-3/script/ws2/bootstrap_ws2: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | echo "Building Docker Containers" 4 | script/ws2/build-containers 5 | echo "Creating Fargate service JSONs" 6 | script/ws2/update-service-json 7 | echo "Creating Fargate Services for Like/Monolith" 8 | script/ws2/create-fargate-services 9 | -------------------------------------------------------------------------------- /workshop-3/script/ws2/build-containers: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | LIKE_ECR_REPO=$(jq < cfn-output.json -r '.LikeEcrRepo') 4 | MONO_ECR_REPO=$(jq < cfn-output.json -r '.MonoEcrRepo') 5 | XRAY_ECR_REPO=$(jq < cfn-output.json -r '.XrayEcrRepo') 6 | 7 | $(aws ecr get-login --no-include-email) 8 | 9 | docker build -t like-service app/like-service 10 | docker tag like-service:latest $LIKE_ECR_REPO:latest 11 | docker push $LIKE_ECR_REPO:latest 12 | 13 | docker build -t monolith-service app/monolith-service 14 | docker tag monolith-service:latest $MONO_ECR_REPO:latest 15 | docker push $MONO_ECR_REPO:latest 16 | 17 | docker build -t x-ray-daemon app/xray 18 | docker tag x-ray-daemon:latest $XRAY_ECR_REPO:latest 19 | docker push $XRAY_ECR_REPO:latest 20 | -------------------------------------------------------------------------------- /workshop-3/script/ws2/create-fargate-services: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | LIKE_TASK_DEF=$(jq < cfn-output.json -r '.LikeTaskDefinition') 4 | MONOLITH_TASK_DEF=$(jq < cfn-output.json -r '.MonolithTaskDefinition') 5 | 6 | aws ecs create-service --cli-input-json file://script/ws2/like-service.json --task-definition $LIKE_TASK_DEF 7 | aws ecs create-service --cli-input-json file://script/ws2/monolith-service.json --task-definition $MONOLITH_TASK_DEF 8 | -------------------------------------------------------------------------------- /workshop-3/script/ws2/service-template.json: -------------------------------------------------------------------------------- 1 | { 2 | "cluster": "CLUSTER_NAME", 3 | "serviceName": "STACK_NAME_Mythical-SERVICE_NAME-Service", 4 | "loadBalancers": [ 5 | { 6 | "targetGroupArn": "TARGET_GROUP_ARN", 7 | "containerName": "CONTAINER_NAME", 8 | "containerPort": 80 9 | } 10 | ], 11 | "desiredCount": 1, 12 | "launchType": "FARGATE", 13 | "deploymentConfiguration": { 14 | "maximumPercent": 200, 15 | "minimumHealthyPercent": 0 16 | }, 17 | "networkConfiguration": { 18 | "awsvpcConfiguration": { 19 | "subnets": [ 20 | "PRIVATE_SUBNET_ONE", 21 | "PRIVATE_SUBNET_TWO" 22 | ], 23 | "securityGroups": [ 24 | "FARGATE_CONTAINER_SECURITY_GROUP" 25 | ], 26 | "assignPublicIp": "DISABLED" 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /workshop-3/script/ws2/update-service-json: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | set -eu 4 | 5 | # declare an associative array, the -A defines the array of this type 6 | declare -A cfnOutputs 7 | 8 | # The output of jq is separated by '|' so that we have a valid delimiter 9 | # to read our keys and values. The read command processes one line at a 10 | # time and puts the values in the variables 'key' and 'value' 11 | while IFS='|' read -r key value; do 12 | # Strip out the text until the last occurrence of '/' 13 | strippedKey="${key##*/}" 14 | # Putting the key/value pair in the array 15 | cfnOutputs["$strippedKey"]="$value" 16 | done< <(jq -r 'keys[] as $k | "\($k)|\(.[$k])"' cfn-output.json) 17 | 18 | # Print the array using the '-p' or do one by one 19 | #declare -p cfnOutputs 20 | 21 | cp script/ws2/service-template.json script/ws2/monolith-service.json 22 | cp script/ws2/service-template.json script/ws2/like-service.json 23 | 24 | sed -i -e 's/CLUSTER_NAME/'"${cfnOutputs[EcsClusterName]}"'/' \ 25 | -e 's/STACK_NAME/'"${cfnOutputs[StackName]}"'/' \ 26 | -e 's/SERVICE_NAME/Monolith/' \ 27 | -e 's~TARGET_GROUP_ARN~'"${cfnOutputs[MonolithTargetGroupArn]}"'~' \ 28 | -e 's/CONTAINER_NAME/monolith-service/' \ 29 | -e 's/PRIVATE_SUBNET_ONE/'"${cfnOutputs[PrivateSubnetOne]}"'/' \ 30 | -e 's/PRIVATE_SUBNET_TWO/'"${cfnOutputs[PrivateSubnetTwo]}"'/' \ 31 | -e 's/FARGATE_CONTAINER_SECURITY_GROUP/'"${cfnOutputs[FargateContainerSecurityGroup]}"'/' script/ws2/monolith-service.json 32 | 33 | sed -i -e 's/CLUSTER_NAME/'"${cfnOutputs[EcsClusterName]}"'/' \ 34 | -e 's/STACK_NAME/'"${cfnOutputs[StackName]}"'/' \ 35 | -e 's/SERVICE_NAME/Like/' \ 36 | -e 's~TARGET_GROUP_ARN~'"${cfnOutputs[LikeTargetGroupArn]}"'~' \ 37 | -e 's/CONTAINER_NAME/like-service/' \ 38 | -e 's/PRIVATE_SUBNET_ONE/'"${cfnOutputs[PrivateSubnetOne]}"'/' \ 39 | -e 's/PRIVATE_SUBNET_TWO/'"${cfnOutputs[PrivateSubnetTwo]}"'/' \ 40 | -e 's/FARGATE_CONTAINER_SECURITY_GROUP/'"${cfnOutputs[FargateContainerSecurityGroup]}"'/' script/ws2/like-service.json 41 | -------------------------------------------------------------------------------- /workshop-3/script/ws3/bootstrap_ws3: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "Cloning Git Repos" 3 | script/ws3/clone 4 | echo "Populating and pushing Git Repos" 5 | script/ws3/populate 6 | -------------------------------------------------------------------------------- /workshop-3/script/ws3/clone: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | git config --global credential.helper "cache --timeout=7200" 4 | git config --global user.email "REPLACEME" 5 | git config --global user.name "ws3-user" 6 | git config --global credential.helper '!aws codecommit credential-helper $@' 7 | git config --global credential.UseHttpPath true 8 | 9 | LIKE_REPO=$(jq < cfn-output.json -r '.MythicalLikeGitRepositoryCloneUrl') 10 | MONOLITH_REPO=$(jq < cfn-output.json -r '.MythicalMonolithGitRepositoryCloneUrl') 11 | 12 | LIKE_REPO_NAME==$(jq < cfn-output.json -r '.MythicalLikeGitRepositoryName') 13 | MONOLITH_REPO_NAME==$(jq < cfn-output.json -r '.MythicalMonolithGitRepositoryName') 14 | 15 | cd ~/environment/ 16 | 17 | git clone $LIKE_REPO 18 | git clone $MONOLITH_REPO 19 | -------------------------------------------------------------------------------- /workshop-3/script/ws3/populate: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | LIKE_REPO_NAME=$(jq < cfn-output.json -r '.MythicalLikeGitRepositoryName') 4 | MONOLITH_REPO_NAME=$(jq < cfn-output.json -r '.MythicalMonolithGitRepositoryName') 5 | 6 | LIKE_ECR_REPO_URI=$(jq < cfn-output.json -r '.LikeEcrRepo') 7 | 8 | cp -R app/like-service/* ~/environment/$LIKE_REPO_NAME/ 9 | sed -i -e 's;REPLACEME_REPO_URI;'"$LIKE_ECR_REPO_URI"';' ~/environment/$LIKE_REPO_NAME/buildspec_prod.yml 10 | cp -R app/monolith-service/* ~/environment/$MONOLITH_REPO_NAME/ 11 | 12 | cd ~/environment/$LIKE_REPO_NAME/ 13 | git add -A 14 | git commit -m "Initial Commit of Like Service" 15 | git push origin master 16 | 17 | cd ~/environment/$MONOLITH_REPO_NAME/ 18 | git add -A 19 | git commit -m "Initial Commit of Monolith Service" 20 | git push origin master 21 | -------------------------------------------------------------------------------- /workshop-3/web/confirm.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | Mythical Mysfits Registration 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 |
22 | 23 |
24 |
25 |

Enter the code sent to the email you provided.
Then, login again on the home page.

26 |
27 |
28 | 29 | 30 |
31 | 32 |
33 |

34 | 35 | 36 | 37 | 71 | 72 | -------------------------------------------------------------------------------- /workshop-3/web/register.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | Register for Mythical Mysfits 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |
21 | 22 |
23 |
24 |

Register for Mythical Mysfits!

25 |
26 |
27 | 28 | 29 |
30 |
31 | 32 | 33 |
34 |
35 | 36 | 37 |
38 | 39 |
40 |
41 | 42 | 43 | 44 | 90 | 91 | --------------------------------------------------------------------------------