Files
thrillwiki_django_no_react/shared/scripts/unraid/deploy-thrillwiki.sh
pacnpal d504d41de2 feat: complete monorepo structure with frontend and shared resources
- 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
2025-08-23 18:40:07 -04:00

468 lines
15 KiB
Bash
Executable File

#!/bin/bash
# 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=30
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 10 seconds..."
sleep 10
attempt=$((attempt + 1))
done
log "WARNING: Network connectivity check failed after $max_attempts attempts"
return 1
}
# Function to install uv if not available
install_uv() {
log "Checking for uv installation..."
export PATH="/home/ubuntu/.cargo/bin:$PATH"
if command_exists uv; then
log "uv is already available"
return 0
fi
log "Installing uv..."
# Wait for network connectivity first
wait_for_network || {
log "Network not available, skipping uv installation"
return 1
}
# Try to install uv with multiple attempts
local max_attempts=3
local attempt=1
while [ $attempt -le $max_attempts ]; do
log "uv installation attempt $attempt/$max_attempts"
if curl -LsSf --connect-timeout 30 --retry 2 --retry-delay 5 https://astral.sh/uv/install.sh | sh; then
# Reload PATH
export PATH="/home/ubuntu/.cargo/bin:$PATH"
if command_exists uv; then
log "uv installed successfully"
return 0
else
log "uv installation completed but command not found, checking PATH..."
# Try to source the shell profile to get updated PATH
if [ -f /home/ubuntu/.bashrc ]; then
source /home/ubuntu/.bashrc 2>/dev/null || true
fi
if [ -f /home/ubuntu/.cargo/env ]; then
source /home/ubuntu/.cargo/env 2>/dev/null || true
fi
export PATH="/home/ubuntu/.cargo/bin:$PATH"
if command_exists uv; then
log "uv is now available after PATH update"
return 0
fi
fi
fi
log "uv installation attempt $attempt failed"
attempt=$((attempt + 1))
[ $attempt -le $max_attempts ] && sleep 10
done
log "Failed to install uv after $max_attempts attempts, will use pip fallback"
return 1
}
# Function to setup Python environment with fallbacks
setup_python_env() {
log "Setting up Python environment..."
# Try to install uv first if not available
install_uv
export PATH="/home/ubuntu/.cargo/bin:$PATH"
# Try uv first
if command_exists uv; then
log "Using uv for Python environment management"
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
else
log "uv not available, using pip"
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 with fallbacks
setup_database() {
log "Setting up PostgreSQL database..."
# Ensure PostgreSQL is running
if ! sudo systemctl is-active --quiet postgresql; then
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
# Create database user and database with error handling
if sudo -u postgres createuser ubuntu 2>/dev/null || sudo -u postgres psql -c "SELECT 1 FROM pg_user WHERE usename = 'ubuntu'" | grep -q 1; then
log "Database user 'ubuntu' created or already exists"
else
log "ERROR: Failed to create database user"
return 1
fi
if sudo -u postgres createdb thrillwiki_production 2>/dev/null || sudo -u postgres psql -lqt | cut -d \| -f 1 | grep -qw thrillwiki_production; then
log "Database 'thrillwiki_production' created or already exists"
else
log "ERROR: Failed to create database"
return 1
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 with fallbacks
setup_services() {
log "Setting up systemd services..."
# Check if systemd service files exist
if [ -f scripts/systemd/thrillwiki.service ]; then
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
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
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 (nginx) with fallbacks
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"
fi
else
log "nginx not installed, ThrillWiki will run on port 8000 directly"
fi
}
# Main deployment function
main() {
log "Starting ThrillWiki deployment..."
# Wait for system to be ready
log "Waiting for system to be ready..."
sleep 30
# Wait for network
wait_for_network || log "WARNING: Network check failed, continuing anyway"
# Clone repository
log "Cloning 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
# 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 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 "Deployment completed successfully!"
else
log "Deployment completed with errors (exit code: $exit_code)"
fi
exit $exit_code