Skip to content

Commit

Permalink
CD & Terraform (#3)
Browse files Browse the repository at this point in the history
* cd & tf wip

* action

* more wip

* TF for new instance

* cd environment

* tf var fix

* tf logs

* tf vars

* fmt

* ssh keys

* instance size

* checks

* ssh key wip

* ssh fix

* re ssh fix

* key chown

* key string

* user-data

* fmt

* cd

* wip

* fmt

* user data order

* user data wip

* dist and TF refinements

* , fix

* tf fix

* cd check TF

* re-check

* re-check

* app service

* domain setup

* quick fix

* ip fix

* ip fix

* github token

* IPs

* IPs

* project fix for dns

* fmt

* fix

* fmt

* ips

* record domain name

* record domain name

* root dns

* ufw

* ufw non interactive

* fix

* awscli

* fmt

* path fix

* cd key

* cd key

* tf logs

* repo branch

* fix tf script

* dns record delete and tf script copy

* clone fix

* clone lines and s3

* dns order

* clone env

* wip

* fix

* dns in cd

* tf scripts copy

* /n fix

* domain values

* cd fix

* cd fix

* cd fix

* cd fix

* cd fix

* copy scripts

* copy scripts

* fix /n

* aws install

* fixes

* aws config

* aws fix

* nginx

* cleaning

* clichouse users

* fmt

* quick fix

* ch wip

* ch wip

* ch startup

* disabled certificate

* ch xml

* ts service, ch users

* users file

* npm install

* docker chqnges; entrypoint

* ch env

* fixed cd erro from find

* Terraform config OK; Still issue with DNS/Nginx (WIP with support)

* enabled certbot

* dist build and restart endpoints

* restart files

* clickhouse refinement wip

* tf wip

* init script

* fmt

* cleansed files; improved responses; added total metrics to list endpoints

* linting setup and readme

* dist update

* save tf script

* scaleway cleanup in cd

* checks

* $ fix

* fixed INSTANCE_ID

* server stop

* echo fix

* cd fix

* quotes fix

* force-shutdown

* delete

* wait

* wip

* continue-on-error: true

* tf output

* s3 logs

* aws logs

* chown logs

* /snap/bin/aws

* wait for snap

* split remote-exec

* new approval-timeout action

* repo checkout

* cleanup

* cd/tf variables cleansing

* more logs

* pre-commit

* check

* check

* lock

* test commit

* test commit

* check

* re-check

* re-check

* dist, readme, lock, pre-commit linting

* export PATH=snap/bin

---------

Co-authored-by: Pierre-Edouard Barrault <[email protected]>
  • Loading branch information
pierrz and Pierre-Edouard Barrault authored Nov 11, 2024
1 parent 5621edf commit 5a40819
Show file tree
Hide file tree
Showing 54 changed files with 6,447 additions and 2,364 deletions.
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.env
node_modules/
12 changes: 7 additions & 5 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
# Docker setup
DOCKER_SUBNET_BASE=172.30.0
DATA_DIR=/path/to/data/directory

# ClickHouse Connection
CLICKHOUSE_IP=172.30.0.101
CLICKHOUSE_PORT=9000
CLICKHOUSE_DB=my_blockchain_db
CLICKHOUSE_USER=blockchain_user
CLICKHOUSE_PASSWORD=REPLACE_WITH_SECURE_PASSWORD

# Import Settings
DATA_DIR=/path/to/data/directory
CLICKHOUSE_APP_USER=some-user
CLICKHOUSE_APP_PASSWORD=REPLACE_WITH_SECURE_PASSWORD
# used only via CD and Terraform for now
CLICKHOUSE_ADMIN_USER=some-admin
CLICKHOUSE_ADMIN_PASSWORD=REPLACE_WITH_SECURE_PASSWORD

# Optional: Avalanche RPC URL (defaults to public endpoint)
AVALANCHE_RPC_URL=https://api.avax.network/ext/bc/C/rpc
22 changes: 22 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"env": {
"browser": true,
"es2021": true,
"node": true
},
"parser": "@typescript-eslint/parser",
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"prettier" // optional: if you want to integrate with Prettier
],
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": ["@typescript-eslint"],
"rules": {
// Add any custom ESLint rules here
},
"ignorePatterns": ["node_modules"]
}
74 changes: 74 additions & 0 deletions .github/actions/approval-timeout/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
name: Approval timeout template
description: |
"This is a custom action to check whether a deployment was approved "
"and eventually cancel it if not approved before the chosen timeout deadline."
author: pierrz

inputs:
ENVIRONMENT:
required: true
TIMEOUT_MINUTES:
required: true
GITHUB_TOKEN:
required: true
GITHUB_REPO:
required: true
GITHUB_RUN_ID:
required: true

runs:
using: "composite"
steps:
- name: Run approval timeout action
shell: bash
run: |
echo "Waiting ${{ inputs.TIMEOUT_MINUTES }} minutes for approval ..."
# iterative checks every minute
for ((i=1; i<=${{ inputs.TIMEOUT_MINUTES }}; i++)); do
if [[ $i -gt 1 ]]; then
MINUTE_STRING="minutes"
else
MINUTE_STRING="minute"
fi
sleep 60
echo "Checking status after $i $MINUTE_STRING ..."
DEPLOYMENT_RESPONSE=$(curl -s \
-H "Authorization: Bearer ${{ inputs.GITHUB_TOKEN }}" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/${{ inputs.GITHUB_REPO }}/deployments?environment=${{ inputs.ENVIRONMENT }}&per_page=1")
DEPLOYMENT_ID=$(echo "$DEPLOYMENT_RESPONSE" | jq -r '.[0].id')
STATUS_RESPONSE=$(curl -s \
-H "Authorization: Bearer ${{ inputs.GITHUB_TOKEN }}" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/${{ inputs.GITHUB_REPO }}/deployments/$DEPLOYMENT_ID/statuses")
STATUS=$(echo "$STATUS_RESPONSE" | jq -r '.[0].state')
if [[ ($STATUS == "error" || "$STATUS" == "waiting") && $i -lt ${{ inputs.TIMEOUT_MINUTES }} ]]; then
echo "Approval not received yet - keep waiting for it"
else
break
fi
done
# tags: error, failure, inactive, in_progress, queued, pending, success
echo "Current deployment status is '$STATUS'"
if [[ $STATUS != "error" && "$STATUS" != "waiting" ]]; then
echo "--> Approval received"
exit 0
else
echo "--> No approval found - cancelling workflow ..."
curl -L \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${{ inputs.GITHUB_TOKEN }}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"https://api.github.com/repos/${{ inputs.GITHUB_REPO }}/actions/runs/${{ inputs.GITHUB_RUN_ID }}/cancel"
echo "Workflow cancelled"
exit 1
fi
46 changes: 46 additions & 0 deletions .github/actions/condition-check/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# TODO: improve the following logic in PRs -> after the CI workflow is successful/completed
# - get the CD workflow to trigger
# - avoid the CD workflow to get triggered from the main branch (as it is behind the current PR branch)

name: "Check Deployment Condition"
description: "Checks if deployment conditions are met"
author: pierrz

inputs:
GITHUB_TOKEN:
required: true

runs:
using: "composite"
steps:
- name: Prepare condition output
shell: bash
run: |
RESPONSE=$(curl -s \
-H "Authorization: Bearer ${{ inputs.GITHUB_TOKEN }}" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/${{ github.repository }}/deployments?environment=$ENVIRONMENT_NAME&per_page=1")
# echo "$RESPONSE"
BRANCH=$(echo "$RESPONSE" | jq -r '.[0].ref')
echo "BRANCH: $BRANCH"
if [[
"${{ github.event_name }}" == "workflow_dispatch" ||
(
"${{ github.event_name }}" == "workflow_run" &&
"${{ github.event.workflow_run.conclusion }}" == "success" &&
(
( "$BRANCH" != "main" &&
"${{ github.event.workflow_run.event }}" == "pull_request" ) ||
( "$BRANCH" == "main" &&
"${{ github.event.workflow_run.event }}" == "push" )
)
)
]]; then
echo "Conditions met!"
echo "RUN_DEPLOYMENT=true" >> $GITHUB_OUTPUT
else
echo "RUN_DEPLOYMENT=false" >> $GITHUB_OUTPUT
fi
15 changes: 15 additions & 0 deletions .github/actions/terraform/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: Terraform template
description: This is a custom action to do Terraform operations
author: pierrz

inputs:
command:
required: true

runs:
using: "composite"
steps:
- name: Run Terraform command
shell: bash
run: terraform ${{ inputs.command }}
working-directory: ./terraform
161 changes: 161 additions & 0 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# CD pipeline with timeout based cancellation logic to deploy the code on a brand new Scaleway instance

name: CD pipeline

on:
workflow_dispatch: # manual trigger
push:
branches: ["main"]
pull_request:
branches: ["main"]

jobs:

check-condition:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/[email protected]
- name: Run condition check
uses: ./.github/actions/condition-check
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

approval-timeout:
runs-on: ubuntu-latest
needs: check-condition
if: ${{ needs.check-condition.outputs.RUN_DEPLOYMENT }} == 'true'
steps:
- name: Checkout repository
uses: actions/[email protected]
- name: Run approval timeout mechanism
uses: ./.github/actions/approval-timeout
with:
ENVIRONMENT: production
TIMEOUT_MINUTES: 15
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_REPO: ${{ github.repository }}
GITHUB_RUN_ID: ${{ github.run_id }}

deployment:
runs-on: ubuntu-latest
needs: check-condition
if: ${{ needs.check-condition.outputs.RUN_DEPLOYMENT }} == 'true'
environment:
name: production
url: https://bctk-demo.fullofstack.eu

# TF_VAR_* are variables for Terraform
env:

# TF_LOG: DEBUG

# Domain
TF_VAR_bctk_domain: ${{ secrets.BCTK_DOMAIN }}

# Scaleway credentials
TF_VAR_scaleway_access_key: ${{ secrets.SCALEWAY_ACCESS_KEY }}
TF_VAR_scaleway_secret_key: ${{ secrets.SCALEWAY_SECRET_KEY }}
TF_VAR_scaleway_organization_id: ${{ secrets.SCALEWAY_ORGANIZATION_ID }}
TF_VAR_scaleway_project_id: ${{ secrets.SCALEWAY_PROJECT_ID }}
TF_VAR_scaleway_server_user: ${{ secrets.SCALEWAY_SERVER_USER }}
TF_VAR_scaleway_ssh_pub_key_name: ${{ secrets.SCALEWAY_SSH_PUB_KEY_NAME }}
TF_VAR_scaleway_ssh_private_key: ${{ secrets.SCALEWAY_SSH_PRIVATE_KEY }}
TF_VAR_scaleway_zone: ${{ secrets.SCALEWAY_ZONE }}

# Data stored in Scaleway
TF_VAR_data_bucket: ${{ secrets.DATA_BUCKET }}
TF_VAR_data_source: ${{ secrets.DATA_SOURCE }}

# Github secrets
TF_VAR_bctk_github_token: ${{ secrets.BCTK_GITHUB_TOKEN }}
TF_VAR_github_workspace: ${{ github.workspace }}
TF_VAR_github_repo_name: ${{ github.repository }}

# Clickhouse
TF_VAR_clickhouse_ip: ${{ secrets.CLICKHOUSE_IP }}
TF_VAR_clickhouse_port: ${{ secrets.CLICKHOUSE_PORT }}
TF_VAR_clickhouse_db: ${{ secrets.CLICKHOUSE_DB }}
TF_VAR_clickhouse_admin_user: ${{ secrets.CLICKHOUSE_ADMIN_USER }}
TF_VAR_clickhouse_admin_password: ${{ secrets.CLICKHOUSE_ADMIN_PASSWORD }}
TF_VAR_clickhouse_app_user: ${{ secrets.CLICKHOUSE_APP_USER }}
TF_VAR_clickhouse_app_password: ${{ secrets.CLICKHOUSE_APP_PASSWORD }}

# Typescript application
TF_VAR_avalanche_rpc_url: ${{ secrets.AVALANCHE_RPC_URL }}

steps:
- name: Set Secrets for Pull Request
if: github.event_name == 'pull_request'
run: echo "TF_VAR_github_repo_branch=${{ github.head_ref }}" >> $GITHUB_ENV

- name: Set repository branch environment variable
run: |
if [ -z "${{ env.TF_VAR_github_repo_branch }}" ]; then
echo "TF_VAR_github_repo_branch is not set"
echo "TF_VAR_github_repo_branch=${{ github.ref_name }}" >> $GITHUB_ENV
fi
echo "TF_VAR_github_repo_branch is set to: ${{ env.TF_VAR_github_repo_branch }}"
- name: Checkout repository
uses: actions/[email protected]

- name: Delete deprecated Scaleway resources (DNS records & instance)
continue-on-error: true # when there is no instance to delete
run: |
# Install Scaleway CLI
ZONE=${{ secrets.SCALEWAY_ZONE }}
REGION="${ZONE:0:-2}"
echo 'Installing Scaleway CLI ...'
curl -s https://raw.githubusercontent.com/scaleway/scaleway-cli/master/scripts/get.sh | sh
mkdir -p ~/.config/scw
tee ~/.config/scw/config.yaml << EOF
access_key: ${{ secrets.SCALEWAY_ACCESS_KEY }}
secret_key: ${{ secrets.SCALEWAY_SECRET_KEY }}
default_organization_id: ${{ secrets.SCALEWAY_ORGANIZATION_ID }}
default_project_id: ${{ secrets.SCALEWAY_PROJECT_ID }}
default_zone: ${{ secrets.SCALEWAY_ZONE }}
default_region: $REGION
api_url: https://api.scaleway.com
EOF
# Delete previous DNS records
ROOT_DOMAIN=$(echo "$(echo ${{ secrets.BCTK_DOMAIN }} | cut -d'.' -f2).$(echo ${{ secrets.BCTK_DOMAIN }} | cut -d'.' -f3)")
SUB_DOMAIN=$(echo ${{ secrets.BCTK_DOMAIN }} | cut -d'.' -f1)
echo 'Deleting previous DNS records for '$SUB_DOMAIN' in '$ROOT_DOMAIN' ...'
scw dns record delete $ROOT_DOMAIN name=$SUB_DOMAIN type=A
scw dns record delete $ROOT_DOMAIN name=$SUB_DOMAIN type=AAAA
# Delete previous instance
scw instance server list project-id=${{ secrets.SCALEWAY_PROJECT_ID }}
INSTANCE_META=$(scw instance server list project-id=${{ secrets.SCALEWAY_PROJECT_ID }})
INSTANCE_ID=$(echo "$INSTANCE_META" | awk 'NR==2 {print $1}')
INSTANCE_NAME=$(echo "$INSTANCE_META" | awk 'NR==2 {print $2}')
echo "Deleting instance '$INSTANCE_NAME' ..."
scw instance server stop "$INSTANCE_ID"
scw instance server wait "$INSTANCE_ID"
scw instance server delete "$INSTANCE_ID" with-volumes=all with-ip
- name: Set up Terraform
uses: hashicorp/[email protected]

- name: Initialize Terraform
uses: ./.github/actions/terraform
with:
command: init

- name: Terraform Format
uses: ./.github/actions/terraform
with:
command: fmt -check

- name: Terraform Plan
uses: ./.github/actions/terraform
with:
command: plan

- name: Apply Terraform configuration
uses: ./.github/actions/terraform
with:
command: apply -auto-approve
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# Node.js Tools
node_modules/

# Environment variables
# Environment variables / Configs
.env
terraform/bctk_ssl.conf

# Logs
logs/
Expand Down
3 changes: 3 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env sh

npx lint-staged
12 changes: 12 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"$schema": "https://json.schemastore.org/prettierrc.json",
"tabWidth": 2,
"useTabs": false,
"bracketSpacing": false,
"endOfLine": "auto",
"arrowParens": "always",
"trailingComma": "all",
"semi": true,
"singleQuote": true,
"printWidth": 80
}
Loading

0 comments on commit 5a40819

Please sign in to comment.