PHP architecture: - Extract common.php from monitor.php — shared system functions (vv_system_info, vv_memory_breakdown, vv_remote_hosts_stats, disk/GPU/UPS/network/docker/parity, etc.) now live in one place; monitor.php and watchdog.php both require common.php - Add unraid_api.php as explicit include (was implicit via config.php chain) - confform.php: add missing require_once config.php (implicit dep made explicit) - Delete orphaned pages/docs.php and pages/config.php (absorbed into scheduler) Watchdog page: - Add Storage watchdog card (growth + log strikes, baseline age, suppress ceilings) - Add Network watchdog card (NPM strikes, DDNS domain/container, NPM URL) - One host per row layout — all 5 watchdog cards equally spaced via inner grid - Watchdog now uses Unraid API for local system stats; remote nodes with API key but no SSH get system info from vv_remote_hosts_stats() with api_only flag - SSH bundle: /proc/meminfo passed as raw section instead of awk-parsed header fields — fixes RAM showing 0 on remote hosts where awk quoting was unreliable - vv_wd_local_system() rewritten as thin wrapper over vv_system_info() + vv_memory_breakdown() Monitor page: - Watchdog card: add stability strikes, storage watchdog strikes, network NPM status, live system stats (rootfs/log/tmp %, RAM free, load, CPU temp, zombies, NIC, sshd) - Row height: switch from max-height on cards to minmax(0, calc(...)) on grid track — all cards in a row now fill to the tallest card's height correctly (fixes Pools card being shorter than neighbours) Scheduler page: - Add Tools section above Custom Scripts — lists Tools/*.sh with run/dry-run/cron/log - vv_tools_scripts() function in scheduler.php include Tools: - Add docker_prune_images.sh — removes dangling Docker images; --dry-run and --status modes
96 lines
3.7 KiB
Bash
Executable File
96 lines
3.7 KiB
Bash
Executable File
#!/bin/bash
|
|
# ==============================================================================================
|
|
# ============================= Docker Prune Images ============================================
|
|
# ==============================================================================================
|
|
#
|
|
# PURPOSE
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
# Removes dangling Docker images — images no longer tagged or referenced by any
|
|
# container. These accumulate after container updates pull a new image version,
|
|
# leaving the old image behind with no tag.
|
|
#
|
|
# Safe to run at any time. Only removes images with no tag and no container
|
|
# reference — running containers are never affected.
|
|
#
|
|
# ==============================================================================================
|
|
# RUNTIME MODES
|
|
# ==============================================================================================
|
|
#
|
|
# docker_prune_images.sh
|
|
# Show dangling images and remove them.
|
|
#
|
|
# docker_prune_images.sh --dry-run
|
|
# Show what would be removed without removing anything.
|
|
#
|
|
# docker_prune_images.sh --status
|
|
# Show current dangling images and disk usage. No changes.
|
|
#
|
|
# ==============================================================================================
|
|
|
|
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"
|
|
exit 1
|
|
fi
|
|
|
|
acquire_lock
|
|
|
|
# ==============================================================================================
|
|
# ━━━ Status ━━━
|
|
# ==============================================================================================
|
|
if [[ "$SHOW_STATUS" == true ]]; then
|
|
echo ""
|
|
echo "━━━━━ $ICON_SUMMARY DOCKER PRUNE IMAGES STATUS ━━━━━"
|
|
DANGLING=$(docker images -f "dangling=true" --format "{{.ID}}\t{{.Size}}\t{{.CreatedSince}}" 2>/dev/null)
|
|
if [[ -z "$DANGLING" ]]; then
|
|
echo "$ICON_DONE No dangling images."
|
|
else
|
|
COUNT=$(echo "$DANGLING" | wc -l)
|
|
echo "$ICON_CONTAINERS $COUNT dangling image(s):"
|
|
echo "$DANGLING" | while IFS=$'\t' read -r id size age; do
|
|
echo " $id $size created $age"
|
|
done
|
|
fi
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━"
|
|
exit 0
|
|
fi
|
|
|
|
# ==============================================================================================
|
|
# ━━━ Run ━━━
|
|
# ==============================================================================================
|
|
echo "━━━ $ICON_CONTAINERS Docker Prune Images — $(date '+%Y-%m-%d %H:%M:%S') ━━━"
|
|
|
|
DANGLING_IDS=$(docker images -f "dangling=true" -q 2>/dev/null)
|
|
|
|
if [[ -z "$DANGLING_IDS" ]]; then
|
|
success "No dangling images — nothing to do"
|
|
exit 0
|
|
fi
|
|
|
|
COUNT=$(echo "$DANGLING_IDS" | wc -l)
|
|
log "Found $COUNT dangling image(s)"
|
|
|
|
if [[ "$DRY_RUN" == true ]]; then
|
|
warn "DRY RUN — would remove $COUNT dangling image(s):"
|
|
docker images -f "dangling=true" --format " {{.ID}} {{.Size}} created {{.CreatedSince}}" 2>/dev/null
|
|
exit 0
|
|
fi
|
|
|
|
OUTPUT=$(docker image prune -f 2>&1)
|
|
echo "$OUTPUT"
|
|
|
|
RECLAIMED=$(echo "$OUTPUT" | grep -E "^Total reclaimed" || echo "")
|
|
if [[ -n "$RECLAIMED" ]]; then
|
|
success "Done — $RECLAIMED"
|
|
else
|
|
success "Done — $COUNT image(s) removed"
|
|
fi
|