mirror of
https://github.com/frappe/frappe_docker.git
synced 2026-06-17 13:55:08 +00:00
248 lines
9.7 KiB
YAML
248 lines
9.7 KiB
YAML
name: Remove Frappe Site
|
|
|
|
on:
|
|
# Manual trigger only
|
|
workflow_dispatch:
|
|
inputs:
|
|
environment:
|
|
description: 'Deployment environment'
|
|
required: true
|
|
default: 'test'
|
|
type: choice
|
|
options:
|
|
- production
|
|
- test
|
|
site_name:
|
|
description: 'Site name (e.g., academy.example.com)'
|
|
required: true
|
|
type: string
|
|
should_remove_backups:
|
|
description: 'Remove backups as well after site removal (⚠️ Backup is created by default before dropping the site. Do not use this option if you want to keep the backups)'
|
|
required: false
|
|
default: false
|
|
type: boolean
|
|
|
|
env:
|
|
HETZNER_HOST: 188.245.211.114
|
|
HETZNER_USER: ignis_academy_lms
|
|
DEPLOY_PATH: /opt/frappe-deployment
|
|
|
|
jobs:
|
|
remove-site:
|
|
runs-on: ubuntu-latest
|
|
# Use environment for secrets management
|
|
environment: ${{ github.event.inputs.environment }}
|
|
|
|
steps:
|
|
- name: Validate site name
|
|
run: |
|
|
SITE_NAME="${{ github.event.inputs.site_name }}"
|
|
|
|
# Validate site name (domain name or IP address)
|
|
# Domain name pattern
|
|
DOMAIN_PATTERN="^[a-zA-Z0-9][a-zA-Z0-9.-]*[a-zA-Z0-9]$"
|
|
# IP address pattern (simple IPv4)
|
|
IP_PATTERN="^([0-9]{1,3}\.){3}[0-9]{1,3}$"
|
|
|
|
if [[ "$SITE_NAME" =~ $IP_PATTERN ]]; then
|
|
# Validate IP address ranges (0-255 for each octet)
|
|
IFS='.' read -ra OCTETS <<< "$SITE_NAME"
|
|
for octet in "${OCTETS[@]}"; do
|
|
if [[ $octet -lt 0 || $octet -gt 255 ]]; then
|
|
echo "❌ Invalid IP address. Each octet must be between 0-255."
|
|
exit 1
|
|
fi
|
|
done
|
|
echo "✅ Valid IP address format: $SITE_NAME"
|
|
elif [[ "$SITE_NAME" =~ $DOMAIN_PATTERN ]]; then
|
|
echo "✅ Valid domain name format: $SITE_NAME"
|
|
else
|
|
echo "❌ Invalid site name format. Please use a valid domain name or IP address."
|
|
echo "Examples: academy.example.com, test-site.local, 192.168.1.100, 188.231.133.113"
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ${#SITE_NAME} -lt 3 ]]; then
|
|
echo "❌ Site name must be at least 3 characters long."
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ${#SITE_NAME} -gt 253 ]]; then
|
|
echo "❌ Site name must be less than 253 characters long."
|
|
exit 1
|
|
fi
|
|
|
|
echo "✅ Site name validation passed: $SITE_NAME"
|
|
|
|
- name: Setup SSH key
|
|
uses: webfactory/ssh-agent@v0.8.0
|
|
with:
|
|
ssh-private-key: ${{ secrets.HETZNER_SSH_KEY }}
|
|
|
|
- name: Add Hetzner server to known hosts
|
|
run: |
|
|
ssh-keyscan -H ${{ env.HETZNER_HOST }} >> ~/.ssh/known_hosts
|
|
|
|
- name: Check if deployment exists
|
|
run: |
|
|
echo "🔍 Checking if deployment exists on server..."
|
|
ssh ${{ env.HETZNER_USER }}@${{ env.HETZNER_HOST }} "
|
|
if [ ! -d ${{ env.DEPLOY_PATH }} ]; then
|
|
echo '❌ Deployment directory not found at ${{ env.DEPLOY_PATH }}'
|
|
echo 'Please run the deploy action first to set up the application.'
|
|
exit 1
|
|
fi
|
|
|
|
echo '✅ Deployment found and ready'
|
|
"
|
|
|
|
- name: Check if site exists
|
|
run: |
|
|
echo "🔍 Checking if site exists..."
|
|
SITE_EXISTS=$(ssh ${{ env.HETZNER_USER }}@${{ env.HETZNER_HOST }} "
|
|
cd ${{ env.DEPLOY_PATH }}
|
|
# Check if site directory exists in sites folder
|
|
if docker compose exec -T backend test -d '/home/frappe/frappe-bench/sites/${{ github.event.inputs.site_name }}'; then
|
|
echo 'true'
|
|
else
|
|
echo 'false'
|
|
fi
|
|
")
|
|
|
|
if [ "$SITE_EXISTS" = "false" ]; then
|
|
echo "✅ Site '${{ github.event.inputs.site_name }}' doesn't exist!"
|
|
echo "Please choose a different site name"
|
|
exit 1
|
|
fi
|
|
|
|
- name: Check services status
|
|
run: |
|
|
echo "🔍 Checking if services are running..."
|
|
ssh ${{ env.HETZNER_USER }}@${{ env.HETZNER_HOST }} "
|
|
cd ${{ env.DEPLOY_PATH }}
|
|
|
|
# Check if containers are running
|
|
if ! docker compose ps --services --filter 'status=running' | grep -q 'backend'; then
|
|
echo '❌ Backend service is not running'
|
|
echo 'Please ensure the application is deployed and running'
|
|
exit 1
|
|
fi
|
|
|
|
if ! docker compose ps --services --filter 'status=running' | grep -q 'mariadb'; then
|
|
echo '❌ MariaDB service is not running'
|
|
echo 'Please ensure the database is running'
|
|
exit 1
|
|
fi
|
|
|
|
echo '✅ Required services are running'
|
|
"
|
|
|
|
- name: Removing the site
|
|
run: |
|
|
echo "🗑️ Removing site: ${{ github.event.inputs.site_name }}"
|
|
echo "Environment: ${{ github.event.inputs.environment }}"
|
|
|
|
ssh ${{ env.HETZNER_USER }}@${{ env.HETZNER_HOST }} "
|
|
cd ${{ env.DEPLOY_PATH }}
|
|
|
|
# Load environment variables
|
|
if [ -f .env ]; then
|
|
export \$(cat .env | grep -E '^[A-Z_][A-Z0-9_]*=' | sed 's/#.*\$//' | xargs)
|
|
else
|
|
echo '❌ .env file not found. Please create it from .env.example'
|
|
exit 1
|
|
fi
|
|
|
|
# Drop the site (this will create backup files automatically)
|
|
docker compose exec -T backend bench drop-site ${{ github.event.inputs.site_name }} --db-root-password \$MARIADB_ROOT_PASSWORD --force
|
|
"
|
|
|
|
- name: Verify site removal
|
|
run: |
|
|
echo "🔍 Verifying site removal..."
|
|
ssh ${{ env.HETZNER_USER }}@${{ env.HETZNER_HOST }} "
|
|
cd ${{ env.DEPLOY_PATH }}
|
|
|
|
# Check if site was created successfully by checking if site directory exists
|
|
if docker compose exec -T backend test -d '/home/frappe/frappe-bench/sites/${{ github.event.inputs.site_name }}'; then
|
|
echo '❌ Site removal failed!'
|
|
exit 1
|
|
else
|
|
echo '✅ Site removed successfully!'
|
|
fi
|
|
"
|
|
|
|
- name: Remove backup files if needed
|
|
if: ${{ github.event.inputs.should_remove_backups == 'true' }}
|
|
run: |
|
|
echo "🗑️ Removing backup files for site: ${{ github.event.inputs.site_name }}"
|
|
echo "Environment: ${{ github.event.inputs.environment }}"
|
|
|
|
ssh ${{ env.HETZNER_USER }}@${{ env.HETZNER_HOST }} "
|
|
cd ${{ env.DEPLOY_PATH }}
|
|
|
|
docker compose exec -T backend bash -c '
|
|
cd /home/frappe/frappe-bench/archived/sites/
|
|
rm -rf \"${{ github.event.inputs.site_name }}\" \"${{ github.event.inputs.site_name }}\"[0-9]* 2>/dev/null || true
|
|
echo \"Removed: ${{ github.event.inputs.site_name }} and ${{ github.event.inputs.site_name }}[0-9]*\"
|
|
'
|
|
"
|
|
|
|
|
|
- name: Display backup information
|
|
if: ${{ github.event.inputs.should_remove_backups == 'false' }}
|
|
run: |
|
|
# Find and display the latest backup files after removal
|
|
echo ''
|
|
echo '📦 Searching for the backup created during removal...'
|
|
|
|
ssh ${{ env.HETZNER_USER }}@${{ env.HETZNER_HOST }} "
|
|
cd ${{ env.DEPLOY_PATH }}
|
|
|
|
BACKUP_INFO=\$(docker compose exec -T backend bash -c \"
|
|
# Match the site directory in archived/sites (it might have an incremented suffix)
|
|
cd /home/frappe/frappe-bench/archived/sites/ 2>/dev/null || exit 1
|
|
|
|
# Find latest directory matching site_name* (sorted by time)
|
|
LATEST_DIR=\\\$(ls -td ${{ github.event.inputs.site_name }}* 2>/dev/null | head -n 1)
|
|
|
|
if [ -n \\\"\\\$LATEST_DIR\\\" ]; then
|
|
echo \\\"ARCHIVED_DIR=\\\$LATEST_DIR\\\"
|
|
cd \\\"\\\$LATEST_DIR/private/backups\\\" 2>/dev/null || exit 1
|
|
|
|
# Get the latest timestamp (from any file)
|
|
LATEST_TIMESTAMP=\\\$(ls -t *.sql.gz 2>/dev/null | head -n 1 | cut -d'-' -f1)
|
|
|
|
if [ -n \\\"\\\$LATEST_TIMESTAMP\\\" ]; then
|
|
echo \\\"TIMESTAMP=\\\$LATEST_TIMESTAMP\\\"
|
|
ls -lh \\\${LATEST_TIMESTAMP}-* 2>/dev/null | awk '{print \\\$9, \\\$5}' || echo 'No files found'
|
|
else
|
|
echo 'No backups found'
|
|
fi
|
|
else
|
|
echo 'No archived directory found'
|
|
exit 1
|
|
fi
|
|
\")
|
|
|
|
if echo \"\$BACKUP_INFO\" | grep -q \"TIMESTAMP=\"; then
|
|
ARCHIVED_DIR=\$(echo \"\$BACKUP_INFO\" | grep -o \"ARCHIVED_DIR=[^ ]*\" | cut -d'=' -f2)
|
|
TIMESTAMP=\$(echo \"\$BACKUP_INFO\" | grep -o \"TIMESTAMP=[^ ]*\" | cut -d'=' -f2)
|
|
|
|
# Extract just the filenames (everything after TIMESTAMP= that looks like a file)
|
|
FILES=\$(echo \"\$BACKUP_INFO\" | sed 's/.*TIMESTAMP=[^ ]* //' | tr ' ' '\n' | grep \"^\$TIMESTAMP\")
|
|
|
|
echo \"\"
|
|
echo \"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\"
|
|
echo \"✅ Site removed successfully!\"
|
|
echo \"\"
|
|
echo \"📦 Backup location:\"
|
|
echo \" /home/frappe/frappe-bench/archived/sites/\$ARCHIVED_DIR/private/backups/\"
|
|
echo \"\"
|
|
echo \"📋 Backup files (timestamp: \$TIMESTAMP):\"
|
|
echo \"\$FILES\" | sed 's/^/ - /'
|
|
echo \"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\"
|
|
else
|
|
echo \"⚠️ Could not find the archived backup (but site was removed)\"
|
|
fi
|
|
"
|