mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 14:51:08 -05:00
- Add complete backend/ directory with full Django application - Add frontend/ directory with Vite + TypeScript setup ready for Next.js - Add comprehensive shared/ directory with: - Complete documentation and memory-bank archives - Media files and avatars (letters, park/ride images) - Deployment scripts and automation tools - Shared types and utilities - Add architecture/ directory with migration guides - Configure pnpm workspace for monorepo development - Update .gitignore to exclude .django_tailwind_cli/ build artifacts - Preserve all historical documentation in shared/docs/memory-bank/ - Set up proper structure for full-stack development with shared resources
452 lines
15 KiB
Bash
452 lines
15 KiB
Bash
#!/bin/bash
|
|
#
|
|
# ThrillWiki Template-Based Deployment Script
|
|
# Optimized for VMs deployed from templates that already have basic setup
|
|
#
|
|
|
|
# Function to log messages with timestamp
|
|
log() {
|
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a /home/ubuntu/thrillwiki-deploy.log
|
|
}
|
|
|
|
# Function to check if a command exists
|
|
command_exists() {
|
|
command -v "$1" >/dev/null 2>&1
|
|
}
|
|
|
|
# Function to wait for network connectivity
|
|
wait_for_network() {
|
|
log "Waiting for network connectivity..."
|
|
local max_attempts=20 # Reduced from 30 since template VMs boot faster
|
|
local attempt=1
|
|
while [ $attempt -le $max_attempts ]; do
|
|
if curl -s --connect-timeout 5 https://github.com >/dev/null 2>&1; then
|
|
log "Network connectivity confirmed"
|
|
return 0
|
|
fi
|
|
log "Network attempt $attempt/$max_attempts failed, retrying in 5 seconds..."
|
|
sleep 5 # Reduced from 10 since template VMs should have faster networking
|
|
attempt=$((attempt + 1))
|
|
done
|
|
log "WARNING: Network connectivity check failed after $max_attempts attempts"
|
|
return 1
|
|
}
|
|
|
|
# Function to update system packages (lighter since template should be recent)
|
|
update_system() {
|
|
log "Updating system packages..."
|
|
|
|
# Quick update - template should already have most packages
|
|
sudo apt update || log "WARNING: apt update failed"
|
|
|
|
# Only upgrade security packages to save time
|
|
sudo apt list --upgradable 2>/dev/null | grep -q security && {
|
|
log "Installing security updates..."
|
|
sudo apt upgrade -y --with-new-pkgs -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" || log "WARNING: Security updates failed"
|
|
} || log "No security updates needed"
|
|
}
|
|
|
|
# Function to setup Python environment with template optimizations
|
|
setup_python_env() {
|
|
log "Setting up Python environment..."
|
|
|
|
# Check if uv is already available (should be in template)
|
|
export PATH="/home/ubuntu/.cargo/bin:$PATH"
|
|
|
|
if command_exists uv; then
|
|
log "Using existing uv installation from template"
|
|
uv --version
|
|
else
|
|
log "Installing uv (not found in template)..."
|
|
if wait_for_network; then
|
|
curl -LsSf --connect-timeout 30 --retry 2 --retry-delay 5 https://astral.sh/uv/install.sh | sh
|
|
export PATH="/home/ubuntu/.cargo/bin:$PATH"
|
|
else
|
|
log "WARNING: Network not available, falling back to pip"
|
|
fi
|
|
fi
|
|
|
|
# Setup virtual environment
|
|
if command_exists uv; then
|
|
log "Creating virtual environment with uv..."
|
|
if uv venv .venv && source .venv/bin/activate; then
|
|
if uv sync; then
|
|
log "Successfully set up environment with uv"
|
|
return 0
|
|
else
|
|
log "uv sync failed, falling back to pip"
|
|
fi
|
|
else
|
|
log "uv venv failed, falling back to pip"
|
|
fi
|
|
fi
|
|
|
|
# Fallback to pip with venv
|
|
log "Setting up environment with pip and venv"
|
|
if python3 -m venv .venv && source .venv/bin/activate; then
|
|
pip install --upgrade pip || log "WARNING: Failed to upgrade pip"
|
|
|
|
# Try different dependency installation methods
|
|
if [ -f pyproject.toml ]; then
|
|
log "Installing dependencies from pyproject.toml"
|
|
if pip install -e . || pip install .; then
|
|
log "Successfully installed dependencies from pyproject.toml"
|
|
return 0
|
|
else
|
|
log "Failed to install from pyproject.toml"
|
|
fi
|
|
fi
|
|
|
|
if [ -f requirements.txt ]; then
|
|
log "Installing dependencies from requirements.txt"
|
|
if pip install -r requirements.txt; then
|
|
log "Successfully installed dependencies from requirements.txt"
|
|
return 0
|
|
else
|
|
log "Failed to install from requirements.txt"
|
|
fi
|
|
fi
|
|
|
|
# Last resort: install common Django packages
|
|
log "Installing basic Django packages as fallback"
|
|
pip install django psycopg2-binary gunicorn || log "WARNING: Failed to install basic packages"
|
|
else
|
|
log "ERROR: Failed to create virtual environment"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Function to setup database (should already exist in template)
|
|
setup_database() {
|
|
log "Setting up PostgreSQL database..."
|
|
|
|
# Check if PostgreSQL is already running (should be in template)
|
|
if sudo systemctl is-active --quiet postgresql; then
|
|
log "PostgreSQL is already running"
|
|
else
|
|
log "Starting PostgreSQL service..."
|
|
sudo systemctl start postgresql || {
|
|
log "Failed to start PostgreSQL, trying alternative methods"
|
|
sudo service postgresql start || {
|
|
log "ERROR: Could not start PostgreSQL"
|
|
return 1
|
|
}
|
|
}
|
|
fi
|
|
|
|
# Check if database and user already exist (may be in template)
|
|
if sudo -u postgres psql -lqt | cut -d \| -f 1 | grep -qw thrillwiki_production; then
|
|
log "Database 'thrillwiki_production' already exists"
|
|
else
|
|
log "Creating database 'thrillwiki_production'..."
|
|
sudo -u postgres createdb thrillwiki_production || {
|
|
log "ERROR: Failed to create database"
|
|
return 1
|
|
}
|
|
fi
|
|
|
|
# Create/update database user
|
|
if sudo -u postgres psql -c "SELECT 1 FROM pg_user WHERE usename = 'ubuntu'" | grep -q 1; then
|
|
log "Database user 'ubuntu' already exists"
|
|
else
|
|
sudo -u postgres createuser ubuntu || log "WARNING: Failed to create user (may already exist)"
|
|
fi
|
|
|
|
# Grant permissions
|
|
sudo -u postgres psql -c "ALTER USER ubuntu WITH SUPERUSER;" || {
|
|
log "WARNING: Failed to grant superuser privileges, trying alternative permissions"
|
|
sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE thrillwiki_production TO ubuntu;" || log "WARNING: Failed to grant database privileges"
|
|
}
|
|
|
|
log "Database setup completed"
|
|
}
|
|
|
|
# Function to run Django commands with fallbacks
|
|
run_django_commands() {
|
|
log "Running Django management commands..."
|
|
|
|
# Ensure we're in the virtual environment
|
|
if [ ! -d ".venv" ] || ! source .venv/bin/activate; then
|
|
log "WARNING: Virtual environment not found or failed to activate"
|
|
# Try to run without venv activation
|
|
fi
|
|
|
|
# Function to run a Django command with fallbacks
|
|
run_django_cmd() {
|
|
local cmd="$1"
|
|
local description="$2"
|
|
|
|
log "Running: $description"
|
|
|
|
# Try uv run first
|
|
if command_exists uv && uv run manage.py $cmd; then
|
|
log "Successfully ran '$cmd' with uv"
|
|
return 0
|
|
fi
|
|
|
|
# Try python in venv
|
|
if python manage.py $cmd; then
|
|
log "Successfully ran '$cmd' with python"
|
|
return 0
|
|
fi
|
|
|
|
# Try python3
|
|
if python3 manage.py $cmd; then
|
|
log "Successfully ran '$cmd' with python3"
|
|
return 0
|
|
fi
|
|
|
|
log "WARNING: Failed to run '$cmd'"
|
|
return 1
|
|
}
|
|
|
|
# Run migrations
|
|
run_django_cmd "migrate" "Database migrations" || log "WARNING: Database migration failed"
|
|
|
|
# Collect static files
|
|
run_django_cmd "collectstatic --noinput" "Static files collection" || log "WARNING: Static files collection failed"
|
|
|
|
# Build Tailwind CSS (if available)
|
|
if run_django_cmd "tailwind build" "Tailwind CSS build"; then
|
|
log "Tailwind CSS built successfully"
|
|
else
|
|
log "Tailwind CSS build not available or failed - this is optional"
|
|
fi
|
|
}
|
|
|
|
# Function to setup systemd services (may already exist in template)
|
|
setup_services() {
|
|
log "Setting up systemd services..."
|
|
|
|
# Check if systemd service files exist
|
|
if [ -f scripts/systemd/thrillwiki.service ]; then
|
|
log "Copying ThrillWiki systemd service..."
|
|
sudo cp scripts/systemd/thrillwiki.service /etc/systemd/system/ || {
|
|
log "Failed to copy thrillwiki.service, creating basic service"
|
|
create_basic_service
|
|
}
|
|
else
|
|
log "Systemd service file not found, creating basic service"
|
|
create_basic_service
|
|
fi
|
|
|
|
# Copy webhook service if available
|
|
if [ -f scripts/systemd/thrillwiki-webhook.service ]; then
|
|
sudo cp scripts/systemd/thrillwiki-webhook.service /etc/systemd/system/ || {
|
|
log "Failed to copy webhook service, skipping"
|
|
}
|
|
else
|
|
log "Webhook service file not found, skipping"
|
|
fi
|
|
|
|
# Update service files with correct paths
|
|
if [ -f /etc/systemd/system/thrillwiki.service ]; then
|
|
sudo sed -i "s|/opt/thrillwiki|/home/ubuntu/thrillwiki|g" /etc/systemd/system/thrillwiki.service
|
|
sudo sed -i "s|User=thrillwiki|User=ubuntu|g" /etc/systemd/system/thrillwiki.service
|
|
fi
|
|
|
|
if [ -f /etc/systemd/system/thrillwiki-webhook.service ]; then
|
|
sudo sed -i "s|/opt/thrillwiki|/home/ubuntu/thrillwiki|g" /etc/systemd/system/thrillwiki-webhook.service
|
|
sudo sed -i "s|User=thrillwiki|User=ubuntu|g" /etc/systemd/system/thrillwiki-webhook.service
|
|
fi
|
|
|
|
# Reload systemd and start services
|
|
sudo systemctl daemon-reload
|
|
|
|
# Enable and start main service
|
|
if sudo systemctl enable thrillwiki 2>/dev/null; then
|
|
log "ThrillWiki service enabled"
|
|
if sudo systemctl start thrillwiki; then
|
|
log "ThrillWiki service started successfully"
|
|
else
|
|
log "WARNING: Failed to start ThrillWiki service"
|
|
sudo systemctl status thrillwiki --no-pager || true
|
|
fi
|
|
else
|
|
log "WARNING: Failed to enable ThrillWiki service"
|
|
fi
|
|
|
|
# Try to start webhook service if it exists
|
|
if [ -f /etc/systemd/system/thrillwiki-webhook.service ]; then
|
|
sudo systemctl enable thrillwiki-webhook 2>/dev/null && sudo systemctl start thrillwiki-webhook || {
|
|
log "WARNING: Failed to start webhook service"
|
|
}
|
|
fi
|
|
}
|
|
|
|
# Function to create a basic systemd service if none exists
|
|
create_basic_service() {
|
|
log "Creating basic systemd service..."
|
|
|
|
sudo tee /etc/systemd/system/thrillwiki.service > /dev/null << 'SERVICE_EOF'
|
|
[Unit]
|
|
Description=ThrillWiki Django Application
|
|
After=network.target postgresql.service
|
|
Wants=postgresql.service
|
|
|
|
[Service]
|
|
Type=exec
|
|
User=ubuntu
|
|
Group=ubuntu
|
|
[AWS-SECRET-REMOVED]
|
|
[AWS-SECRET-REMOVED]/.venv/bin:/home/ubuntu/.cargo/bin:/usr/local/bin:/usr/bin:/bin
|
|
ExecStart=/home/ubuntu/thrillwiki/.venv/bin/python manage.py runserver 0.0.0.0:8000
|
|
Restart=always
|
|
RestartSec=3
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
SERVICE_EOF
|
|
|
|
log "Basic systemd service created"
|
|
}
|
|
|
|
# Function to setup web server (may already be configured in template)
|
|
setup_webserver() {
|
|
log "Setting up web server..."
|
|
|
|
# Check if nginx is installed and running
|
|
if command_exists nginx; then
|
|
if ! sudo systemctl is-active --quiet nginx; then
|
|
log "Starting nginx..."
|
|
sudo systemctl start nginx || log "WARNING: Failed to start nginx"
|
|
fi
|
|
|
|
# Create basic nginx config if none exists
|
|
if [ ! -f /etc/nginx/sites-available/thrillwiki ]; then
|
|
log "Creating nginx configuration..."
|
|
sudo tee /etc/nginx/sites-available/thrillwiki > /dev/null << 'NGINX_EOF'
|
|
server {
|
|
listen 80;
|
|
server_name _;
|
|
|
|
location /static/ {
|
|
alias /home/ubuntu/thrillwiki/staticfiles/;
|
|
}
|
|
|
|
location /media/ {
|
|
alias /home/ubuntu/thrillwiki/media/;
|
|
}
|
|
|
|
location / {
|
|
proxy_pass http://127.0.0.1:8000;
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
}
|
|
}
|
|
NGINX_EOF
|
|
|
|
# Enable the site
|
|
sudo ln -sf /etc/nginx/sites-available/thrillwiki /etc/nginx/sites-enabled/ || log "WARNING: Failed to enable nginx site"
|
|
sudo nginx -t && sudo systemctl reload nginx || log "WARNING: nginx configuration test failed"
|
|
else
|
|
log "nginx configuration already exists"
|
|
fi
|
|
else
|
|
log "nginx not installed, ThrillWiki will run on port 8000 directly"
|
|
fi
|
|
}
|
|
|
|
# Main deployment function
|
|
main() {
|
|
log "Starting ThrillWiki template-based deployment..."
|
|
|
|
# Shorter wait time since template VMs boot faster
|
|
log "Waiting for system to be ready..."
|
|
sleep 10
|
|
|
|
# Wait for network
|
|
wait_for_network || log "WARNING: Network check failed, continuing anyway"
|
|
|
|
# Clone or update repository
|
|
log "Setting up ThrillWiki repository..."
|
|
export GITHUB_TOKEN=$(cat /home/ubuntu/.github-token 2>/dev/null || echo "")
|
|
|
|
# Get the GitHub repository from environment or parameter
|
|
GITHUB_REPO="${1:-}"
|
|
if [ -z "$GITHUB_REPO" ]; then
|
|
log "ERROR: GitHub repository not specified"
|
|
return 1
|
|
fi
|
|
|
|
if [ -d "/home/ubuntu/thrillwiki" ]; then
|
|
log "ThrillWiki directory already exists, updating..."
|
|
cd /home/ubuntu/thrillwiki
|
|
git pull || log "WARNING: Failed to update repository"
|
|
else
|
|
if [ -n "$GITHUB_TOKEN" ]; then
|
|
log "Cloning with GitHub token..."
|
|
git clone https://$GITHUB_TOKEN@github.com/$GITHUB_REPO /home/ubuntu/thrillwiki || {
|
|
log "Failed to clone with token, trying without..."
|
|
git clone https://github.com/$GITHUB_REPO /home/ubuntu/thrillwiki || {
|
|
log "ERROR: Failed to clone repository"
|
|
return 1
|
|
}
|
|
}
|
|
else
|
|
log "Cloning without GitHub token..."
|
|
git clone https://github.com/$GITHUB_REPO /home/ubuntu/thrillwiki || {
|
|
log "ERROR: Failed to clone repository"
|
|
return 1
|
|
}
|
|
fi
|
|
cd /home/ubuntu/thrillwiki
|
|
fi
|
|
|
|
# Update system (lighter for template VMs)
|
|
update_system
|
|
|
|
# Setup Python environment
|
|
setup_python_env || {
|
|
log "ERROR: Failed to set up Python environment"
|
|
return 1
|
|
}
|
|
|
|
# Setup environment file
|
|
log "Setting up environment configuration..."
|
|
if [ -f ***REMOVED***.example ]; then
|
|
cp ***REMOVED***.example ***REMOVED*** || log "WARNING: Failed to copy ***REMOVED***.example"
|
|
fi
|
|
|
|
# Update ***REMOVED*** with production settings
|
|
{
|
|
echo "DEBUG=False"
|
|
echo "DATABASE_URL=postgresql://ubuntu@localhost/thrillwiki_production"
|
|
echo "ALLOWED_HOSTS=*"
|
|
echo "STATIC_[AWS-SECRET-REMOVED]"
|
|
} >> ***REMOVED***
|
|
|
|
# Setup database
|
|
setup_database || {
|
|
log "ERROR: Database setup failed"
|
|
return 1
|
|
}
|
|
|
|
# Run Django commands
|
|
run_django_commands
|
|
|
|
# Setup systemd services
|
|
setup_services
|
|
|
|
# Setup web server
|
|
setup_webserver
|
|
|
|
log "ThrillWiki template-based deployment completed!"
|
|
log "Application should be available at http://$(hostname -I | awk '{print $1}'):8000"
|
|
log "Logs are available at /home/ubuntu/thrillwiki-deploy.log"
|
|
}
|
|
|
|
# Run main function and capture any errors
|
|
main "$@" 2>&1 | tee -a /home/ubuntu/thrillwiki-deploy.log
|
|
exit_code=${PIPESTATUS[0]}
|
|
|
|
if [ $exit_code -eq 0 ]; then
|
|
log "Template-based deployment completed successfully!"
|
|
else
|
|
log "Template-based deployment completed with errors (exit code: $exit_code)"
|
|
fi
|
|
|
|
exit $exit_code
|