Skip to content

Ephemeral Test Environment Infrastructure #15

@rdhyee

Description

@rdhyee

Goal

Quickly spin up and tear down test instances for:

  • Django upgrades (1.11 → 2.2 → 3.2 → 4.2 → 5.1)
  • Ansible playbook validation
  • Feature development with realistic data

Approach

Two complementary paths:

  1. AWS Cloud - EC2 + optional RDS clone (realistic, ephemeral, ~$0.35-0.65/day)
  2. Local Development - Docker + database dumps (free, laptop-friendly)

Existing Infrastructure (Already in Repo)

Component Status Notes
setup-test.yml ✅ Ready Playbook exists, uses regluit_prod role
group_vars/test/vars.yml ✅ Ready Configured for Let's Encrypt staging
group_vars/test/vault.yml ✅ Exists Copy of production vault
hosts [test] ⚠️ Commented Needs EC2 IP when instance created

Path A: AWS Cloud Test Environment

Step 1: Create EC2 Instance

# Set environment
export ANSIBLE_VAULT_PASSWORD_FILE=/Volumes/ryvault1/ebookfoundation/vault_pass.txt

# Create instance (Ubuntu 22.04, t3.medium)
INSTANCE_ID=$(aws ec2 run-instances \
  --image-id ami-0c7217cdde317cfec \
  --instance-type t3.medium \
  --key-name production \
  --security-group-ids sg-0a1b2c3d4e5f \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=regluit-test}]' \
  --query 'Instances[0].InstanceId' --output text)

# Wait and get IP
aws ec2 wait instance-running --instance-ids $INSTANCE_ID
PUBLIC_IP=$(aws ec2 describe-instances --instance-ids $INSTANCE_ID \
  --query 'Reservations[0].Instances[0].PublicIpAddress' --output text)
echo "Public IP: $PUBLIC_IP"

Step 2: Update Hosts File

# Edit hosts - uncomment [test] and add IP
sed -i '' "s/#regluit-test ansible_host=<PUBLIC_IP>/regluit-test ansible_host=$PUBLIC_IP/" hosts

Step 3: Run Ansible Playbook

cd /Users/raymondyee/C/src/Gluejar/regluit-provisioning
ansible-playbook -i hosts setup-test.yml -e git_branch=production

Step 4: (Optional) Clone Production RDS

For isolated database testing:

# Create snapshot
aws rds create-db-snapshot \
  --db-instance-identifier production-2024 \
  --db-snapshot-identifier regluit-test-$(date +%Y%m%d)

# Restore to smaller instance
aws rds restore-db-instance-from-db-snapshot \
  --db-instance-identifier regluit-test \
  --db-snapshot-identifier regluit-test-YYYYMMDD \
  --db-instance-class db.t3.small

# Update vault with new endpoint
ansible-vault edit group_vars/test/vault.yml
# Change: vault_mysql_db_host: "regluit-test.xxx.us-east-1.rds.amazonaws.com"

Step 5: Tear Down When Done

# Terminate EC2
aws ec2 terminate-instances --instance-ids $INSTANCE_ID

# Delete test RDS (if created)
aws rds delete-db-instance --db-instance-identifier regluit-test --skip-final-snapshot

# Re-comment hosts file
sed -i '' "s/^regluit-test ansible_host=.*/#regluit-test ansible_host=<PUBLIC_IP>/" hosts

Path B: Local Development (Laptop)

Step 1: Start Local Services (Docker)

Create docker/docker-compose.yml:

version: '3.8'
services:
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
      MYSQL_DATABASE: regluit
      MYSQL_USER: regluit
      MYSQL_PASSWORD: devpass
    ports:
      - "3306:3306"
    volumes:
      - mysql_data:/var/lib/mysql

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

volumes:
  mysql_data:
docker compose -f docker/docker-compose.yml up -d

Step 2: Dump Production Database

# Via SSH to production (uses existing dump.sh)
ssh ubuntu@unglue.it 'cd ~ && ./dump.sh'
scp ubuntu@unglue.it:~/unglue.it.sql.gz ./db_dumps/

# OR via direct SSH tunnel + mysqldump
ssh -L 3307:production-2024.cboagmr25pjs.us-east-1.rds.amazonaws.com:3306 ubuntu@unglue.it -N &
mysqldump -h 127.0.0.1 -P 3307 -u $DB_USER -p$DB_PASS unglueit \
  --single-transaction --no-tablespaces | gzip > db_dumps/unglueit.sql.gz

Step 3: Load Into Local MySQL

gunzip -c db_dumps/unglueit.sql.gz | docker exec -i regluit-mysql mysql -u root -prootpass regluit

Step 4: Run Django Locally

cd /path/to/regluit
python3 -m venv venv && source venv/bin/activate
pip install -r requirements.txt

# Create local settings (point to Docker MySQL/Redis)
export DJANGO_SETTINGS_MODULE=regluit.settings.local
python manage.py runserver

Cost Breakdown (Ephemeral Usage)

Resource Hourly 8-hour session Notes
EC2 t3.medium $0.042 $0.34 2 vCPU, 4GB
RDS t3.small (optional) $0.034 $0.27 Only if cloned
Total (EC2 only) ~$0.35/day Uses prod RDS
Total (EC2 + RDS) ~$0.65/day Isolated DB
Local Docker $0 $0 Laptop only

Files to Create

File Purpose
scripts/spin-up-test.sh Automate EC2 creation + hosts update
scripts/tear-down-test.sh Automate cleanup
scripts/dump-production-db.sh Create database dumps
docker/docker-compose.yml Local MySQL + Redis
regluit/settings/local.py Local development settings

Verification Checklist

  • SSH to test instance works
  • Ansible playbook completes without errors
  • Django manage.py check passes
  • Homepage loads (HTTP redirects to HTTPS)
  • Database queries work (manage.py dbshell)
  • Celery/Redis running (systemctl status celery)
  • Can log in with existing user credentials

Django Upgrade Testing Workflow

Once test environment is running:

ssh ubuntu@<test-ip>
cd /opt/regluit && source venv/bin/activate

# Test current state
python manage.py check --deploy
python manage.py test

# Upgrade Django incrementally
pip install Django==2.2
python manage.py check  # Fix deprecation warnings
python manage.py migrate --check

# Repeat for 3.2, 4.2, 5.1

Related Issues

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    status:needs-decisionBlocked on architectural/policy choicetype:opsInfrastructure and deployment work

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions