summaryrefslogblamecommitdiffstats
path: root/core/modules/hardware-stats/data/opt/openslx/scripts/systemd-hardware_stats
blob: 1b319faaeff5dd249a10b847720db57fc6fff32e (plain) (tree)
1
2
3
4
5
6
7
8
9
10









                                                                                                        



                                             
          




                                                                 




























                                                                                            

 
            
                        
                                                                                 


                                                                  
                                                                                                        




                           















                                                                                                               
                          
 
                                                                                                              


                                                                                           
                                       
  

                                                                                              
                                      
                                       
  
                 



                                           



                                                             










                                                                                                                 
                                            


                                                                                                             
                

        
                                                             







                                                                                 
                  




                                                                        
                                           




















                                                                         
                       


                        






                                                                                                        

                                                                                        






                                                             
                               

                       
               
                      




                                                                 
                                                                              
                               



                                                                                                                





                                                                          
                                                                    





                                                                         


                                                                    





                                                                                             
                                                               


                                       

                                                                                                                        
                                                                             
                                        

                          
                      
 


                                            
                           


                                                       

  


                                     
  
                           


                            



                                                                         
                      

                                                                         
                           
















                                                                                 
                          


                                          




















                                                                                                  



































                                                                                                                                               
          



              
           












                                                                                                                        
 

                                                                                                                    
 






                                                                                                                
                        
  


                                                                              
       

      
#!/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
export LC_ALL=C

touch "/tmp/hw-delete-list" || exit 10
chmod 0600 "/tmp/hw-delete-list" || exit 11
echo -n "" > "/tmp/hw-delete-list" || exit 12

mktemp() {
	local FILE=
	if [ -x /bin/mktemp ]; then
		FILE=$(/bin/mktemp)
	fi
	if [ -z "$FILE" ] && [ -x /opt/openslx/bin/mktemp ]; then
		FILE=$(/opt/openslx/bin/mktemp)
	fi
	if [ -z "$FILE" ]; then
		local FN DIR
		for DIR in "tmp" "tmp" "tmp" "run/user/$UID" "run"; do
			FN="/${DIR}/${RANDOM}-${$}-${UID}-$(date +%N)"
			[ -e "$FN" ] && continue
			touch "$FN" || continue
			chmod 0600 "$FN" || continue
			echo -n "" > "$FN" || continue
			FILE="$FN"
			break
		done
	fi
	if [ -z "$FILE" ]; then
		# Uhm...
		echo "/dev/null"
		exit 1
	fi
	echo "$FILE" >> "/tmp/hw-delete-list"
	echo "$FILE"
}

# Can't just place all temp file names in a variable since mktemp usually runs in a subshell
cleanup() {
	local FILE=
	while read -r FILE _ || [ -n "$FILE" ]; do
		[ -f "$FILE" ] && rm -f -- "$FILE"
	done < "/tmp/hw-delete-list"
}

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
}

if [ -z "$SLX_REMOTE_LOG" ]; then
	echo "No remote log url given, will not report"
	exit 1
fi

# 1) Get MAC Address used for booting
eval $(grep -Eo BOOTIF=\\S+ /proc/cmdline)
if [ "${#BOOTIF}" -ne "20" ]; then
	echo "Getting MAC from /proc/cmdline failed, using 'ip a'..."
	BOOTIF=01-$(ip a | grep -A 1 ': br0' | grep -o 'ether ..:..:..:..:..:..' | cut -d' ' -f2 | sed s/:/-/g)
	if [ "${#BOOTIF}" -ne "20" ]; then
		echo "FAIL FAIL FAIL"
		BOOTIF="99-88-77-66-55-44-33"
	fi
fi
MAC=${BOOTIF:3}
echo "Determined MAC=$MAC"

# 2) Get machine UUID, with fallback to MAC address if it fails for some reason, or if the UUID is blacklisted
UUID=$(cat /etc/system-uuid)
if [ -z "$UUID" ] || [ "${#UUID}" -ne "36" ]; then
	UUID=$(dmidecode -q -s system-uuid | grep -v '^#' | head -n 1 | tr '[a-z]' '[A-Z]')
	echo "$UUID" > /etc/system-uuid
fi
if [ "${#UUID}" -ne "36" ]; then
	echo "Determined UUID (${UUID}) has not expected length of 36, falling back to MAC..."
	UUID="000000000000001-$BOOTIF"
	echo "$UUID" > /etc/system-uuid
fi
echo "UUID=$UUID"

# 3) Uptime in seconds
UPTIME=$(grep -o -E '^[0-9]+' /proc/uptime)

# 4) 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)
# 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\s*:' /proc/cpuinfo | xargs -l2 echo | sort -u | wc -l)
fi
echo "$CPUCORES real cores, $VCORES with HT"

# 5) 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"

# 6) 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"

# 7) 64bit virtualization support
VT="UNSUPPORTED"
VIRTTYPE=$(grep -m1 '^flags\s*:' /proc/cpuinfo | grep -wo -e svm -e vmx)
[ -n "$VIRTTYPE" ] && modprobe msr
echo "Virtualization technology: $VIRTTYPE"

if [ "$VIRTTYPE" = "vmx" ]; then    # intel
	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" -o "$BIT2" = "fail" ]; then
		VT="UNKNOWN"
	elif [ "$BIT1" = "0" -o "$BIT2" = "1" ]; then
		VT="ENABLED"
	else
		VT="DISABLED"
	fi
elif [ "$VIRTTYPE" = "svm" ]; then  # amd
	BIT=$(rdmsr --bitfield 4:4 0xc0010114 2>/dev/null || echo "fail")
	if [ "$BIT" = "fail" ]; then
		VT="UNKNOWN"
	elif [ "$BIT" = "0" ]; then
		VT="ENABLED"
	else
		VT="DISABLED"
	fi
fi
echo "$VIRTTYPE is $VT"

# 8) ID44 partition size
ID44=0
# 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 /tmp | grep ' /tmp$')
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]+[\-\+]?\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
echo "Temp partition: $ID44 MB"

# 9) check smart values
FDISK=$(mktemp)
slxfdisk -l > "$FDISK"
BADSECTORS=0
if which smartctl; then
	ALLSMART=$(mktemp)
	FILE=$(mktemp)
	[ -z "$FILE" ] && FILE="/tmp/smartctl.$$.$RANDOM.$RANDOM"
	for dev in $(cat "$FDISK" | grep -o '^Disk /dev/\S*:' | cut -c 6-); do
		dev=${dev:0:-1}
		smartctl -i -H -A -f "brief" "$dev" > "$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]' "$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"

# A) 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"|*"product name"*)
			RETVAL="Unknown"
			;;
	esac
	echo "$RETVAL"
}

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

MODEL="$HW_MODEL"
if [ "$HW_MANUF" != "Unknown" ]; then
	MODEL="$MODEL ($HW_MANUF)"
fi
echo "System model: $MODEL"

# n) Dump raw data to a file
DATAFILE=$(mktemp)
cat > "$DATAFILE" <<-EOF
############################### CPU #####################################
Sockets:       $(grep '^physical id' /proc/cpuinfo | sort -u | wc -l)
Real cores:    $CPUCORES
Virtual cores: $VCORES
######################## Partition tables ###############################
EOF
cat "$FDISK" >> "$DATAFILE"
cat >> "$DATAFILE" <<-EOF
############################ PCI ID #####################################
EOF
lspci -n -m >> "$DATAFILE"
cat >> "$DATAFILE" <<-EOF
########################## dmidecode ####################################
EOF
dmidecode >> "$DATAFILE"
if [ -n "$ALLSMART" ] && [ -s "$ALLSMART" ]; then
	cat >> "$DATAFILE" <<-EOF
	########################### smartctl ####################################
	EOF
	cat "$ALLSMART" >> "$DATAFILE"
fi
cat >> "$DATAFILE" <<-EOF
#########################
EOF
echo "Created report file"

[ -n "$ALLSMART" ] && rm -f -- "$ALLSMART"

# Put some info in local file for later use
HDDCOUNT=0
for size in $(cat "$FDISK" | grep -E '^Disk /dev.*[0-9]{11,} bytes' | grep -o -E '[0-9]{11,}'); do
	[ "$size" -gt 50000000000 ] && HDDCOUNT=$(( HDDCOUNT + 1 ))
done
bashesc () {
	sed s/\'/\'\"\'\"\'/g <<<$*
}
HW_MANUF=$(bashesc "$HW_MANUF")
HW_MODEL=$(bashesc "$HW_MODEL")
cat > "/run/hwinfo" <<HORST
HW_KVM='${VT}'
HW_ID44='${ID44}'
HW_MBRAM='${RAM}'
HW_HDDCOUNT='${HDDCOUNT}'
HW_MANUF='${HW_MANUF}'
HW_MODEL='${HW_MODEL}'
HW_CORES='${CPUCORES}'
HW_THREADS='${VCORES}'
HORST

# Build warning logfile (for lightdm)
buildlogfile() {
	. /run/hwinfo
	exec 4> /run/hw-warnings.log
	CONTACT_RZ=
	if [ "$HW_KVM" = "DISABLED" ]; then
		echo "ff0000" "* 64Bit-Gast-Support (VT-x oder AMD-V) ist im BIOS deaktiviert. 64Bit VMs können nicht gestartet werden." >&4
		CONTACT_RZ=jau
	elif [ "$HW_KVM" = "UNSUPPORTED" ]; then
		echo "000000" "* CPU hat keinen 64Bit-Gast-Support (VT-x oder AMD-V). 64Bit VMs können nicht gestartet werden." >&4
	fi
	if [ -n "$HW_MBRAM" ] && [ "$HW_MBRAM" -lt 3400 ]; then
		local GB=$(( ( HW_MBRAM + 300 ) / 1024 ))
		echo "000000" "* Dieser PC hat wenig RAM (${GB}GB). Die Leistung von VM-Sitzungen wird nicht optimal sein." >&4
	fi
	if [ "$HW_ID44" = "0" ]; then
		echo "000000" "* Keine ID44-Partition gefunden. VMs bekommen wenig RAM zugewiesen." >&4
		if [ "$HW_HDDCOUNT" = "0" ]; then
			echo "000000" "  Keine Festplatte erkannt; eine Festplatte wird empfohlen, wenn Sie VMs nutzen wollen." >&4
		elif [ -n "$HW_HDDCOUNT" ]; then
			CONTACT_RZ=klar
		fi
		if [ -n "$HW_MBRAM" ] && [ "$HW_MBRAM" -lt 4500 ]; then
			echo "ff0000" "  Da der PC wenig RAM hat, ist die Einrichtung einer ID44-Partition dringend zu empfehlen." >&4
		fi
	elif [ -n "$HW_ID44" ] && [ "$HW_ID44" -lt 10000 ]; then
		echo "000000" "* Die ID44-Partition ist sehr klein. VM-Sitzungen könnten nach einiger Zeit aus Speichermangel abstürzen." >&4
		CONTACT_RZ=fjeden
	fi
	if [ -n "$SLX_VM_NFS" ] && ! systemctl status mount-vm-store >/dev/null; then
		echo "ff0000" "* Der VM-Store konnte nicht eingehängt werden. VMs können nicht gestartet werden." >&4
		echo "ff0000" "  Versuchen Sie das Problem zu lösen, indem Sie den Computer neu starten." >&4
	fi
	if [ -n "$CONTACT_RZ" ]; then
		echo "000000" " -- " >&4
		echo "000000" " -- Wenden Sie sich ggf. an den bwLehrpool-Support Ihres Rechenzentrums -- " >&4
	fi
}

buildlogfile &

# Fire away
echo "Submitting to $SLX_REMOTE_LOG"
if curl --retry 4 --retry-connrefused \
		--data-urlencode "type=~poweron" --data-urlencode "uuid=$UUID" --data-urlencode "macaddr=$MAC" \
		--data-urlencode "uptime=$UPTIME" --data-urlencode "realcores=$CPUCORES" --data-urlencode "mbram=$RAM" \
		--data-urlencode "kvmstate=$VT" --data-urlencode "cpumodel=$CPUMODEL" --data-urlencode "id44mb=$ID44" \
		--data-urlencode "badsectors=$BADSECTORS" --data-urlencode "systemmodel=$MODEL" \
		--data-urlencode "data@$DATAFILE" "$SLX_REMOTE_LOG" | grep -q "RESULT=0"; then
	echo "Success"
	rm -f -- "$DATAFILE"
	START=$(( $RANDOM % 5 ))
	DELAY=$(( $RANDOM % 20 ))
	cat > "/etc/cron.d/usage_stats" <<-EOF
		# Update usage statistics on server

		SHELL=/bin/sh
		PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/opt/openslx/sbin:/opt/openslx/bin

		${START}-59/5 *   * * *    root    sleep ${DELAY}; /opt/openslx/scripts/cron-system_usage_update
	EOF
	touch "/etc/cron.d" # Sometimes, aufs doesn't update the mtime of dirs when creating files,
	# so cron would not rescan the cron directory
	cleanup
	exit 0
else
	echo "Failed..."
fi

echo "Server doesn't seem to support hardware/usage stats - disabling logging"
rm -f -- "/etc/cron.d/usage_stats"
cleanup
exit 1