Skip to content

Commit

Permalink
Merge pull request #1302 from ChildMindInstitute/M2-6368-preview-apps
Browse files Browse the repository at this point in the history
chore: Create preview apps on ECS (M2-6368)
  • Loading branch information
aweiland authored Jun 5, 2024
2 parents 82e2bc8 + 25efa62 commit e6de398
Show file tree
Hide file tree
Showing 28 changed files with 1,401 additions and 118 deletions.
40 changes: 40 additions & 0 deletions .github/workflows/branch-delete.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Tear down preview environment for feature branch

on:
delete: {}


env:
APP_NAME: ${{ github.event.repository.name }}
COPILOT_SERVICE: mindlogger-backend
AWS_REGION: us-east-1

jobs:
set-env-name:
uses: ./.github/workflows/env-name.yaml
destroy-preview-env:
name: Destroy Preview Env
if: github.event.ref_type == 'branch'
needs: [set-env-name]
permissions:
id-token: write
contents: read
runs-on: ubuntu-latest
env:
ENV_NAME: ${{ needs.set-env-name.outputs.env-name }}
ENV_SNAKE_NAME: ${{ needs.set-env-name.outputs.env-snake-name }}
steps:
- name: configure aws credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::992382368072:role/cmiml-feature-oidc-github-role
role-session-name: gha-preview-env
aws-region: ${{ env.AWS_REGION }}
- name: Install copilot
run: |
curl -Lo copilot https://github.com/aws/copilot-cli/releases/latest/download/copilot-linux && chmod +x copilot &&
sudo mv copilot /usr/local/bin/copilot && copilot -v
- uses: actions/checkout@v4
name: Checkout
- name: Delete environment
run: scripts/env-stop.sh
92 changes: 92 additions & 0 deletions .github/workflows/create-preview-env.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
on:
workflow_call:
outputs:
service-url:
value: "${{ jobs.create-preview-env.outputs.service-url }}"
inputs:
env-name:
type: string
description: Environment name
required: true
env-snake-name:
type: string
description: Env name is snake case
required: true
copilot-service:
type: string
description: Copilot service name
required: true
app-name:
type: string
description: App Name (likely the GH repo)
required: true
vpc-id:
type: string
description: VPC ID for preview envs
required: true
aws-region:
type: string
default: us-east-1
required: false

jobs:
create-preview-env:
runs-on: ubuntu-latest
name: Create Preview Env
permissions:
id-token: write
contents: read
pull-requests: write
discussions: write
env:
ENV_NAME: ${{ inputs.env-name }}
ENV_NAME_SNAKE: ${{ inputs.env-snake-name }}
APP_NAME: ${{ inputs.app-name }}
VPC_ID: ${{ inputs.vpc-id }}
COPILOT_SERVICE: ${{ inputs.copilot-service }}
AWS_REGION: us-east-1
steps:
- name: configure aws credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::992382368072:role/cmiml-feature-oidc-github-role
role-session-name: gha-preview-env
aws-region: ${{ inputs.aws-region }}
- name: Install copilot
run: |
curl -Lo copilot https://github.com/aws/copilot-cli/releases/latest/download/copilot-linux && chmod +x copilot &&
sudo mv copilot /usr/local/bin/copilot && copilot -v
- name: Install session manager plugin
run: |
curl "https://s3.amazonaws.com/session-manager-downloads/plugin/latest/ubuntu_64bit/session-manager-plugin.deb" -o "session-manager-plugin.deb" &&
sudo dpkg -i session-manager-plugin.deb
- name: Create secrets for environment
# Each env needs a secret. This is a copilot limitation. So the baseline secret
# is copied and tagged properly for copilot to pick it up.
run: |
COUNT=$(aws secretsmanager list-secrets --query SecretList --filters Key=name,Values=cmiml-feature-${{ inputs.env-name }} | jq length)
if [ "$COUNT" -ne "0" ]; then
echo "Secret exists, skipping..."
exit 0
fi
SECRET_STRING=$(aws secretsmanager get-secret-value --secret-id cmiml-feature-feature --query SecretString --output text)
aws secretsmanager create-secret --name cmiml-feature-${{ inputs.env-name }} --secret-string "$SECRET_STRING" --kms-key-id alias/aws/secretsmanager --tags "Key=copilot-application,Value=${{ inputs.app-name }}" "Key=copilot-environment,Value=${{ inputs.env-name }}"
- uses: actions/checkout@v4
name: Checkout
- name: Create environment
run: copilot/scripts/env-init.sh
- name: Deploy environment
run: copilot/scripts/env-deploy.sh
- name: Deploy service
run: copilot/scripts/svc-deploy.sh
- name: Run DB migration
run: |
copilot svc exec -a ${{ inputs.app-name }} -e ${{ inputs.env-name }} -n ${{ inputs.copilot-service }} --command "/fastapi-migrate"
- name: Get service URL
id: service-url
run: echo "SERVICE_URL=$(copilot svc show -n ${{ inputs.copilot-service }} --json | jq -r '.routes[] | select( .environment | contains("${{ inputs.env-name }}") ) | .url')" >> $GITHUB_OUTPUT

# TODO Slack notification?
outputs:
service-url: ${{ steps.service-url.outputs.SERVICE_URL }}
113 changes: 66 additions & 47 deletions .github/workflows/create_db.yaml
Original file line number Diff line number Diff line change
@@ -1,57 +1,76 @@
name: Create-RDS-Database
name: Create RDS Database

on:
workflow_run:
workflows: ["Name-of-Your-Triggering-Workflow"]
types:
- completed
# TODO Delete this after testing
workflow_dispatch:
inputs:
db-name:
required: true
type: string
description: Database name to create
workflow_call:
inputs:
db-name:
required: true
type: string
description: Database name to create

jobs:
create_database:
runs-on: ubuntu-latest
runs-on: [self-hosted]

steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Create Database
run: >-
PGPASSWORD="${{ secrets.DB_PASSWORD }}" psql -h "${{ secrets.RDS_ENDPOINT }}" -U "${{ secrets.DB_ROOT_USERNAME }}" -tc "SELECT 1 FROM pg_database WHERE datname = '${{ inputs.db-name }}'" postgres | grep -q 1 ||
PGPASSWORD="${{ secrets.DB_PASSWORD }}" psql -h "${{ secrets.RDS_ENDPOINT }}" -U "${{ secrets.DB_ROOT_USERNAME }}" -c "CREATE DATABASE ${{ inputs.db-name }}" postgres
- name: Set Owner
run: >-
PGPASSWORD="${{ secrets.DB_PASSWORD }}" psql -h "${{ secrets.RDS_ENDPOINT }}" -U "${{ secrets.DB_ROOT_USERNAME }}"
-c "alter database ${{ inputs.db-name }} owner to ${{ secrets.DB_BACKEND_USERNAME }};" postgres
- name: Install PostgreSQL client 16
run: |
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
sudo apt-get install -y wget ca-certificates
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo apt-get update
sudo apt-get install -y postgresql-client-16
- name: Grant privileges
run: >-
PGPASSWORD="${{ secrets.DB_PASSWORD }}" psql -h "${{ secrets.RDS_ENDPOINT }}" -U "${{ secrets.DB_ROOT_USERNAME }}"
-c "grant all privileges on database ${{ inputs.db-name }} to ${{ secrets.DB_BACKEND_USERNAME }};" postgres
- name: Create Database
run: |
PGPASSWORD="${{ secrets.DB_PASSWORD }}" psql -h "${{ secrets.RDS_ENDPOINT }}" -U "${{ secrets.USERNAME }}" -d "${{ secrets.DATABASE_NAME }}" -c "CREATE DATABASE <DATABASE_NAME>;"
- name: Create pg_cron schema
run: >-
PGPASSWORD="${{ secrets.DB_BACKEND_PASSWORD }}" psql -h "${{ secrets.RDS_ENDPOINT }}" -U "${{ secrets.DB_BACKEND_USERNAME }}"
-c "CREATE SCHEMA IF NOT EXISTS cron;" ${{ inputs.db-name }}
on-failure:
runs-on: ubuntu-latest
if: ${{ always() && (needs.create_database.result == 'failure' || needs.create_database.result == 'timed_out') }}
needs:
- create_database
steps:
- uses: actions/checkout@v4
- name: "Send Slack message on failure"
uses: rtCamp/action-slack-notify@v2
env:
SLACK_COLOR: failure
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL_TEST_WORKFLOW }}
SLACK_TITLE: Create Database
SLACK_MESSAGE: 'Error during database creation!'

on-success:
runs-on: ubuntu-latest
if: ${{ always() && (needs.create_database.result == 'success') }}
needs:
- create_database
steps:
- uses: actions/checkout@v4
- name: "Send Slack message on success"
uses: rtCamp/action-slack-notify@v2
env:
SLACK_COLOR: success
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL_TEST_WORKFLOW }}
SLACK_TITLE: Create Database
SLACK_MESSAGE: 'The database has been successfully created!'
# on-failure:
# name: Database creation failed
# runs-on: ubuntu-latest
# if: ${{ always() && (needs.create_database.result == 'failure' || needs.create_database.result == 'timed_out') }}
# needs:
# - create_database
# steps:
# - uses: actions/checkout@v4
# - name: "Send Slack message on failure"
# uses: rtCamp/action-slack-notify@v2
# env:
# SLACK_COLOR: failure
# SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_TEST_RESULTS }}
# SLACK_TITLE: Create Database
# SLACK_MESSAGE: 'Error during database creation!'
# SLACK_ICON: https://github.com/github.png?size=48
# MSG_MINIMAL: actions url
#
# on-success:
# name: Database creation succeeded
# runs-on: ubuntu-latest
# if: ${{ always() && (needs.create_database.result == 'success') }}
# needs:
# - create_database
# steps:
# - uses: actions/checkout@v4
# - name: "Send Slack message on success"
# uses: rtCamp/action-slack-notify@v2
# env:
# SLACK_COLOR: success
# SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_TEST_RESULTS }}
# SLACK_TITLE: Create Database
# SLACK_MESSAGE: 'The database has been successfully created!'
# SLACK_ICON: https://github.com/github.png?size=48
# MSG_MINIMAL: actions url
69 changes: 69 additions & 0 deletions .github/workflows/destroy-preview-env.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
name: Destroy preview environment

on:
workflow_call:
outputs:
service-url:
value: "${{ jobs.create-preview-env.outputs.service-url }}"
inputs:
env-name:
type: string
description: Environment name
required: true
env-snake-name:
type: string
description: Env name is snake case
required: true
copilot-service:
type: string
description: Copilot service name
required: true
app-name:
type: string
description: App Name (likely the GH repo)
required: true
vpc-id:
type: string
description: VPC ID for preview envs
required: true
aws-region:
type: string
default: us-east-1
required: false

jobs:
destroy-preview-env:
runs-on: ubuntu-latest
name: Destroy Preview Env
permissions:
id-token: write
contents: read
pull-requests: write
discussions: write
env:
ENV_NAME: ${{ inputs.env-name }}
ENV_NAME_SNAKE: ${{ inputs.env-snake-name }}
APP_NAME: ${{ inputs.app-name }}
VPC_ID: ${{ inputs.vpc-id }}
COPILOT_SERVICE: ${{ inputs.copilot-service }}
AWS_REGION: us-east-1
steps:
- name: configure aws credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::992382368072:role/cmiml-feature-oidc-github-role
role-session-name: gha-preview-env
aws-region: ${{ inputs.aws-region }}
- name: Install copilot
run: |
curl -Lo copilot https://github.com/aws/copilot-cli/releases/latest/download/copilot-linux && chmod +x copilot &&
sudo mv copilot /usr/local/bin/copilot && copilot -v
- uses: actions/checkout@v4
name: Checkout
- name: Delete environment
run: copilot/scripts/env-stop.sh
- name: Cleanup secrets for environment
# Each env needs a secret. This is a copilot limitation. So the baseline secret
# is copied and tagged properly for copilot to pick it up.
run: |
aws secretsmanager delete-secret --name cmiml-feature-${{ inputs.env-name }} --force-delete-without-recovery
Loading

0 comments on commit e6de398

Please sign in to comment.