diff --git a/sk1/backup.sh b/sk1/backup.sh new file mode 100755 index 0000000..c3ddcd4 --- /dev/null +++ b/sk1/backup.sh @@ -0,0 +1,97 @@ +#!/bin/bash +set -euo pipefail + +# ========================================== +# LOGGER — source the shared library +# ========================================== +# shellcheck source=lib/logger.sh +source "$(dirname "$0")/lib/logger.sh" "backup" +trap 'log_error "Failure at line $LINENO. See $LOG_FILE"' ERR + +# ========================================== +# VARIABLES +# ========================================== +NAMESPACE="vigimeteo" +DB_LABEL="app=vigimeteo-db" +DB_USER_OVERRIDE="${DB_USER:-postgres}" +DB_NAME="postgres" +OUTPUT_DIR="$(dirname "$0")/sql" +TIMESTAMP="$(date +%Y%m%d_%H%M%S)" +OUTPUT_FILE="${OUTPUT_DIR}/backup_${TIMESTAMP}.sql" + +# ========================================== +log_info "========================================" +log_info " Vigimétéo – Database Backup" +log_info " Full log : $LOG_FILE" +log_info "========================================" + +# ========================================== +log_info "STEP 1 — Locate the PostgreSQL pod" +# ========================================== + +log_debug "Looking for a running pod with label '$DB_LABEL' in namespace '$NAMESPACE'..." + +POD=$(kubectl get pod \ + --namespace "$NAMESPACE" \ + --selector "$DB_LABEL" \ + --field-selector="status.phase=Running" \ + -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || true) + +if [ -z "$POD" ]; then + log_error "No running pod found with label '$DB_LABEL' in namespace '$NAMESPACE'." + log_error "Is the cluster running? kubectl get pods -n $NAMESPACE" + exit 1 +fi + +log_info "Target pod: $POD" + +# ========================================== +log_info "STEP 2 — Verify database readiness" +# ========================================== + +log_debug "Checking pg_isready on pod '$POD'..." +if ! kubectl exec --namespace "$NAMESPACE" "$POD" -- \ + pg_isready -U "$DB_USER_OVERRIDE" -d "$DB_NAME" -q; then + log_error "PostgreSQL is not ready on pod '$POD'. Aborting backup." + exit 1 +fi +log_info "PostgreSQL is ready." + +# ========================================== +log_info "STEP 3 — Run pg_dump and save to $OUTPUT_FILE" +# ========================================== + +mkdir -p "$OUTPUT_DIR" + +log_info "Dumping database '$DB_NAME' (user: $DB_USER_OVERRIDE)..." +kubectl exec --namespace "$NAMESPACE" "$POD" -- \ + pg_dump \ + --username "$DB_USER_OVERRIDE" \ + --dbname "$DB_NAME" \ + --clean \ + --if-exists \ + --no-password \ + > "$OUTPUT_FILE" + +# Verify the file was produced and is non-empty +if [ ! -s "$OUTPUT_FILE" ]; then + log_error "Backup file '$OUTPUT_FILE' is empty or was not created." + rm -f "$OUTPUT_FILE" + exit 1 +fi + +FILESIZE=$(du -sh "$OUTPUT_FILE" | cut -f1) +log_info "Backup written: $OUTPUT_FILE ($FILESIZE)" + +# ========================================== +log_info "========================================" +log_info "BACKUP COMPLETE" +log_info " File : $OUTPUT_FILE" +log_info " Size : $FILESIZE" +log_info " Log : $LOG_FILE" +log_info "" +log_info "To restore:" +log_info " bash backup.sh # create a new backup first" +log_info " kubectl exec -i -n $NAMESPACE $POD -- \\" +log_info " psql -U $DB_USER_OVERRIDE -d $DB_NAME < $OUTPUT_FILE" +log_info "========================================" \ No newline at end of file diff --git a/sk1/lib/logger.sh b/sk1/lib/logger.sh index 1774c40..e8465fd 100755 --- a/sk1/lib/logger.sh +++ b/sk1/lib/logger.sh @@ -20,24 +20,24 @@ LOG_FILE="$(dirname "$0")/logs/${_LOG_PREFIX}-$(date +%Y%m%d-%H%M%S).log" LOG_LEVEL="${LOG_LEVEL:-INFO}" _log() { - local level="$1"; shift - local message="$*" - local timestamp; timestamp="$(date '+%Y-%m-%d %H:%M:%S')" - local line="[$timestamp] [$level] $message" + local level="$1"; shift + local message="$*" + local timestamp; timestamp="$(date '+%Y-%m-%d %H:%M:%S')" + local line="[$timestamp] [$level] $message" - case "$level" in - INFO) echo -e "\033[0;32m${line}\033[0m" ;; - WARN) echo -e "\033[0;33m${line}\033[0m" ;; - ERROR) echo -e "\033[0;31m${line}\033[0m" ;; - DEBUG) - [ "$LOG_LEVEL" = "DEBUG" ] && echo -e "\033[0;36m${line}\033[0m" || return 0 - ;; - esac + case "$level" in + INFO) printf "\033[0;32m%s\033[0m\n" "$line" ;; + WARN) printf "\033[0;33m%s\033[0m\n" "$line" ;; + ERROR) printf "\033[0;31m%s\033[0m\n" "$line" ;; + DEBUG) + [ "$LOG_LEVEL" = "DEBUG" ] && printf "\033[0;36m%s\033[0m\n" "$line" || return 0 + ;; + esac - echo "$line" >> "$LOG_FILE" + printf "%s\n" "$line" >> "$LOG_FILE" } log_info() { _log INFO "$@"; } log_warn() { _log WARN "$@"; } log_error() { _log ERROR "$@"; } -log_debug() { _log DEBUG "$@"; } +log_debug() { _log DEBUG "$@"; } \ No newline at end of file