mirror of
https://github.com/community-scripts/ProxmoxVE.git
synced 2026-06-27 09:45:00 +02:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 493c3244fd | |||
| 2bd2833c07 | |||
| ab14266389 | |||
| 6f08f3dede |
@@ -0,0 +1,6 @@
|
||||
_______ __ __ __ __
|
||||
/ ____(_)________ _ ______ _________ / / / /___ ____/ /___ _/ /____
|
||||
/ /_ / / ___/ __ `/ | /| / / __ `/ ___/ _ \ / / / / __ \/ __ / __ `/ __/ _ \
|
||||
/ __/ / / / / /_/ /| |/ |/ / /_/ / / / __/ / /_/ / /_/ / /_/ / /_/ / /_/ __/
|
||||
/_/ /_/_/ \__,_/ |__/|__/\__,_/_/ \___/ \____/ .___/\__,_/\__,_/\__/\___/
|
||||
/_/
|
||||
@@ -1,156 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: MickLesk (CanbiZ)
|
||||
# License: MIT
|
||||
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/refs/heads/main/misc/core.func)
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true
|
||||
load_functions
|
||||
declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "disk-health" "pve"
|
||||
|
||||
function header_info {
|
||||
clear
|
||||
cat <<"EOF"
|
||||
____ _ __ __ __ ____ __
|
||||
/ __ \(_)____/ /__ / / / /__ ____ _/ / /_/ /_
|
||||
/ / / / / ___/ //_/ / /_/ / _ \/ __ `/ / __/ __ \
|
||||
/ /_/ / (__ ) ,< / __ / __/ /_/ / / /_/ / / /
|
||||
/_____/_/____/_/|_| /_/ /_/\___/\__,_/_/\__/_/ /_/
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
header_info
|
||||
|
||||
# Must run as root (SMART access requires it)
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
msg_error "This script must be run as root."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v pveversion >/dev/null 2>&1; then
|
||||
msg_error "No Proxmox VE detected!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Install required tooling on demand
|
||||
if ! command -v smartctl >/dev/null 2>&1; then
|
||||
msg_info "Installing smartmontools"
|
||||
apt-get update &>/dev/null
|
||||
if apt-get install -y smartmontools &>/dev/null; then
|
||||
msg_ok "Installed smartmontools"
|
||||
else
|
||||
msg_error "Failed to install smartmontools"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
if ! command -v nvme >/dev/null 2>&1; then
|
||||
msg_info "Installing nvme-cli"
|
||||
if apt-get install -y nvme-cli &>/dev/null; then
|
||||
msg_ok "Installed nvme-cli"
|
||||
else
|
||||
msg_error "nvme-cli not available (NVMe details limited)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Collect physical disks (exclude loop, zram and device-mapper devices)
|
||||
mapfile -t DISKS < <(lsblk -dn -o NAME,TYPE | awk '$2=="disk"{print $1}' | grep -vE '^(loop|zram|dm-)' | sort)
|
||||
|
||||
if [ "${#DISKS[@]}" -eq 0 ]; then
|
||||
msg_error "No physical disks found."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Pull a single attribute value out of "smartctl -A" output by attribute name
|
||||
sata_attr() {
|
||||
local output="$1" name="$2"
|
||||
echo "$output" | awk -v n="$name" '$2==n {print $10; exit}'
|
||||
}
|
||||
|
||||
report_disk() {
|
||||
local dev="$1"
|
||||
local path="/dev/${dev}"
|
||||
local model size health
|
||||
model=$(lsblk -dn -o MODEL "$path" 2>/dev/null | sed 's/[[:space:]]*$//')
|
||||
size=$(lsblk -dn -o SIZE "$path" 2>/dev/null | tr -d ' ')
|
||||
|
||||
echo -e "\n${BL}======================================================${CL}"
|
||||
echo -e "${GN}${path}${CL} ${YW}${size:-?}${CL} ${model:-Unknown model}"
|
||||
echo -e "${BL}======================================================${CL}"
|
||||
|
||||
# Overall SMART health verdict
|
||||
health=$(smartctl -H "$path" 2>/dev/null | grep -iE "SMART overall-health|SMART Health Status" | sed 's/.*: *//')
|
||||
if [ -z "$health" ]; then
|
||||
echo -e " Health: ${YW}SMART not available for this device${CL}"
|
||||
elif echo "$health" | grep -qiE "PASSED|OK"; then
|
||||
echo -e " Health: ${GN}${health}${CL}"
|
||||
else
|
||||
echo -e " Health: ${RD}${health}${CL}"
|
||||
fi
|
||||
|
||||
if [[ "$dev" == nvme* ]]; then
|
||||
local a
|
||||
a=$(smartctl -A "$path" 2>/dev/null)
|
||||
echo "$a" | grep -iE "Temperature:|Available Spare:|Percentage Used:|Data Units Written:|Power On Hours:|Unsafe Shutdowns:|Media and Data Integrity Errors:" |
|
||||
sed 's/^/ /'
|
||||
else
|
||||
local a poh temp realloc pending offline crc wear
|
||||
a=$(smartctl -A "$path" 2>/dev/null)
|
||||
poh=$(sata_attr "$a" "Power_On_Hours")
|
||||
temp=$(sata_attr "$a" "Temperature_Celsius")
|
||||
realloc=$(sata_attr "$a" "Reallocated_Sector_Ct")
|
||||
pending=$(sata_attr "$a" "Current_Pending_Sector")
|
||||
offline=$(sata_attr "$a" "Offline_Uncorrectable")
|
||||
crc=$(sata_attr "$a" "UDMA_CRC_Error_Count")
|
||||
wear=$(sata_attr "$a" "Wear_Leveling_Count")
|
||||
[ -z "$wear" ] && wear=$(sata_attr "$a" "Media_Wearout_Indicator")
|
||||
|
||||
[ -n "$temp" ] && echo -e " Temperature: ${temp} C"
|
||||
[ -n "$poh" ] && echo -e " Power On Hours: ${poh}"
|
||||
[ -n "$wear" ] && echo -e " Wear Leveling/Wearout: ${wear}"
|
||||
print_attr() {
|
||||
local label="$1" val="$2"
|
||||
[ -z "$val" ] && return
|
||||
if [ "$val" -gt 0 ] 2>/dev/null; then
|
||||
echo -e " ${label} ${RD}${val}${CL}"
|
||||
else
|
||||
echo -e " ${label} ${GN}${val}${CL}"
|
||||
fi
|
||||
}
|
||||
print_attr "Reallocated Sectors: " "$realloc"
|
||||
print_attr "Pending Sectors: " "$pending"
|
||||
print_attr "Offline Uncorrectable:" "$offline"
|
||||
print_attr "UDMA CRC Errors: " "$crc"
|
||||
fi
|
||||
}
|
||||
|
||||
header_info
|
||||
echo -e "${YW}Scanning ${#DISKS[@]} disk(s) for SMART health...${CL}"
|
||||
for d in "${DISKS[@]}"; do
|
||||
report_disk "$d"
|
||||
done
|
||||
echo
|
||||
|
||||
# Offer an optional, non-destructive short self-test
|
||||
if whiptail --backtitle "Proxmox VE Helper Scripts" --title "SMART Self-Test" \
|
||||
--yesno "Health report complete.\n\nDo you want to start a non-destructive SHORT SMART self-test on a disk?\n\n(The test runs in the background; check results later with: smartctl -a /dev/XXX)" 14 70; then
|
||||
TEST_MENU=()
|
||||
for d in "${DISKS[@]}"; do
|
||||
TEST_MENU+=("$d" "/dev/$d" "OFF")
|
||||
done
|
||||
sel=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Select Disk for Short Self-Test" \
|
||||
--radiolist "\nSelect a disk:\n" 16 60 6 "${TEST_MENU[@]}" 3>&1 1>&2 2>&3 | tr -d '"')
|
||||
if [ -n "$sel" ]; then
|
||||
msg_info "Starting short self-test on /dev/$sel"
|
||||
if smartctl -t short "/dev/$sel" &>/dev/null; then
|
||||
msg_ok "Short self-test started on /dev/$sel"
|
||||
echo -e "${YW}Check progress/result with: ${GN}smartctl -a /dev/$sel${CL}"
|
||||
else
|
||||
msg_error "Could not start self-test on /dev/$sel"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
echo -e "\n${GN}Disk health check complete.${CL}\n"
|
||||
Executable
+116
@@ -0,0 +1,116 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: MickLesk (CanbiZ)
|
||||
# License: MIT
|
||||
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/refs/heads/main/misc/core.func)
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true
|
||||
load_functions
|
||||
declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "firmware-update" "pve"
|
||||
|
||||
APP="Firmware-Update"
|
||||
APP_TYPE="tools"
|
||||
header_info "$APP"
|
||||
|
||||
# Must run as root
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
msg_error "This script must be run as root."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Must run on Proxmox VE 8.x or 9.x
|
||||
if ! command -v pveversion >/dev/null 2>&1; then
|
||||
msg_error "No Proxmox VE detected!"
|
||||
exit 1
|
||||
fi
|
||||
if ! pveversion | grep -Eq "pve-manager/(8\.[0-4]|9\.[0-9]+)(\.[0-9]+)*"; then
|
||||
msg_error "This version of Proxmox Virtual Environment is not supported."
|
||||
msg_error "Requires Proxmox Virtual Environment Version 8.0-8.4 or 9.x."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Firmware updates only make sense on bare metal. systemd-detect-virt prints
|
||||
# "none" but exits non-zero on bare metal, so a `|| echo none` fallback would
|
||||
# duplicate the value; capture the output as-is instead.
|
||||
virt=$(systemd-detect-virt 2>/dev/null)
|
||||
if [ -n "$virt" ] && [ "$virt" != "none" ]; then
|
||||
msg_error "Firmware updates can only be applied on bare metal. Detected: $virt"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Only x86_64/arm64 with UEFI/LVFS support; fwupd itself handles capability checks
|
||||
whiptail --backtitle "Proxmox VE Helper Scripts" --title "Firmware Update (fwupd / LVFS)" \
|
||||
--yesno "This tool uses fwupd to check for and optionally install firmware updates (UEFI/BIOS and supported devices) from the Linux Vendor Firmware Service (LVFS).\n\nWARNING: Flashing firmware carries risk. Ensure stable power and do not interrupt the process. Some updates require a reboot to be applied.\n\nProceed?" 16 70 || exit 0
|
||||
|
||||
# Install fwupd if missing
|
||||
if ! command -v fwupdmgr >/dev/null 2>&1; then
|
||||
msg_info "Installing fwupd"
|
||||
apt-get update &>/dev/null
|
||||
if ! apt-get install -y fwupd &>/dev/null; then
|
||||
msg_error "Failed to install fwupd"
|
||||
exit 1
|
||||
fi
|
||||
msg_ok "Installed fwupd"
|
||||
else
|
||||
msg_ok "fwupd is already installed"
|
||||
fi
|
||||
|
||||
# Refresh metadata from LVFS
|
||||
msg_info "Refreshing firmware metadata from LVFS"
|
||||
if fwupdmgr refresh --force &>/dev/null; then
|
||||
msg_ok "Refreshed firmware metadata"
|
||||
else
|
||||
# A failed refresh is not fatal (cached metadata may still be usable)
|
||||
msg_error "Could not refresh metadata (continuing with cached data)"
|
||||
fi
|
||||
|
||||
# Show detected, updatable devices. --no-metadata-check / -y keep fwupd from
|
||||
# prompting interactively (e.g. the "metadata is 30 days old, update now?"
|
||||
# question) which would otherwise block and garble the output.
|
||||
echo -e "\n${YW}Detected devices with firmware management support:${CL}\n"
|
||||
fwupdmgr get-devices --no-unreported-check --no-metadata-check 2>/dev/null || true
|
||||
echo
|
||||
|
||||
# Check for available updates (non-interactive)
|
||||
msg_info "Checking for available firmware updates"
|
||||
updates_output=$(fwupdmgr get-updates --no-unreported-check --no-metadata-check -y 2>&1)
|
||||
updates_rc=$?
|
||||
msg_ok "Checked for firmware updates"
|
||||
|
||||
# Many Proxmox hosts have no permanently mounted EFI System Partition (e.g.
|
||||
# ZFS root managed by proxmox-boot-tool). Without it, fwupd cannot stage
|
||||
# UEFI/BIOS capsule updates, so make that explicit instead of burying it.
|
||||
if echo "$updates_output" | grep -qi "ESP partition not detected"; then
|
||||
echo -e "${YW}Note:${CL} No mounted EFI System Partition (ESP) was detected."
|
||||
echo -e " UEFI/BIOS capsule firmware updates cannot be staged on this host."
|
||||
echo -e " Device firmware (e.g. NVMe/SSD) can still be updated if offered.\n"
|
||||
fi
|
||||
|
||||
if [ "$updates_rc" -ne 0 ] || echo "$updates_output" | grep -qiE "No (updates|upgrades) available|Devices with no available firmware updates|No updatable devices"; then
|
||||
whiptail --backtitle "Proxmox VE Helper Scripts" --title "No Firmware Updates" \
|
||||
--msgbox "No applicable firmware updates were found for this system." 10 68
|
||||
echo -e "${GN}Nothing to do.${CL}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo -e "\n${YW}Available firmware updates:${CL}\n"
|
||||
echo "$updates_output"
|
||||
echo
|
||||
|
||||
whiptail --backtitle "Proxmox VE Helper Scripts" --title "Apply Firmware Updates" \
|
||||
--yesno "Firmware updates are available (see terminal output).\n\nDo you want to apply them now?\n\nNOTE: Some updates schedule a flash on the next reboot. Do NOT power off during the process." 14 70 || {
|
||||
echo -e "${YW}Skipped applying updates.${CL}"
|
||||
exit 0
|
||||
}
|
||||
|
||||
msg_info "Applying firmware updates (this may take a while)"
|
||||
echo
|
||||
if fwupdmgr update -y; then
|
||||
msg_ok "Firmware update process completed"
|
||||
echo -e "\n${YW}A reboot may be required to finalize some firmware updates.${CL}\n"
|
||||
else
|
||||
msg_error "Firmware update reported an error. Review the output above."
|
||||
exit 1
|
||||
fi
|
||||
Reference in New Issue
Block a user