moved old files
This commit is contained in:
337
old/harvester-v2.1.sh
Normal file
337
old/harvester-v2.1.sh
Normal file
@@ -0,0 +1,337 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Disk Health Check Script for Harvester OS
|
||||
# Checks SSD TBW/lifespan and HDD health status
|
||||
# Supports RAID controllers and direct disks
|
||||
|
||||
SCRIPT_NAME=$(basename "$0")
|
||||
VERSION="2.1"
|
||||
|
||||
# Color codes
|
||||
RED=$(tput setaf 1)
|
||||
GREEN=$(tput setaf 2)
|
||||
YELLOW=$(tput setaf 3)
|
||||
BLUE=$(tput setaf 4)
|
||||
CYAN=$(tput setaf 6)
|
||||
NC=$(tput sgr0)
|
||||
|
||||
# Function to print colored output
|
||||
print_color() {
|
||||
local color=$1
|
||||
local message=$2
|
||||
echo -e "${color}${message}${NC}"
|
||||
}
|
||||
|
||||
# Check if smartctl is installed
|
||||
command_exists() {
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
if ! command_exists smartctl; then
|
||||
print_color $RED "Error: smartctl is not installed. Please install smartmontools package."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Function to get disk type
|
||||
get_disk_type() {
|
||||
local disk=$1
|
||||
local controller=$2
|
||||
|
||||
local smart_cmd="smartctl"
|
||||
[[ -n "$controller" ]] && smart_cmd+=" -d $controller"
|
||||
smart_cmd+=" -i $disk"
|
||||
|
||||
local info=$($smart_cmd 2>/dev/null)
|
||||
|
||||
if echo "$info" | grep -q "Solid State Device"; then
|
||||
echo "SSD"
|
||||
elif echo "$info" | grep -q "Rotation Rate"; then
|
||||
echo "HDD"
|
||||
else
|
||||
echo "UNKNOWN"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to calculate TBW for SSD
|
||||
calculate_tbw() {
|
||||
local raw_value=$1
|
||||
local sectors=$2
|
||||
|
||||
if [[ -n "$sectors" && "$sectors" != "0" ]]; then
|
||||
# Calculate from sectors (most common)
|
||||
local bytes=$((sectors * 512))
|
||||
local tbw=$(echo "scale=2; $bytes / 1000 / 1000 / 1000 / 1000" | bc -l 2>/dev/null || echo "0")
|
||||
echo "$tbw"
|
||||
elif [[ -n "$raw_value" && "$raw_value" != "0" ]]; then
|
||||
# Try to calculate from raw value (varies by manufacturer)
|
||||
local tbw=$(echo "scale=2; $raw_value * 32 / 1000 / 1000" | bc -l 2>/dev/null || echo "0")
|
||||
echo "$tbw"
|
||||
else
|
||||
echo "0"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to estimate SSD endurance based on model and capacity
|
||||
estimate_ssd_endurance() {
|
||||
local disk_model=$1
|
||||
local capacity_gb=$2
|
||||
|
||||
# Enterprise SSDs typically have higher endurance
|
||||
if echo "$disk_model" | grep -qi "MTFDDAK480TDS\|MICRON\|INTEL\|SAMSUNG"; then
|
||||
# Enterprise SSDs
|
||||
if [[ $capacity_gb -ge 1000 ]]; then
|
||||
echo "1200" # 1.2PB for 1TB enterprise
|
||||
elif [[ $capacity_gb -ge 480 ]]; then
|
||||
echo "600" # 600TB for 480GB enterprise
|
||||
elif [[ $capacity_gb -ge 240 ]]; then
|
||||
echo "300" # 300TB for 240GB enterprise
|
||||
else
|
||||
echo "150" # 150TB for smaller enterprise
|
||||
fi
|
||||
else
|
||||
# Consumer SSDs
|
||||
if [[ $capacity_gb -ge 1000 ]]; then
|
||||
echo "600" # 600TB for 1TB consumer
|
||||
elif [[ $capacity_gb -ge 480 ]]; then
|
||||
echo "300" # 300TB for 480GB consumer
|
||||
elif [[ $capacity_gb -ge 240 ]]; then
|
||||
echo "150" # 150TB for 240GB consumer
|
||||
elif [[ $capacity_gb -ge 120 ]]; then
|
||||
echo "80" # 80TB for 120GB consumer
|
||||
else
|
||||
echo "40" # 40TB for smaller drives
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to estimate SSD lifespan with TBW remaining
|
||||
estimate_ssd_lifespan() {
|
||||
local power_on_hours=$1
|
||||
local tbw_used=$2
|
||||
local disk_model=$3
|
||||
local capacity_gb=$4
|
||||
|
||||
if [[ -z "$power_on_hours" || "$power_on_hours" -eq 0 ]]; then
|
||||
echo "Unknown||Unknown"
|
||||
return
|
||||
fi
|
||||
|
||||
local estimated_endurance=$(estimate_ssd_endurance "$disk_model" "$capacity_gb")
|
||||
local tbw_remaining=$(echo "scale=2; $estimated_endurance - $tbw_used" | bc -l 2>/dev/null || echo "0")
|
||||
|
||||
if [[ $(echo "$tbw_used > 0" | bc -l 2>/dev/null) -eq 1 ]]; then
|
||||
local lifespan_used=$(echo "scale=1; $tbw_used * 100 / $estimated_endurance" | bc -l 2>/dev/null || echo "0")
|
||||
local lifespan_remaining=$(echo "scale=1; 100 - $lifespan_used" | bc -l 2>/dev/null || echo "100")
|
||||
|
||||
if [[ $(echo "$lifespan_used >= 80" | bc -l) -eq 1 ]]; then
|
||||
echo "${RED}${lifespan_remaining}%${NC}|${RED}${tbw_remaining} TB${NC}|High wear"
|
||||
elif [[ $(echo "$lifespan_used >= 50" | bc -l) -eq 1 ]]; then
|
||||
echo "${YELLOW}${lifespan_remaining}%${NC}|${YELLOW}${tbw_remaining} TB${NC}|Moderate wear"
|
||||
else
|
||||
echo "${GREEN}${lifespan_remaining}%${NC}|${GREEN}${tbw_remaining} TB${NC}|Healthy"
|
||||
fi
|
||||
else
|
||||
echo "Unknown|${estimated_endurance} TB|New"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to estimate HDD lifespan
|
||||
estimate_hdd_lifespan() {
|
||||
local power_on_hours=$1
|
||||
local reallocated_sectors=$2
|
||||
local pending_sectors=$3
|
||||
|
||||
if [[ -z "$power_on_hours" ]]; then
|
||||
echo "Unknown"
|
||||
return
|
||||
fi
|
||||
|
||||
# HDD lifespan estimation based on common failure patterns
|
||||
if [[ "$pending_sectors" -gt 0 ]]; then
|
||||
echo "${RED}CRITICAL${NC} (Pending sectors: $pending_sectors)"
|
||||
elif [[ "$reallocated_sectors" -gt 100 ]]; then
|
||||
echo "${RED}< 6 months${NC} (High reallocated sectors: $reallocated_sectors)"
|
||||
elif [[ "$reallocated_sectors" -gt 10 ]]; then
|
||||
echo "${YELLOW}6-12 months${NC} (Reallocated sectors: $reallocated_sectors)"
|
||||
elif [[ "$power_on_hours" -gt 40000 ]]; then
|
||||
echo "${YELLOW}1-2 years${NC} (High usage: $power_on_hours hours)"
|
||||
elif [[ "$power_on_hours" -gt 25000 ]]; then
|
||||
echo "${GREEN}2-3 years${NC} (Moderate usage: $power_on_hours hours)"
|
||||
else
|
||||
echo "${GREEN}> 3 years${NC} (Low usage: $power_on_hours hours)"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to check a single disk
|
||||
check_disk() {
|
||||
local disk=$1
|
||||
local controller=$2
|
||||
|
||||
local smart_cmd="smartctl"
|
||||
[[ -n "$controller" ]] && smart_cmd+=" -d $controller"
|
||||
|
||||
print_color $CYAN "Checking disk: $disk (Controller: ${controller:-direct})"
|
||||
echo "=================================================="
|
||||
|
||||
# Get basic disk information
|
||||
local info=$($smart_cmd -i "$disk" 2>/dev/null)
|
||||
local health=$($smart_cmd -H "$disk" 2>/dev/null)
|
||||
local attributes=$($smart_cmd -A "$disk" 2>/dev/null)
|
||||
|
||||
# Extract disk information
|
||||
local model=$(echo "$info" | grep "Device Model:" | cut -d: -f2 | sed 's/^[ \t]*//')
|
||||
local serial=$(echo "$info" | grep "Serial Number:" | cut -d: -f2 | sed 's/^[ \t]*//')
|
||||
local capacity=$(echo "$info" | grep "User Capacity:" | cut -d: -f2 | sed 's/^[ \t]*//' | cut -d'[' -f1)
|
||||
local firmware=$(echo "$info" | grep "Firmware Version:" | cut -d: -f2 | sed 's/^[ \t]*//')
|
||||
|
||||
# Extract capacity in GB for endurance calculation
|
||||
local capacity_gb=0
|
||||
if [[ $capacity =~ \[([0-9.]+)\s+GB\] ]]; then
|
||||
capacity_gb=${BASH_REMATCH[1]}
|
||||
elif [[ $capacity =~ \[([0-9.]+)\s+TB\] ]]; then
|
||||
capacity_gb=$(echo "${BASH_REMATCH[1]} * 1000" | bc -l 2>/dev/null | cut -d. -f1)
|
||||
fi
|
||||
|
||||
local disk_type=$(get_disk_type "$disk" "$controller")
|
||||
local health_status=$(echo "$health" | grep "result:" | cut -d: -f2 | sed 's/^[ \t]*//')
|
||||
|
||||
# Extract SMART attributes
|
||||
local power_on_hours=$(echo "$attributes" | grep "Power_On_Hours" | awk '{print $10}')
|
||||
local reallocated_sectors=$(echo "$attributes" | grep "Reallocated_Sector_Ct" | awk '{print $10}')
|
||||
local pending_sectors=$(echo "$attributes" | grep "Current_Pending_Sector" | awk '{print $10}')
|
||||
local total_written=$(echo "$attributes" | grep -E "Total_LBAs_Written|Host_Writes_32MiB" | awk '{print $10}')
|
||||
|
||||
# For SSDs with Host_Writes_32MiB
|
||||
local host_writes_32mib=$(echo "$attributes" | grep "Host_Writes_32MiB" | awk '{print $10}')
|
||||
|
||||
# Display basic information
|
||||
echo "Model: $model"
|
||||
echo "Serial: $serial"
|
||||
echo "Type: $disk_type"
|
||||
echo "Capacity: $capacity"
|
||||
echo "Firmware: $firmware"
|
||||
echo "Health: $health_status"
|
||||
echo "Power On Hours: $power_on_hours"
|
||||
|
||||
# Disk type specific analysis
|
||||
if [[ "$disk_type" == "SSD" ]]; then
|
||||
local tbw_used=0
|
||||
if [[ -n "$total_written" && "$total_written" != "0" ]]; then
|
||||
tbw_used=$(calculate_tbw "" "$total_written")
|
||||
elif [[ -n "$host_writes_32mib" && "$host_writes_32mib" != "0" ]]; then
|
||||
tbw_used=$(calculate_tbw "$host_writes_32mib" "")
|
||||
fi
|
||||
|
||||
echo "TBW Used: ${tbw_used} TB"
|
||||
|
||||
local lifespan_info=$(estimate_ssd_lifespan "$power_on_hours" "$tbw_used" "$model" "$capacity_gb")
|
||||
local lifespan_percent=$(echo "$lifespan_info" | cut -d'|' -f1)
|
||||
local tbw_remaining=$(echo "$lifespan_info" | cut -d'|' -f2)
|
||||
local wear_status=$(echo "$lifespan_info" | cut -d'|' -f3)
|
||||
|
||||
echo "TBW Remaining: $tbw_remaining"
|
||||
echo "Lifespan: $lifespan_percent ($wear_status)"
|
||||
|
||||
elif [[ "$disk_type" == "HDD" ]]; then
|
||||
echo "Realloc Sectors: ${reallocated_sectors:-0}"
|
||||
echo "Pending Sectors: ${pending_sectors:-0}"
|
||||
|
||||
local lifespan=$(estimate_hdd_lifespan "$power_on_hours" "${reallocated_sectors:-0}" "${pending_sectors:-0}")
|
||||
echo "Lifespan: $lifespan"
|
||||
else
|
||||
print_color $YELLOW "Unknown disk type - limited information available"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Function to detect RAID controllers and disks
|
||||
detect_raid_disks() {
|
||||
local controllers=("megaraid" "cciss" "areca" "3ware" "hpt")
|
||||
local disks=()
|
||||
|
||||
# Check for direct disks first
|
||||
for disk in /dev/sd[a-z] /dev/nvme[0-9]n[0-9]; do
|
||||
if [[ -b "$disk" ]]; then
|
||||
disks+=("$disk:direct")
|
||||
fi
|
||||
done
|
||||
|
||||
# Check for RAID controllers
|
||||
for controller in "${controllers[@]}"; do
|
||||
for i in {0..15}; do
|
||||
if smartctl -d "$controller,$i" -i /dev/sda >/dev/null 2>&1; then
|
||||
disks+=("/dev/sda:$controller,$i")
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
echo "${disks[@]}"
|
||||
}
|
||||
|
||||
# Main function
|
||||
main() {
|
||||
print_color $BLUE "Disk Health Check Script v$VERSION for Harvester OS"
|
||||
print_color $BLUE "===================================================="
|
||||
echo ""
|
||||
|
||||
local disks=()
|
||||
|
||||
# If specific disk provided, check only that disk
|
||||
if [[ $# -gt 0 ]]; then
|
||||
for disk in "$@"; do
|
||||
if [[ -b "$disk" ]]; then
|
||||
disks+=("$disk:direct")
|
||||
else
|
||||
print_color $RED "Error: $disk is not a valid block device"
|
||||
fi
|
||||
done
|
||||
else
|
||||
# Auto-detect disks
|
||||
print_color $CYAN "Auto-detecting disks..."
|
||||
read -ra disks <<< "$(detect_raid_disks)"
|
||||
fi
|
||||
|
||||
if [[ ${#disks[@]} -eq 0 ]]; then
|
||||
print_color $RED "No disks found or accessible"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_color $GREEN "Found ${#disks[@]} disk(s) to check"
|
||||
echo ""
|
||||
|
||||
# Check each disk
|
||||
for disk_info in "${disks[@]}"; do
|
||||
IFS=':' read -r disk controller <<< "$disk_info"
|
||||
check_disk "$disk" "$controller"
|
||||
done
|
||||
|
||||
print_color $BLUE "Check completed!"
|
||||
}
|
||||
|
||||
# Usage information
|
||||
usage() {
|
||||
echo "Usage: $SCRIPT_NAME [DISK1 DISK2 ...]"
|
||||
echo ""
|
||||
echo "If no disks specified, auto-detects all available disks and RAID arrays"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $SCRIPT_NAME # Check all auto-detected disks"
|
||||
echo " $SCRIPT_NAME /dev/sda # Check specific disk"
|
||||
echo " $SCRIPT_NAME /dev/sda /dev/sdb # Check multiple disks"
|
||||
}
|
||||
|
||||
# Parse command line arguments
|
||||
case "${1:-}" in
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
-v|--version)
|
||||
echo "$SCRIPT_NAME version $VERSION"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
main "$@"
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user