Skip to content

CloudWatch & SNS Integration for Real-Time Error Alerts in Dev and Prod Environments #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 16 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
232 changes: 232 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
name: EC2 Deploy

on:
push:
branches:
- devops/a5
tags:
- deploy-dev
- deploy-prod

workflow_dispatch:
inputs:
stage:
description: "Select stage to deploy"
required: true
default: dev
type: choice
options:
- dev
- prod

env:
AWS_REGION: ap-south-1
TF_WORKING_DIR: ./terraform

jobs:
deploy:
runs-on: ubuntu-latest

steps:
# Checkout Repository
- name: Checkout repository
uses: actions/checkout@v4

# Configure AWS Credentials
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}

# Install Terraform
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3

# Determine Stage - dev/prod defaults to dev
- name: Determine Stage
id: set_stage
run: |
if [[ "${GITHUB_REF}" == "refs/tags/deploy-dev" ]]; then
echo "STAGE=dev" >> $GITHUB_ENV
elif [[ "${GITHUB_REF}" == "refs/tags/deploy-prod" ]]; then
echo "STAGE=prod" >> $GITHUB_ENV
elif [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then
echo "STAGE=${{ github.event.inputs.stage }}" >> $GITHUB_ENV
else
echo "STAGE=dev" >> $GITHUB_ENV # fallback
fi

echo "πŸ› οΈ Deployment stage: $STAGE"

# Clone private repo for prod config
- name: Clone Private Repo for Prod Config
if: env.STAGE == 'prod'
run: |
echo "πŸ”’ Cloning private repo for prod configuration..."
git clone https://${{ secrets.PRIVATE_REPO_KEY }}@${{ secrets.PRIVATE_REPO }} private-config
echo "βœ… Cloned private config repo"

# Terraform Init
- name: Terraform Init
working-directory: ${{ env.TF_WORKING_DIR }}
run: terraform init

# Terraform Apply (Full Infra)
- name: Terraform Apply
working-directory: ${{ env.TF_WORKING_DIR }}
run: |
if [ "${STAGE}" == "prod" ]; then
echo "Applying Terraform with private prod configuration..."
terraform apply -var-file=../private-config/prod_config.tfvars -auto-approve
else
echo "Applying Terraform with public dev configuration..."
terraform apply -var-file="${STAGE}_config.tfvars" -auto-approve
fi

# Get Outputs: App IP, Verifier IP, S3 Bucket
- name: Get Terraform Outputs
working-directory: ${{ env.TF_WORKING_DIR }}
run: |
INSTANCE_IP=$(terraform output -raw instance_public_ip)
S3_BUCKET=$(terraform output -raw s3_log_bucket)
echo "INSTANCE_IP=$INSTANCE_IP" >> $GITHUB_ENV
echo "S3_BUCKET=$S3_BUCKET" >> $GITHUB_ENV

echo "πŸ“¦ App IP: $INSTANCE_IP"
echo "πŸͺ£ S3 Bucket: $S3_BUCKET"

# Wait for App Initialization
- name: Wait for App Initialization
run: |
echo "⏳ Waiting 90 seconds for app EC2 to initialize..."
sleep 90

# Validate App Health
- name: Validate App Health
run: |
echo -e "\nπŸ“¦ Full Response from App:\n"
curl -s http://${{ env.INSTANCE_IP }}:80/hello || echo "❌ Failed to get response"
echo -e "\n"
echo "Checking app health at http://${{ env.INSTANCE_IP }}:80/hello"
for i in {1..10}; do
STATUS=$(curl -o /dev/null -s -w "%{http_code}" http://${{ env.INSTANCE_IP }}:80/hello)
if [[ "$STATUS" == "200" ]]; then
echo "βœ… App is healthy (HTTP 200)"
exit 0
else
echo "Attempt $i: got HTTP $STATUS"
sleep 10
fi
done
echo "❌ App failed health check"
exit 1


# Setup SSH Key for EC2 Access
- name: Setup SSH Key for EC2 Access
uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}


# Provision Verifier EC2
- name: Terraform Apply Verifier EC2
working-directory: ${{ env.TF_WORKING_DIR }}
run: |
terraform apply -var-file="${STAGE}_config.tfvars" \
-target=aws_instance.log_verifier -auto-approve

# Get Verifier IP
- name: Get Verifier IP
working-directory: ${{ env.TF_WORKING_DIR }}
run: |
VERIFIER_IP=$(terraform output -raw verifier_instance_public_ip)
echo "VERIFIER_IP=$VERIFIER_IP" >> $GITHUB_ENV
echo "πŸ”‘ Verifier IP: $VERIFIER_IP"

# Wait for Verifier EC2 Initialization
- name: Wait for Verifier EC2 Initialization
run: |
echo "⏳ Waiting 60 seconds for verifier EC2 to initialize..."
sleep 60

# SSH into Verifier EC2 and Validate Logs
- name: Validate Logs from Verifier EC2
run: |
echo "πŸ” Validating logs in S3 from verifier EC2"

for attempt in {1..5}; do
ssh -o StrictHostKeyChecking=no ubuntu@${VERIFIER_IP} "echo 'βœ… SSH to verifier successful'" && break
echo "⏳ Verifier not ready, retrying SSH (attempt $attempt)..."
sleep 15
done

for log in system/cloud-init.log app/my-app.log; do
ssh -o StrictHostKeyChecking=no ubuntu@${VERIFIER_IP} \
"if aws s3 ls s3://${S3_BUCKET}/${STAGE}/$log > /dev/null 2>&1; then
echo 'βœ… Found: $log';
else
echo '❌ Missing: $log'; exit 1;
fi"
done
echo "πŸŽ‰ All required logs are present in S3"

# Print Logs from Verifier EC2
- name: Print Logs from Verifier EC2
run: |
echo "πŸ“„ Fetching logs from /mylogs/${STAGE} on verifier EC2"

for attempt in {1..5}; do
ssh -o StrictHostKeyChecking=no ubuntu@${VERIFIER_IP} "echo 'βœ… SSH to verifier successful for log fetch'" && break
echo "⏳ Verifier not ready for log fetch, retrying SSH (attempt $attempt)..."
sleep 15
done

ssh -o StrictHostKeyChecking=no ubuntu@${VERIFIER_IP} \
"if [ -f /mylogs/${STAGE}/system/cloud-init.log ]; then
echo 'πŸ“„ ====== system/cloud-init.log ======'
cat /mylogs/${STAGE}/system/cloud-init.log | tail -n 20
else
echo '❌ system/cloud-init.log not found'
fi"

ssh -o StrictHostKeyChecking=no ubuntu@${VERIFIER_IP} \
"if [ -f /mylogs/${STAGE}/app/my-app.log ]; then
echo 'πŸ“„ ====== app/my-app.log ======'
cat /mylogs/${STAGE}/app/my-app.log | tail -n 20
else
echo '❌ app/my-app.log not found'
fi"

echo "βœ… Printed last 20 lines of logs from verifier EC2"

# Inject ERROR/EXCEPTION into App Log
- name: Inject ERROR/EXCEPTION into App Log via SSH
run: |
echo "πŸ” Injecting fake error/exception logs into /var/log/my-app.log on App EC2"
for attempt in {1..5}; do
ssh -o StrictHostKeyChecking=no ubuntu@${INSTANCE_IP} "echo 'βœ… SSH to App EC2 successful'" && break
echo "⏳ App EC2 not ready for SSH (attempt $attempt)..."
sleep 15
done

ssh -o StrictHostKeyChecking=no ubuntu@${INSTANCE_IP} <<EOF
echo "Error: Simulated failure on \$(date)" >> /var/log/my-app.log
echo "Exception: Simulated exception on \$(date)" >> /var/log/my-app.log
EOF

echo "βœ… Injected fake error/exception logs into /var/log/my-app.log"

# Destroy Infrastructure
- name: Destroy Infrastructure
if: always()
working-directory: ${{ env.TF_WORKING_DIR }}
run: |
echo "πŸ—‘οΈ Destroying infrastructure for stage: ${STAGE}"
if [ "${STAGE}" == "prod" ]; then
terraform destroy -var-file=../private-config/prod_config.tfvars -auto-approve
else
terraform destroy -var-file="${STAGE}_config.tfvars" -auto-approve
fi
Loading