added icons and improved ux

This commit is contained in:
2026-04-06 01:11:30 +00:00
parent 227cdaac19
commit 9cad6ba306
4 changed files with 119 additions and 70 deletions
+1
View File
@@ -64,6 +64,7 @@ DAILY_SYNC_SHARES=(
/mnt/user/Nextcloud /mnt/user/Nextcloud
/mnt/user/stand-up_comedy /mnt/user/stand-up_comedy
/mnt/user/Tv_Shows /mnt/user/Tv_Shows
/mnt/user/appdata-Failover/Gmer4Lfe/
) )
# ------------------- unRAID essentail scripts ------------------ # ------------------- unRAID essentail scripts ------------------
+20 -12
View File
@@ -23,9 +23,16 @@ echo "--- $ICON_GEAR Setup ---"
detect_hosts detect_hosts
resolve_remote_ip resolve_remote_ip
# Single connectivity check upfront — fail fast before attempting all shares # -----------------------------------------------------------------------------------------------
# against an unreachable host rather than failing per-share through the loop # --- $ICON_SHIELD Pre-flight Checks ---
# -----------------------------------------------------------------------------------------------
echo ""
echo "--- $ICON_SHIELD Pre-flight Checks ---"
# Single connectivity and rootfs check upfront — fail fast before attempting all shares
# Individual share and disk checks run per-share inside rsync.sh
check_connectivity check_connectivity
check_remote_rootfs
# ----------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------
# Tracking # Tracking
@@ -41,7 +48,7 @@ SHARE_COUNT=${#DAILY_SYNC_SHARES[@]}
# ----------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------
echo "" echo ""
echo "--- $ICON_SYNC Daily Sync Starting — $(date '+%Y-%m-%d %H:%M:%S') ---" echo "--- $ICON_SYNC Daily Sync Starting — $(date '+%Y-%m-%d %H:%M:%S') ---"
echo "Shares: $SHARE_COUNT" echo "$ICON_SUMMARY Shares: $SHARE_COUNT"
echo "" echo ""
SHARE_INDEX=0 SHARE_INDEX=0
@@ -57,6 +64,7 @@ for SHARE in "${DAILY_SYNC_SHARES[@]}"; do
SHARE_END=$(date +%s) SHARE_END=$(date +%s)
SHARE_TIMES+=("$SHARE_NAME:$((SHARE_END - SHARE_START))") SHARE_TIMES+=("$SHARE_NAME:$((SHARE_END - SHARE_START))")
PASS+=("$SHARE_NAME") PASS+=("$SHARE_NAME")
echo "$ICON_DONE $SHARE_NAME complete"
else else
SHARE_END=$(date +%s) SHARE_END=$(date +%s)
SHARE_TIMES+=("$SHARE_NAME:$((SHARE_END - SHARE_START))") SHARE_TIMES+=("$SHARE_NAME:$((SHARE_END - SHARE_START))")
@@ -71,11 +79,11 @@ TOTAL_END=$(date +%s)
TOTAL_DURATION=$((TOTAL_END - TOTAL_START)) TOTAL_DURATION=$((TOTAL_END - TOTAL_START))
# ----------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------
# --- $ICON_SUCCESS Summary --- # --- $ICON_SUMMARY Summary ---
# ----------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------
echo "===== DAILY SYNC SUMMARY =====" echo "===== $ICON_SUMMARY DAILY SYNC SUMMARY ====="
echo "Started: $(date -d @$TOTAL_START '+%Y-%m-%d %H:%M:%S')" echo "$ICON_TIME Started: $(date -d @$TOTAL_START '+%Y-%m-%d %H:%M:%S')"
echo "Finished: $(date -d @$TOTAL_END '+%Y-%m-%d %H:%M:%S')" echo "$ICON_TIME Finished: $(date -d @$TOTAL_END '+%Y-%m-%d %H:%M:%S')"
echo "" echo ""
for entry in "${SHARE_TIMES[@]}"; do for entry in "${SHARE_TIMES[@]}"; do
SHARE_NAME="${entry%%:*}" SHARE_NAME="${entry%%:*}"
@@ -83,14 +91,14 @@ for entry in "${SHARE_TIMES[@]}"; do
if printf '%s\n' "${FAIL[@]}" | grep -qx "$SHARE_NAME"; then if printf '%s\n' "${FAIL[@]}" | grep -qx "$SHARE_NAME"; then
echo " $ICON_ERROR $SHARE_NAME$(format_duration $DURATION)" echo " $ICON_ERROR $SHARE_NAME$(format_duration $DURATION)"
else else
echo " $ICON_SUCCESS $SHARE_NAME$(format_duration $DURATION)" echo " $ICON_DONE $SHARE_NAME$(format_duration $DURATION)"
fi fi
done done
echo "" echo ""
echo " Passed: ${#PASS[@]}/$SHARE_COUNT" echo " $ICON_SUCCESS Passed: ${#PASS[@]}/$SHARE_COUNT"
echo " Failed: ${#FAIL[@]}/$SHARE_COUNT" echo " $ICON_ERROR Failed: ${#FAIL[@]}/$SHARE_COUNT"
echo " Duration: $(format_duration $TOTAL_DURATION)" echo " $ICON_TIME Duration: $(format_duration $TOTAL_DURATION)"
echo "==============================" echo "========================================="
[[ ${#FAIL[@]} -gt 0 ]] && exit 1 [[ ${#FAIL[@]} -gt 0 ]] && exit 1
exit 0 exit 0
+24 -14
View File
@@ -36,13 +36,23 @@ echo "--- $ICON_GEAR Setup ---"
detect_hosts detect_hosts
resolve_remote_ip resolve_remote_ip
# -----------------------------------------------------------------------------------------------
# --- $ICON_SHIELD Pre-flight Checks ---
# -----------------------------------------------------------------------------------------------
echo ""
echo "--- $ICON_SHIELD Pre-flight Checks ---"
check_connectivity check_connectivity
check_remote_rootfs check_remote_rootfs
check_remote_share "$DIRECTORY" check_remote_share "$DIRECTORY"
check_remote_disks "$DIRECTORY" check_remote_disks "$DIRECTORY"
# -----------------------------------------------------------------------------------------------
# Profile is inferred from the directory basename (lowercased) # Profile is inferred from the directory basename (lowercased)
# e.g. /mnt/user/appdata-Failover/Arrs_Stack → arrs_stack # e.g. /mnt/user/appdata-Failover/Arrs_Stack → arrs_stack
# -----------------------------------------------------------------------------------------------
echo ""
PROFILE_NAME=$(basename "$DIRECTORY" | tr '[:upper:]' '[:lower:]') PROFILE_NAME=$(basename "$DIRECTORY" | tr '[:upper:]' '[:lower:]')
info "$ICON_GEAR Loading profile: $PROFILE_NAME" info "$ICON_GEAR Loading profile: $PROFILE_NAME"
@@ -72,9 +82,9 @@ stop_containers
# ----------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------
echo "" echo ""
echo "--- $ICON_SYNC Transfer ---" echo "--- $ICON_SYNC Transfer ---"
echo "Source: $DIRECTORY" echo "$ICON_RUN Source: $DIRECTORY"
echo "Remote: $REMOTE_SERVER:$DIRECTORY" echo "$ICON_NET Remote: $REMOTE_SERVER:$DIRECTORY"
echo "Profile: $PROFILE_NAME" echo "$ICON_GEAR Profile: $PROFILE_NAME"
echo "" echo ""
get_rsync_opts get_rsync_opts
@@ -97,7 +107,7 @@ for i in $(seq 1 "$RETRY_COUNT"); do
if rsync "${RSYNC_OPTS[@]}" \ 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}:$(dirname "$DIRECTORY")/"; then "$DIRECTORY" "root@${REMOTE_SERVER}:$(dirname "$DIRECTORY")/"; then
success "Rsync complete" echo "$ICON_DONE Rsync complete"
RSYNC_SUCCESS=true RSYNC_SUCCESS=true
break break
else else
@@ -107,29 +117,29 @@ for i in $(seq 1 "$RETRY_COUNT"); do
done done
# ----------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------
# --- $ICON_RUN Containers --- # --- $ICON_START Containers ---
# ----------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------
echo "" echo ""
echo "--- $ICON_RUN Containers ---" echo "--- $ICON_START Containers ---"
start_containers start_containers
END=$(date +%s) END=$(date +%s)
# ----------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------
# --- Summary --- # --- $ICON_SUMMARY Summary ---
# ----------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------
echo "" echo ""
echo "===== SUMMARY =====" echo "===== $ICON_SUMMARY SUMMARY ====="
echo "Directory: $DIRECTORY" echo "$ICON_RUN Directory: $DIRECTORY"
echo "Profile: $PROFILE_NAME" echo "$ICON_GEAR Profile: $PROFILE_NAME"
echo "Duration: $(format_duration $((END - START)))" echo "$ICON_TIME Duration: $(format_duration $((END - START)))"
if [[ "$RSYNC_SUCCESS" == true ]]; then if [[ "$RSYNC_SUCCESS" == true ]]; then
echo "Status: $ICON_SUCCESS DONE" echo "$ICON_DONE Status: $ICON_SUCCESS DONE"
else else
echo "Status: $ICON_ERROR FAILED after $RETRY_COUNT attempts" echo "$ICON_ERROR Status: $ICON_ERROR FAILED after $RETRY_COUNT attempts"
fi fi
echo "===================" echo "========================="
[[ "$RSYNC_SUCCESS" == false ]] && exit 1 [[ "$RSYNC_SUCCESS" == false ]] && exit 1
exit 0 exit 0
+57 -27
View File
@@ -2,7 +2,7 @@
# ----------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------
# ----------------- UNRAID OPS COMMON LIBRARY (STABLE FRAMEWORK v1) ---------------------------- # ----------------- UNRAID OPS COMMON LIBRARY (STABLE FRAMEWORK v1) ----------------------------
# ----------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------
# Version: 1.4 # Version: 1.5
# ----------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------
# Changelog: # Changelog:
# v1.0 — Initial stable framework # v1.0 — Initial stable framework
@@ -18,19 +18,50 @@
# v1.4 — check_remote_disks added — verifies all physical disks backing a share are mounted # v1.4 — check_remote_disks added — verifies all physical disks backing a share are mounted
# Discovers disk layout automatically at runtime, no configuration required # Discovers disk layout automatically at runtime, no configuration required
# Aborts if any single disk backing the share is offline or unmounted # Aborts if any single disk backing the share is offline or unmounted
# v1.5 — Full icon set expanded — each operation and state has its own distinct icon
# All function output updated to use correct icon per context
# Icons grouped and commented by category for clarity
# ----------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------
# -----------------------------------------------------------------------------------------------
# ICONS # ICONS
# Each icon has one job — do not reuse across different contexts.
# -----------------------------------------------------------------------------------------------
# System / Host
ICON_HOST="🖥️" # host detection
ICON_NET="🌐" # network / IP resolution
ICON_PING="📡" # connectivity check
ICON_GEAR="⚙️" # setup section header / profile load
# Health Checks
ICON_DISK="💾" # disk checks
ICON_HEALTH="🩺" # rootfs / share health checks
ICON_SHIELD="🛡️" # pre-flight section header
# Containers
ICON_STOP="⛔" # stop command being issued
ICON_STOPPED="🔴" # container confirmed stopped
ICON_START="▶️" # start command being issued
ICON_STARTED="💚" # container confirmed started
ICON_RUNNING="🟢" # container already running when checked
ICON_NOT_RUNNING="🔴" # container already stopped when checked
# Transfer
ICON_SYNC="🔄" # transfer section header
ICON_RUN="🚀" # sync starting / rsync attempt
ICON_RETRY="🔁" # retry attempt
ICON_DONE="🏁" # transfer complete
# Summary
ICON_SUMMARY="📋" # summary section header
ICON_TIME="⏱️" # duration line
# Output
ICON_INFO="️" ICON_INFO="️"
ICON_WARN="⚠️" ICON_WARN="⚠️"
ICON_ERROR="❌" ICON_ERROR="❌"
ICON_SUCCESS="✅" ICON_SUCCESS="✅"
ICON_RUN="🚀"
ICON_STOP="🛑"
ICON_RETRY="🔁"
ICON_SYNC="🔄"
ICON_GEAR="⚙️"
ICON_DISK="💾"
# ----------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------
# OUTPUT HELPERS # OUTPUT HELPERS
@@ -149,7 +180,7 @@ detect_hosts() {
[[ -z "$SSH_KEY" ]] && error "Missing SSH key mapping for $LOCAL_SERVER_NAME$REMOTE_SERVER_NAME" && exit 1 [[ -z "$SSH_KEY" ]] && error "Missing SSH key mapping for $LOCAL_SERVER_NAME$REMOTE_SERVER_NAME" && exit 1
info "$ICON_GEAR Host: $LOCAL_SERVER_NAME$REMOTE_SERVER_NAME" info "$ICON_HOST Host: $LOCAL_SERVER_NAME$REMOTE_SERVER_NAME"
} }
# ----------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------
@@ -159,12 +190,12 @@ detect_hosts() {
# Exits if resolution fails — likely means Tailscale is down or peer is offline. # Exits if resolution fails — likely means Tailscale is down or peer is offline.
# ----------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------
resolve_remote_ip() { resolve_remote_ip() {
log "$ICON_SYNC Resolving remote IP for $REMOTE_SERVER_NAME..." log "Resolving remote IP for $REMOTE_SERVER_NAME..."
REMOTE_SERVER=$(tailscale ip -4 "$REMOTE_SERVER_NAME" 2>/dev/null) REMOTE_SERVER=$(tailscale ip -4 "$REMOTE_SERVER_NAME" 2>/dev/null)
[[ -z "$REMOTE_SERVER" ]] && error "Failed to resolve Tailscale IP for $REMOTE_SERVER_NAME" && exit 1 [[ -z "$REMOTE_SERVER" ]] && error "Failed to resolve Tailscale IP for $REMOTE_SERVER_NAME" && exit 1
info "$ICON_SYNC Remote IP: $REMOTE_SERVER" info "$ICON_NET Remote IP: $REMOTE_SERVER"
} }
# ----------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------
@@ -176,11 +207,11 @@ resolve_remote_ip() {
check_connectivity() { check_connectivity() {
log "Checking connectivity to $REMOTE_SERVER..." log "Checking connectivity to $REMOTE_SERVER..."
if ! ping -c1 -W3 "$REMOTE_SERVER" &>/dev/null; then if ! ping -c1 -W3 "$REMOTE_SERVER" &>/dev/null; then
error "Remote $REMOTE_SERVER ($REMOTE_SERVER_NAME) is unreachable" error "$ICON_PING Remote $REMOTE_SERVER ($REMOTE_SERVER_NAME) is unreachable"
info "Hint: tailscale status | grep $REMOTE_SERVER_NAME" info "Hint: tailscale status | grep $REMOTE_SERVER_NAME"
exit 1 exit 1
fi fi
log "Remote is reachable" info "$ICON_PING $REMOTE_SERVER_NAME is reachable"
} }
# ----------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------
@@ -204,14 +235,14 @@ check_remote_rootfs() {
if [[ "$REMOTE_USAGE" -ge "${ROOTFS_WARN:-75}" ]]; then if [[ "$REMOTE_USAGE" -ge "${ROOTFS_WARN:-75}" ]]; then
echo "" echo ""
error "Remote rootfs is ${REMOTE_USAGE}% full — threshold is ${ROOTFS_WARN:-75}%" error "$ICON_HEALTH Remote rootfs is ${REMOTE_USAGE}% full — threshold is ${ROOTFS_WARN:-75}%"
warn "Array may be down or drives missing on $REMOTE_SERVER_NAME" warn "Array may be down or drives missing on $REMOTE_SERVER_NAME"
info "Hint: Check array status on $REMOTE_SERVER_NAME before retrying" info "Hint: Check array status on $REMOTE_SERVER_NAME before retrying"
echo "" echo ""
exit 1 exit 1
fi fi
success "Remote rootfs: ${REMOTE_USAGE}% used (threshold: ${ROOTFS_WARN:-75}%)" info "$ICON_HEALTH Remote rootfs: ${REMOTE_USAGE}% used (threshold: ${ROOTFS_WARN:-75}%)"
} }
# ----------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------
@@ -232,7 +263,7 @@ check_remote_share() {
if [[ "$SHARE_EXISTS" != "yes" ]]; then if [[ "$SHARE_EXISTS" != "yes" ]]; then
echo "" echo ""
error "Remote share does not exist: $dir" error "$ICON_HEALTH Remote share does not exist: $dir"
warn "Array may not be started or share is not configured on $REMOTE_SERVER_NAME" warn "Array may not be started or share is not configured on $REMOTE_SERVER_NAME"
info "Hint: Check shares and array status on $REMOTE_SERVER_NAME before retrying" info "Hint: Check shares and array status on $REMOTE_SERVER_NAME before retrying"
echo "" echo ""
@@ -244,14 +275,14 @@ check_remote_share() {
if [[ "$SHARE_EMPTY" == "yes" ]]; then if [[ "$SHARE_EMPTY" == "yes" ]]; then
echo "" echo ""
warn "Remote share exists but is empty: $dir" warn "$ICON_HEALTH Remote share exists but is empty: $dir"
warn "Drives may not be mounted on $REMOTE_SERVER_NAME — aborting to protect data" warn "Drives may not be mounted on $REMOTE_SERVER_NAME — aborting to protect data"
info "Hint: Verify array and drive assignments on $REMOTE_SERVER_NAME before retrying" info "Hint: Verify array and drive assignments on $REMOTE_SERVER_NAME before retrying"
echo "" echo ""
exit 1 exit 1
fi fi
success "Remote share verified: $dir" info "$ICON_HEALTH Remote share verified: $dir"
} }
# ----------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------
@@ -276,7 +307,7 @@ check_remote_disks() {
if [[ -z "$DISK_PATHS" ]]; then if [[ -z "$DISK_PATHS" ]]; then
echo "" echo ""
error "No disks found backing share $share_name on $REMOTE_SERVER_NAME" error "$ICON_DISK No disks found backing share $share_name on $REMOTE_SERVER_NAME"
warn "Share may not exist on any disk or array may not be started" warn "Share may not exist on any disk or array may not be started"
info "Hint: Check array and share configuration on $REMOTE_SERVER_NAME" info "Hint: Check array and share configuration on $REMOTE_SERVER_NAME"
echo "" echo ""
@@ -286,7 +317,6 @@ check_remote_disks() {
local all_ok=true local all_ok=true
while IFS= read -r disk_share_path; do while IFS= read -r disk_share_path; do
# Extract the disk mountpoint — e.g. /mnt/disk8 from /mnt/disk8/Movies
local disk_mount local disk_mount
disk_mount=$(dirname "$disk_share_path") disk_mount=$(dirname "$disk_share_path")
local disk_name local disk_name
@@ -296,9 +326,9 @@ check_remote_disks() {
"mountpoint -q '$disk_mount' && echo yes || echo no" 2>/dev/null) "mountpoint -q '$disk_mount' && echo yes || echo no" 2>/dev/null)
if [[ "$MOUNTED" == "yes" ]]; then if [[ "$MOUNTED" == "yes" ]]; then
success "$ICON_DISK $disk_name online$share_name present" info "$ICON_DISK $disk_name $ICON_RUNNING$share_name present"
else else
error "$disk_name is not mounted$share_name may be incomplete" error "$ICON_DISK $disk_name $ICON_STOPPED$share_name missing or incomplete"
all_ok=false all_ok=false
fi fi
done <<< "$DISK_PATHS" done <<< "$DISK_PATHS"
@@ -347,12 +377,12 @@ stop_containers() {
RUNNING_CONTAINERS+=("$c") RUNNING_CONTAINERS+=("$c")
if ssh -i "$SSH_KEY" root@"$REMOTE_SERVER" "docker stop $c" >/dev/null; then if ssh -i "$SSH_KEY" root@"$REMOTE_SERVER" "docker stop $c" >/dev/null; then
success "$c stopped" echo "$ICON_STOPPED $c stopped"
else else
error "Failed to stop $c" error "Failed to stop $c"
fi fi
else else
warn "$c is not running, skipping" echo "$ICON_NOT_RUNNING $c is not running, skipping"
fi fi
done done
} }
@@ -388,9 +418,9 @@ start_containers() {
sleep "$CONTAINER_DELAY" sleep "$CONTAINER_DELAY"
fi fi
echo "$ICON_RUN Starting $c..." echo "$ICON_START Starting $c..."
if ssh -i "$SSH_KEY" root@"$REMOTE_SERVER" "docker start $c" >/dev/null; then if ssh -i "$SSH_KEY" root@"$REMOTE_SERVER" "docker start $c" >/dev/null; then
success "$c started" echo "$ICON_STARTED $c started"
else else
error "Failed to start $c" error "Failed to start $c"
fi fi
@@ -421,7 +451,7 @@ get_rsync_opts() {
# Useful for verifying profile resolution and variable state before a live run. # Useful for verifying profile resolution and variable state before a live run.
# ----------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------
show_status() { show_status() {
echo "===== STATUS =====" echo "===== $ICON_SUMMARY STATUS ====="
echo "Local: $LOCAL_SERVER_NAME" echo "Local: $LOCAL_SERVER_NAME"
echo "Remote: $REMOTE_SERVER_NAME" echo "Remote: $REMOTE_SERVER_NAME"
echo "IP: $REMOTE_SERVER" echo "IP: $REMOTE_SERVER"
@@ -431,5 +461,5 @@ show_status() {
echo "Containers: ${CRITICAL_CONTAINER_NAMES[*]}" echo "Containers: ${CRITICAL_CONTAINER_NAMES[*]}"
echo "Delayed: ${DELAYED_CONTAINERS[*]}" echo "Delayed: ${DELAYED_CONTAINERS[*]}"
echo "Excludes: ${EXCLUDE_DIRS[*]}" echo "Excludes: ${EXCLUDE_DIRS[*]}"
echo "==================" echo "========================"
} }