From 87964171ad48fcdf1782bc8266e3c91197937566 Mon Sep 17 00:00:00 2001 From: FailedProxy Date: Fri, 27 Mar 2026 22:16:07 +0000 Subject: [PATCH] revert back to last stable --- common.sh | 211 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 122 insertions(+), 89 deletions(-) diff --git a/common.sh b/common.sh index 8bc7734..144124a 100644 --- a/common.sh +++ b/common.sh @@ -1,171 +1,204 @@ #!/bin/bash # ----------------------------------------------------------------------------------------------- -# ----------------- UNRAID OPS COMMON LIBRARY (FINAL STABLE FRAMEWORK v2) ----------------------- +# ----------------- UNRAID OPS COMMON LIBRARY (STABLE FRAMEWORK v1) ----------------------- # ----------------------------------------------------------------------------------------------- -# ----------------------------- ICONS ----------------------------- +# ICONS Profiles ICON_INFO="ℹ️" ICON_WARN="⚠️" ICON_ERROR="❌" ICON_SUCCESS="✅" ICON_RUN="🚀" ICON_STOP="🛑" -ICON_STOPPED="🟢" +ICON_RETRY="🔁" ICON_SYNC="🔄" +ICON_GEAR="⚙️" -# ----------------------------- LOGGING ----------------------------- +# OUTPUT info() { echo "$ICON_INFO [INFO] $*"; } warn() { echo "$ICON_WARN [WARN] $*"; } error() { echo "$ICON_ERROR [ERROR] $*"; } success() { echo "$ICON_SUCCESS [OK] $*"; } -log() { [[ "${ENABLE_LOGGING:-false}" == true ]] && echo "[LOG] $*"; } -# ----------------------------- LOAD MASTER CONF ----------------------------- -[[ -n "${MASTER_CONF_PATH:-}" ]] && source "$MASTER_CONF_PATH" +log() { + [[ "${ENABLE_LOGGING:-false}" == true ]] && echo "[LOG] $*" +} -# ----------------------------- ARG PARSING ----------------------------- +# ARG PARSER parse_args() { ENABLE_LOGGING=${ENABLE_LOGGING:-false} DRY_RUN=${DRY_RUN:-false} + SHOW_STATUS=${SHOW_STATUS:-false} CLEAN_ARGS=() + for ARG in "$@"; do - case "$ARG" in - --dry-run|-n) DRY_RUN=true ;; - --log) ENABLE_LOGGING=true ;; - --no-log) ENABLE_LOGGING=false ;; - *) CLEAN_ARGS+=("$ARG") ;; - esac + if [[ "$ARG" == *=* ]]; then + VAR="${ARG%%=*}" + VAL="${ARG#*=}" + + case "$VAR" in + LOG) + [[ "$VAL" == "true" ]] && ENABLE_LOGGING=true + [[ "$VAL" == "false" ]] && ENABLE_LOGGING=false + ;; + *) + if declare -p "$VAR" &>/dev/null; then + printf -v "$VAR" '%s' "$VAL" + log "Set $VAR=$VAL" + else + warn "Unknown variable: $VAR" + fi + ;; + esac + else + case "$ARG" in + --dry-run|-n) DRY_RUN=true ;; + --log) ENABLE_LOGGING=true ;; + --no-log) ENABLE_LOGGING=false ;; + --status|--summary) SHOW_STATUS=true ;; + --help|-h) + echo "Usage: script [--dry-run] [--log]" + exit 0 + ;; + *) CLEAN_ARGS+=("$ARG") ;; + esac + fi done + PARSED_ARGS=("${CLEAN_ARGS[@]}") } -# ----------------------------- HOST ----------------------------- +# VALIDATION +require_var() { + [[ -z "${!1:-}" ]] && error "Missing required: $1" && exit 1 +} + +# HOST DETECTION detect_hosts() { LOCAL_HOSTNAME="$(hostname)" if [[ "$LOCAL_HOSTNAME" == "$HOST1" ]]; then LOCAL_SERVER_NAME="$HOST1" REMOTE_SERVER_NAME="$HOST2" - else + elif [[ "$LOCAL_HOSTNAME" == "$HOST2" ]]; then LOCAL_SERVER_NAME="$HOST2" REMOTE_SERVER_NAME="$HOST1" + else + error "Unknown host: $LOCAL_HOSTNAME" + exit 1 fi + declare -A SSH_KEYS + SSH_KEYS["$HOST1|$HOST2"]="$HOST1_SSH_KEY" + SSH_KEYS["$HOST2|$HOST1"]="$HOST2_SSH_KEY" + + SSH_KEY="${SSH_KEYS[$LOCAL_SERVER_NAME|$REMOTE_SERVER_NAME]}" + + [[ -z "$SSH_KEY" ]] && error "Missing SSH key mapping" && exit 1 + info "Host: $LOCAL_SERVER_NAME → $REMOTE_SERVER_NAME" } +# REMOTE resolve_remote_ip() { - REMOTE_SERVER=$(tailscale ip -4 "$REMOTE_SERVER_NAME") + log "Resolving remote IP..." + REMOTE_SERVER=$(tailscale ip -4 "$REMOTE_SERVER_NAME" 2>/dev/null) + + [[ -z "$REMOTE_SERVER" ]] && error "Failed to resolve remote IP" && exit 1 + info "Remote IP: $REMOTE_SERVER" } -# ----------------------------- CONTAINERS ----------------------------- +# CONTAINERS RUNNING_CONTAINERS=() stop_containers() { + [[ ${#CRITICAL_CONTAINER_NAMES[@]} -eq 0 ]] && return + info "Stopping containers..." RUNNING_CONTAINERS=() for c in "${CRITICAL_CONTAINER_NAMES[@]}"; do - STATUS=$(ssh root@"$REMOTE_SERVER" "docker inspect -f '{{.State.Running}}' $c 2>/dev/null" || echo "false") + log "Checking container: $c" + + STATUS=$(ssh -i "$SSH_KEY" root@"$REMOTE_SERVER" \ + "docker inspect -f '{{.State.Running}}' $c 2>/dev/null" || echo "false") if [[ "$STATUS" == "true" ]]; then warn "Stopping $c" RUNNING_CONTAINERS+=("$c") - ssh root@"$REMOTE_SERVER" "docker stop $c" >/dev/null && \ - success "$c stopped" || error "$c failed to stop" + if ssh -i "$SSH_KEY" root@"$REMOTE_SERVER" "docker stop $c" >/dev/null; then + success "$c stopped" + else + error "Failed to stop $c" + fi else - echo "🟢 $c already stopped" + log "$c already stopped" fi done } start_containers() { + [[ ${#RUNNING_CONTAINERS[@]} -eq 0 ]] && return + info "Starting containers..." for c in "${RUNNING_CONTAINERS[@]}"; do info "Starting $c" - ssh root@"$REMOTE_SERVER" "docker start $c" >/dev/null && \ - success "$c started" || error "$c failed to start" + + if ssh -i "$SSH_KEY" root@"$REMOTE_SERVER" "docker start $c" >/dev/null; then + success "$c started" + else + error "Failed to start $c" + fi done } -# ----------------------------- RSYNC LIMITER ----------------------------- +# RSYNC LIMITER wait_for_rsync() { - COUNT=$(pgrep -x rsync | wc -l || true) + : "${RETRY_COUNT:=5}" + : "${MAX_RSYNC_PROCS:=2}" + : "${SLEEP:=2}" - while [[ "$COUNT" -ge "${MAX_RSYNC_PROCS:-2}" ]]; do - warn "Waiting rsync slot..." - sleep 2 - COUNT=$(pgrep -x rsync | wc -l || true) + for i in $(seq 1 "$RETRY_COUNT"); do + + COUNT=$(ps -eo pid,cmd | grep "[r]sync .*${REMOTE_SERVER:-}" | wc -l || true) + + if [[ -z "$REMOTE_SERVER" ]]; then + COUNT=$(pgrep -x rsync | wc -l || true) + fi + + if [[ "$COUNT" -ge "$MAX_RSYNC_PROCS" ]]; then + warn "Waiting rsync slot ($COUNT/$MAX_RSYNC_PROCS)" + sleep "$SLEEP" + else + return 0 + fi done + + error "Too many rsync processes" + exit 1 } -# ----------------------------- RSYNC OPTIONS ----------------------------- -DEFAULT_RSYNC_OPTS=( - --archive - --delete - --partial - --compress - --info=progress2 - --stats -) - +# RSYNC OPTIONS get_rsync_opts() { - - RSYNC_OPTS=("${DEFAULT_RSYNC_OPTS[@]}") - - BW_LIMIT="${PROFILE_BW_LIMIT[$PROFILE_NAME]:-0}" - - if [[ "$BW_LIMIT" -gt 0 ]]; then - RSYNC_OPTS+=(--bwlimit="$BW_LIMIT") - log "bwlimit=${BW_LIMIT}KB/s applied (profile: $PROFILE_NAME)" + if [[ -n "${PROFILE_RSYNC_OPTS[$PROFILE_NAME]:-}" ]]; then + read -r -a RSYNC_OPTS <<< "${PROFILE_RSYNC_OPTS[$PROFILE_NAME]}" else - log "bwlimit unlimited (profile: $PROFILE_NAME)" + RSYNC_OPTS=("${DEFAULT_RSYNC_OPTS[@]}") fi } -# ----------------------------- RSYNC EXECUTION (WITH METRICS) ----------------------------- -run_rsync() { - - wait_for_rsync - get_rsync_opts - - echo "🚀 Running rsync..." - - RSYNC_START=$(date +%s) - - RSYNC_OUTPUT=$(rsync "${RSYNC_OPTS[@]}" \ - "$SRC/" \ - "root@$REMOTE_SERVER:$DEST/") - - RSYNC_END=$(date +%s) - DURATION=$((RSYNC_END - RSYNC_START)) - - # ----------------------------- METRICS EXTRACTION ----------------------------- - TRANSFERRED=$(echo "$RSYNC_OUTPUT" | grep "Total transferred file size" | awk '{print $5}') - FILES_CHANGED=$(echo "$RSYNC_OUTPUT" | grep "Number of regular files transferred" | awk '{print $6}') - DELETED=$(echo "$RSYNC_OUTPUT" | grep "Number of deleted files" | awk '{print $5}') - AVG_SPEED=$(echo "$RSYNC_OUTPUT" | grep -Eo '[0-9.]+[ ]*bytes/sec' | tail -1) -} - -# ----------------------------- SUMMARY (SINGLE SOURCE OF TRUTH) ----------------------------- -show_summary() { - - echo "" - echo "===== SUMMARY =====" - echo "Directory: $SRC" +# STATUS +show_status() { + echo "===== STATUS =====" + echo "Local: $LOCAL_SERVER_NAME" + echo "Remote: $REMOTE_SERVER_NAME" + echo "IP: $REMOTE_SERVER" echo "Profile: $PROFILE_NAME" - echo "" - echo "Transferred: ${TRANSFERRED:-unknown}" - echo "Changed files: ${FILES_CHANGED:-0}" - echo "Deleted files: ${DELETED:-0}" - echo "" - echo "Duration: ${DURATION:-0}s" - echo "Avg speed: ${AVG_SPEED:-unknown}" - echo "" - echo "Status: DONE" - echo "===================" + echo "DryRun: $DRY_RUN" + echo "Logging: $ENABLE_LOGGING" + echo "==================" } \ No newline at end of file