diff options
Diffstat (limited to 'core/modules/hardware-stats/data/opt/openslx/scripts/systemd-gather_hw_info')
-rwxr-xr-x | core/modules/hardware-stats/data/opt/openslx/scripts/systemd-gather_hw_info | 308 |
1 files changed, 308 insertions, 0 deletions
diff --git a/core/modules/hardware-stats/data/opt/openslx/scripts/systemd-gather_hw_info b/core/modules/hardware-stats/data/opt/openslx/scripts/systemd-gather_hw_info new file mode 100755 index 00000000..cdeb6d63 --- /dev/null +++ b/core/modules/hardware-stats/data/opt/openslx/scripts/systemd-gather_hw_info @@ -0,0 +1,308 @@ +#!/bin/bash +# Use bash since ash can only do math on 32bit numbers, which is not sufficient for ID44 calculations +# also for negative length to ${x:0:-1} + +# This script gathers information about the hardware and configuration and reports it back to the server + +. /opt/openslx/config + +export LANG=C.UTF-8 +export LC_ALL=C.UTF-8 + +declare -rg REPORTFILE="/run/hwreport" +declare -rg jsonfile="/run/hwreport.json" + +# new json-based reporting, run first in background and wait at the end of script +# This is only supported by Sat3.11, released 12-2023, so keep creating the old format +# too below this call, until we don't support 3.10 anymore. +if ! python3 /opt/openslx/hardware-stats/collect_hw_info_json.py -p > "$jsonfile"; then + echo -n "" > "$jsonfile" +fi & + +tmpmask="/tmp/hwreport-$$." + +mktemp() { + local FILE= + if [ -x /bin/mktemp ]; then + FILE=$( /bin/mktemp "${tmpmask}XXXXXXXX" ) + fi + if [ -z "$FILE" ] && [ -x /opt/openslx/bin/mktemp ]; then + FILE=$( /opt/openslx/bin/mktemp "${tmpmask}XXXXXXXX" ) + fi + if [ -z "$FILE" ]; then + FILE="${tmpmask}$RANDOM$RANDOM$$" + fi + echo "$FILE" +} + +# Run on exit +cleanup_exit() { + wait + rm -f -- "$tmpmask"* # no space! + exit 0 +} + +slxfdisk() { + local binary RET + for binary in "/opt/openslx/sbin/fdisk -u" "busybox fdisk -u" "fdisk"; do + $binary "$@" + RET=$? + [ "$RET" = "127" ] && continue # command not found + [ "$RET" = "1" ] && [ "${binary%% *}" = "busybox" ] && continue # maybe applet not found + return $RET + done + return 127 +} + +################################################################################ +# 1) Get MAC Address used for booting +# +MAC="${SLX_PXE_MAC}" +if [ -z "$MAC" ]; then + # get MAC from sysfs + MAC="$(cat /sys/class/net/${SLX_PXE_NETIF:-br0}/address)" +fi +if [ -z "$MAC" ]; then + BOOTIF="$(grep -Po '(?<=BOOTIF=)[0-9a-f\-:]+' /proc/cmdline)" + [ "${#BOOTIF}" -eq "20" ] && MAC="${BOOTIF:3}" +fi +if [ -z "$MAC" ]; then + echo "Getting MAC from /proc/cmdline failed, using 'ip a'..." + _mac="$(ip a | grep -A 1 ': br0' | grep -o 'ether ..:..:..:..:..:..' | cut -d' ' -f2)" + [ "$_mac" -eq 17 ] && MAC="$_mac" +fi +if [ -z "$MAC" ]; then + MAC="88-77-66-55-44-33" +fi +# always uppercase and dash-separated +MAC="${MAC^^}" +MAC="${MAC//:/-}" +echo "Determined MAC=$MAC" + +################################################################################ +# 2) Number of real and virtual CPU cores +# Virtual, cheap way +VCORES=$(grep '^processor\s' /proc/cpuinfo | sort -u | wc -l) +# Real cores +CPUCORES=$(cat /sys/devices/system/cpu/cpu*/topology/thread_siblings_list | sort -u | wc -l) +CPUSOCKETS=$(grep '^physical id' /proc/cpuinfo | sort -u | wc -l) +# Fallback 1... +if [ -z "$CPUCORES" ] || [ "$CPUCORES" = "0" ]; then + for c in $(dmidecode -t 4 | grep 'Core Enabled' | awk -F ':' '{print $2}'); do + CPUCORES=$(( $CPUCORES + $c )) + done +fi +# Fallback 2... +if [ -z "$CPUCORES" ] || [ "$CPUCORES" = "0" ]; then + CPUCORES=$(grep -E -e '^core id\s*:' -e '^physical id\s*:' /proc/cpuinfo | xargs -l2 echo | sort -u | wc -l) +fi +echo "$CPUCORES real cores, $VCORES with HT" + +################################################################################ +# 3) CPU model name +# +CPUMODEL=$(grep -m1 '^model name\s*:' /proc/cpuinfo | sed 's/^model name\s*:\s*//;s/\s\s*/ /g;s/^ //;s/ $//') +echo "$CPUMODEL" + +################################################################################ +# 4) RAM +# +RAM=$(grep -m1 '^MemTotal:' /proc/meminfo | awk '{print $2}') +RAM=$(( $RAM / 1024 )) +if [ -z "$RAM" ] || [ "$RAM" -lt 500 ]; then + # Fallback to dmidecode + RAM=0 + for c in $(dmidecode -t 17 | grep -o 'Size:.*MB$' | awk '{print $2}'); do + RAM=$(( $RAM + $c )) + done +fi +echo "$RAM MB RAM" + +################################################################################ +# 5) 64bit virtualization support +# +VT="UNSUPPORTED" +CPU_VENDOR=$( grep -m1 '^vendor_id\s*:' /proc/cpuinfo | awk '{print $3}' ) +VIRTTYPE=$(grep -m1 '^flags\s*:' /proc/cpuinfo | grep -wo -e svm -e vmx) +[ -n "$CPU_VENDOR" ] && modprobe msr +echo "CPUID: $CPU_VENDOR" + +if [ "$CPU_VENDOR" = "GenuineIntel" ]; then + BIT1="$( rdmsr --bitfield 0:0 0x3a 2>/dev/null || echo "fail" )" + BIT2="$( rdmsr --bitfield 2:2 0x3a 2>/dev/null || echo "fail" )" + if [ "$BIT1" = "fail" ] || [ "$BIT2" = "fail" ]; then + VT="UNKNOWN" + elif [ "$BIT1" = "1" ] && [ "$BIT2" = "0" ]; then + VT="DISABLED" + elif [ "$VIRTTYPE" = "vmx" ]; then + VT="ENABLED" + fi +elif [ "$CPU_VENDOR" = "AuthenticAMD" ]; then + BIT="$( rdmsr --bitfield 4:4 0xc0010114 2>/dev/null || echo "fail" )" + if [ "$BIT" = "fail" ]; then + VT="UNKNOWN" + elif [ "$BIT" = "1" ]; then + VT="DISABLED" + elif [ "$VIRTTYPE" = "svm" ]; then + VT="ENABLED" + fi +fi +echo "KVM support is $VT" + +################################################################################ +# 6) ID44 partition size +# +ID44=0 +if ! slx-tools fs_path_isvolatile "/tmp/virt" ; then + ID44_SPACE=($(slx-tools fs_path_space "/tmp/virt")) + [ -n "${ID44_SPACE[1]}" ] && ID44="$(( ${ID44_SPACE[1]} / 1024 ))" + + if [ "$ID44" -eq 0 ]; then + # Fallback to old way to detect it + # Try df first, make sure device starts with /dev + read -r df_dev df_size df_used df_avail df_usepercent df_mountpoint df_crap < <(df -P /tmp/virt | grep ' /tmp/virt$') + if [ -n "${df_size}" ] && [ "${df_dev:0:5}" = "/dev/" ]; then + # df reports kbytes, convert to MB + ID44=$(( df_size / 1024 )) + fi + if [ "$ID44" = 0 ]; then + # slxfdisk fallback + for c in $(slxfdisk -l | grep -E '[0-9]+[\-\+MG]?\s+44\s+' | awk '{print $1}'); do + val=$(blockdev --getsize64 "$c") + [ -z "$val" ] && continue + [ "$val" -gt "$ID44" ] && ID44=$val + done + # blockdev reports bytes, convert to MB + ID44=$(( $ID44 / 1058576 )) # we'd rather underreport + fi + fi +fi +echo "Scratch space: $ID44 MB" + +################################################################################ +# 7) check smart values +# +FDISK=$(mktemp) +declare -a DISKS +shopt -s extglob +for disk in /dev/disk/by-path/!(*-part*|*-usb-*); do + [ -L "$disk" ] || continue + disk="$( readlink -f "$disk" )" + DISKS+=("$disk") + slxfdisk -l "$disk" | sed -r 's/\s+[0-9]+,[0-9]+,[0-9]+/ /g;/^\// s/\s[0-9]+\.?[0-9]+[MGT]\s/ /;s/^Units: /Units =foo= /' | awk '{if ($1 !~ /^[0-9]+$/ || $5 ~ /^[0-9a-f]{4}/) { print $0 } else { $5 = "0700 " $5; print $0 }}' # Work around busybox YET AGAIN changing something in an incompatible way +done > "$FDISK" +shopt -u extglob +[ -z "$SLX_SMARTCTL_MIN_REALLOC" ] && SLX_SMARTCTL_MIN_REALLOC=0 +BADSECTORS=0 +if which smartctl; then + ALLSMART=$(mktemp) + FILE=$(mktemp) + [ -z "$FILE" ] && FILE="/tmp/smartctl.$$.$RANDOM.$RANDOM" + for dev in "${DISKS[@]}"; do + smartctl -i -H -A -f "brief" "${dev%n[0-9]}" > "$FILE" + # Exit code might be nonzero to indicate fail status, or because some (but not all) ATA commands + # failed. So instead, see if we at least got basic device information and go on if so. + grep -q -E -e '^Device Model:' -e '^\s*5\s.+\s.+\s.+\s[0-9]' -e '^Model Number:' "$FILE" || continue + echo "NEXTHDD=$dev" >> "$ALLSMART" + cat "$FILE" >> "$ALLSMART" + # parse + OVERALL=$(grep -o "test result: .*$" "$FILE" | cut -c 14-) + [ "x$OVERALL" = "xPASSED" ] && OVERALL="" + REALLOC=$(grep "^ *5 " "$FILE" | awk '{print $8}') + PENDING=$(grep "^ *197 " "$FILE" | awk '{print $8}') + SPINRETRY_VAL=$(grep "^ *10 " "$FILE" | awk '{print $4}') + SPINRETRY_THR=$(grep "^ *10 " "$FILE" | awk '{print $6}') + [ -n "$OVERALL" ] && BADSECTORS=$(( $BADSECTORS + 100 )) + if [ -n "$REALLOC" ] && [ "$REALLOC" -gt "0" ]; then + BADSECTORS=$(( $BADSECTORS + $REALLOC )) + fi + if [ -n "$PENDING" ] && [ "$PENDING" -gt "5" ]; then + BADSECTORS=$(( $BADSECTORS + $PENDING )) + fi + if [ -n "$SPINRETRY_VAL" ] && [ "$SPINRETRY_VAL" -le "$SPINRETRY_THR" ]; then + BADSECTORS=$(( $BADSECTORS + 100 )) + fi + done + rm -f -- "$FILE" +fi +echo "SMART: $OVERALL - $REALLOC reallocated, $PENDING pending" + +################################################################################ +# 8) Read system model and manufacturer +# +dmidec() { + local RETVAL=$(dmidecode "$@" 2>/dev/null | grep -v '^#' | grep -v '^Invalid' | sed 's/\s\s*/ /g;s/^ //;s/ $//') + case "$RETVAL" in + ""|*"Product Name"*|*"be filled"*|"unknown"|*"efault string"*|*"efault String"*|*"product name"*|*"anufacturer"*|*"ystem model"*) + RETVAL="Unknown" + ;; + esac + echo "$RETVAL" +} + +bashesc () { + sed s/\'/\'\"\'\"\'/g <<< $* +} + +HW_MODEL=$(dmidec -q -s system-product-name) +HW_MANUF=$(dmidec -q -s system-manufacturer) +# Try fallback to baseboard +if [ "$HW_MODEL" = "Unknown" ]; then + HW_MODEL=$(dmidec -q -s baseboard-product-name) + HW_MANUF=$(dmidec -q -s baseboard-manufacturer) +fi + +HW_MANUF=$(bashesc "$HW_MANUF") +HW_MODEL=$(bashesc "$HW_MODEL") + +################################################################################ +# Save raw data to report file +# +cat > "$REPORTFILE" <<-EOF +############################### CPU ##################################### +Sockets: $CPUSOCKETS +Real cores: $CPUCORES +Virtual cores: $VCORES +######################## Partition tables ############################### +EOF +cat "$FDISK" >> "$REPORTFILE" +cat >> "$REPORTFILE" <<-EOF +############################ PCI ID ##################################### +EOF +lspci -n -m >> "$REPORTFILE" +cat >> "$REPORTFILE" <<-EOF +########################## dmidecode #################################### +EOF +dmidecode >> "$REPORTFILE" +if [ -n "$ALLSMART" ] && [ -s "$ALLSMART" ]; then + cat >> "$REPORTFILE" <<-EOF + ########################### smartctl #################################### + EOF + cat "$ALLSMART" >> "$REPORTFILE" +fi +cat >> "$REPORTFILE" <<-EOF +######################### +EOF +echo "Created report file" + +[ -n "$ALLSMART" ] && rm -f -- "$ALLSMART" + +################################################################################ +# Save information to local file for later use +# +cat > "/run/hwinfo" <<HORST +HW_KVM='${VT}' +HW_ID44='${ID44}' +HW_MAC='${MAC}' +HW_MBRAM='${RAM}' +HW_HDDCOUNT='${#DISKS[@]}' +HW_BADSECTORS='${BADSECTORS}' +HW_MANUF='${HW_MANUF}' +HW_MODEL='${HW_MODEL}' +HW_CPUMODEL='${CPUMODEL}' +HW_SOCKETS='${CPUSOCKETS}' +HW_CORES='${CPUCORES}' +HW_THREADS='${VCORES}' +HORST + +cleanup_exit |