From 1b9f584fb9152284a9dba2fe29bfffca66b17990 Mon Sep 17 00:00:00 2001 From: FailedProxy Date: Fri, 27 Mar 2026 18:02:36 +0000 Subject: [PATCH] Trying v1 framework again --- Rsync/rsync.sh | 126 ++++++++++++++++++---------------------- common.sh | 155 +++++++++++++++++++------------------------------ 2 files changed, 117 insertions(+), 164 deletions(-) diff --git a/Rsync/rsync.sh b/Rsync/rsync.sh index 9632c70..0f101e5 100644 --- a/Rsync/rsync.sh +++ b/Rsync/rsync.sh @@ -20,15 +20,12 @@ set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# Load configs & helpers source "$SCRIPT_DIR/../Master.conf" source "$SCRIPT_DIR/../common.sh" -# ---------------------------- -# INPUT HANDLING (FIXED) -# ---------------------------- +parse_args "$@" -# If first argument is NOT a flag or VAR=VALUE, treat it as DIRECTORY +# ----------------------------- INPUT ----------------------------- if [[ -z "$DIRECTORY" ]]; then if [[ "${1:-}" != "" && "${1:-}" != --* && "${1:-}" != *=* ]]; then DIRECTORY="$1" @@ -36,16 +33,13 @@ if [[ -z "$DIRECTORY" ]]; then fi fi -if [[ -z "$DIRECTORY" ]]; then - echo "Usage: $0 [--dry-run] [--status] [VAR=value ...]" - exit 1 -fi +[[ -z "$DIRECTORY" ]] && error "Missing directory" && exit 1 -# ----------------------------- Host & IP ----------------------------- +# ----------------------------- HOST ----------------------------- detect_hosts resolve_remote_ip -# ----------------------------- Profile ----------------------------- +# ----------------------------- PROFILE ----------------------------- PROFILE_NAME=$(basename "$DIRECTORY" | tr '[:upper:]' '[:lower:]') MAX_RSYNC_PROCS=${PROFILE_MAX_PROCS[$PROFILE_NAME]:-$MAX_RSYNC_PROCS} @@ -57,113 +51,105 @@ RETRY_COUNT=${PROFILE_RETRY_COUNT[$PROFILE_NAME]:-$RETRY_COUNT} SLEEP=${PROFILE_SLEEP[$PROFILE_NAME]:-$SLEEP} EXCLUDE_DIRS=(${PROFILE_EXCLUDE_DIRS[$PROFILE_NAME]:-${EXCLUDE_DIRS[@]}}) -# ----------------------------- Status Mode ----------------------------- +# ----------------------------- STATUS MODE ----------------------------- if [[ "$SHOW_STATUS" == true ]]; then show_status exit 0 fi +# ----------------------------- HEADER ----------------------------- +echo +echo "$ICON_RUN Sync Starting" +echo "--------------------------------------------" +echo "Source: $DIRECTORY" +echo "Destination: $REMOTE_SERVER:$DIRECTORY" +echo "Profile: $PROFILE_NAME" +echo "Dry Run: $DRY_RUN" +echo "--------------------------------------------" -# ----------------------------- User Info ----------------------------- -echo "============================================================" -echo " Sync Job Starting" -echo "------------------------------------------------------------" -echo " Source: $DIRECTORY" -echo " Destination: $REMOTE_SERVER:$DIRECTORY" -echo " Profile: $PROFILE_NAME" -echo " Dry Run: $DRY_RUN" -echo "============================================================" - -log "Settings: MAX_RSYNC_PROCS=$MAX_RSYNC_PROCS, BW_LIMIT=$BW_LIMIT" -log "Containers: ${CRITICAL_CONTAINER_NAMES[*]}" -log "Excludes: ${EXCLUDE_DIRS[*]}" - -# ----------------------------- Rsync Wait ----------------------------- +# ----------------------------- RSYNC LIMIT ----------------------------- wait_for_rsync() { - for attempt in $(seq 1 "$RETRY_COUNT"); do + for i in $(seq 1 "$RETRY_COUNT"); do RSYNC_COUNT=$(pgrep -fc "rsync.*root@${REMOTE_SERVER}" || true) - if [ "$RSYNC_COUNT" -ge "$MAX_RSYNC_PROCS" ]; then - echo "Waiting for available rsync slot... ($RSYNC_COUNT running)" - log "RSYNC_COUNT=$RSYNC_COUNT >= MAX=$MAX_RSYNC_PROCS" + + if [[ "$RSYNC_COUNT" -ge "$MAX_RSYNC_PROCS" ]]; then + warn "Waiting for rsync slot ($RSYNC_COUNT)" sleep "$SLEEP" else return 0 fi done - echo "Too many rsync processes, exiting." - exit 1 + + error "Too many rsync processes" } -# ----------------------------- Main ----------------------------- -main() { - echo "" - echo "🔍 Checking remote connectivity..." +# ----------------------------- SUMMARY ----------------------------- +print_summary() { + echo + echo "================ SUMMARY ================" + echo "Directory: $DIRECTORY" + echo "Profile: $PROFILE_NAME" + echo "Remote: $REMOTE_SERVER" + echo "Duration: ${DURATION:-unknown}s" + echo "Status: $1" + echo "Dry Run: $DRY_RUN" + echo "========================================" +} +# ----------------------------- MAIN ----------------------------- +main() { + + echo "$ICON_GEAR Checking remote..." for i in $(seq 1 "$RETRY_COUNT"); do if ping -c 1 "$REMOTE_SERVER" &>/dev/null; then - echo "✅ Remote server reachable" + success "Remote reachable" break fi - echo "âš ī¸ Remote down, retrying in $SLEEP seconds..." + warn "Retrying ($i/$RETRY_COUNT)" sleep "$SLEEP" done - if ! ping -c 1 "$REMOTE_SERVER" &>/dev/null; then - echo "❌ Remote server unreachable. Exiting." - exit 1 - fi + [[ ! $(ping -c 1 "$REMOTE_SERVER" &>/dev/null) ]] && error "Remote unreachable" wait_for_rsync - echo "" - echo "🛑 Stopping containers on remote..." + echo "$ICON_STOP Stopping containers..." stop_containers - echo "" - echo "đŸ“Ļ Building rsync options..." + echo "$ICON_GEAR Building rsync opts..." get_rsync_opts for ex in "${EXCLUDE_DIRS[@]}"; do RSYNC_OPTS+=(--exclude="$ex") done - [ "$DRY_RUN" = true ] && RSYNC_OPTS+=("--dry-run") + [[ "$DRY_RUN" == true ]] && RSYNC_OPTS+=("--dry-run") - log "Final rsync opts: ${RSYNC_OPTS[*]}" + echo "$ICON_RUN Running rsync..." - echo "" - echo "🚀 Starting rsync..." - - for attempt in $(seq 1 "$RETRY_COUNT"); do - echo "Attempt $attempt/$RETRY_COUNT" + START=$(date +%s) + for i in $(seq 1 "$RETRY_COUNT"); do if rsync "${RSYNC_OPTS[@]}" \ - -e "ssh -i \"$SSH_KEY\" -T -o Compression=no -o IPQoS=throughput" \ + -e "ssh -i $SSH_KEY -T -o Compression=no -o IPQoS=throughput" \ "$DIRECTORY" "root@${REMOTE_SERVER}:$DIRECTORY"; then - echo "✅ Rsync completed successfully" + success "Rsync complete" break - else - echo "❌ Rsync failed" + warn "Rsync failed" - if [ "$attempt" -lt "$RETRY_COUNT" ]; then - echo "Retrying in $SLEEP seconds..." - sleep "$SLEEP" - else - echo "đŸ’Ĩ All retries failed" - start_containers - exit 1 - fi + [[ $i -lt $RETRY_COUNT ]] && sleep "$SLEEP" fi done - echo "" - echo "🔄 Restarting containers..." + echo "$ICON_SYNC Restarting containers..." start_containers - echo "" - echo "🎉 Sync complete!" + END=$(date +%s) + DURATION=$((END - START)) + + print_summary "SUCCESS" } main \ No newline at end of file diff --git a/common.sh b/common.sh index 8d141a0..4a3be37 100644 --- a/common.sh +++ b/common.sh @@ -3,17 +3,32 @@ # ----------------- UNRAID OPS COMMON LIBRARY (CORE FRAMEWORK v1) ------------------------------- # ----------------------------------------------------------------------------------------------- +# ----------------------------- ICON LAYER ----------------------------- +ICON_INFO="â„šī¸" +ICON_WARN="âš ī¸" +ICON_ERROR="❌" +ICON_SUCCESS="✅" +ICON_RUN="🚀" +ICON_STOP="🛑" +ICON_RETRY="🔁" +ICON_SYNC="🔄" +ICON_GEAR="âš™ī¸" + # ----------------------------- Output Helpers ----------------------------- info() { - echo "[INFO] $*" + echo "$ICON_INFO [INFO] $*" } warn() { - echo "[WARN] $*" + echo "$ICON_WARN [WARN] $*" } error() { - echo "[ERROR] $*" + echo "$ICON_ERROR [ERROR] $*" +} + +success() { + echo "$ICON_SUCCESS [OK] $*" } log() { @@ -38,7 +53,7 @@ parse_args() { elif [[ "$VAR_VALUE" == "false" ]]; then ENABLE_LOGGING=false else - warn "Invalid value for LOG: $VAR_VALUE (use true/false)" + warn "Invalid LOG value: $VAR_VALUE" fi ;; *) @@ -46,7 +61,7 @@ parse_args() { printf -v "$VAR_NAME" '%s' "$VAR_VALUE" log "Overriding $VAR_NAME -> $VAR_VALUE" else - warn "Unknown variable $VAR_NAME, ignoring." + warn "Unknown variable $VAR_NAME" fi ;; esac @@ -55,24 +70,24 @@ parse_args() { case "$ARG" in --dry-run|-n) DRY_RUN=true - info "Dry-run mode enabled" + info "Dry-run enabled" ;; --log) ENABLE_LOGGING=true - info "Verbose logging enabled" + info "Logging enabled" ;; --no-log) ENABLE_LOGGING=false ;; --status|--summary) SHOW_STATUS=true - ;; + ;; --help|-h) - echo "Usage: script [--dry-run|-n] [--log] [LOG=true] [VAR=value ...]" + echo "Usage: script [--dry-run|-n] [--log] [VAR=value ...]" exit 0 ;; *) - warn "Unknown argument $ARG" + warn "Unknown argument: $ARG" ;; esac fi @@ -82,23 +97,17 @@ parse_args() { # ----------------------------- Validation ----------------------------- require_var() { local var="$1" - if [[ -z "${!var:-}" ]]; then - error "Required variable $var is not set." - exit 1 - fi + [[ -z "${!var:-}" ]] && error "Missing required variable: $var" && exit 1 } validate_int() { local name="$1" local value="$2" - if ! [[ "${value:-}" =~ ^[0-9]+$ ]]; then - error "$name must be a non-negative integer." - exit 1 - fi + [[ ! "${value:-}" =~ ^[0-9]+$ ]] && error "$name must be integer" && exit 1 } -# ----------------------------- Host Detection ----------------------------- +# ----------------------------- HOST DETECTION ----------------------------- detect_hosts() { LOCAL_HOSTNAME="$(hostname)" @@ -109,127 +118,85 @@ detect_hosts() { LOCAL_SERVER_NAME="$HOST2" REMOTE_SERVER_NAME="$HOST1" else - error "Local hostname ($LOCAL_HOSTNAME) not recognized." - exit 1 + error "Unknown host: $LOCAL_HOSTNAME" fi declare -A SSH_KEYS SSH_KEYS["$HOST1|$HOST2"]="$HOST1_SSH_KEY" SSH_KEYS["$HOST2|$HOST1"]="$HOST2_SSH_KEY" - KEY_ID="$LOCAL_SERVER_NAME|$REMOTE_SERVER_NAME" - SSH_KEY="${SSH_KEYS[$KEY_ID]}" + SSH_KEY="${SSH_KEYS[$LOCAL_SERVER_NAME|$REMOTE_SERVER_NAME]}" - if [[ -z "$SSH_KEY" ]]; then - error "No SSH key defined for $LOCAL_SERVER_NAME → $REMOTE_SERVER_NAME" - exit 1 - fi - - info "Local: $LOCAL_SERVER_NAME → Remote: $REMOTE_SERVER_NAME" - log "SSH key: $SSH_KEY" + [[ -z "$SSH_KEY" ]] && error "Missing SSH key mapping" + info "Host: $LOCAL_SERVER_NAME → $REMOTE_SERVER_NAME" } -# ----------------------------- Remote IP ----------------------------- +# ----------------------------- REMOTE ----------------------------- resolve_remote_ip() { - log "Resolving Tailscale IP for $REMOTE_SERVER_NAME..." - + log "Resolving remote IP..." REMOTE_SERVER=$(tailscale ip -4 "$REMOTE_SERVER_NAME" 2>/dev/null) - if [[ -z "$REMOTE_SERVER" ]]; then - error "Could not resolve Tailscale IP for $REMOTE_SERVER_NAME" - exit 1 - fi - + [[ -z "$REMOTE_SERVER" ]] && error "Failed to resolve remote IP" info "Remote IP: $REMOTE_SERVER" } -# ----------------------------- Connectivity ----------------------------- check_remote_online() { - log "Pinging $REMOTE_SERVER..." ping -c 1 "$REMOTE_SERVER" &>/dev/null } -# ----------------------------- Containers ----------------------------- +# ----------------------------- CONTAINERS ----------------------------- declare -a RUNNING_CONTAINERS=() stop_containers() { - if [[ ${#CRITICAL_CONTAINER_NAMES[@]} -eq 0 ]]; then - log "No containers defined to stop" - return - fi + [[ ${#CRITICAL_CONTAINER_NAMES[@]} -eq 0 ]] && return - info "Stopping containers on $REMOTE_SERVER_NAME..." + info "Stopping containers..." RUNNING_CONTAINERS=() - for container in "${CRITICAL_CONTAINER_NAMES[@]}"; do - log "Checking container: $container" - + for c in "${CRITICAL_CONTAINER_NAMES[@]}"; do STATUS=$(ssh -i "$SSH_KEY" root@"$REMOTE_SERVER" \ - "docker inspect -f '{{.State.Running}}' $container 2>/dev/null" || echo "false") + "docker inspect -f '{{.State.Running}}' $c 2>/dev/null" || echo "false") if [[ "$STATUS" == "true" ]]; then - info "Stopping $container" - RUNNING_CONTAINERS+=("$container") - ssh -i "$SSH_KEY" root@"$REMOTE_SERVER" "docker stop $container" - else - log "$container already stopped" + warn "Stopping $c" + RUNNING_CONTAINERS+=("$c") + ssh -i "$SSH_KEY" root@"$REMOTE_SERVER" "docker stop $c" fi done } start_containers() { - if [[ ${#RUNNING_CONTAINERS[@]} -eq 0 ]]; then - log "No containers to restart" - return - fi + [[ ${#RUNNING_CONTAINERS[@]} -eq 0 ]] && return - info "Starting containers on $REMOTE_SERVER_NAME..." + info "Starting containers..." - for container in "${RUNNING_CONTAINERS[@]}"; do - if [[ " ${DELAYED_CONTAINERS[*]} " == *" $container "* ]]; then - info "Delaying $container (${CONTAINER_DELAY}s)" - sleep "$CONTAINER_DELAY" - fi - - info "Starting $container" - ssh -i "$SSH_KEY" root@"$REMOTE_SERVER" "docker start $container" + for c in "${RUNNING_CONTAINERS[@]}"; do + info "Starting $c" + ssh -i "$SSH_KEY" root@"$REMOTE_SERVER" "docker start $c" done } -# ----------------------------- Rsync Options ----------------------------- +# ----------------------------- RSYNC ----------------------------- get_rsync_opts() { if [[ -n "${PROFILE_RSYNC_OPTS[$PROFILE_NAME]:-}" ]]; then read -r -a RSYNC_OPTS <<< "${PROFILE_RSYNC_OPTS[$PROFILE_NAME]}" - log "Using profile rsync options: ${PROFILE_RSYNC_OPTS[$PROFILE_NAME]}" + log "Profile rsync opts loaded" else RSYNC_OPTS=("${DEFAULT_RSYNC_OPTS[@]}") - log "Using default rsync options: ${DEFAULT_RSYNC_OPTS[*]}" + log "Default rsync opts loaded" fi } -# ----------------------------- Status Output ----------------------------- +# ----------------------------- STATUS ----------------------------- show_status() { - echo "===== RSYNC STATUS =====" - echo "Local: $LOCAL_SERVER_NAME" - echo "Remote: $REMOTE_SERVER_NAME" - echo "Remote IP: $REMOTE_SERVER" - echo "SSH Key: $SSH_KEY" echo - echo "Directory: $DIRECTORY" - echo "Profile: $PROFILE_NAME" - echo - echo "Max Procs: $MAX_RSYNC_PROCS" - echo "Bandwidth: $BW_LIMIT KB/s" - echo "Retries: $RETRY_COUNT" - echo "Sleep: $SLEEP" - echo "Dry Run: $DRY_RUN" - echo - echo "Containers: ${CRITICAL_CONTAINER_NAMES[*]:-(none)}" - echo "Delayed: ${DELAYED_CONTAINERS[*]:-(none)}" - echo - echo "Excludes: ${EXCLUDE_DIRS[*]:-(none)}" - echo - echo "Rsync Opts:" - printf ' %s\n' "${RSYNC_OPTS[@]}" - echo "=========================" + echo "================= STATUS =================" + echo "Local: $LOCAL_SERVER_NAME" + echo "Remote: $REMOTE_SERVER_NAME" + echo "IP: $REMOTE_SERVER" + echo "Profile: $PROFILE_NAME" + echo "Dry Run: $DRY_RUN" + echo "Logging: $ENABLE_LOGGING" + echo "Containers:${CRITICAL_CONTAINER_NAMES[*]:-(none)}" + echo "=========================================" } \ No newline at end of file