diff --git a/CLAUDE.md b/CLAUDE.md index 06d2e9e..254ae6e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -66,9 +66,12 @@ The repository includes comprehensive migration tools: - `scripts/migrate.sh` - Main migration script that: - Backs up existing Ghost installation + - Automatically tries Ghost's database credentials first + - Only prompts for alternative credentials if needed + - Uses `--no-tablespaces` flag to avoid PROCESS privilege requirements - Converts config.json to environment variables - Preserves content and database - - Creates recovery script + - Creates recovery script with clear restoration instructions - Sets up Docker Compose environment - `scripts/config-to-env.js` - Converts Ghost JSON config to .env format diff --git a/scripts/migrate.sh b/scripts/migrate.sh index fac8cae..3cf2f84 100644 --- a/scripts/migrate.sh +++ b/scripts/migrate.sh @@ -52,10 +52,17 @@ cleanup() { if [[ $exit_code -ne 0 && -f "$RECOVERY_SCRIPT" ]]; then echo "" - echo "ERROR: Migration failed!" + echo "════════════════════════════════════════════════════════════" + echo "❌ MIGRATION FAILED!" + echo "════════════════════════════════════════════════════════════" + echo "" + echo "Don't worry - your data is safe!" + echo "" echo "To restore your original Ghost installation, run:" echo " bash $RECOVERY_SCRIPT" echo "" + echo "Need help? Check the migration logs above for error details." + echo "════════════════════════════════════════════════════════════" fi exit $exit_code @@ -66,6 +73,7 @@ trap cleanup EXIT INT TERM # Create recovery script create_recovery_script() { + local service_name="$1" cat > "$RECOVERY_SCRIPT" << EOF #!/usr/bin/env bash # Recovery script generated by Ghost migration on $(date) @@ -79,15 +87,19 @@ echo "Restoring original Ghost installation..." docker compose down 2>/dev/null || true # Re-enable and start the original Ghost service -systemctl enable "${ghost_service_name}" -systemctl start "${ghost_service_name}" - -echo "Original Ghost installation has been restored." -echo "You can check the status with: systemctl status ${ghost_service_name}" +if [[ -n "${service_name}" ]]; then + systemctl enable "${service_name}" 2>/dev/null || true + systemctl start "${service_name}" 2>/dev/null || true + echo "Original Ghost installation has been restored." + echo "You can check the status with: systemctl status ${service_name}" +else + echo "Note: Ghost service was not yet stopped, so no restoration needed." + echo "Your original installation should still be running." +fi EOF chmod +x "$RECOVERY_SCRIPT" - echo "Recovery script created at: $RECOVERY_SCRIPT" + echo "✓ Recovery script created at: $RECOVERY_SCRIPT" } # Validate MySQL connection @@ -188,6 +200,21 @@ migrate_content() { echo "✓ Content migration completed" } +# Test if we can dump database with given credentials +test_mysql_dump() { + local host=$1 + local database=$2 + local user=$3 + local password=$4 + + # Try a minimal dump to test permissions + if mysqldump --no-tablespaces --no-data -h"$host" -u"$user" -p"$password" "$database" >/dev/null 2>&1; then + return 0 + else + return 1 + fi +} + # Export and import database migrate_database() { local mysql_host @@ -197,9 +224,38 @@ migrate_database() { echo "Exporting database from $mysql_host..." - # Export database - if ! mysqldump -h"$mysql_host" -u"$mysql_user" -p"$mysql_password" "$mysql_database" > "$TEMP_SQL_FILE"; then + # Export database with proper error handling + local dump_output + local dump_status + dump_output=$(mysqldump --no-tablespaces -h"$mysql_host" -u"$mysql_user" -p"$mysql_password" "$mysql_database" 2>&1 > "$TEMP_SQL_FILE") + dump_status=$? + + # Check for errors in output (mysqldump may return 0 even with some errors) + if [[ $dump_status -ne 0 ]] || [[ "$dump_output" =~ "Error:" ]]; then + echo "" echo "ERROR: Failed to export database" + if [[ "$dump_output" =~ "PROCESS privilege" ]]; then + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "The MySQL user '$mysql_user' needs the PROCESS privilege." + echo "" + echo "To fix this, connect to MySQL as a privileged user and run:" + echo " GRANT PROCESS ON *.* TO '$mysql_user'@'%';" + echo " FLUSH PRIVILEGES;" + echo "" + echo "Or retry with a user that has sufficient privileges (e.g., root)." + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + elif [[ -n "$dump_output" ]]; then + echo "Error details: $dump_output" + fi + exit 1 + fi + + # Verify the dump file exists and has content + if [[ ! -f "$TEMP_SQL_FILE" ]] || [[ ! -s "$TEMP_SQL_FILE" ]]; then + echo "" + echo "ERROR: Database dump file is empty or missing" + echo "This might indicate insufficient disk space or permissions issues." exit 1 fi @@ -286,8 +342,12 @@ main() { # Get database configuration local mysql_host local mysql_database + local ghost_mysql_user + local ghost_mysql_password mysql_host=$(jq -r < "${current_location}/config.production.json" '.database.connection.host') mysql_database=$(jq -r < "${current_location}/config.production.json" '.database.connection.database') + ghost_mysql_user=$(jq -r < "${current_location}/config.production.json" '.database.connection.user') + ghost_mysql_password=$(jq -r < "${current_location}/config.production.json" '.database.connection.password') # Check disk space echo "" @@ -321,23 +381,52 @@ main() { echo "✓ Disk space check passed" echo "" - # Get MySQL credentials and validate - read -rp "MySQL user for database export (default: root): " mysql_user - mysql_user=${mysql_user:-root} + # Try Ghost's own credentials first + echo "Testing database export with Ghost's credentials..." + if test_mysql_dump "$mysql_host" "$mysql_database" "$ghost_mysql_user" "$ghost_mysql_password"; then + echo "✓ Ghost's credentials have sufficient privileges" + mysql_user="$ghost_mysql_user" + mysql_password="$ghost_mysql_password" + else + echo "Ghost's database user doesn't have sufficient privileges for export." + echo "Please provide credentials for a MySQL user with dump privileges." + echo "" - # Get password securely - echo -n "MySQL password for ${mysql_user}: " - read -rs mysql_password - echo "" + # Get MySQL credentials and validate + read -rp "MySQL user for database export (default: root): " mysql_user + mysql_user=${mysql_user:-root} - # Validate connection - if ! validate_mysql_connection "$mysql_host" "$mysql_database" "$mysql_user" "$mysql_password"; then - echo "Please check your MySQL credentials and try again." - exit 1 + # Get password securely + echo -n "MySQL password for ${mysql_user}: " + read -rs mysql_password + echo "" + + # Validate connection + if ! validate_mysql_connection "$mysql_host" "$mysql_database" "$mysql_user" "$mysql_password"; then + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "Could not connect to MySQL database." + echo "" + echo "Please verify:" + echo " • MySQL service is running" + echo " • Credentials are correct" + echo " • User has access from this host" + echo " • Database name is correct" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + exit 1 + fi + + # Test dump permissions + if ! test_mysql_dump "$mysql_host" "$mysql_database" "$mysql_user" "$mysql_password"; then + echo "" + echo "ERROR: The provided user doesn't have sufficient privileges for database export." + echo "Please ensure the user has the necessary privileges or try a different user." + exit 1 + fi fi - # Create recovery script - create_recovery_script + # Create recovery script (with empty service name since we haven't stopped anything yet) + create_recovery_script "" # Final confirmation before stopping Ghost echo "" @@ -365,8 +454,17 @@ main() { # Stop Ghost service echo "" echo "Stopping Ghost service..." - systemctl stop "$ghost_service_name" - systemctl disable "$ghost_service_name" + + # Update recovery script with actual service name before stopping + create_recovery_script "$ghost_service_name" + + if ! systemctl stop "$ghost_service_name"; then + echo "ERROR: Failed to stop Ghost service" + echo "Please check: systemctl status $ghost_service_name" + exit 1 + fi + + systemctl disable "$ghost_service_name" 2>/dev/null || true echo "✓ Ghost service stopped" # Migrate content