audit echo vs log across all scripts — outcomes always visible, verbose for per-item loops
This commit is contained in:
+365
@@ -0,0 +1,365 @@
|
||||
#!/bin/bash
|
||||
# ==============================================================================================
|
||||
# ================================= Ramdisk Setup ==============================================
|
||||
# ==============================================================================================
|
||||
#
|
||||
# PURPOSE
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# Creates the tmpfs ramdisk, SSD fallback directory, transcode symlink, and
|
||||
# pre-creates transcoding-temp on the ramdisk. Run once at array start via
|
||||
# array_started.sh (System_Essentials/). Idempotent — already-mounted ramdisk
|
||||
# reports status and exits cleanly. Always resets the symlink to the ramdisk
|
||||
# on boot, ensuring a clean state regardless of what state it was in before
|
||||
# shutdown.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# OPERATIONAL MODEL
|
||||
# ==============================================================================================
|
||||
#
|
||||
# Creates four things in order:
|
||||
# 1. RAMDISK_PATH — tmpfs mount (size: HOST*_RAMDISK_SIZE ceiling, not a reservation)
|
||||
# 2. TRANSCODE_SSD — SSD fallback directory and transcoding-temp inside it
|
||||
# 3. TRANSCODE_LINK — symlink reset to RAMDISK_PATH (clean state at every boot)
|
||||
# 4. transcoding-temp/ inside RAMDISK_PATH — pre-created before Emby starts
|
||||
#
|
||||
# The transcoding-temp pre-creation is critical: if it doesn't exist on the ramdisk
|
||||
# when Emby starts, Emby searches all accessible paths for an existing one and finds
|
||||
# the SSD fallback version — routing all sessions there until Emby restarts.
|
||||
#
|
||||
# Initialises /tmp/transcode_state.db with current target and flip counters.
|
||||
# /tmp resets on reboot — correct, transcode state should not persist across boots.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# OPERATIONAL SAFEGUARDS
|
||||
# ==============================================================================================
|
||||
#
|
||||
# Root Required
|
||||
# mount and symlink creation require root.
|
||||
#
|
||||
# Single Instance Lock
|
||||
# acquire_lock prevents duplicate runs at array start.
|
||||
#
|
||||
# Idempotent Mount Check
|
||||
# If RAMDISK_PATH is already a mountpoint, reports status and exits cleanly
|
||||
# without attempting to remount or changing anything.
|
||||
#
|
||||
# Notification Validated
|
||||
# platform_require_cmd confirms the notify script is present before use.
|
||||
#
|
||||
# Silent on Success
|
||||
# Startup script runs on every boot — no output when healthy.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# CONFIGURATION
|
||||
# ==============================================================================================
|
||||
#
|
||||
# host*.conf
|
||||
#
|
||||
# HOST*_RAMDISK_SIZE
|
||||
# tmpfs ceiling (e.g. 10G). Must change together with WARN_GB and LOW_GB.
|
||||
# Aliased by detect_hosts() → RAMDISK_SIZE.
|
||||
#
|
||||
# HOST*_RAMDISK_WARN_GB
|
||||
# Usage level at which transcode_manager.sh flips symlink to SSD.
|
||||
#
|
||||
# HOST*_RAMDISK_LOW_GB
|
||||
# Usage level at which transcode_manager.sh flips back to ramdisk.
|
||||
#
|
||||
# HOST*_TRANSCODE_SSD
|
||||
# SSD fallback directory path.
|
||||
# Aliased by detect_hosts() → TRANSCODE_SSD.
|
||||
#
|
||||
# master.conf
|
||||
#
|
||||
# TRANSCODE_LINK
|
||||
# Symlink path Emby uses as its transcode directory. Must match the path
|
||||
# configured in Emby's transcoding settings.
|
||||
#
|
||||
# TRANSCODE_CHMOD / TRANSCODE_OWNER
|
||||
# Permissions applied to both ramdisk and SSD directories. (default: 755 / nobody:users)
|
||||
#
|
||||
# TRANSCODE_STATE_FILE
|
||||
# Override state file path. (default: ${STATE_DIR}/transcode_state.db)
|
||||
#
|
||||
# ==============================================================================================
|
||||
# STATE FILES
|
||||
# ==============================================================================================
|
||||
#
|
||||
# TRANSCODE_STATE_FILE (default: ${STATE_DIR}/transcode_state.db)
|
||||
# Current symlink target + flip count tracking. Lives in STATE_DIR
|
||||
# (ephemeral on Unraid — resets on reboot correctly).
|
||||
#
|
||||
# ==============================================================================================
|
||||
# RUNTIME MODES
|
||||
# ==============================================================================================
|
||||
#
|
||||
# ramdisk_setup.sh
|
||||
# Normal setup run. Called by array_started.sh at boot.
|
||||
#
|
||||
# ramdisk_setup.sh --dry-run
|
||||
# Show what would be created without creating anything.
|
||||
#
|
||||
# ramdisk_setup.sh --status
|
||||
# Show current ramdisk mount state, symlink target, and SSD directory state.
|
||||
#
|
||||
# ramdisk_setup.sh --log
|
||||
# Verbose output showing each creation step.
|
||||
#
|
||||
# ==============================================================================================
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
source "$SCRIPT_DIR/../load_config.sh"
|
||||
|
||||
parse_args "$@"
|
||||
|
||||
# ==============================================================================================
|
||||
# ━━━ Setup ━━━
|
||||
# ==============================================================================================
|
||||
if [[ "$EUID" -ne 0 ]]; then
|
||||
error "Must be run as root — mount and symlink require root"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
acquire_lock
|
||||
|
||||
# detect_hosts() sets MY_ID and aliases RAMDISK_SIZE, TRANSCODE_SSD etc.
|
||||
detect_hosts
|
||||
|
||||
log "Identity: $MY_ID ($LOCAL_SERVER_NAME)"
|
||||
log "Ramdisk: $RAMDISK_PATH ($RAMDISK_SIZE)"
|
||||
log "Fallback: $TRANSCODE_SSD"
|
||||
log "Symlink: $TRANSCODE_LINK"
|
||||
|
||||
[[ "$DRY_RUN" == true ]] && warn "DRY RUN — no changes will be made"
|
||||
|
||||
# ==============================================================================================
|
||||
# ━━━ Status ━━━
|
||||
# ==============================================================================================
|
||||
if [[ "$SHOW_STATUS" == true ]]; then
|
||||
echo ""
|
||||
echo "━━━━━ $ICON_SUMMARY STATUS ━━━━━"
|
||||
echo "$ICON_HOST Identity: $MY_ID ($LOCAL_SERVER_NAME)"
|
||||
echo "$ICON_RAM Ramdisk path: $RAMDISK_PATH"
|
||||
echo "$ICON_RAM Ramdisk size: $RAMDISK_SIZE"
|
||||
echo "$ICON_RAM Warn at: ${RAMDISK_WARN_GB}GB"
|
||||
echo "$ICON_RAM Flip at: ${RAMDISK_LOW_GB}GB"
|
||||
echo "$ICON_DISK SSD fallback: $TRANSCODE_SSD"
|
||||
echo "$ICON_LINK Symlink: $TRANSCODE_LINK"
|
||||
echo "$ICON_GEAR Owner: $TRANSCODE_OWNER"
|
||||
echo "$ICON_GEAR Mode: $TRANSCODE_CHMOD"
|
||||
echo ""
|
||||
|
||||
if mountpoint -q "$RAMDISK_PATH" 2>/dev/null; then
|
||||
USAGE=$(df -BG "$RAMDISK_PATH" | awk 'NR==2 {print $3}')
|
||||
AVAIL=$(df -BG "$RAMDISK_PATH" | awk 'NR==2 {print $4}')
|
||||
echo " $ICON_RAM Ramdisk: mounted — $USAGE used / $AVAIL available ✅"
|
||||
else
|
||||
echo " $ICON_RAM Ramdisk: NOT mounted"
|
||||
fi
|
||||
|
||||
if [[ -L "$TRANSCODE_LINK" ]]; then
|
||||
TARGET=$(readlink "$TRANSCODE_LINK")
|
||||
echo " $ICON_LINK Symlink: $TRANSCODE_LINK → $TARGET"
|
||||
else
|
||||
echo " $ICON_LINK Symlink: not set"
|
||||
fi
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ==============================================================================================
|
||||
# ━━━ Ramdisk ━━━
|
||||
# ==============================================================================================
|
||||
echo ""
|
||||
echo "━━━ $ICON_RAM Ramdisk — $MY_ID ━━━"
|
||||
log "$ICON_RAM Path: $RAMDISK_PATH"
|
||||
log "$ICON_RAM Size: $RAMDISK_SIZE"
|
||||
echo ""
|
||||
|
||||
START=$(date +%s)
|
||||
SETUP_SUCCESS=true
|
||||
|
||||
if mountpoint -q "$RAMDISK_PATH" 2>/dev/null; then
|
||||
USAGE=$(df -BG "$RAMDISK_PATH" | awk 'NR==2 {print $3}')
|
||||
AVAIL=$(df -BG "$RAMDISK_PATH" | awk 'NR==2 {print $4}')
|
||||
log "Ramdisk already mounted — $USAGE used / $AVAIL available"
|
||||
log "Skipping mount — verifying symlink and permissions"
|
||||
else
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
warn "DRY RUN — would create $RAMDISK_PATH"
|
||||
warn "DRY RUN — would mount tmpfs ${RAMDISK_SIZE} at $RAMDISK_PATH"
|
||||
else
|
||||
log "Creating ramdisk mount point: $RAMDISK_PATH"
|
||||
mkdir -p "$RAMDISK_PATH" || {
|
||||
error "Failed to create $RAMDISK_PATH"
|
||||
notify "Ramdisk setup failed on $(hostname) ($MY_ID) — could not create mount point" \
|
||||
"Ramdisk Setup" "warning"
|
||||
exit 1
|
||||
}
|
||||
|
||||
log "Mounting tmpfs ${RAMDISK_SIZE} at $RAMDISK_PATH..."
|
||||
if mount -t tmpfs -o size="$RAMDISK_SIZE" tmpfs "$RAMDISK_PATH"; then
|
||||
warn "Ramdisk mounted — ${RAMDISK_SIZE} at $RAMDISK_PATH ✅"
|
||||
else
|
||||
error "Failed to mount ramdisk at $RAMDISK_PATH"
|
||||
notify "Ramdisk setup failed on $(hostname) ($MY_ID) — mount failed" \
|
||||
"Ramdisk Setup" "warning"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# ==============================================================================================
|
||||
# ━━━ SSD Fallback ━━━
|
||||
# ==============================================================================================
|
||||
echo ""
|
||||
echo "━━━ $ICON_DISK SSD Fallback ━━━"
|
||||
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
warn "DRY RUN — would create SSD fallback: $TRANSCODE_SSD"
|
||||
else
|
||||
if [[ -d "$TRANSCODE_SSD" ]]; then
|
||||
log "SSD fallback already exists: $TRANSCODE_SSD"
|
||||
else
|
||||
log "Creating SSD fallback directory: $TRANSCODE_SSD"
|
||||
if mkdir -p "$TRANSCODE_SSD"; then
|
||||
log "SSD fallback created: $TRANSCODE_SSD ✅"
|
||||
else
|
||||
error "Failed to create SSD fallback: $TRANSCODE_SSD"
|
||||
SETUP_SUCCESS=false
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# ==============================================================================================
|
||||
# ━━━ Symlink ━━━
|
||||
# ==============================================================================================
|
||||
echo ""
|
||||
echo "━━━ $ICON_LINK Symlink ━━━"
|
||||
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
warn "DRY RUN — would set $TRANSCODE_LINK → $RAMDISK_PATH"
|
||||
else
|
||||
if [[ -L "$TRANSCODE_LINK" ]]; then
|
||||
CURRENT_TARGET=$(readlink "$TRANSCODE_LINK")
|
||||
if [[ "$CURRENT_TARGET" == "$RAMDISK_PATH" ]]; then
|
||||
log "Symlink already points to ramdisk — no change needed ✅"
|
||||
else
|
||||
log "Updating symlink: $CURRENT_TARGET → $RAMDISK_PATH"
|
||||
ln -sfn "$RAMDISK_PATH" "$TRANSCODE_LINK" || {
|
||||
error "Failed to update symlink"
|
||||
SETUP_SUCCESS=false
|
||||
}
|
||||
fi
|
||||
elif [[ -e "$TRANSCODE_LINK" ]]; then
|
||||
warn "$TRANSCODE_LINK exists but is not a symlink — removing and replacing"
|
||||
rm -rf "$TRANSCODE_LINK"
|
||||
ln -sfn "$RAMDISK_PATH" "$TRANSCODE_LINK" || {
|
||||
error "Failed to create symlink"
|
||||
SETUP_SUCCESS=false
|
||||
}
|
||||
else
|
||||
log "Creating symlink: $TRANSCODE_LINK → $RAMDISK_PATH"
|
||||
mkdir -p "$(dirname "$TRANSCODE_LINK")"
|
||||
ln -sfn "$RAMDISK_PATH" "$TRANSCODE_LINK" || {
|
||||
error "Failed to create symlink"
|
||||
SETUP_SUCCESS=false
|
||||
}
|
||||
fi
|
||||
|
||||
[[ "$SETUP_SUCCESS" == true ]] && log "Symlink: $TRANSCODE_LINK → $RAMDISK_PATH ✅"
|
||||
fi
|
||||
|
||||
# ==============================================================================================
|
||||
# ━━━ Transcoding-temp Directory ━━━
|
||||
# ==============================================================================================
|
||||
# Pre-created inside ramdisk so Emby always finds it there at session start.
|
||||
# Without this Emby creates it at its own first-writable path — which may be
|
||||
# SSD even when the symlink points at the ramdisk — locking all sessions onto SSD.
|
||||
echo ""
|
||||
echo "━━━ $ICON_GEAR Transcoding Temp Directory ━━━"
|
||||
|
||||
TRANSCODE_TEMP_DIR="${RAMDISK_PATH}/transcoding-temp"
|
||||
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
warn "DRY RUN — would create $TRANSCODE_TEMP_DIR"
|
||||
else
|
||||
if [[ -d "$TRANSCODE_TEMP_DIR" ]]; then
|
||||
log "transcoding-temp already exists on ramdisk"
|
||||
else
|
||||
if mkdir -p "$TRANSCODE_TEMP_DIR"; then
|
||||
log "Created transcoding-temp on ramdisk ✅"
|
||||
else
|
||||
error "Failed to create transcoding-temp on ramdisk"
|
||||
SETUP_SUCCESS=false
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -d "$TRANSCODE_TEMP_DIR" ]]; then
|
||||
chmod "$TRANSCODE_CHMOD" "$TRANSCODE_TEMP_DIR"
|
||||
chown "$TRANSCODE_OWNER" "$TRANSCODE_TEMP_DIR"
|
||||
log "Permissions set on transcoding-temp ($TRANSCODE_CHMOD $TRANSCODE_OWNER)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ==============================================================================================
|
||||
# ━━━ Permissions ━━━
|
||||
# ==============================================================================================
|
||||
echo ""
|
||||
echo "━━━ $ICON_GEAR Permissions ━━━"
|
||||
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
warn "DRY RUN — would apply $TRANSCODE_CHMOD $TRANSCODE_OWNER to $RAMDISK_PATH and $TRANSCODE_SSD"
|
||||
else
|
||||
for path in "$RAMDISK_PATH" "$TRANSCODE_SSD"; do
|
||||
if [[ -d "$path" ]]; then
|
||||
chmod "$TRANSCODE_CHMOD" "$path"
|
||||
chown "$TRANSCODE_OWNER" "$path"
|
||||
log "Permissions set: $path ($TRANSCODE_CHMOD $TRANSCODE_OWNER)"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# ==============================================================================================
|
||||
# ━━━ Initialise State File ━━━
|
||||
# ==============================================================================================
|
||||
if [[ "$DRY_RUN" == false ]]; then
|
||||
STATE_FILE="${TRANSCODE_STATE_FILE:-${STATE_DIR:-/tmp}/transcode_state.db}"
|
||||
NOW=$(date +%s)
|
||||
cat > "$STATE_FILE" <<EOF
|
||||
current_target=$RAMDISK_PATH
|
||||
last_flip_time=$NOW
|
||||
flip_count_hour=0
|
||||
flip_hour_start=$NOW
|
||||
EOF
|
||||
log "State file initialised: $STATE_FILE"
|
||||
fi
|
||||
|
||||
END=$(date +%s)
|
||||
|
||||
# ==============================================================================================
|
||||
# ━━━ Summary ━━━
|
||||
# ==============================================================================================
|
||||
echo ""
|
||||
echo "━━━━━ $ICON_SUMMARY RAMDISK SETUP SUMMARY ━━━━━"
|
||||
echo "$ICON_HOST Identity: $MY_ID ($LOCAL_SERVER_NAME)"
|
||||
echo "$ICON_RAM Ramdisk: $RAMDISK_PATH ($RAMDISK_SIZE)"
|
||||
echo "$ICON_DISK Fallback: $TRANSCODE_SSD"
|
||||
echo "$ICON_LINK Symlink: $TRANSCODE_LINK"
|
||||
echo "$ICON_TIME Duration: $(format_duration $(( END - START )))"
|
||||
echo ""
|
||||
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
warn "DRY RUN — no changes made"
|
||||
elif [[ "$SETUP_SUCCESS" == true ]]; then
|
||||
echo "$ICON_DONE Status: done ✅"
|
||||
else
|
||||
echo "$ICON_ERROR Status: SETUP HAD ERRORS"
|
||||
notify "Ramdisk setup errors on $(hostname) ($MY_ID) — check output" \
|
||||
"Ramdisk Setup" "warning"
|
||||
exit 1
|
||||
fi
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
Reference in New Issue
Block a user