generated from ieeeuoft/hackathon-template
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from ieeeuoft/setting-up-workflow-files
Pushing new workflow + init.py file changes
- Loading branch information
Showing
9 changed files
with
397 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
name: Deploy | ||
|
||
on: | ||
push: | ||
branches: | ||
- 'develop' | ||
|
||
env: | ||
REGISTRY: ghcr.io | ||
IMAGE_NAME: ${{ github.repository }} | ||
STACK_NAME: ${{ github.repository }} | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
outputs: | ||
GITHUB_SHA_SHORT: ${{ steps.sha7.outputs.GITHUB_SHA_SHORT }} | ||
|
||
steps: | ||
- uses: actions/checkout@v2 | ||
- name: Get short SHA | ||
id: sha7 | ||
run: | | ||
GITHUB_SHA_SHORT=$(echo ${{ github.sha }} | cut -c1-7) | ||
echo "GITHUB_SHA_SHORT=${GITHUB_SHA_SHORT}" >> $GITHUB_ENV | ||
echo "::set-output name=GITHUB_SHA_SHORT::${GITHUB_SHA_SHORT}" | ||
- name: Build image | ||
run: docker compose -f deployment/docker-compose.ci.yml build | ||
- name: Docker login | ||
uses: docker/login-action@v1.10.0 | ||
with: | ||
registry: ${{ env.REGISTRY }} | ||
username: ${{ github.actor }} | ||
password: ${{ secrets.GITHUB_TOKEN }} | ||
- name: Push image | ||
run: docker compose -f deployment/docker-compose.ci.yml push | ||
|
||
deploy: | ||
runs-on: ubuntu-latest | ||
needs: [ build ] | ||
environment: | ||
name: production | ||
url: https://hackstudentlife.ca | ||
defaults: | ||
run: | ||
working-directory: deployment | ||
env: | ||
GITHUB_SHA_SHORT: ${{ needs.build.outputs.GITHUB_SHA_SHORT }} | ||
|
||
steps: | ||
- uses: actions/checkout@v3 | ||
- name: Set up Python 3.8 | ||
uses: actions/setup-python@v1 | ||
with: | ||
python-version: 3.8 | ||
- name: Install python dependencies | ||
working-directory: hackathon_site | ||
run: | | ||
python -m pip install --upgrade pip | ||
pip install -r requirements.txt | ||
- name: Use Node.js 16.x | ||
uses: actions/setup-node@v3 | ||
with: | ||
node-version: '16.x' | ||
- name: Install nodejs dependencies | ||
working-directory: hackathon_site/event | ||
run: yarn install | ||
- name: Compile scss | ||
working-directory: hackathon_site/event | ||
run: yarn scss | ||
- name: Collect static | ||
working-directory: hackathon_site | ||
env: | ||
SECRET_KEY: ${{ secrets.CI_SECRET_KEY }} | ||
run: python manage.py collectstatic | ||
- name: Build frontend | ||
working-directory: hackathon_site/dashboard/frontend | ||
run: | | ||
yarn install | ||
yarn run build | ||
- name: Set environment variables in .env | ||
run: | | ||
echo 'DEBUG=0' >> .env | ||
echo 'SECRET_KEY=${{ secrets.CI_SECRET_KEY }}' >> .env | ||
echo 'DB_NAME=${{ secrets.DB_NAME }}' >> .env | ||
echo 'DB_USER=${{ secrets.DB_USER }}' >> .env | ||
echo 'DB_PASSWORD=${{ secrets.DB_PASSWORD }}' >> .env | ||
echo 'DB_HOST=${{ secrets.DB_HOST }}' >> .env | ||
echo 'DB_PORT=${{ secrets.DB_PORT }}' >> .env | ||
echo 'EMAIL_HOST=${{ secrets.EMAIL_HOST }}' >> .env | ||
echo 'EMAIL_PORT=${{ secrets.EMAIL_PORT }}' >> .env | ||
echo 'EMAIL_HOST_USER=${{ secrets.EMAIL_HOST_USER }}' >> .env | ||
echo 'EMAIL_HOST_PASSWORD=${{ secrets.EMAIL_HOST_PASSWORD }}' >> .env | ||
echo 'EMAIL_FROM_ADDRESS=${{ secrets.EMAIL_FROM_ADDRESS }}' >> .env | ||
echo 'REDIS_URI=${{ secrets.REDIS_URI }}' >> .env | ||
echo 'RECAPTCHA_PUBLIC_KEY=${{ secrets.RECAPTCHA_PUBLIC_KEY }}' >> .env | ||
echo 'RECAPTCHA_PRIVATE_KEY=${{ secrets.RECAPTCHA_PRIVATE_KEY }}' >> .env | ||
- name: Transfer static files to the Swarm manager | ||
uses: appleboy/scp-action@v0.1.1 | ||
with: | ||
host: ${{ secrets.SWARM_MANAGER_IP }} | ||
username: ${{ secrets.SSH_USER }} | ||
key: ${{ secrets.SSH_PRIVATE_KEY }} | ||
overwrite: true | ||
# scp-action doesn't obey working-directory, runs at repo root | ||
source: "hackathon_site/static/" | ||
target: "/usr/src/${{ env.IMAGE_NAME }}" | ||
strip_components: 1 | ||
- name: Set up SSH | ||
run: | | ||
mkdir -p ~/.ssh | ||
ssh-keyscan -t ed25519 ${{ secrets.SWARM_MANAGER_IP }} >> ~/.ssh/known_hosts | ||
echo "${{ secrets.SSH_PRIVATE_KEY }}" >> ~/.ssh/id_ed25519 | ||
chmod 600 ~/.ssh/id_ed25519 | ||
- name: Transfer frontend files to server | ||
uses: appleboy/scp-action@v0.1.1 | ||
with: | ||
host: ${{ secrets.SWARM_MANAGER_IP }} | ||
username: ${{ secrets.SSH_USER }} | ||
key: ${{ secrets.SSH_PRIVATE_KEY }} | ||
overwrite: true | ||
# scp-action doesn't obey working-directory, runs at repo root | ||
source: "hackathon_site/dashboard/frontend/build/" | ||
target: "/usr/src/${{ env.IMAGE_NAME }}" | ||
strip_components: 3 | ||
- name: Bring up deployment | ||
env: | ||
DOCKER_HOST: ssh://${{ secrets.SSH_USER }}@${{ secrets.SWARM_MANAGER_IP }} | ||
run: | | ||
echo "Logging in to GitHub packages..." | ||
echo ${{ secrets.GITHUB_TOKEN }} | docker login ${{ env.REGISTRY }} -u ${{ github.actor }} --password-stdin | ||
echo "Bringing up deployment..." | ||
docker stack deploy --prune --with-registry-auth -c docker-compose.prod.yml ${{ env.STACK_NAME }} | ||
echo "Waiting for deployment..." | ||
sleep 30 | ||
chmod 777 docker-stack-wait.sh | ||
./docker-stack-wait.sh -t 600 ${{ env.STACK_NAME }} | ||
echo "Running migrations..." | ||
# TODO: It would be better to use docker-compose against the django service, | ||
# but there is currently a bug in docker-compose preventing running services | ||
# over an SSH host. | ||
IMAGE=${REGISTRY}/${IMAGE_NAME}/django:${GITHUB_SHA_SHORT} | ||
docker run --rm --env-file .env ${IMAGE} python manage.py migrate | ||
echo "Deployment complete" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
version: "3.8" | ||
|
||
services: | ||
django: | ||
build: | ||
context: .. | ||
dockerfile: ./deployment/Dockerfile | ||
image: ${REGISTRY}/${IMAGE_NAME}/django:${GITHUB_SHA_SHORT} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
version: "3.8" | ||
|
||
services: | ||
django: | ||
image: ${REGISTRY}/${IMAGE_NAME}/django:${GITHUB_SHA_SHORT} | ||
command: gunicorn hackathon_site.wsgi:application --bind 0.0.0.0:8000 --workers 5 --capture-output --access-logfile - --error-logfile - | ||
ports: | ||
- "8000:8000" | ||
env_file: .env | ||
volumes: | ||
- /var/www/${IMAGE_NAME}/media/:/var/www/media/ | ||
deploy: | ||
replicas: 1 | ||
update_config: | ||
failure_action: rollback | ||
order: start-first | ||
restart_policy: | ||
condition: on-failure | ||
networks: | ||
- aws-hacks-2024 | ||
redis: | ||
image: redis:6-alpine | ||
ports: | ||
- "6379:6379" | ||
deploy: | ||
replicas: 1 | ||
update_config: | ||
failure_action: rollback | ||
order: start-first | ||
restart_policy: | ||
condition: on-failure | ||
networks: | ||
- aws-hacks-2024 | ||
|
||
networks: | ||
aws-hacks-2024: | ||
driver: overlay |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
#!/bin/sh | ||
|
||
# By: Brandon Mitchell <public@bmitch.net> | ||
# License: MIT | ||
# Source repo: https://github.com/sudo-bmitch/docker-stack-wait | ||
|
||
set -e | ||
trap "{ exit 1; }" TERM INT | ||
opt_h=0 | ||
opt_r=0 | ||
opt_s=5 | ||
opt_t=3600 | ||
start_epoc=$(date +%s) | ||
|
||
usage() { | ||
echo "$(basename $0) [opts] stack_name" | ||
echo " -f filter: only wait for services matching filter, may be passed multiple" | ||
echo " times, see docker stack services for the filter syntax" | ||
echo " -h: this help message" | ||
echo " -n name: only wait for specific service names, overrides any filters," | ||
echo " may be passed multiple times, do not include the stack name prefix" | ||
echo " -r: treat a rollback as successful" | ||
echo " -s sec: frequency to poll service state (default $opt_s sec)" | ||
echo " -t sec: timeout to stop waiting" | ||
[ "$opt_h" = "1" ] && exit 0 || exit 1 | ||
} | ||
check_timeout() { | ||
# timeout when a timeout is defined and we will exceed the timeout after the | ||
# next sleep completes | ||
if [ "$opt_t" -gt 0 ]; then | ||
cur_epoc=$(date +%s) | ||
cutoff_epoc=$(expr ${start_epoc} + $opt_t - $opt_s) | ||
if [ "$cur_epoc" -gt "$cutoff_epoc" ]; then | ||
echo "Error: Timeout exceeded" | ||
exit 1 | ||
fi | ||
fi | ||
} | ||
get_service_ids() { | ||
if [ -n "$opt_n" ]; then | ||
service_list="" | ||
for name in $opt_n; do | ||
service_list="${service_list:+${service_list} }${stack_name}_${name}" | ||
done | ||
docker service inspect --format '{{.ID}}' ${service_list} | ||
else | ||
docker stack services ${opt_f} -q "${stack_name}" | ||
fi | ||
} | ||
service_state() { | ||
# output the state when it changes from the last state for the service | ||
service=$1 | ||
# strip any invalid chars from service name for caching state | ||
service_safe=$(echo "$service" | sed 's/[^A-Za-z0-9_]/_/g') | ||
state=$2 | ||
if eval [ \"\$cache_${service_safe}\" != \"\$state\" ]; then | ||
echo "Service $service state: $state" | ||
eval cache_${service_safe}=\"\$state\" | ||
fi | ||
} | ||
|
||
while getopts 'f:hn:rs:t:' opt; do | ||
case $opt in | ||
f) opt_f="${opt_f:+${opt_f} }-f $OPTARG";; | ||
h) opt_h=1;; | ||
n) opt_n="${opt_n:+${opt_n} } $OPTARG";; | ||
r) opt_r=1;; | ||
s) opt_s="$OPTARG";; | ||
t) opt_t="$OPTARG";; | ||
esac | ||
done | ||
shift $(expr $OPTIND - 1) | ||
|
||
if [ $# -ne 1 -o "$opt_h" = "1" -o "$opt_s" -le "0" ]; then | ||
usage | ||
fi | ||
|
||
stack_name=$1 | ||
|
||
# 0 = running, 1 = success, 2 = error | ||
stack_done=0 | ||
while [ "$stack_done" != "1" ]; do | ||
stack_done=1 | ||
# run get_service_ids outside of the for loop to catch errors | ||
service_ids=$(get_service_ids) | ||
for service_id in ${service_ids}; do | ||
service_done=1 | ||
service=$(docker service inspect --format '{{.Spec.Name}}' "$service_id") | ||
|
||
# hardcode a "new" state when UpdateStatus is not defined | ||
state=$(docker service inspect -f '{{if .UpdateStatus}}{{.UpdateStatus.State}}{{else}}new{{end}}' "$service_id") | ||
|
||
# check for failed update states | ||
case "$state" in | ||
paused|rollback_paused) | ||
service_done=2 | ||
;; | ||
rollback_*) | ||
if [ "$opt_r" = "0" ]; then | ||
service_done=2 | ||
fi | ||
;; | ||
esac | ||
|
||
# identify/report current state | ||
if [ "$service_done" != "2" ]; then | ||
replicas=$(docker service ls --format '{{.Replicas}}' --filter "id=$service_id" | cut -d' ' -f1) | ||
current=$(echo "$replicas" | cut -d/ -f1) | ||
target=$(echo "$replicas" | cut -d/ -f2) | ||
if [ "$current" != "$target" ]; then | ||
# actively replicating service | ||
service_done=0 | ||
state="replicating $replicas" | ||
fi | ||
fi | ||
service_state "$service" "$state" | ||
|
||
# check for states that indicate an update is done | ||
if [ "$service_done" = "1" ]; then | ||
case "$state" in | ||
new|completed|rollback_completed) | ||
service_done=1 | ||
;; | ||
*) | ||
# any other state is unknown, not necessarily finished | ||
service_done=0 | ||
;; | ||
esac | ||
fi | ||
|
||
# update stack done state | ||
if [ "$service_done" = "2" ]; then | ||
# error condition | ||
stack_done=2 | ||
elif [ "$service_done" = "0" -a "$stack_done" = "1" ]; then | ||
# only go to an updating state if not in an error state | ||
stack_done=0 | ||
fi | ||
done | ||
if [ "$stack_done" = "2" ]; then | ||
echo "Error: This deployment will not complete" | ||
exit 1 | ||
fi | ||
if [ "$stack_done" != "1" ]; then | ||
check_timeout | ||
sleep "${opt_s}" | ||
fi | ||
done |
Oops, something went wrong.