Bash common.sh: consolidate docker_cmd/retry_docker/verify_running/emby_api, fix tailscale dups

common.sh gains:
- docker_cmd() + verify_running() + retry_docker() — removed from all 3 Docker_Essentials
  scripts where they were byte-for-byte duplicates
- emby_api(endpoint, [timeout=30]) — removed from 6 Media/Tools scripts that each defined
  their own _emby_api() with the same curl/parse/error pattern; call sites renamed emby_api
- format_duration() extended with days/hours branch (was capped at minutes+seconds)
- notify() comment: scripts do not need to preflight the notify script via validate_unraid_cmd

Tailscale deduplication:
- arr_sync.sh: _resolve_node_ip() and inline block in _delete_remote_item() both replaced
  with resolve_tailscale_ip() from common.sh
- git_pull_execute.sh: inline tailscale ip -4 replaced with resolve_tailscale_ip() (adds
  the tailscale status fallback that was missing)
This commit is contained in:
Gmer4Lfe
2026-06-04 17:00:50 -04:00
parent 0bcb773332
commit b5d33cd6a5
12 changed files with 98 additions and 238 deletions
+75 -3
View File
@@ -228,6 +228,7 @@ notify() {
log "$ICON_NOTIFY Sending notification: $subject$message"
# Guard is built in — scripts do NOT need to validate_unraid_cmd for the notify script.
if [[ "${NOTIFY_UNRAID:-false}" == true ]]; then
local notify_script="/usr/local/emhttp/plugins/dynamix/scripts/notify"
if [[ -x "$notify_script" ]]; then
@@ -261,9 +262,14 @@ notify() {
format_duration() {
local secs=$1
local mins=$((secs / 60))
local rem=$((secs % 60))
[[ $mins -gt 0 ]] && echo "${mins}m${rem}s" || echo "${rem}s"
local days=$(( secs / 86400 ))
local hrs=$(( (secs % 86400) / 3600 ))
local mins=$(( (secs % 3600) / 60 ))
local rem=$(( secs % 60 ))
if [[ $days -gt 0 ]]; then echo "${days}d ${hrs}h ${mins}m"
elif [[ $hrs -gt 0 ]]; then echo "${hrs}h ${mins}m"
elif [[ $mins -gt 0 ]]; then echo "${mins}m${rem}s"
else echo "${rem}s"; fi
}
# ==============================================================================================
@@ -1102,6 +1108,72 @@ check_remote_disks() {
# Tracks which remote containers were running before stop — used by start_containers()
RUNNING_CONTAINERS=()
# ── Docker command helpers (used by docker_daily_restart, docker_weekly_restart, docker_update) ──
# Default timeouts — scripts can override before calling.
DOCKER_TIMEOUT=${DOCKER_TIMEOUT:-30} # seconds before docker command is killed
RESTART_VERIFY_WAIT=${RESTART_VERIFY_WAIT:-5} # seconds to wait before checking state post-restart
# Run a docker command with a hard timeout. Returns 124 on timeout, else docker's exit code.
docker_cmd() {
timeout "$DOCKER_TIMEOUT" "$@"
local exit_code=$?
if [[ "$exit_code" -eq 124 ]]; then
error "Docker command timed out after ${DOCKER_TIMEOUT}s: $*"
return 1
fi
return "$exit_code"
}
# Verify a container is still running after a restart.
# Waits RESTART_VERIFY_WAIT seconds to let it settle, then checks State.Running.
verify_running() {
local container="$1"
sleep "$RESTART_VERIFY_WAIT"
local state
state=$(docker inspect -f '{{.State.Running}}' "$container" 2>/dev/null)
if [[ "$state" != "true" ]]; then
error "$container failed to stay running after restart — may have crashed"
return 1
fi
return 0
}
# Retry a docker command up to RETRY_COUNT times, sleeping SLEEP seconds between attempts.
retry_docker() {
local attempt=1
while [[ "$attempt" -le "$RETRY_COUNT" ]]; do
log "$ICON_RETRY Attempt $attempt of $RETRY_COUNT: $*"
if docker_cmd "$@"; then
log "Succeeded on attempt $attempt"
return 0
else
warn "Attempt $attempt failed"
(( attempt++ ))
[[ "$attempt" -le "$RETRY_COUNT" ]] && sleep "$SLEEP"
fi
done
error "Command failed after $RETRY_COUNT attempts: $*"
return 1
}
# ── Emby API helper ───────────────────────────────────────────────────────────
# General Emby REST call. Uses EMBY_URL and EMBY_API_KEY (aliased by detect_hosts).
# Usage: emby_api <endpoint> [timeout_seconds]
# Prints response body on 200; returns 1 on HTTP error or curl failure.
emby_api() {
local endpoint="$1" max_time="${2:-30}"
local response http_code body
response=$(curl -sf --max-time "$max_time" \
-H "X-Emby-Token: $EMBY_API_KEY" \
-w "\n%{http_code}" \
"${EMBY_URL}/${endpoint}" 2>/dev/null)
http_code=$(echo "$response" | tail -1)
body=$(echo "$response" | head -n -1)
[[ "$http_code" != "200" ]] && { error "Emby API HTTP $http_code: $endpoint"; return 1; }
echo "$body"
}
# Stop containers on the REMOTE server via SSH.
# Reads CRITICAL_CONTAINER_NAMES — set from profile arrays by rsync.sh.
# Tracks running state in RUNNING_CONTAINERS for restart after sync.