diff --git a/Rsync/rsync.sh b/Rsync/rsync.sh index 8511533..b03e657 100644 --- a/Rsync/rsync.sh +++ b/Rsync/rsync.sh @@ -8,98 +8,63 @@ set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/../common.sh" -# Load config +# Load Master.conf and detect remote server load_master_conf - -# Detect hosts / SSH / Tailscale detect_remote -#---------------------------------------------------------- -# Input Arguments -#---------------------------------------------------------- +#----------------------------------------------------------------------------------------------- +# --------------------------- Input Arguments -------------------------------------------------- +#----------------------------------------------------------------------------------------------- DIRECTORY="$1" if [[ -z "$DIRECTORY" ]]; then echo "Usage: $0 [--dry-run|-n] [VAR=value ...]" exit 1 fi -shift +shift # remove DIRECTORY # Parse CLI args parse_args "$@" -#---------------------------------------------------------- -# Profile Detection (FIXED) -#---------------------------------------------------------- -DIR_CLEAN="${DIRECTORY%/}" -PROFILE_NAME=$(basename "$DIR_CLEAN" | tr '[:upper:]' '[:lower:]') - +#----------------------------------------------------------------------------------------------- +# --------------------------- Profile Detection ------------------------------------------------- +#----------------------------------------------------------------------------------------------- +PROFILE_NAME=$(basename "$DIRECTORY" | tr '[:upper:]' '[:lower:]') echo "Detected profile: $PROFILE_NAME" -# Debug (remove later if you want) -echo "DEBUG: DIRECTORY=$DIRECTORY" -echo "DEBUG: DIR_CLEAN=$DIR_CLEAN" -echo "DEBUG: PROFILE_NAME=$PROFILE_NAME" -echo "DEBUG: Available profiles: ${!PROFILE_MAX_PROCS[@]}" - -#---------------------------------------------------------- -# Apply profile overrides (SAFE) -#---------------------------------------------------------- - -# Scalars (safe fallback) +# Apply profile defaults or fallback to global defaults MAX_RSYNC_PROCS=${PROFILE_MAX_PROCS[$PROFILE_NAME]:-$MAX_RSYNC_PROCS} BW_LIMIT=${PROFILE_BW_LIMIT[$PROFILE_NAME]:-$BW_LIMIT} +CRITICAL_CONTAINER_NAMES=(${PROFILE_CRITICAL_CONTAINER_NAMES[$PROFILE_NAME]}) +DELAYED_CONTAINERS=(${PROFILE_DELAYED_CONTAINERS[$PROFILE_NAME]}) CONTAINER_DELAY=${PROFILE_CONTAINER_DELAY[$PROFILE_NAME]:-$CONTAINER_DELAY} RETRY_COUNT=${PROFILE_RETRY_COUNT[$PROFILE_NAME]:-$RETRY_COUNT} SLEEP=${PROFILE_SLEEP[$PROFILE_NAME]:-$SLEEP} +EXCLUDE_DIRS=(${PROFILE_EXCLUDE_DIRS[$PROFILE_NAME]:-${EXCLUDE_DIRS[@]}}) -# Arrays (ONLY override if profile exists) -if [[ -n "${PROFILE_CRITICAL_CONTAINER_NAMES[$PROFILE_NAME]}" ]]; then - IFS=' ' read -r -a CRITICAL_CONTAINER_NAMES <<< "${PROFILE_CRITICAL_CONTAINER_NAMES[$PROFILE_NAME]}" -fi - -if [[ -n "${PROFILE_DELAYED_CONTAINERS[$PROFILE_NAME]}" ]]; then - IFS=' ' read -r -a DELAYED_CONTAINERS <<< "${PROFILE_DELAYED_CONTAINERS[$PROFILE_NAME]}" -fi - -if [[ -n "${PROFILE_EXCLUDE_DIRS[$PROFILE_NAME]}" ]]; then - IFS=' ' read -r -a EXCLUDE_DIRS <<< "${PROFILE_EXCLUDE_DIRS[$PROFILE_NAME]}" -fi - -#---------------------------------------------------------- -# Validate -#---------------------------------------------------------- +# Validate numeric variables validate_int MAX_RSYNC_PROCS "$MAX_RSYNC_PROCS" validate_int BW_LIMIT "$BW_LIMIT" validate_int CONTAINER_DELAY "$CONTAINER_DELAY" validate_int RETRY_COUNT "$RETRY_COUNT" validate_int SLEEP "$SLEEP" -echo "Settings:" -echo " MAX_RSYNC_PROCS=$MAX_RSYNC_PROCS" -echo " BW_LIMIT=$BW_LIMIT" -echo " CONTAINERS=${CRITICAL_CONTAINER_NAMES[*]}" -echo " EXCLUDES=${EXCLUDE_DIRS[*]}" +echo "Settings: MAX_RSYNC_PROCS=$MAX_RSYNC_PROCS, BW_LIMIT=$BW_LIMIT, CONTAINERS=${CRITICAL_CONTAINER_NAMES[*]}, EXCLUDES=${EXCLUDE_DIRS[*]}" -#---------------------------------------------------------- -# Dependency check -#---------------------------------------------------------- +#----------------------------------------------------------------------------------------------- +# --------------------------- Dependency Check -------------------------------------------------- +#----------------------------------------------------------------------------------------------- for cmd in rsync ssh ping timeout docker tailscale; do - command -v "$cmd" >/dev/null 2>&1 || { - echo "Error: Required command '$cmd' is not installed." - exit 1 - } + command -v "$cmd" >/dev/null 2>&1 || { echo "Error: Required command '$cmd' is not installed."; exit 1; } done trap 'echo "Script interrupted. Exiting."; exit 130' INT TERM -#---------------------------------------------------------- -# Helper Functions -#---------------------------------------------------------- - +#----------------------------------------------------------------------------------------------- +# --------------------------- Helper Functions ------------------------------------------------- +#----------------------------------------------------------------------------------------------- wait_for_rsync() { for attempt in $(seq 1 "$RETRY_COUNT"); do RSYNC_COUNT=$(pgrep -fc "rsync.*root@${REMOTE_SERVER}" || true) - if [ "$RSYNC_COUNT" -ge "$MAX_RSYNC_PROCS" ]; then echo "[$LOCAL_SERVER_NAME] Waiting... ($RSYNC_COUNT active rsync processes)" sleep "$SLEEP" @@ -107,7 +72,6 @@ wait_for_rsync() { return 0 fi done - echo "Too many rsync processes, exiting." exit 1 } @@ -121,18 +85,13 @@ declare -a RUNNING_CONTAINERS=() stop_containers() { echo "[$LOCAL_SERVER_NAME] Checking containers on ${REMOTE_SERVER_NAME}..." RUNNING_CONTAINERS=() - for container in "${CRITICAL_CONTAINER_NAMES[@]}"; do - [ -z "$container" ] && continue - STATUS=$(ssh -i "$SSH_KEY" root@"$REMOTE_SERVER" \ "docker inspect -f '{{.State.Running}}' $container 2>/dev/null" || echo "false") - - if [[ "$STATUS" == "true" ]]; then + if [ "$STATUS" == "true" ]; then echo "Stopping $container" RUNNING_CONTAINERS+=("$container") - - if [[ "$DRY_RUN" == true ]]; then + if [ "$DRY_RUN" = true ]; then echo "[DRY-RUN] Would stop container $container" else ssh -i "$SSH_KEY" root@"$REMOTE_SERVER" "docker stop $container" @@ -143,14 +102,12 @@ stop_containers() { start_containers() { echo "[$LOCAL_SERVER_NAME] Restarting containers on ${REMOTE_SERVER_NAME}..." - for container in "${RUNNING_CONTAINERS[@]}"; do if [[ " ${DELAYED_CONTAINERS[*]} " == *" $container "* ]]; then echo "Delaying start of $container by ${CONTAINER_DELAY}s..." - [[ "$DRY_RUN" == false ]] && sleep "$CONTAINER_DELAY" + [ "$DRY_RUN" = false ] && sleep "$CONTAINER_DELAY" fi - - if [[ "$DRY_RUN" == true ]]; then + if [ "$DRY_RUN" = true ]; then echo "[DRY-RUN] Would start container $container" else ssh -i "$SSH_KEY" root@"$REMOTE_SERVER" "docker start $container" @@ -158,10 +115,9 @@ start_containers() { done } -#---------------------------------------------------------- -# Main -#---------------------------------------------------------- - +#----------------------------------------------------------------------------------------------- +# --------------------------- Main Rsync Logic ------------------------------------------------- +#----------------------------------------------------------------------------------------------- main() { echo "[$LOCAL_SERVER_NAME] Syncing $DIRECTORY → $REMOTE_SERVER:$DIRECTORY" @@ -171,10 +127,7 @@ main() { sleep "$SLEEP" done - check_server_online || { - echo "Remote $REMOTE_SERVER_NAME unreachable. Exiting." - exit 1 - } + check_server_online || { echo "Remote $REMOTE_SERVER_NAME unreachable. Exiting."; exit 1; } wait_for_rsync stop_containers @@ -190,24 +143,20 @@ main() { ) for pattern in "${EXCLUDE_DIRS[@]}"; do - [[ -n "$pattern" ]] && RSYNC_OPTS+=(--exclude="$pattern") + RSYNC_OPTS+=(--exclude="$pattern") done - [[ "$DRY_RUN" == true ]] && RSYNC_OPTS+=("--dry-run") + [ "$DRY_RUN" = true ] && RSYNC_OPTS+=("--dry-run") for attempt in $(seq 1 "$RETRY_COUNT"); do echo "Starting rsync attempt $attempt/$RETRY_COUNT..." - if rsync "${RSYNC_OPTS[@]}" \ -e "ssh -i \"$SSH_KEY\" -T -o Compression=no -o IPQoS=throughput" \ "$DIRECTORY" "root@${REMOTE_SERVER}:$DIRECTORY"; then - echo "Rsync completed successfully." break - else echo "Rsync attempt $attempt failed." - if [[ "$attempt" -lt "$RETRY_COUNT" ]]; then echo "Retrying in $SLEEP seconds..." sleep "$SLEEP" @@ -223,4 +172,7 @@ main() { echo "[$LOCAL_SERVER_NAME] Sync complete." } +#----------------------------------------------------------------------------------------------- +# --------------------------- Execute --------------------------------------------------------- +#----------------------------------------------------------------------------------------------- main \ No newline at end of file diff --git a/common.sh b/common.sh index 7d09e6e..1d5a24f 100644 --- a/common.sh +++ b/common.sh @@ -11,11 +11,11 @@ #----------------------------------------------------------------------------------------------- # Load Master.conf #----------------------------------------------------------------------------------------------- +# Load Master.conf load_master_conf() { local script_dir - script_dir="$(cd "$(dirname "${BASH_SOURCE[1]}")" && pwd)" + script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" local master_conf="$script_dir/../Master.conf" - if [ -f "$master_conf" ]; then source "$master_conf" echo "Loaded Master.conf from $master_conf" @@ -25,73 +25,51 @@ load_master_conf() { fi } -#----------------------------------------------------------------------------------------------- -# Parse CLI args (flags + VAR=value overrides) -#----------------------------------------------------------------------------------------------- +# Parse CLI arguments parse_args() { DRY_RUN=${DRY_RUN:-false} - for ARG in "$@"; do if [[ "$ARG" == *=* ]]; then local VAR_NAME="${ARG%%=*}" local VAR_VALUE="${ARG#*=}" - if declare -p "$VAR_NAME" &>/dev/null; then printf -v "$VAR_NAME" '%s' "$VAR_VALUE" echo "Overriding $VAR_NAME -> $VAR_VALUE" else - echo "Warning: Unknown variable $VAR_NAME, ignoring." + echo "Warning: Unknown variable $VAR_NAME" fi else case "$ARG" in - --dry-run|-n) - DRY_RUN=true - ;; - --help|-h) - echo "Usage: script [--dry-run|-n] [VAR=value ...]" - exit 0 - ;; - *) - echo "Warning: Unknown argument $ARG" - ;; + --dry-run|-n) DRY_RUN=true ;; + --help|-h) echo "Usage: script [--dry-run|-n] [VAR=value ...]"; exit 0 ;; + *) echo "Warning: Unknown argument $ARG" ;; esac fi done } -#----------------------------------------------------------------------------------------------- -# Validate integer (non-negative) -#----------------------------------------------------------------------------------------------- +# Validate integer validate_int() { local name="$1" local value="$2" - if ! [[ "${value:-}" =~ ^[0-9]+$ ]]; then echo "Error: $name must be a non-negative integer." exit 1 fi } -#----------------------------------------------------------------------------------------------- -# Require variable to be set -#----------------------------------------------------------------------------------------------- +# Require variable require_var() { local var="$1" - if [[ -z "${!var:-}" ]]; then echo "Error: Required variable $var is not set." exit 1 fi } -#----------------------------------------------------------------------------------------------- -# Host + Remote + SSH Detection (RUN THIS AFTER load_master_conf) -#----------------------------------------------------------------------------------------------- +# Detect local hostname and set remote detect_remote() { - - # Detect local hostname LOCAL_HOSTNAME="$(hostname)" - if [[ "$LOCAL_HOSTNAME" == "$HOST1" ]]; then LOCAL_SERVER_NAME="$HOST1" REMOTE_SERVER_NAME="$HOST2" @@ -102,33 +80,22 @@ detect_remote() { echo "Error: Local hostname ($LOCAL_HOSTNAME) not recognized." exit 1 fi - echo "Local server: $LOCAL_SERVER_NAME" echo "Remote server: $REMOTE_SERVER_NAME" - # Resolve Tailscale IP REMOTE_SERVER=$(tailscale ip -4 "$REMOTE_SERVER_NAME" 2>/dev/null) - if [[ -z "$REMOTE_SERVER" ]]; then echo "Error: Could not resolve Tailscale IP for $REMOTE_SERVER_NAME" exit 1 fi - echo "Resolved $REMOTE_SERVER_NAME → $REMOTE_SERVER" - # SSH key mapping - declare -A SSH_KEYS - SSH_KEYS["$HOST1|$HOST2"]="/root/.ssh/Gmer4Lfe-rsync-key" - SSH_KEYS["$HOST2|$HOST1"]="/root/.ssh/Jayred365-rsync-key" - KEY_ID="$LOCAL_SERVER_NAME|$REMOTE_SERVER_NAME" - if [[ -n "${SSH_KEYS[$KEY_ID]}" ]]; then SSH_KEY="${SSH_KEYS[$KEY_ID]}" else echo "Error: No SSH key defined for $LOCAL_SERVER_NAME → $REMOTE_SERVER_NAME" exit 1 fi - echo "Using SSH key: $SSH_KEY" } \ No newline at end of file