Friday, November 14, 2025

#!/bin/bash ################################################################################ # Oracle 19c RAC Database Administration - Data Guard Switchover Functions # Description: Data Guard switchover with automatic rollback capability # Created: 2025-11-02 # Updated: 2025-11-14 - Integrated with database loading fix and wrapper functions ################################################################################ ################################################################################ # Function: perform_dg_switchover # Description: Main wrapper function for Data Guard switchover # Parameters: $1 - Primary database name # $2 - Primary SCAN address # $3 - Primary service name # $4 - Standby database name # $5 - Standby SCAN address # $6 - Standby service name # Returns: 0 on success, 1 on failure ################################################################################ perform_dg_switchover() { local primary_db=$1 local primary_scan=$2 local primary_service=$3 local standby_db=$4 local standby_scan=$5 local standby_service=$6 log_message "INFO" "Starting Data Guard switchover process" log_message "INFO" "Primary: ${primary_db} @ ${primary_scan}/${primary_service}" log_message "INFO" "Standby: ${standby_db} @ ${standby_scan}/${standby_service}" # Validate connections to both databases echo "" echo "Validating database connections..." if ! test_db_connection "${primary_scan}" "${primary_service}"; then log_message "ERROR" "Cannot connect to primary database ${primary_db}" echo "ERROR: Cannot connect to primary database ${primary_db}" return 1 fi echo "✓ Primary database connection OK" if ! test_db_connection "${standby_scan}" "${standby_service}"; then log_message "ERROR" "Cannot connect to standby database ${standby_db}" echo "ERROR: Cannot connect to standby database ${standby_db}" return 1 fi echo "✓ Standby database connection OK" # Call the actual switchover function perform_switchover "$primary_db" "$standby_db" return $? } ################################################################################ # Function: perform_switchover # Description: Perform Data Guard switchover with validation and rollback # Parameters: $1 - Current primary database name # $2 - Target standby database name (new primary) # Returns: 0 on success, 1 on failure ################################################################################ perform_switchover() { local current_primary=$1 local target_standby=$2 log_message "INFO" "==========================================" log_message "INFO" "Starting Data Guard Switchover" log_message "INFO" "Current Primary: $current_primary" log_message "INFO" "Target Primary: $target_standby" log_message "INFO" "==========================================" # Generate switchover report file local timestamp=$(date '+%Y%m%d_%H%M%S') local report_file="${REPORT_BASE_DIR}/switchover_${current_primary}_${timestamp}.log" # Create restore point for rollback local restore_point="SWITCHOVER_${timestamp}" echo "" echo "==========================================" echo "Data Guard Switchover Process" echo "==========================================" echo "" echo "Phase 1: Pre-Switchover Validation" echo "-----------------------------------" # Pre-switchover validation if ! validate_switchover_prerequisites "$current_primary" "$target_standby"; then log_message "ERROR" "Pre-switchover validation failed" echo "✗ Pre-switchover validation FAILED" echo " Switchover cannot proceed safely" return 1 fi echo "✓ Pre-switchover validation PASSED" log_message "INFO" "Pre-switchover validation passed" # Create restore points for rollback echo "" echo "Phase 2: Creating Restore Points" echo "---------------------------------" if ! create_switchover_restore_points "$current_primary" "$restore_point"; then log_message "ERROR" "Failed to create restore points" echo "✗ Failed to create restore points" echo " Switchover aborted for safety" return 1 fi echo "✓ Restore points created successfully" log_message "INFO" "Restore points created: $restore_point" # Perform the switchover echo "" echo "Phase 3: Executing Switchover" echo "------------------------------" if ! execute_switchover "$current_primary" "$target_standby"; then log_message "ERROR" "Switchover execution failed" echo "✗ Switchover FAILED" echo "" echo "Attempting automatic rollback..." if perform_switchover_rollback "$current_primary" "$target_standby" "$restore_point"; then echo "✓ Rollback successful - databases restored to original state" log_message "INFO" "Switchover rolled back successfully" else echo "✗ Rollback FAILED - manual intervention required" log_message "ERROR" "Switchover rollback failed - manual intervention needed" fi return 1 fi echo "✓ Switchover executed successfully" log_message "INFO" "Switchover execution completed" # Post-switchover validation echo "" echo "Phase 4: Post-Switchover Validation" echo "------------------------------------" if ! validate_post_switchover "$target_standby" "$current_primary"; then log_message "ERROR" "Post-switchover validation failed" echo "✗ Post-switchover validation FAILED" echo " WARNING: Databases may not be in sync" echo "" echo "Attempting automatic rollback..." if perform_switchover_rollback "$target_standby" "$current_primary" "$restore_point"; then echo "✓ Rollback successful - databases restored" log_message "INFO" "Post-validation failure - rolled back successfully" else echo "✗ Rollback FAILED - manual intervention required" log_message "ERROR" "Post-validation rollback failed" fi return 1 fi echo "✓ Post-switchover validation PASSED" log_message "INFO" "Post-switchover validation successful" # Generate switchover report generate_switchover_report "$current_primary" "$target_standby" "$timestamp" "SUCCESS" echo "" echo "==========================================" echo "Switchover Completed Successfully" echo "==========================================" echo "" echo "New Configuration:" echo " Primary: $target_standby" echo " Standby: $current_primary" echo "" echo "Report: $report_file" echo "" log_message "INFO" "==========================================" log_message "INFO" "Switchover completed successfully" log_message "INFO" "New Primary: $target_standby" log_message "INFO" "==========================================" return 0 } ################################################################################ # Function: validate_switchover_prerequisites # Description: Validate that switchover can be performed safely ################################################################################ validate_switchover_prerequisites() { local current_primary=$1 local target_standby=$2 log_message "INFO" "Validating switchover prerequisites" echo " Checking primary database status..." # Check primary database role local primary_role=$(sqlplus -s / as sysdba << EOF SET HEADING OFF SET FEEDBACK OFF SET PAGESIZE 0 SELECT database_role FROM v\$database; EXIT; EOF ) primary_role=$(echo "$primary_role" | xargs) if [[ "$primary_role" != "PRIMARY" ]]; then echo " ✗ Database is not in PRIMARY role (current: $primary_role)" log_message "ERROR" "Database not in PRIMARY role: $primary_role" return 1 fi echo " ✓ Database is in PRIMARY role" # Check switchover status local switchover_status=$(sqlplus -s / as sysdba << EOF SET HEADING OFF SET FEEDBACK OFF SET PAGESIZE 0 SELECT switchover_status FROM v\$database; EXIT; EOF ) switchover_status=$(echo "$switchover_status" | xargs) if [[ "$switchover_status" != "TO STANDBY" && "$switchover_status" != "SESSIONS ACTIVE" ]]; then echo " ✗ Switchover not allowed (status: $switchover_status)" log_message "ERROR" "Invalid switchover status: $switchover_status" return 1 fi echo " ✓ Switchover status is valid: $switchover_status" # Check for active sessions if needed if [[ "$switchover_status" == "SESSIONS ACTIVE" ]]; then echo " ⚠ Warning: Active sessions present - will be terminated during switchover" log_message "WARN" "Active sessions present during switchover" fi # Check Data Guard configuration echo " Checking Data Guard configuration..." local dg_status=$(dgmgrl / << EOF SHOW CONFIGURATION; EXIT; EOF ) if echo "$dg_status" | grep -q "SUCCESS"; then echo " ✓ Data Guard configuration is valid" else echo " ✗ Data Guard configuration has issues" log_message "ERROR" "Data Guard configuration validation failed" return 1 fi # Check standby database status via DGMGRL echo " Checking standby database status..." local standby_status=$(dgmgrl / << EOF SHOW DATABASE $target_standby; EXIT; EOF ) if echo "$standby_status" | grep -q "SUCCESS"; then echo " ✓ Standby database is ready" else echo " ✗ Standby database has issues" echo "$standby_status" log_message "ERROR" "Standby database validation failed" return 1 fi # Check apply lag echo " Checking apply lag..." local apply_lag=$(sqlplus -s / as sysdba << EOF SET HEADING OFF SET FEEDBACK OFF SET PAGESIZE 0 SELECT value FROM v\$dataguard_stats WHERE name = 'apply lag'; EXIT; EOF ) apply_lag=$(echo "$apply_lag" | xargs) if [[ -n "$apply_lag" ]]; then echo " Apply lag: $apply_lag" log_message "INFO" "Current apply lag: $apply_lag" else echo " ✓ No significant apply lag" fi # Check for archive gaps echo " Checking for archive log gaps..." local gap_count=$(sqlplus -s / as sysdba << EOF SET HEADING OFF SET FEEDBACK OFF SET PAGESIZE 0 SELECT COUNT(*) FROM v\$archive_gap; EXIT; EOF ) gap_count=$(echo "$gap_count" | xargs) if [[ $gap_count -gt 0 ]]; then echo " ✗ Archive log gaps detected: $gap_count" log_message "ERROR" "Archive log gaps present: $gap_count" return 1 fi echo " ✓ No archive log gaps" log_message "INFO" "All prerequisite checks passed" return 0 } ################################################################################ # Function: create_switchover_restore_points # Description: Create restore points for rollback capability ################################################################################ create_switchover_restore_points() { local current_primary=$1 local restore_point=$2 log_message "INFO" "Creating restore points for rollback" echo " Creating restore point on primary: $restore_point" # Create guaranteed restore point on primary sqlplus -s / as sysdba << EOF WHENEVER SQLERROR EXIT 1 CREATE RESTORE POINT ${restore_point} GUARANTEE FLASHBACK DATABASE; EXIT; EOF if [[ $? -eq 0 ]]; then echo " ✓ Restore point created on primary" log_message "INFO" "Restore point created on primary: $restore_point" else echo " ✗ Failed to create restore point on primary" log_message "ERROR" "Failed to create restore point on primary" return 1 fi # Note: Restore point will be automatically created on standby via redo apply echo " Restore point will replicate to standby via redo apply" return 0 } ################################################################################ # Function: execute_switchover # Description: Execute the actual switchover operation ################################################################################ execute_switchover() { local current_primary=$1 local target_standby=$2 log_message "INFO" "Executing switchover from $current_primary to $target_standby" echo " Step 1: Switching $current_primary to standby role..." # Switchover current primary to standby local switch_result=$(dgmgrl / << EOF SWITCHOVER TO $target_standby; EXIT; EOF ) echo "$switch_result" if echo "$switch_result" | grep -q "SUCCESS"; then echo " ✓ Switchover command executed successfully" log_message "INFO" "Switchover command successful" else echo " ✗ Switchover command failed" log_message "ERROR" "Switchover command failed" return 1 fi # Wait for switchover to complete echo " Step 2: Waiting for switchover to complete..." sleep 10 # Verify new primary is open echo " Step 3: Verifying new primary database..." local retries=0 local max_retries=30 while [[ $retries -lt $max_retries ]]; do local db_status=$(dgmgrl / << EOF SHOW DATABASE $target_standby; EXIT; EOF ) if echo "$db_status" | grep -q "PRIMARY" && echo "$db_status" | grep -q "SUCCESS"; then echo " ✓ New primary database is open and ready" log_message "INFO" "New primary database confirmed: $target_standby" return 0 fi ((retries++)) echo " Waiting for database to transition... (attempt $retries/$max_retries)" sleep 5 done echo " ✗ Timeout waiting for database transition" log_message "ERROR" "Timeout waiting for new primary to be ready" return 1 } ################################################################################ # Function: validate_post_switchover # Description: Validate switchover completed successfully ################################################################################ validate_post_switchover() { local new_primary=$1 local new_standby=$2 log_message "INFO" "Validating post-switchover state" echo " Checking new configuration..." # Show configuration local config=$(dgmgrl / << EOF SHOW CONFIGURATION; EXIT; EOF ) echo "$config" if echo "$config" | grep -q "$new_primary" | grep -q "PRIMARY"; then echo " ✓ New primary confirmed: $new_primary" else echo " ✗ New primary validation failed" log_message "ERROR" "New primary validation failed" return 1 fi if echo "$config" | grep -q "$new_standby" | grep -q "STANDBY"; then echo " ✓ New standby confirmed: $new_standby" else echo " ✗ New standby validation failed" log_message "ERROR" "New standby validation failed" return 1 fi # Check for errors if echo "$config" | grep -qi "error\|warning"; then echo " ⚠ Configuration warnings/errors detected" log_message "WARN" "Post-switchover configuration has warnings" else echo " ✓ No configuration errors detected" fi # Verify redo transport is working echo " Checking redo transport..." sleep 5 local transport_check=$(dgmgrl / << EOF SHOW DATABASE $new_standby; EXIT; EOF ) if echo "$transport_check" | grep -q "SUCCESS"; then echo " ✓ Redo transport is active" else echo " ⚠ Redo transport may have issues" log_message "WARN" "Redo transport validation inconclusive" fi log_message "INFO" "Post-switchover validation completed" return 0 } ################################################################################ # Function: perform_switchover_rollback # Description: Rollback switchover using restore points ################################################################################ perform_switchover_rollback() { local current_primary=$1 local current_standby=$2 local restore_point=$3 log_message "INFO" "==========================================" log_message "INFO" "Starting Switchover Rollback" log_message "INFO" "==========================================" echo "" echo "Rollback Process:" echo "=================" # Attempt to switchover back echo " Attempting to switch back to original configuration..." local rollback_result=$(dgmgrl / << EOF SWITCHOVER TO $current_standby; EXIT; EOF ) if echo "$rollback_result" | grep -q "SUCCESS"; then echo " ✓ Switchover rollback successful" log_message "INFO" "Switchover rolled back successfully" # Wait for completion sleep 10 # Verify original configuration echo " Verifying original configuration restored..." local verify=$(dgmgrl / << EOF SHOW CONFIGURATION; EXIT; EOF ) if echo "$verify" | grep -q "$current_standby" | grep -q "PRIMARY"; then echo " ✓ Original configuration confirmed" log_message "INFO" "Original configuration restored" return 0 else echo " ⚠ Configuration verification inconclusive" log_message "WARN" "Rollback verification inconclusive" return 1 fi else echo " ✗ Automatic rollback failed" log_message "ERROR" "Automatic switchover rollback failed" echo "" echo "Manual Rollback Required:" echo "========================" echo "1. Connect to $current_primary" echo "2. Execute: FLASHBACK DATABASE TO RESTORE POINT $restore_point;" echo "3. Execute: ALTER DATABASE OPEN RESETLOGS;" echo "4. Reconfigure Data Guard" echo "" return 1 fi } ################################################################################ # Function: generate_switchover_report # Description: Generate detailed switchover report ################################################################################ generate_switchover_report() { local old_primary=$1 local new_primary=$2 local timestamp=$3 local status=$4 local report_file="${REPORT_BASE_DIR}/switchover_${old_primary}_${timestamp}.html" { cat << EOF Data Guard Switchover Report

Data Guard Switchover Report

Generated: $(date '+%Y-%m-%d %H:%M:%S')

Status: $status

Switchover Summary

ItemValue
Original Primary$old_primary
New Primary$new_primary
Switchover Time$(date '+%Y-%m-%d %H:%M:%S')
Status$status

Current Configuration

EOF
        dgmgrl / << DGEOF
SHOW CONFIGURATION;
EXIT;
DGEOF
        
        echo "
" echo "
" generate_html_footer } > "$report_file" log_message "INFO" "Switchover report generated: $report_file" } ################################################################################ # Export functions ################################################################################ export -f perform_switchover export -f validate_switchover_prerequisites export -f execute_switchover export -f perform_switchover_rollback log_message "INFO" "Data Guard switchover functions loaded"