Skip to content

Commit

Permalink
Add initial CodeDeploy setup
Browse files Browse the repository at this point in the history
  • Loading branch information
object-Object committed Jan 2, 2024
1 parent b361512 commit 283e96e
Show file tree
Hide file tree
Showing 12 changed files with 408 additions and 1 deletion.
143 changes: 143 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
name: Build and deploy

on:
push:
branches:
- "main"
workflow_dispatch:

env:
AWS_REGION: us-east-1
STACK_NAME: prod-HexBug
S3_BUCKET: prod-objectobject-ca-codedeploy-artifacts
CDK_IAM_ROLE_ARN: arn:aws:iam::511603859520:role/prod-objectobject-ca-GitHubActionsCDKRole19D97701-sweSB0Sp33WN

jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
with:
submodules: true

- uses: actions/setup-python@v4
with:
python-version: "3.11"
cache: pip

- name: Install Python packages
run: pip install . hatch

# we use a GitHub deployment for this, so there's no artifact upload
# the build is just to see if it breaks or not
- name: Build wheel
run: hatch build --target wheel

deploy-aws-cdk:
needs: build
runs-on: ubuntu-latest
environment:
name: prod-aws-cdk
permissions:
id-token: write
contents: read
outputs:
application-name: ${{ steps.cdk-outputs.outputs.application-name }}
deployment-group-name: ${{ steps.cdk-outputs.outputs.deployment-group-name }}
iam-role-arn: ${{ steps.cdk-outputs.outputs.iam-role-arn }}
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v3
with:
node-version: 18

- uses: actions/setup-python@v4
with:
python-version: "3.11"
cache: "pip"

- uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ${{ env.AWS_REGION }}
role-to-assume: ${{ env.CDK_IAM_ROLE_ARN }}

- name: Install CDK CLI
run: npm install -g aws-cdk

- name: Install Python packages
run: pip install .[aws-cdk]

- name: Deploy CDK stack
run: cdk deploy prod --ci --require-approval never --outputs-file outputs.json

- name: Parse CDK outputs file
id: cdk-outputs
run: |
outputs_json="$(cat outputs.json | jq '.["${{ env.STACK_NAME }}"]')"
echo "application-name=$(echo "$outputs_json" | jq '.ApplicationName' --raw-output)" >> "$GITHUB_OUTPUT"
echo "deployment-group-name=$(echo "$outputs_json" | jq '.DeploymentGroupName' --raw-output)" >> "$GITHUB_OUTPUT"
echo "iam-role-arn=$(echo "$outputs_json" | jq '.GitHubActionsRoleARN' --raw-output)" >> "$GITHUB_OUTPUT"
# deploy-codedeploy:
# needs: deploy-aws-cdk
# runs-on: ubuntu-latest
# environment:
# name: prod-codedeploy
# url: ${{ steps.create-deployment.outputs.url }}
# permissions:
# id-token: write
# contents: read
# steps:
# - uses: actions/checkout@v4

# - uses: aws-actions/configure-aws-credentials@v4
# with:
# aws-region: ${{ env.AWS_REGION }}
# role-to-assume: ${{ needs.deploy-aws-cdk.outputs.iam-role-arn }}

# - name: Download build artifact
# uses: actions/download-artifact@v3
# with:
# name: build
# path: codedeploy/dist

# - name: Set environment variables
# run: |
# cat <<EOF > codedeploy/.env
# TOKEN="${{ secrets.DISCORD_TOKEN }}"
# LOG_WEBHOOK_URL="${{ secrets.LOG_WEBHOOK_URL }}"
# GITHUB_SHA=main
# GITHUB_REPOSITORY=object-Object/HexBug
# GITHUB_PAGES_URL=https://object-object.github.io/HexBug
# EOF

# - name: Upload deployment bundle to S3
# id: upload-bundle
# run: |
# S3_KEY="${{ env.STACK_NAME }}/${{ github.sha }}.zip"
# echo "s3-key=$S3_KEY" >> "$GITHUB_OUTPUT"
# aws deploy push \
# --application-name ${{ needs.deploy-aws-cdk.outputs.application-name }} \
# --s3-location s3://${{ env.S3_BUCKET }}/$S3_KEY \
# --source codedeploy

# - name: Create CodeDeploy deployment
# id: create-deployment
# run: |
# response="$(aws deploy create-deployment \
# --application-name ${{ needs.deploy-aws-cdk.outputs.application-name }} \
# --deployment-group-name ${{ needs.deploy-aws-cdk.outputs.deployment-group-name }} \
# --s3-location "bucket=${{ env.S3_BUCKET }},key=${{ steps.upload-bundle.outputs.s3-key }},bundleType=zip")"

# deployment_id="$(echo "$response" | jq '.deploymentId' --raw-output)"
# url="https://${{ env.AWS_REGION }}.console.aws.amazon.com/codesuite/codedeploy/deployments/${deployment_id}?region=${{ env.AWS_REGION }}"
# echo "Deployment URL: $url"

# echo "deployment-id=$deployment_id" >> "$GITHUB_OUTPUT"
# echo "url=$url" >> "$GITHUB_OUTPUT"

# - name: Wait for deployment to finish
# run: aws deploy wait deployment-successful --deployment-id ${{ steps.create-deployment.outputs.deployment-id }}
19 changes: 19 additions & 0 deletions codedeploy/appspec.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
version: 0.0
os: linux
files:
- source: /
destination: /var/lib/codedeploy-apps/HexBug/
file_exists_behavior: OVERWRITE
hooks:
ApplicationStop:
- location: scripts/aws/application-stop.sh
timeout: 60
AfterInstall:
- location: scripts/aws/after-install.sh
timeout: 300
ApplicationStart:
- location: scripts/aws/application-start.sh
timeout: 60
ValidateService:
- location: scripts/aws/validate-service.sh
timeout: 60
8 changes: 8 additions & 0 deletions codedeploy/pm2.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
apps: [{
name: "HexBug",
script: "./scripts/pm2/run.sh",
min_uptime: "5s",
max_restarts: 5,
}]
}
8 changes: 8 additions & 0 deletions codedeploy/scripts/aws/after-install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash
set -euo pipefail

cd /var/lib/codedeploy-apps/HexBug

python3.11 -m venv venv #--clear
source venv/bin/activate
pip install -e ".[runtime]"
11 changes: 11 additions & 0 deletions codedeploy/scripts/aws/application-start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash
set -euo pipefail

run_pm2() {
sudo su object -c "pm2 --no-color --mini-list $*"
}

cd /var/lib/codedeploy-apps/HexBug

run_pm2 start pm2.config.js
run_pm2 save
11 changes: 11 additions & 0 deletions codedeploy/scripts/aws/application-stop.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash
set -euo pipefail

run_pm2() {
sudo su object -c "pm2 --no-color --mini-list $*"
}

cd /var/lib/codedeploy-apps/HexBug

run_pm2 delete pm2.config.js || true
run_pm2 save
21 changes: 21 additions & 0 deletions codedeploy/scripts/aws/validate-service.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/bin/bash
set -euo pipefail

run_pm2() {
sudo su object -c "pm2 --no-color --mini-list $*"
}

# give it time to start up
sleep 10s

# unix timestamp in milliseconds when the process was last started
start="$(run_pm2 jlist | jq --exit-status '[.[] | if .name == "HexBug" then .pm2_env.pm_uptime else null end | values][0]')"

# current unix timestamp in milliseconds
end="$(date +%s%3N)"

elapsed="$(( (end - start) / 1000 ))"
if [[ $elapsed -lt 5 ]]; then
echo "Uptime too low (expected >=5 seconds, got $elapsed)."
exit 1
fi
5 changes: 5 additions & 0 deletions codedeploy/scripts/pm2/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash
set -euo pipefail

source venv/bin/activate
python main.py
9 changes: 8 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ dependencies = [
]

[project.optional-dependencies]
all = [
aws-cdk = [
"aws-cdk-lib==2.102.0",
"aws-cdk-github-oidc==2.4.0",
]
runtime = [
"networkx~=3.1",
"matplotlib~=3.6",
"lark~=1.1",
Expand All @@ -35,6 +39,9 @@ all = [
"semver~=3.0",
"hexnumgen @ git+https://github.com/object-Object/hexnumgen-rs.git@70d683ee9b",
]
dev = [
"HexBug[runtime,aws-cdk]"
]

[project.urls]
Source = "https://github.com/object-Object/HexBug"
Expand Down
Empty file added src/infra/__init__.py
Empty file.
64 changes: 64 additions & 0 deletions src/infra/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import logging
from typing import TypedDict

import aws_cdk as cdk

from .stack import CDKStack

logger = logging.getLogger(__name__)


class CommonKwargs(TypedDict):
oidc_owner: str
oidc_repo: str


def main():
setup_logging()

logger.info("Ready.")
app = cdk.App()

common = CommonKwargs(
oidc_owner="object-Object",
oidc_repo="HexBug",
)

CDKStack(
app,
stage="prod",
env=cdk.Environment(
account="511603859520",
region="us-east-1",
),
artifacts_bucket_name="prod-objectobject-ca-codedeploy-artifacts",
on_premise_instance_tag="prod-objectobject-ca",
oidc_environment="prod-codedeploy",
**common,
)

logger.info("Synthesizing.")
app.synth()

print()


def setup_logging(verbose: bool = False):
if verbose:
level = logging.DEBUG
fmt = "[{asctime} | {name} | {levelname}] {message}"
else:
level = logging.INFO
fmt = "[{levelname}] {message}"

logging.basicConfig(
style="{",
datefmt="%Y-%m-%d %H:%M:%S",
format=fmt,
level=level,
)
logging.getLogger(__name__).debug("Logger initialized.")


if __name__ == "__main__":
main()
Loading

0 comments on commit 283e96e

Please sign in to comment.