Compare commits
3 Commits
6125fb9d6b
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| daafb6c4fb | |||
| 76f7aaa64c | |||
| ef004c621e |
21
README.md
21
README.md
@@ -32,6 +32,7 @@ The script requires the following tools to be installed:
|
||||
- smartctl
|
||||
- sensors
|
||||
- lspci
|
||||
- bc
|
||||
|
||||
Optional tools for enhanced diagnostics:
|
||||
- ethtool (for detailed NIC information including link speed and firmware)
|
||||
@@ -73,6 +74,8 @@ curl -sL "http://10.10.10.63:3000/LotusGuild/proxDoc/raw/branch/main/proxDoc.sh"
|
||||
- `--vm-list`: Check VM vitals
|
||||
- `--ct-list`: Check container vitals
|
||||
- `--backup`: Review backup health
|
||||
- `--checks=LIST`: Run only specific checks (comma-separated)
|
||||
- Valid checks: cpu, ram, memory, storage, disk, network, hardware, temps, services, ceph, vms, containers
|
||||
|
||||
## Output Information
|
||||
|
||||
@@ -101,10 +104,26 @@ The script provides detailed information about:
|
||||
|
||||
## Version
|
||||
|
||||
Current Version: 1.1.0
|
||||
Current Version: 1.2.0
|
||||
|
||||
### Changelog
|
||||
|
||||
#### v1.2.0
|
||||
- Fixed variable quoting in disk iteration loops (security)
|
||||
- Added input validation with whitelist of valid options
|
||||
- Added examples to help documentation
|
||||
- Added timeout protection to smartctl and ceph commands
|
||||
- Added `--checks=` option for selective diagnostics
|
||||
- Extracted magic strings into named constants
|
||||
- Added validation for potentially empty variables
|
||||
- Standardized error handling with cleanup trap
|
||||
- Added optional logging infrastructure (PROXDOC_LOGFILE)
|
||||
- Cached disk list and unit files to reduce command overhead
|
||||
- Added efficient process wait utility function
|
||||
- Fixed CPU MHz parsing showing multiple values
|
||||
- Fixed memory DIMM table not displaying data
|
||||
- Fixed bonding_masters showing as network interface
|
||||
|
||||
#### v1.1.0
|
||||
- Added DriveAtlas integration (`--drives`) for physical drive bay mapping
|
||||
- Added Ceph cluster health monitoring (`--ceph`)
|
||||
|
||||
134
proxDoc.sh
134
proxDoc.sh
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
VERSION="1.1.0"
|
||||
VERSION="1.2.0"
|
||||
|
||||
###################
|
||||
# Timeout Configuration
|
||||
@@ -210,15 +210,21 @@ get_disk_health() {
|
||||
}
|
||||
|
||||
get_cpu_info() {
|
||||
local cpu_info cpu_cores cpu_mhz
|
||||
local cpu_info cpu_cores cpu_mhz cpu_max_mhz
|
||||
|
||||
cpu_info=$(grep -m 1 -w 'model name' /proc/cpuinfo 2>/dev/null | awk -F: '{print $2}' | xargs)
|
||||
cpu_cores=$(lscpu 2>/dev/null | grep '^CPU(s):' | awk '{print $2}')
|
||||
cpu_mhz=$(lscpu 2>/dev/null | grep 'MHz' | awk '{print $4}')
|
||||
cpu_cores=$(lscpu 2>/dev/null | grep -E '^CPU\(s\):' | awk '{print $2}')
|
||||
# Get current CPU MHz (first match only) - handle both "CPU MHz:" and "CPU(s) MHz:" formats
|
||||
cpu_mhz=$(lscpu 2>/dev/null | grep -E '^CPU( )?(max )?MHz:' | head -1 | awk -F: '{print $2}' | xargs)
|
||||
cpu_max_mhz=$(lscpu 2>/dev/null | grep -E '^CPU max MHz:' | awk -F: '{print $2}' | xargs)
|
||||
|
||||
echo -e "${GREEN}CPU Model:${NC} ${cpu_info:-Unknown}"
|
||||
echo -e "${GREEN}CPU Cores:${NC} ${cpu_cores:-Unknown}"
|
||||
echo -e "${GREEN}CPU MHz:${NC} ${cpu_mhz:-Unknown}"
|
||||
if [[ -n "$cpu_max_mhz" ]]; then
|
||||
echo -e "${GREEN}CPU MHz:${NC} ${cpu_mhz:-Unknown} (max: ${cpu_max_mhz})"
|
||||
else
|
||||
echo -e "${GREEN}CPU MHz:${NC} ${cpu_mhz:-Unknown}"
|
||||
fi
|
||||
}
|
||||
|
||||
get_ram_info() {
|
||||
@@ -292,97 +298,93 @@ get_motherboard_info() {
|
||||
|
||||
get_memory_details() {
|
||||
echo -e "\n${GREEN}=== Memory DIMM Information ===${NC}"
|
||||
|
||||
# Use a more robust parsing approach
|
||||
local locator size type speed manufacturer
|
||||
local in_device=false
|
||||
|
||||
|
||||
# Print header
|
||||
printf "%-12s %-12s %-10s %-12s %-20s\n" "Slot" "Size" "Type" "Speed" "Manufacturer"
|
||||
printf "%-12s %-12s %-10s %-12s %-20s\n" "----" "----" "----" "-----" "------------"
|
||||
|
||||
|
||||
local locator="" size="" type="" speed="" manufacturer=""
|
||||
local in_device=false
|
||||
local dimm_count=0
|
||||
|
||||
while IFS= read -r line; do
|
||||
# Detect start of a memory device section
|
||||
if [[ "$line" =~ ^Memory[[:space:]]Device ]]; then
|
||||
# If we have data from previous device, print it
|
||||
if [[ -n "$locator" && -n "$size" && ! "$size" =~ (No|Not|Installed) ]]; then
|
||||
# Detect start of a memory device section (may have leading whitespace or not)
|
||||
if [[ "$line" =~ Memory[[:space:]]+Device$ ]] || [[ "$line" == "Memory Device" ]]; then
|
||||
# Print previous device if it had valid data
|
||||
if [[ -n "$locator" && -n "$size" && ! "$size" =~ ^(No|Not)[[:space:]] ]]; then
|
||||
printf "%-12s %-12s %-10s %-12s %-20s\n" \
|
||||
"${locator:-N/A}" \
|
||||
"${size:-N/A}" \
|
||||
"${type:-N/A}" \
|
||||
"${speed:-N/A}" \
|
||||
"${manufacturer:-N/A}"
|
||||
((dimm_count++))
|
||||
fi
|
||||
|
||||
# Reset variables for new device
|
||||
locator=""
|
||||
size=""
|
||||
type=""
|
||||
speed=""
|
||||
manufacturer=""
|
||||
# Reset for new device
|
||||
locator="" size="" type="" speed="" manufacturer=""
|
||||
in_device=true
|
||||
continue
|
||||
fi
|
||||
|
||||
|
||||
# Skip if not in a device section
|
||||
[[ "$in_device" != true ]] && continue
|
||||
|
||||
# Parse fields (case-insensitive, flexible whitespace)
|
||||
if [[ "$line" =~ ^[[:space:]]*Locator:[[:space:]]*(.+)$ ]] && [[ ! "$line" =~ Bank ]]; then
|
||||
|
||||
# Parse fields - be very specific to avoid matching wrong lines
|
||||
# Locator (but not Bank Locator)
|
||||
if [[ "$line" =~ ^[[:space:]]*Locator:[[:space:]]*(.+)$ ]] && [[ ! "$line" == *Bank*Locator* ]]; then
|
||||
locator="${BASH_REMATCH[1]}"
|
||||
locator="${locator// /_}" # Replace spaces with underscores
|
||||
locator="${locator// /_}"
|
||||
# Size
|
||||
elif [[ "$line" =~ ^[[:space:]]*Size:[[:space:]]*(.+)$ ]]; then
|
||||
size="${BASH_REMATCH[1]}"
|
||||
elif [[ "$line" =~ ^[[:space:]]*Type:[[:space:]]*(.+)$ ]]; then
|
||||
# Type (exact match, not Type Detail or other Type fields)
|
||||
elif [[ "$line" =~ ^[[:space:]]*Type:[[:space:]]*([A-Za-z0-9]+)$ ]]; then
|
||||
type="${BASH_REMATCH[1]}"
|
||||
# Skip if it's an error or unknown type
|
||||
[[ "$type" =~ (Unknown|Error|Correction) ]] && type=""
|
||||
# Only clear if it's truly unknown
|
||||
[[ "$type" == "Unknown" ]] && type=""
|
||||
# Speed (exact field)
|
||||
elif [[ "$line" =~ ^[[:space:]]*Speed:[[:space:]]*(.+)$ ]]; then
|
||||
speed="${BASH_REMATCH[1]}"
|
||||
[[ "$speed" =~ Unknown ]] && speed=""
|
||||
[[ "$speed" == "Unknown" ]] && speed=""
|
||||
# Manufacturer
|
||||
elif [[ "$line" =~ ^[[:space:]]*Manufacturer:[[:space:]]*(.+)$ ]]; then
|
||||
manufacturer="${BASH_REMATCH[1]}"
|
||||
[[ "$manufacturer" =~ (Unknown|NO DIMM) ]] && manufacturer=""
|
||||
# Clear common placeholder values
|
||||
[[ "$manufacturer" =~ ^(Unknown|NO[[:space:]]DIMM|Not[[:space:]]Specified)$ ]] && manufacturer=""
|
||||
fi
|
||||
|
||||
# Empty line marks end of device section
|
||||
if [[ -z "$line" ]]; then
|
||||
|
||||
# Empty line or new section marks end
|
||||
if [[ -z "$line" ]] || [[ "$line" =~ ^Handle ]]; then
|
||||
in_device=false
|
||||
fi
|
||||
|
||||
|
||||
done < <(dmidecode -t memory 2>/dev/null)
|
||||
|
||||
# Print last device if it has data
|
||||
if [[ -n "$locator" && -n "$size" && ! "$size" =~ (No|Not|Installed) ]]; then
|
||||
|
||||
# Print last device if valid
|
||||
if [[ -n "$locator" && -n "$size" && ! "$size" =~ ^(No|Not)[[:space:]] ]]; then
|
||||
printf "%-12s %-12s %-10s %-12s %-20s\n" \
|
||||
"${locator:-N/A}" \
|
||||
"${size:-N/A}" \
|
||||
"${type:-N/A}" \
|
||||
"${speed:-N/A}" \
|
||||
"${manufacturer:-N/A}"
|
||||
((dimm_count++))
|
||||
fi
|
||||
|
||||
|
||||
# If no DIMMs were printed, show a message
|
||||
if [[ $dimm_count -eq 0 ]]; then
|
||||
echo " (Unable to parse DIMM details from dmidecode)"
|
||||
fi
|
||||
|
||||
# Memory summary
|
||||
echo -e "\n${GREEN}Memory Summary:${NC}"
|
||||
|
||||
# Count slots more reliably
|
||||
local total_slots=0
|
||||
local populated=0
|
||||
|
||||
while IFS= read -r line; do
|
||||
if [[ "$line" =~ ^[[:space:]]*Locator: ]] && [[ ! "$line" =~ Bank ]]; then
|
||||
((total_slots++))
|
||||
fi
|
||||
done < <(dmidecode -t memory 2>/dev/null)
|
||||
|
||||
while IFS= read -r line; do
|
||||
if [[ "$line" =~ ^[[:space:]]*Size:[[:space:]]*(.+)$ ]]; then
|
||||
local size_val="${BASH_REMATCH[1]}"
|
||||
if [[ ! "$size_val" =~ (No|Not|Installed) ]]; then
|
||||
((populated++))
|
||||
fi
|
||||
fi
|
||||
done < <(dmidecode -t memory 2>/dev/null)
|
||||
|
||||
# Count slots and populated using simpler grep approach
|
||||
# Pattern ^[[:space:]]*Locator: already excludes "Bank Locator:" lines
|
||||
local total_slots populated
|
||||
total_slots=$(dmidecode -t memory 2>/dev/null | grep -c "^[[:space:]]*Locator:")
|
||||
|
||||
populated=$(dmidecode -t memory 2>/dev/null | grep "^[[:space:]]*Size:" | grep -cv "No Module\|Not Installed")
|
||||
|
||||
echo -e " Total Slots: $total_slots"
|
||||
echo -e " Populated: $populated"
|
||||
@@ -445,16 +447,19 @@ get_physical_interfaces() {
|
||||
for iface in /sys/class/net/*; do
|
||||
# Skip if glob didn't match anything
|
||||
[[ -e "$iface" ]] || continue
|
||||
|
||||
|
||||
# Get just the interface name
|
||||
iface=$(basename "$iface")
|
||||
|
||||
|
||||
# Skip loopback
|
||||
[[ "$iface" == "lo" ]] && continue
|
||||
|
||||
|
||||
# Skip bonding_masters (virtual file, not an interface)
|
||||
[[ "$iface" == "bonding_masters" ]] && continue
|
||||
|
||||
# Skip virtual/firewall interfaces
|
||||
[[ "$iface" =~ $VIRTUAL_IFACE_PATTERN ]] && continue
|
||||
|
||||
|
||||
# This is a physical interface
|
||||
echo "$iface"
|
||||
done
|
||||
@@ -662,7 +667,8 @@ check_services() {
|
||||
local services=("pvedaemon" "pveproxy" "pvecluster" "pve-cluster" "corosync")
|
||||
for service in "${services[@]}"; do
|
||||
local status
|
||||
status=$(systemctl is-active "$service" 2>/dev/null || echo "not-found")
|
||||
status=$(systemctl is-active "$service" 2>/dev/null)
|
||||
[[ -z "$status" ]] && status="not-found"
|
||||
echo -e "${GREEN}$service:${NC} $status"
|
||||
done
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user