diff --git a/.github/scripts/cloud-init.sh b/.github/scripts/cloud-init.sh new file mode 100755 index 00000000..4c067184 --- /dev/null +++ b/.github/scripts/cloud-init.sh @@ -0,0 +1,36 @@ +#!/bin/sh + +set -eux +trap 'poweroff' TERM EXIT INT + +Repo=$(curl http://169.254.169.254/latest/meta-data/tags/instance/Repo) +Branch=$(curl http://169.254.169.254/latest/meta-data/tags/instance/Branch) + +Local_IP=$(curl http://169.254.169.254/latest/meta-data/local-ipv4) + +# Install pkgs +apt-get update +apt-get install -y net-tools +for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt-get remove $pkg; done +install -m 0755 -d /etc/apt/keyrings +curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg +chmod a+r /etc/apt/keyrings/docker.gpg +echo \ + "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ + "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \ + tee /etc/apt/sources.list.d/docker.list > /dev/null +apt-get update +apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin +usermod -aG docker ubuntu + +su -P ubuntu -c "git clone -b $Branch --single-branch https://github.com/ntampakas/$Repo.git /home/ubuntu/$Repo" +su -P ubuntu -c "cp /home/ubuntu/$Repo/apps/api/.env.example /home/ubuntu/$Repo/apps/api/.env" +su -P ubuntu -c "sed -i 's/\(DB_TYPE=\).*/\1postgres/' /home/ubuntu/$Repo/apps/api/.env" +su -P ubuntu -c "sed -i 's/\(DB_URL=\).*/\1postgres:\/\/root:helloworld\@postgres:5432\/bandada/' /home/ubuntu/$Repo/apps/api/.env" + +su -P ubuntu -c "rm /home/ubuntu/$Repo/apps/{client,dashboard}/.env.production /home/ubuntu/$Repo/apps/{client,dashboard}/.env.staging" +su -P ubuntu -c "sed -i 's/localhost/$Local_IP/g' /home/ubuntu/$Repo/apps/{client,dashboard}/.env.local" + +su -P ubuntu -c "cd /home/ubuntu/$Repo ; docker compose up -d" + +sleep 6h diff --git a/.github/scripts/get_ip.sh b/.github/scripts/get_ip.sh new file mode 100755 index 00000000..7ca23774 --- /dev/null +++ b/.github/scripts/get_ip.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +set -eux + +TRIGGER=$1 +ACTOR=$2 +VPC="vpc-07d12b28fd72d152e" + +# Stop here in schedule +[ ! $TRIGGER = "maintenance" ] || exit 0 + +sleep 10 + +EC2_IP=$(aws ec2 describe-instances --filters "Name=instance-state-name,Values=[running]" "Name=tag:Name,Values='bandada-ephemeral-$ACTOR-*'" "Name=network-interface.vpc-id,Values=[$VPC]" --query "Reservations[*].Instances[*].[NetworkInterfaces[*].[PrivateIpAddress]]" --output text) + +echo "URL: http://$EC2_IP:3001" diff --git a/.github/scripts/run.sh b/.github/scripts/run.sh new file mode 100755 index 00000000..6e9edae0 --- /dev/null +++ b/.github/scripts/run.sh @@ -0,0 +1,47 @@ +#!/bin/sh + +set -eux + +TRIGGER=$1 +BRANCH=$2 +ACTOR=$3 +SHA=$4 +AMI="ami-04e601abe3e1a910f" +SG="sg-04d8c2eb4beca2de9" +SUBNET="subnet-066cf21c696ef55c8" +VPC="vpc-07d12b28fd72d152e" + +# Kill old instances +CURRENT_TIME_EPOCH=$(date -d `date -Is` +"%s") +EC2=$(aws ec2 describe-instances --filters "Name=instance-state-name,Values=[running]" "Name=tag:Name,Values='bandada-ephemeral-*'" "Name=network-interface.vpc-id,Values=[$VPC]" --query "Reservations[*].Instances[*].InstanceId" --output text) +for i in $EC2; do + EC2_LAUNCH_TIME=$(aws ec2 describe-instances --instance-ids $i --query 'Reservations[*].Instances[*].LaunchTime' --output text) + LAUNCH_TIME_EPOCH=$(date -d $EC2_LAUNCH_TIME +"%s") + diff=$(expr $CURRENT_TIME_EPOCH - $LAUNCH_TIME_EPOCH) + + if [ $diff -gt 21600 ]; then + aws ec2 terminate-instances --instance-ids $i + fi +done + +# Stop here in schedule +[ ! $TRIGGER = "maintenance" ] || exit 0 + +# Check if actor ec2 exists +ACTOR_EC2=$(aws ec2 describe-instances --filters "Name=instance-state-name,Values=[running]" "Name=tag:Name,Values='bandada-ephemeral-$ACTOR-*'" "Name=network-interface.vpc-id,Values=[$VPC]" --query "Reservations[*].Instances[*].InstanceId" --output text) + +[ -z $ACTOR_EC2 ] || aws ec2 terminate-instances --instance-ids $ACTOR_EC2 + +# Launch new instance +aws ec2 run-instances \ + --user-data "file://.github/scripts/cloud-init.sh" \ + --image-id $AMI \ + --count 1 \ + --instance-type t3a.large \ + --key-name bandada \ + --security-group-ids $SG \ + --subnet-id $SUBNET \ + --block-device-mappings "[{\"DeviceName\":\"/dev/sda1\",\"Ebs\":{\"VolumeSize\":32,\"DeleteOnTermination\":true}}]" \ + --instance-initiated-shutdown-behavior terminate \ + --tag-specification "ResourceType=instance,Tags=[{Key=Name,Value="bandada-ephemeral-$ACTOR-$SHA"},{Key=Repo,Value="bandada"},{Key=Branch,Value="$BRANCH"}]" \ + --metadata-options "InstanceMetadataTags=enabled" diff --git a/.github/workflows/ephemeral.yml b/.github/workflows/ephemeral.yml new file mode 100644 index 00000000..9c5c1417 --- /dev/null +++ b/.github/workflows/ephemeral.yml @@ -0,0 +1,48 @@ +name: Ephemeral +on: + schedule: + - cron: "0 */6 * * *" + workflow_dispatch: + inputs: + action: + description: "Action" + required: true + default: "spawn" + type: choice + options: + - spawn + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: false + +jobs: + deploy: + timeout-minutes: 5 + runs-on: ubuntu-latest + env: + DATA: ${{ github.event.inputs.action || 'maintenance' }} + permissions: + id-token: write + contents: read + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: arn:aws:iam::490752553772:role/bandada-ephemeral-deploy-slc + role-duration-seconds: 900 + aws-region: eu-central-1 + + - name: Launch instance + run: | + .github/scripts/run.sh ${{ env.DATA }} $GITHUB_REF_NAME $GITHUB_TRIGGERING_ACTOR $GITHUB_SHA + + - name: Instance IP + run: | + .github/scripts/get_ip.sh ${{ env.DATA }} $GITHUB_TRIGGERING_ACTOR