diff --git a/tools/pve/fstrim.sh b/tools/pve/fstrim.sh index 1fa5929c..0d53292b 100644 --- a/tools/pve/fstrim.sh +++ b/tools/pve/fstrim.sh @@ -1,7 +1,6 @@ #!/usr/bin/env bash # Copyright (c) 2021-2025 tteck -# Author: tteck (tteckster) # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE set -eEuo pipefail @@ -12,7 +11,7 @@ function header_info() { _______ __ __ ______ _ / ____(_) /__ _______ _______/ /____ ____ ___ /_ __/____(_)___ ___ / /_ / / / _ \/ ___/ / / / ___/ __/ _ \/ __ `__ \ / / / ___/ / __ `__ \ - / __/ / / __(__ ) /_/ (__ ) /_/ __/ / / / / / / / / / / / / / / / / / + / __/ / / / __(__ ) /_/ (__ ) /_/ __/ / / / / / / / / / / / / / / / / /_/ /_/_/\___/____/\__, /____/\__/\___/_/ /_/ /_/ /_/ /_/ /_/_/ /_/ /_/ /____/ EOF @@ -20,7 +19,6 @@ EOF BL="\033[36m" RD="\033[01;31m" -CM='\xE2\x9C\x94\033' GN="\033[1;92m" CL="\033[m" @@ -39,32 +37,39 @@ if [ "$ROOT_FS" != "ext4" ]; then fi NODE=$(hostname) -EXCLUDE_MENU=() -MSG_MAX_LENGTH=0 +MAX_NAME_LEN=0 +declare -A NAMES +declare -A STATUS -# Build EXCLUDE_MENU for main checklist -while read -r TAG ITEM; do - OFFSET=2 - ((${#ITEM} + OFFSET > MSG_MAX_LENGTH)) && MSG_MAX_LENGTH=$((${#ITEM} + OFFSET)) - EXCLUDE_MENU+=("$TAG" "$ITEM " "OFF") -done < <(pct list | awk 'NR>1 {print $1, $2}') +for CTID in $(pct list | awk 'NR>1 {print $1}'); do + NAME=$(pct config "$CTID" | awk -F': ' '/^hostname:/ {print $2}') + CTSTATUS=$(pct status "$CTID" | awk '{print $2}') + NAMES["$CTID"]="$NAME" + STATUS["$CTID"]="$CTSTATUS" + ((${#NAME} > MAX_NAME_LEN)) && MAX_NAME_LEN=${#NAME} +done + +FMT="%-5s | %-${MAX_NAME_LEN}s | %-8s" + +EXCLUDE_MENU=() +for CTID in "${!NAMES[@]}"; do + DESC=$(printf "$FMT" "$CTID" "${NAMES[$CTID]}" "${STATUS[$CTID]}") + EXCLUDE_MENU+=("$CTID" "$DESC" "OFF") +done excluded_containers_raw=$(whiptail --backtitle "Proxmox VE Helper Scripts" \ --title "Containers on $NODE" \ --checklist "\nSelect containers to skip from trimming:\n" \ - 20 $((MSG_MAX_LENGTH + 32)) 10 "${EXCLUDE_MENU[@]}" 3>&1 1>&2 2>&3) - + 20 $((MAX_NAME_LEN + 40)) 12 "${EXCLUDE_MENU[@]}" 3>&1 1>&2 2>&3) [ $? -ne 0 ] && exit read -ra EXCLUDED <<<$(echo "$excluded_containers_raw" | tr -d '"') -# Find all stopped containers STOPPED_MENU=() -for container in $(pct list | awk 'NR>1 {print $1}'); do - state=$(pct status "$container" | awk '{print $2}') - if [[ "$state" != "running" ]]; then - CTNAME=$(pct config "$container" | awk -F ': ' '/^hostname:/ {print $2}') - STOPPED_MENU+=("$container" "$CTNAME" "OFF") +for CTID in "${!NAMES[@]}"; do + if [[ "${STATUS[$CTID]}" == "stopped" ]]; then + DESC=$(printf "$FMT" "$CTID" "${NAMES[$CTID]}" "${STATUS[$CTID]}") + STOPPED_MENU+=("$CTID" "$DESC" "OFF") fi done @@ -72,8 +77,8 @@ TO_START=() if [ ${#STOPPED_MENU[@]} -gt 0 ]; then selected=$(whiptail --backtitle "Proxmox VE Helper Scripts" \ --title "Stopped LXC Containers" \ - --checklist "\nSome LXC containers are currently stopped.\nWhich ones do you want to temporarily start for the trim operation?\n(They will be stopped again afterwards)\n" \ - 20 80 10 "${STOPPED_MENU[@]}" 3>&1 1>&2 2>&3) + --checklist "\nSome LXC containers are currently stopped.\nWhich ones do you want to temporarily start for the trim operation?\n(They can be stopped again afterwards)\n" \ + 16 $((MAX_NAME_LEN + 40)) 8 "${STOPPED_MENU[@]}" 3>&1 1>&2 2>&3) [ $? -ne 0 ] && exit read -ra TO_START <<<$(echo "$selected" | tr -d '"') fi @@ -87,61 +92,55 @@ function trim_container() { local container="$1" header_info echo -e "${BL}[Info]${GN} Trimming ${BL}$container${CL} \n" - local before_trim after_trim before_trim=$(lvs --noheadings -o lv_name,data_percent | awk -v ctid="vm-${container}-disk-0" '$1 == ctid {gsub(/%/, "", $2); print $2}') echo -e "${RD}Data before trim $before_trim%${CL}" - pct fstrim "$container" - after_trim=$(lvs --noheadings -o lv_name,data_percent | awk -v ctid="vm-${container}-disk-0" '$1 == ctid {gsub(/%/, "", $2); print $2}') echo -e "${GN}Data after trim $after_trim%${CL}" - sleep 0.5 } -for container in $(pct list | awk 'NR>1 {print $1}'); do - if [[ " ${EXCLUDED[*]} " =~ " $container " ]]; then +for CTID in $(pct list | awk 'NR>1 {print $1}'); do + if [[ " ${EXCLUDED[*]} " =~ " $CTID " ]]; then header_info - echo -e "${BL}[Info]${GN} Skipping $container (excluded)${CL}" + echo -e "${BL}[Info]${GN} Skipping $CTID (excluded)${CL}" sleep 0.5 continue fi - if pct config "$container" | grep -q "template:"; then + if pct config "$CTID" | grep -q "template:"; then header_info - echo -e "${BL}[Info]${GN} Skipping $container (template)${CL}\n" + echo -e "${BL}[Info]${GN} Skipping $CTID (template)${CL}\n" sleep 0.5 continue fi - state=$(pct status "$container" | awk '{print $2}') - if [[ "$state" != "running" ]]; then - if [[ -n "${WAS_STOPPED[$container]:-}" ]]; then + if [[ "${STATUS[$CTID]}" != "running" ]]; then + if [[ -n "${WAS_STOPPED[$CTID]:-}" ]]; then header_info - echo -e "${BL}[Info]${GN} Starting $container for trim...${CL}" - pct start "$container" + echo -e "${BL}[Info]${GN} Starting $CTID for trim...${CL}" + pct start "$CTID" sleep 2 else header_info - echo -e "${BL}[Info]${GN} Skipping $container (not running, not selected)${CL}" + echo -e "${BL}[Info]${GN} Skipping $CTID (not running, not selected)${CL}" sleep 0.5 continue fi fi - trim_container "$container" + trim_container "$CTID" - # Optionally stop container again if we started it - if [[ -n "${WAS_STOPPED[$container]:-}" ]]; then + if [[ -n "${WAS_STOPPED[$CTID]:-}" ]]; then if whiptail --backtitle "Proxmox VE Helper Scripts" \ --title "Stop container again?" \ - --yesno "Container $container was started for the trim operation.\n\nDo you want to stop it again now?" 10 60; then + --yesno "Container $CTID (${NAMES[$CTID]}) was started for the trim operation.\n\nDo you want to stop it again now?" 10 60; then header_info - echo -e "${BL}[Info]${GN} Stopping $container again...${CL}" - pct stop "$container" + echo -e "${BL}[Info]${GN} Stopping $CTID again...${CL}" + pct stop "$CTID" sleep 1 else header_info - echo -e "${BL}[Info]${GN} Leaving $container running as requested.${CL}" + echo -e "${BL}[Info]${GN} Leaving $CTID running as requested.${CL}" sleep 1 fi fi