621 lines
15 KiB
Bash
Executable File
621 lines
15 KiB
Bash
Executable File
#!/bin/sh
|
|
# bee-tui: interactive text menu for debug LiveCD operations.
|
|
|
|
set -u
|
|
|
|
pause() {
|
|
echo
|
|
printf 'Press Enter to continue... '
|
|
read -r _
|
|
}
|
|
|
|
header() {
|
|
clear
|
|
echo "=============================================="
|
|
echo " bee TUI (debug)"
|
|
echo "=============================================="
|
|
echo
|
|
}
|
|
|
|
list_ifaces() {
|
|
ip -o link show \
|
|
| awk -F': ' '{print $2}' \
|
|
| grep -v '^lo$' \
|
|
| grep -vE '^(docker|virbr|veth|tun|tap|br-|bond|dummy)' \
|
|
| sort
|
|
}
|
|
|
|
show_network_status() {
|
|
header
|
|
echo "Network interfaces"
|
|
echo
|
|
for iface in $(list_ifaces); do
|
|
state=$(ip -o link show "$iface" | awk '{print $9}')
|
|
ipv4=$(ip -o -4 addr show dev "$iface" | awk '{print $4}' | paste -sd ',')
|
|
[ -n "$ipv4" ] || ipv4="(no IPv4)"
|
|
echo "- $iface: state=$state ip=$ipv4"
|
|
done
|
|
echo
|
|
ip route | sed 's/^/ route: /'
|
|
pause
|
|
}
|
|
|
|
choose_interface() {
|
|
ifaces="$(list_ifaces)"
|
|
if [ -z "$ifaces" ]; then
|
|
echo "No physical interfaces found"
|
|
return 1
|
|
fi
|
|
|
|
echo "$ifaces" | nl -w2 -s'. '
|
|
echo
|
|
printf 'Select interface number: '
|
|
read -r idx
|
|
iface=$(echo "$ifaces" | sed -n "${idx}p")
|
|
if [ -z "$iface" ]; then
|
|
echo "Invalid interface selection"
|
|
return 1
|
|
fi
|
|
CHOSEN_IFACE="$iface"
|
|
return 0
|
|
}
|
|
|
|
network_dhcp_one() {
|
|
header
|
|
echo "DHCP on one interface"
|
|
echo
|
|
choose_interface || { pause; return; }
|
|
|
|
iface="$CHOSEN_IFACE"
|
|
echo
|
|
echo "Starting DHCP on $iface..."
|
|
ip link set "$iface" up 2>/dev/null || true
|
|
udhcpc -i "$iface" -t 5 -T 3
|
|
pause
|
|
}
|
|
|
|
network_dhcp_all() {
|
|
header
|
|
echo "Restarting DHCP on all physical interfaces..."
|
|
echo
|
|
/usr/local/bin/bee-net-restart
|
|
pause
|
|
}
|
|
|
|
network_static_one() {
|
|
header
|
|
echo "Static IPv4 setup"
|
|
echo
|
|
choose_interface || { pause; return; }
|
|
|
|
iface="$CHOSEN_IFACE"
|
|
echo
|
|
printf 'IPv4 address (example 192.168.1.10): '
|
|
read -r ip
|
|
if [ -z "$ip" ]; then
|
|
echo "IP address is required"
|
|
pause
|
|
return
|
|
fi
|
|
|
|
printf 'Netmask (example 24 or 255.255.255.0): '
|
|
read -r mask
|
|
if [ -z "$mask" ]; then
|
|
echo "Netmask is required"
|
|
pause
|
|
return
|
|
fi
|
|
prefix=$(mask_to_prefix "$mask")
|
|
if [ -z "$prefix" ]; then
|
|
echo "Invalid netmask: $mask"
|
|
pause
|
|
return
|
|
fi
|
|
cidr="$ip/$prefix"
|
|
|
|
printf 'Default gateway: '
|
|
read -r gw
|
|
if [ -z "$gw" ]; then
|
|
echo "Default gateway is required"
|
|
pause
|
|
return
|
|
fi
|
|
printf 'DNS server (optional): '
|
|
read -r dns
|
|
|
|
ip link set "$iface" up 2>/dev/null || true
|
|
ip addr flush dev "$iface"
|
|
if ! ip addr add "$cidr" dev "$iface"; then
|
|
echo "Failed to set IP"
|
|
pause
|
|
return
|
|
fi
|
|
|
|
if [ -n "$gw" ]; then
|
|
ip route del default >/dev/null 2>&1 || true
|
|
ip route add default via "$gw" dev "$iface"
|
|
fi
|
|
|
|
if [ -n "$dns" ]; then
|
|
printf 'nameserver %s\n' "$dns" > /etc/resolv.conf
|
|
fi
|
|
|
|
echo
|
|
echo "Static config applied to $iface"
|
|
pause
|
|
}
|
|
|
|
mask_to_prefix() {
|
|
mask="$(echo "$1" | tr -d '[:space:]')"
|
|
case "$mask" in
|
|
0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32)
|
|
echo "$mask"
|
|
return 0
|
|
;;
|
|
esac
|
|
case "$mask" in
|
|
255.0.0.0) echo 8 ;;
|
|
255.128.0.0) echo 9 ;;
|
|
255.192.0.0) echo 10 ;;
|
|
255.224.0.0) echo 11 ;;
|
|
255.240.0.0) echo 12 ;;
|
|
255.248.0.0) echo 13 ;;
|
|
255.252.0.0) echo 14 ;;
|
|
255.254.0.0) echo 15 ;;
|
|
255.255.0.0) echo 16 ;;
|
|
255.255.128.0) echo 17 ;;
|
|
255.255.192.0) echo 18 ;;
|
|
255.255.224.0) echo 19 ;;
|
|
255.255.240.0) echo 20 ;;
|
|
255.255.248.0) echo 21 ;;
|
|
255.255.252.0) echo 22 ;;
|
|
255.255.254.0) echo 23 ;;
|
|
255.255.255.0) echo 24 ;;
|
|
255.255.255.128) echo 25 ;;
|
|
255.255.255.192) echo 26 ;;
|
|
255.255.255.224) echo 27 ;;
|
|
255.255.255.240) echo 28 ;;
|
|
255.255.255.248) echo 29 ;;
|
|
255.255.255.252) echo 30 ;;
|
|
255.255.255.254) echo 31 ;;
|
|
255.255.255.255) echo 32 ;;
|
|
*) return 1 ;;
|
|
esac
|
|
}
|
|
|
|
network_menu() {
|
|
while true; do
|
|
header
|
|
echo "Network"
|
|
echo "1. Show network status"
|
|
echo "2. DHCP on all interfaces"
|
|
echo "3. DHCP on one interface"
|
|
echo "4. Set static IPv4 on one interface"
|
|
echo "5. Back"
|
|
echo
|
|
printf 'Choice: '
|
|
read -r choice
|
|
|
|
case "$choice" in
|
|
1) show_network_status ;;
|
|
2) network_dhcp_all ;;
|
|
3) network_dhcp_one ;;
|
|
4) network_static_one ;;
|
|
5) return ;;
|
|
*) echo "Invalid choice"; pause ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
bee_services_list() {
|
|
for path in /etc/init.d/bee-*; do
|
|
[ -e "$path" ] || continue
|
|
basename "$path"
|
|
done
|
|
}
|
|
|
|
services_status_all() {
|
|
header
|
|
echo "bee service status"
|
|
echo
|
|
for svc in $(bee_services_list); do
|
|
if rc-service "$svc" status >/dev/null 2>&1; then
|
|
echo "- $svc: running"
|
|
else
|
|
echo "- $svc: stopped"
|
|
fi
|
|
done
|
|
pause
|
|
}
|
|
|
|
choose_service() {
|
|
svcs="$(bee_services_list)"
|
|
if [ -z "$svcs" ]; then
|
|
echo "No bee-* services found"
|
|
return 1
|
|
fi
|
|
|
|
echo "$svcs" | nl -w2 -s'. '
|
|
echo
|
|
printf 'Select service number: '
|
|
read -r idx
|
|
svc=$(echo "$svcs" | sed -n "${idx}p")
|
|
if [ -z "$svc" ]; then
|
|
echo "Invalid service selection"
|
|
return 1
|
|
fi
|
|
CHOSEN_SERVICE="$svc"
|
|
return 0
|
|
}
|
|
|
|
service_action_menu() {
|
|
header
|
|
echo "Service action"
|
|
echo
|
|
choose_service || { pause; return; }
|
|
svc="$CHOSEN_SERVICE"
|
|
|
|
echo
|
|
echo "Selected: $svc"
|
|
echo "1. status"
|
|
echo "2. restart"
|
|
echo "3. start"
|
|
echo "4. stop"
|
|
echo "5. toggle start/stop"
|
|
echo
|
|
printf 'Choice: '
|
|
read -r act
|
|
|
|
case "$act" in
|
|
1)
|
|
rc-service "$svc" status || true
|
|
;;
|
|
2)
|
|
rc-service "$svc" restart || true
|
|
;;
|
|
3)
|
|
rc-service "$svc" start || true
|
|
;;
|
|
4)
|
|
rc-service "$svc" stop || true
|
|
;;
|
|
5)
|
|
if rc-service "$svc" status >/dev/null 2>&1; then
|
|
rc-service "$svc" stop || true
|
|
else
|
|
rc-service "$svc" start || true
|
|
fi
|
|
;;
|
|
*)
|
|
echo "Invalid action"
|
|
;;
|
|
esac
|
|
pause
|
|
}
|
|
|
|
services_menu() {
|
|
while true; do
|
|
header
|
|
echo "bee Services"
|
|
echo "1. Status of all bee-* services"
|
|
echo "2. Manage one service (status/restart/start/stop/toggle)"
|
|
echo "3. Back"
|
|
echo
|
|
printf 'Choice: '
|
|
read -r choice
|
|
|
|
case "$choice" in
|
|
1) services_status_all ;;
|
|
2) service_action_menu ;;
|
|
3) return ;;
|
|
*) echo "Invalid choice"; pause ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
confirm_phrase() {
|
|
phrase="$1"
|
|
prompt="$2"
|
|
echo
|
|
printf '%s (%s): ' "$prompt" "$phrase"
|
|
read -r value
|
|
[ "$value" = "$phrase" ]
|
|
}
|
|
|
|
shutdown_menu() {
|
|
while true; do
|
|
header
|
|
echo "Shutdown/Reboot Tests"
|
|
echo "1. Reboot now"
|
|
echo "2. Power off now"
|
|
echo "3. Schedule poweroff in 60s"
|
|
echo "4. Cancel scheduled shutdown"
|
|
echo "5. IPMI chassis power status"
|
|
echo "6. IPMI chassis power soft"
|
|
echo "7. IPMI chassis power cycle"
|
|
echo "8. Back"
|
|
echo
|
|
printf 'Choice: '
|
|
read -r choice
|
|
|
|
case "$choice" in
|
|
1)
|
|
confirm_phrase "REBOOT" "Type confirmation" || { echo "Canceled"; pause; continue; }
|
|
reboot
|
|
;;
|
|
2)
|
|
confirm_phrase "POWEROFF" "Type confirmation" || { echo "Canceled"; pause; continue; }
|
|
poweroff
|
|
;;
|
|
3)
|
|
confirm_phrase "SCHEDULE" "Type confirmation" || { echo "Canceled"; pause; continue; }
|
|
shutdown -P +1 "bee test: scheduled poweroff in 60 seconds"
|
|
echo "Scheduled"
|
|
pause
|
|
;;
|
|
4)
|
|
shutdown -c || true
|
|
echo "Canceled (if any schedule existed)"
|
|
pause
|
|
;;
|
|
5)
|
|
ipmitool chassis power status || echo "ipmitool power status failed"
|
|
pause
|
|
;;
|
|
6)
|
|
confirm_phrase "IPMI-SOFT" "Type confirmation" || { echo "Canceled"; pause; continue; }
|
|
ipmitool chassis power soft || echo "ipmitool soft power failed"
|
|
pause
|
|
;;
|
|
7)
|
|
confirm_phrase "IPMI-CYCLE" "Type confirmation" || { echo "Canceled"; pause; continue; }
|
|
ipmitool chassis power cycle || echo "ipmitool power cycle failed"
|
|
pause
|
|
;;
|
|
8)
|
|
return
|
|
;;
|
|
*)
|
|
echo "Invalid choice"
|
|
pause
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
gpu_burn_10m() {
|
|
header
|
|
echo "GPU Burn (10 minutes)"
|
|
echo
|
|
if ! command -v gpu_burn >/dev/null 2>&1; then
|
|
echo "gpu_burn binary not found in PATH"
|
|
echo "Expected command: gpu_burn"
|
|
pause
|
|
return
|
|
fi
|
|
if ! command -v nvidia-smi >/dev/null 2>&1 || ! nvidia-smi -L >/dev/null 2>&1; then
|
|
echo "NVIDIA driver/GPU not ready (nvidia-smi failed)"
|
|
pause
|
|
return
|
|
fi
|
|
|
|
confirm_phrase "GPU-BURN" "Type confirmation to start benchmark" || { echo "Canceled"; pause; return; }
|
|
echo "Running: gpu_burn 600"
|
|
echo "Log: /var/log/bee-gpuburn.log"
|
|
gpu_burn 600 2>&1 | tee /var/log/bee-gpuburn.log
|
|
echo
|
|
echo "GPU Burn finished"
|
|
pause
|
|
}
|
|
|
|
gpu_benchmarks_menu() {
|
|
while true; do
|
|
header
|
|
echo "Benchmarks -> GPU"
|
|
echo "1. GPU Burn (10 minutes)"
|
|
echo "2. Back"
|
|
echo
|
|
printf 'Choice: '
|
|
read -r choice
|
|
|
|
case "$choice" in
|
|
1) gpu_burn_10m ;;
|
|
2) return ;;
|
|
*) echo "Invalid choice"; pause ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
benchmarks_menu() {
|
|
while true; do
|
|
header
|
|
echo "Benchmarks"
|
|
echo "1. GPU"
|
|
echo "2. Back"
|
|
echo
|
|
printf 'Choice: '
|
|
read -r choice
|
|
|
|
case "$choice" in
|
|
1) gpu_benchmarks_menu ;;
|
|
2) return ;;
|
|
*) echo "Invalid choice"; pause ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
run_cmd_log() {
|
|
label="$1"
|
|
cmd="$2"
|
|
log_file="$3"
|
|
|
|
{
|
|
echo "=== $label ==="
|
|
echo "time: $(date -u '+%Y-%m-%dT%H:%M:%SZ')"
|
|
echo "cmd: $cmd"
|
|
echo
|
|
sh -c "$cmd"
|
|
} >"$log_file" 2>&1
|
|
return $?
|
|
}
|
|
|
|
run_gpu_nvidia_acceptance_test() {
|
|
header
|
|
echo "System acceptance tests -> GPU NVIDIA"
|
|
echo
|
|
confirm_phrase "SAT-GPU" "Type confirmation to start tests" || { echo "Canceled"; pause; return; }
|
|
|
|
ts="$(date -u '+%Y%m%d-%H%M%S')"
|
|
base_dir="/var/log/bee-sat"
|
|
run_dir="$base_dir/gpu-nvidia-$ts"
|
|
archive="$base_dir/gpu-nvidia-$ts.tar.gz"
|
|
mkdir -p "$run_dir"
|
|
|
|
summary="$run_dir/summary.txt"
|
|
: >"$summary"
|
|
|
|
echo "Running acceptance commands..."
|
|
echo "Logs directory: $run_dir"
|
|
echo "Archive target: $archive"
|
|
echo
|
|
|
|
c1="nvidia-smi -q"
|
|
c2="dmidecode -t baseboard"
|
|
c3="dmidecode -t system"
|
|
c4="nvidia-bug-report.sh"
|
|
|
|
run_cmd_log "nvidia_smi_q" "$c1" "$run_dir/01-nvidia-smi-q.log"; rc1=$?
|
|
run_cmd_log "dmidecode_baseboard" "$c2" "$run_dir/02-dmidecode-baseboard.log"; rc2=$?
|
|
run_cmd_log "dmidecode_system" "$c3" "$run_dir/03-dmidecode-system.log"; rc3=$?
|
|
run_cmd_log "nvidia_bug_report" "$c4" "$run_dir/04-nvidia-bug-report.log"; rc4=$?
|
|
|
|
# Collect any bug report artifact generated in cwd.
|
|
bug_report="$(ls -1 nvidia-bug-report.log.gz 2>/dev/null | head -n1 || true)"
|
|
if [ -n "$bug_report" ] && [ -f "$bug_report" ]; then
|
|
cp -f "$bug_report" "$run_dir/"
|
|
fi
|
|
|
|
{
|
|
echo "run_at_utc=$(date -u '+%Y-%m-%dT%H:%M:%SZ')"
|
|
echo "cmd_nvidia_smi_q_rc=$rc1"
|
|
echo "cmd_dmidecode_baseboard_rc=$rc2"
|
|
echo "cmd_dmidecode_system_rc=$rc3"
|
|
echo "cmd_nvidia_bug_report_rc=$rc4"
|
|
} >>"$summary"
|
|
|
|
tar -czf "$archive" -C "$base_dir" "gpu-nvidia-$ts"
|
|
tar_rc=$?
|
|
echo "archive_rc=$tar_rc" >>"$summary"
|
|
|
|
echo
|
|
echo "Done."
|
|
echo "- Logs: $run_dir"
|
|
echo "- Archive: $archive (rc=$tar_rc)"
|
|
pause
|
|
}
|
|
|
|
gpu_nvidia_sat_menu() {
|
|
while true; do
|
|
header
|
|
echo "System acceptance tests -> GPU NVIDIA"
|
|
echo "1. Run command pack"
|
|
echo "2. Back"
|
|
echo
|
|
printf 'Choice: '
|
|
read -r choice
|
|
|
|
case "$choice" in
|
|
1) run_gpu_nvidia_acceptance_test ;;
|
|
2) return ;;
|
|
*) echo "Invalid choice"; pause ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
system_acceptance_tests_menu() {
|
|
while true; do
|
|
header
|
|
echo "System acceptance tests"
|
|
echo "1. GPU NVIDIA"
|
|
echo "2. Back"
|
|
echo
|
|
printf 'Choice: '
|
|
read -r choice
|
|
|
|
case "$choice" in
|
|
1) gpu_nvidia_sat_menu ;;
|
|
2) return ;;
|
|
*) echo "Invalid choice"; pause ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
run_audit_now() {
|
|
header
|
|
echo "Run audit now"
|
|
echo
|
|
/usr/local/bin/audit --output stdout > /var/log/bee-audit.json 2>/var/log/bee-audit.log
|
|
rc=$?
|
|
if [ "$rc" -eq 0 ]; then
|
|
echo "Audit completed successfully"
|
|
else
|
|
echo "Audit finished with errors (rc=$rc)"
|
|
fi
|
|
echo "Logs: /var/log/bee-audit.log, /var/log/bee-audit.json"
|
|
pause
|
|
}
|
|
|
|
check_required_tools() {
|
|
header
|
|
echo "Required tools check"
|
|
echo
|
|
for tool in dmidecode smartctl nvme ipmitool lspci audit nvidia-smi gpu_burn; do
|
|
if command -v "$tool" >/dev/null 2>&1; then
|
|
echo "- $tool: OK ($(command -v "$tool"))"
|
|
else
|
|
echo "- $tool: MISSING"
|
|
fi
|
|
done
|
|
pause
|
|
}
|
|
|
|
main_menu() {
|
|
while true; do
|
|
header
|
|
echo "Main Menu"
|
|
echo "1. Network setup"
|
|
echo "2. bee service management"
|
|
echo "3. Shutdown/reboot tests"
|
|
echo "4. Benchmarks"
|
|
echo "5. System acceptance tests"
|
|
echo "6. Run audit now"
|
|
echo "7. Check required tools"
|
|
echo "8. Show last audit log tail"
|
|
echo "9. Exit to console"
|
|
echo
|
|
printf 'Choice: '
|
|
read -r choice
|
|
|
|
case "$choice" in
|
|
1) network_menu ;;
|
|
2) services_menu ;;
|
|
3) shutdown_menu ;;
|
|
4) benchmarks_menu ;;
|
|
5) system_acceptance_tests_menu ;;
|
|
6) run_audit_now ;;
|
|
7) check_required_tools ;;
|
|
8)
|
|
header
|
|
tail -n 40 /var/log/bee-audit.log 2>/dev/null || echo "No /var/log/bee-audit.log"
|
|
echo
|
|
tail -n 20 /var/log/bee-audit.json 2>/dev/null || true
|
|
pause
|
|
;;
|
|
9) exit 0 ;;
|
|
*) echo "Invalid choice"; pause ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
main_menu
|