#!/bin/bash # Version: 1.0.5 # ============================================================================== # SAP HANA Backup Script # # Performs schema exports for one or more schemas and/or tenant backups for a # SAP HANA database. Designed to be executed via a cronjob. # Reads all settings from the backup.conf file in the same directory. # ============================================================================== # --- Configuration and Setup --- # Find the script's own directory to locate the config file SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd) CONFIG_FILE="${SCRIPT_DIR}/backup.conf" # Check for config file and source it if [[ -f "$CONFIG_FILE" ]]; then source "$CONFIG_FILE" else echo "❌ Error: Configuration file not found at '${CONFIG_FILE}'" exit 1 fi # Check if hdbsql executable exists if [[ ! -x "$HDBSQL_PATH" ]]; then echo "❌ Error: hdbsql not found or not executable at '${HDBSQL_PATH}'" exit 1 fi # Calculate threads to use (half of the available cores, but at least 1) TOTAL_THREADS=$(nproc --all) THREADS=$((TOTAL_THREADS / 2)) if [[ "$THREADS" -eq 0 ]]; then THREADS=1 fi # --- Functions --- # Performs a binary export of a specific schema. # Accepts the schema name as its first argument. perform_schema_export() { local schema_name="$1" if [[ -z "$schema_name" ]]; then echo " ❌ Error: No schema name provided to perform_schema_export function." return 1 fi echo "⬇️ Starting schema export for '${schema_name}'..." local timestamp timestamp=$(date +%Y%m%d_%H%M%S) local export_base_dir="${BACKUP_BASE_DIR}/schema" local export_path="${export_base_dir}/${schema_name}_${timestamp}" local query_export_path="$export_path" if [[ "$COMPRESS_SCHEMA" == "true" ]]; then export_path="${export_base_dir}/tmp/${schema_name}_${timestamp}" query_export_path="$export_path" echo " ℹ️ Compression enabled. Using temporary export path: ${export_path}" fi local archive_file="${export_base_dir}/${schema_name}_${timestamp}.tar.gz" mkdir -p "$(dirname "$export_path")" local query="EXPORT \"${schema_name}\".\"*\" AS BINARY INTO '${query_export_path}' WITH REPLACE THREADS ${THREADS};" "$HDBSQL_PATH" -U "$USER_KEY" "$query" > /dev/null 2>&1 local exit_code=$? if [[ "$exit_code" -eq 0 ]]; then echo " ✅ Successfully exported schema '${schema_name}'." if [[ "$COMPRESS_SCHEMA" == "true" ]]; then echo " 🗜️ Compressing exported files..." tar -czf "$archive_file" -C "$(dirname "$export_path")" "$(basename "$export_path")" local tar_exit_code=$? if [[ "$tar_exit_code" -eq 0 ]]; then echo " ✅ Successfully created archive '${archive_file}'." echo " 🧹 Cleaning up temporary directory..." rm -rf "$export_path" rmdir --ignore-fail-on-non-empty "$(dirname "$export_path")" echo " ✨ Cleanup complete." else echo " ❌ Error: Failed to compress '${export_path}'." fi else echo " ℹ️ Compression disabled. Raw export files are located at '${export_path}'." fi else echo " ❌ Error: Failed to export schema '${schema_name}' (hdbsql exit code: ${exit_code})." fi } # Loops through the schemas in the config file and runs an export for each. run_all_schema_exports() { if [[ -z "$SCHEMA_NAMES" ]]; then echo " ⚠️ Warning: SCHEMA_NAMES variable is not set in config. Skipping schema export." return fi echo "🔎 Found schemas to export: ${SCHEMA_NAMES}" for schema in $SCHEMA_NAMES; do perform_schema_export "$schema" echo "--------------------------------------------------" done } # REFACTORED: Generic function to back up any database (Tenant or SYSTEMDB). # Arguments: 1:Backup Name (for logging), 2:User Key, 3:Base Directory, 4:Compression Flag perform_database_backup() { local backup_name="$1" local user_key="$2" local backup_base_dir="$3" local compress_enabled="$4" echo "⬇️ Starting ${backup_name} backup..." local timestamp timestamp=$(date +%Y%m%d_%H%M%S) local backup_path_prefix local backup_target_dir if [[ "$compress_enabled" == "true" ]]; then backup_target_dir="${backup_base_dir}/tmp" backup_path_prefix="${backup_target_dir}/backup_${timestamp}" echo " ℹ️ Compression enabled. Using temporary backup path: ${backup_path_prefix}" else backup_target_dir="$backup_base_dir" backup_path_prefix="${backup_target_dir}/backup_${timestamp}" fi mkdir -p "$backup_target_dir" local query="BACKUP DATA USING FILE ('${backup_path_prefix}')" "$HDBSQL_PATH" -U "$user_key" "$query" > /dev/null 2>&1 local exit_code=$? if [[ "$exit_code" -eq 0 ]]; then echo " ✅ Successfully initiated ${backup_name} backup with prefix '${backup_path_prefix}'." if [[ "$compress_enabled" == "true" ]]; then local archive_file="${backup_base_dir}/backup_${timestamp}.tar.gz" echo " 🗜️ Compressing backup files..." tar -czf "$archive_file" -C "$backup_target_dir" . local tar_exit_code=$? if [[ "$tar_exit_code" -eq 0 ]]; then echo " ✅ Successfully created archive '${archive_file}'." echo " 🧹 Cleaning up temporary directory..." rm -rf "$backup_target_dir" echo " ✨ Cleanup complete." else echo " ❌ Error: Failed to compress backup files in '${backup_target_dir}'." fi fi else echo " ❌ Error: Failed to initiate ${backup_name} backup (hdbsql exit code: ${exit_code})." fi } # --- Main Execution --- echo "⚙️ Starting HANA backup process..." mkdir -p "$BACKUP_BASE_DIR" case "$BACKUP_TYPE" in schema) run_all_schema_exports ;; tenant) perform_database_backup "Tenant" "$USER_KEY" "${BACKUP_BASE_DIR}/tenant" "$COMPRESS_TENANT" ;; all) run_all_schema_exports perform_database_backup "Tenant" "$USER_KEY" "${BACKUP_BASE_DIR}/tenant" "$COMPRESS_TENANT" ;; *) echo " ❌ Error: Invalid BACKUP_TYPE '${BACKUP_TYPE}' in config. Use 'schema', 'tenant', or 'all'." ;; esac # NEW: Check if SYSTEMDB backup is enabled, regardless of BACKUP_TYPE (as long as it's not 'schema' only) if [[ "$BACKUP_TYPE" == "tenant" || "$BACKUP_TYPE" == "all" ]]; then if [[ "$BACKUP_SYSTEMDB" == "true" ]]; then echo "--------------------------------------------------" if [[ -z "$SYSTEMDB_USER_KEY" ]]; then echo " ❌ Error: BACKUP_SYSTEMDB is true, but SYSTEMDB_USER_KEY is not set in config." else perform_database_backup "SYSTEMDB" "$SYSTEMDB_USER_KEY" "${BACKUP_BASE_DIR}/systemdb" "$COMPRESS_TENANT" fi fi fi echo "📦 Backup process complete." echo "👋 Exiting."