#!/usr/bin/env bash # Shared helpers for Kubernetes-focused cron/utility scripts. set -Eeuo pipefail if [[ -n "${COMMON_SH_LOADED:-}" ]]; then return 0 fi readonly COMMON_SH_LOADED=1 if [[ -z "${SCRIPT_NAME:-}" ]]; then _source_last_index=$(( ${#BASH_SOURCE[@]} - 1 )) SCRIPT_NAME="$(basename "${BASH_SOURCE[$_source_last_index]}")" fi LOG_LEVEL="${LOG_LEVEL:-info}" _log_level_to_int() { case "${1,,}" in debug) echo 10 ;; info) echo 20 ;; warn|warning) echo 30 ;; error) echo 40 ;; *) echo 20 ;; esac } readonly _CURRENT_LOG_LEVEL_INT="$(_log_level_to_int "$LOG_LEVEL")" _should_log() { local level="${1:-info}" local requested requested="$(_log_level_to_int "$level")" [[ "$requested" -ge "$_CURRENT_LOG_LEVEL_INT" ]] } _timestamp() { date '+%Y-%m-%d %H:%M:%S' } _log() { local level="${1:-info}" shift || true local message="${*:-}" if _should_log "$level"; then printf '%s [%s] [%s] %s\n' "$(_timestamp)" "${level^^}" "$SCRIPT_NAME" "$message" fi } log_debug() { _log "debug" "$@"; } log_info() { _log "info" "$@"; } log_warn() { _log "warn" "$@"; } log_error() { _log "error" "$@"; } die() { local message="${1:-Unspecified error}" local code="${2:-1}" log_error "$message" exit "$code" } trim() { local value="${1:-}" value="${value#"${value%%[![:space:]]*}"}" value="${value%"${value##*[![:space:]]}"}" printf '%s' "$value" } require_env() { local var_name="${1:?variable name is required}" if [[ -z "${!var_name:-}" ]]; then die "Missing required environment variable: ${var_name}" fi } require_cmd() { local cmd="${1:?command is required}" if ! command -v "$cmd" >/dev/null 2>&1; then die "Required command not found: ${cmd}" fi } retry() { local attempts="${1:?attempt count required}" local delay_seconds="${2:?delay seconds required}" shift 2 if (( attempts < 1 )); then die "retry attempts must be >= 1" fi local attempt=1 local exit_code=0 while true; do if "$@"; then return 0 fi exit_code=$? if (( attempt >= attempts )); then return "$exit_code" fi log_warn "Command failed (attempt ${attempt}/${attempts}): $*; retrying in ${delay_seconds}s" sleep "$delay_seconds" ((attempt++)) done } on_error() { local line="${1:-unknown}" local command="${2:-unknown}" log_error "Unhandled error at line ${line}: ${command}" } on_exit() { local code="${1:-0}" if [[ "$code" -eq 0 ]]; then log_info "Finished successfully" else log_error "Finished with errors (exit code ${code})" fi } setup_exit_handling() { trap 'on_error "${LINENO}" "${BASH_COMMAND:-unknown}"' ERR trap 'on_exit "$?"' EXIT }