#!/bin/bash

set -e
#set -x

# Make a CSV file of VD (Megacli Virtual Disk) and the PD (Megacli Physical Drives) they use
# and "guess" the matching device name (by using a counter).
megacli_vd_list () {
	VD_LIST=$(mktemp)
	F_PDINFO=$(mktemp)
	megacli -LdPdInfo -a0 -NoLog | grep -E '^Virtual Drive:|^Slot Number:' >${F_PDINFO}

	echo "vd,pd,drive" >${VD_LIST}
	COUNT=-1
	while read line ; do
		# If the line contains : (ie: semicolumn) then it can be parsed
		if echo ${line} | grep -q -E "^Virtual Drive:" ; then
			VD_NUM=$(echo ${line} | sed "s/^Virtual Drive: //" | cut -d' ' -f1)
			COUNT=$((${COUNT} + 1))
		fi
		if echo ${line} | grep -q -E "^Slot Number:" ; then
			SLOT=$(echo "${line}" | sed "s/Slot Number: //")
			case ${COUNT} in
			0) D=sda ;;
			1) D=sdb ;;
			2) D=sdc ;;
			3) D=sdd ;;
			4) D=sde ;;
			5) D=sdf ;;
			6) D=sdg ;;
			7) D=sdh ;;
			8) D=sdi ;;
			9) D=sdj ;;
			10) D=sdk ;;
			11) D=sdl ;;
			12) D=sdm ;;
			13) D=sdn ;;
			14) D=sdo ;;
			15) D=sdp ;;
			16) D=sdq ;;
			17) D=sdr ;;
			18) D=sds ;;
			19) D=sdt ;;
			20) D=sdu ;;
			21) D=sdv ;;
			22) D=sdw ;;
			23) D=sdx ;;
			24) D=sdy ;;
			25) D=sdz ;;
			esac
			echo ${VD_NUM},${SLOT},${D} >>${VD_LIST}
		fi
	done <${F_PDINFO}
	rm -f ${F_PDINFO}
}
# Make a CSV file of the PD (Megacli Physical Disks) and their properties
megacli_pd_list () {
	PD_LIST=$(mktemp)

	ENCLOSURE=$(megacli -EncInfo -aALL -NoLog | awk '/Device ID/ {print $4}')

	echo "Slot,Model,Serial,Size,State,Spun" >${PD_LIST}
	for SLOT_NUM in $(megacli -pdlist -a0 -NoLog | grep "Slot Number:" | cut -d':' -f2 | awk '{print $1}') ; do
		SMT_OUT=$(mktemp)
		smartctl -a -d megaraid,${SLOT_NUM} /dev/sda >${SMT_OUT} || true
		MODEL=$(cat ${SMT_OUT} | grep "^Device Model" | sed 's/^Device Model:     //')
		SERIAL=$(cat ${SMT_OUT} | grep "^Serial Number" | sed 's/^Serial Number:    //')
		SIZE=$(cat ${SMT_OUT} | grep "^User Capacity:" | cut -d'[' -f2 | cut -d']' -f1)
		rm -f ${SMT_OUT}
		FULL_STATE=$(megacli -PDInfo -PhysDrv [${ENCLOSURE}:${SLOT_NUM}] -aALL -NoLog | grep -E '^Firmware state: ' | sed 's/Firmware state: //')
		STATE=$(echo ${FULL_STATE} | cut -d, -f1)
		SPUN=$(echo ${FULL_STATE} | cut -d, -f2 | awk '{$1=$1;print}')
		echo "\"${SLOT_NUM}\",\"${MODEL}\",\"${SERIAL}\",\"${SIZE}\",\"${STATE}\",\"${SPUN}\"" >>${PD_LIST}
	done
}


show_disk_status () {
	if [ ""$(lshw -class storage -json 2>/dev/null | jq -r '.[]["id"]' | head -n1) = "raid" ] ; then
		# Make a VD list CSV with output: vd,pd,drive
		megacli_vd_list
		# Make PD list CSV with output: Slot,Model,Serial,Size,State,Spun
		megacli_pd_list
		# LEFT JOIN both with a single q command
		(echo "PD,VD,Drive,Model,Serial,Size,State,Spun";q -H -d, "SELECT myfiles.Slot,pdvd.vd,pdvd.Drive,myfiles.Model,myfiles.Serial,myfiles.Size,myfiles.State,myfiles.Spun FROM ${PD_LIST} myfiles LEFT JOIN ${VD_LIST} pdvd ON (myfiles.Slot = pdvd.pd) ORDER BY pdvd.vd")
		# rm both temp CSV files
		rm ${VD_LIST}
		rm ${PD_LIST}
	else
#		echo "No raid card"
		echo "devname,Logical_ID,Size,Model,Serial"
		for i in $(ls -v /dev/disk/by-path/ | grep -v part | grep -v usb) ; do
			LOGICAL_ID=$(echo $i | cut -d: -f3)
			DISK_NAME=$(basename $(realpath /dev/disk/by-path/$i))
			dmodel=$(smartctl -a /dev/${DISK_NAME} | grep "Device Model" | sed 's/Device Model:     //')
			dserial=$(smartctl -a /dev/${DISK_NAME} | grep "Serial Number" | sed 's/Serial Number:    //')
			dsize=$(smartctl -a /dev/${DISK_NAME} | grep "User Capacity" | cut -d'[' -f2 | cut -d']' -f1)
			echo ${DISK_NAME},${LOGICAL_ID},$dsize,$dmodel,$dserial
		done
	fi
}

replace_disk () {
	OLD_DISK=$1
	NEW_DISK=$2
	OLD_UUID=$(cat /etc/fstab | grep /srv/node/${OLD_DISK} | awk '{print $1}' | sed -e 's/[#]*UUID=//')
	echo "===> Formating /dev/${NEW_DISK} with UUID ${OLD_UUID}"
	mkfs.xfs -f -m uuid=${OLD_UUID} /dev/${NEW_DISK}
	echo "===> Uncommenting from fstab"
	sed -i "s/[#]*UUID=${OLD_UUID}/UUID=${OLD_UUID}/" /etc/fstab
	echo "===> Mounting /srv/node/${OLD_DISK}"
	mount /srv/node/${OLD_DISK}
	echo "===> Changing disk's owner"
	chown swift:swift /srv/node/${OLD_DISK}
}

usage () {
	echo "                     -l : list devices (columns output)"
	echo "                   -csv : list devices (csv output)"
	echo "                -s <ID> : setup RAID device"
	echo "            -y <ID/sdX> : prepare disk for removal for HDD in slot <ID> or /dev/sdX"
	echo "                          (ie: megacli or hdparm commands)"
	echo "                -u <ID> : stop blinking LED for HDD in slot <ID>"
	echo "-r <hold-hdd> <new-hdd> : format and mount <new-hdd> to replace <old-hdd>"
	exit 1
}

if [ "${1}" = "-csv" ] ; then
	show_disk_status
	exit 0
else
	case ${1} in
	"-s")
		if [ -z "${2}" ] ; then
			usage
		fi
		if [ ""$(lshw -class storage -json 2>/dev/null | jq -r '.[]["id"]' | head -n1) = "raid" ] ; then
			echo "Setting up RAID for device ${2}..."
			megacli -DiscardPreservedCache -Lall -a0
			megacli -CfgLdAdd -r0[32:${2}] WB RA Direct -a0
		else
			echo "Didn't detect hardware RAID"
			exit 1
		fi
		;;
	"-l")
		$0 -csv | csvlook --blanks -I
		PRODUCT_NAME=$(dmidecode -s system-product-name)
		case "${PRODUCT_NAME}" in
		"PowerEdge R720xd")
			echo "HDD (PD) disposition:"
			echo "Col1,Col2,Col3,Col4
0,3,6,9
1,4,7,10
2,5,8,11" | csvlook --blanks -I
		;;
		"CL2800 Gen10")
			echo "HDD disposition:"
			echo "Col1,Col2,Col3,Col4
sda,sdb,sdc,sdd
sdg,sdh,sdi,sdj
sdk,sdl,sdm,sdn" | csvlook --blanks -I
		;;
		*)
		;;
		esac
		exit 0
		;;
	"-r")
		if [ -z "${2}" ] ; then
			usage
		fi
		if [ -z "${3}" ] ; then
			usage
		fi
		replace_disk ${2} ${3}
		;;
	"-y")
		if [ ""$(lshw -class storage -json 2>/dev/null | jq -r '.[]["id"]' | head -n1) = "raid" ] ; then
			ENCLOSURE=$(megacli -EncInfo -aALL -NoLog | awk '/Device ID/ {print $4}')
			case ${2} 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|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48|49|50|51|52|53|54|55|56|57|58|59|60|61|62|63)
				echo "Powering off the drive in slot ${2}"
				megacli -PDOffline -PhysDrv [${ENCLOSURE}:${2}] -aall
				echo "Prepare the drive in slot ${2} for removal"
				megacli -PDPrpRmv -PhysDrv [${ENCLOSURE}:${2}] -aall
				echo "Making the LED of HDD ${2} blink."
				megacli -PdLocate -start -PhysDrv [${ENCLOSURE}:${2}] -aall
				exit 0
			;;
			*)
				echo "HDD slot not recognized: exiting."
				exit 1
			;;
			esac
		else
			case ${2} in
			sda|sdb|sdc|sdd|sde|sdf|sdg|sdh|sdi|sdj|sdk|sdl|sdm|sdn|sdo|sdp|sdq|sdr|sds|sdt|sdu|sdv|sdw|sdx|sdy|sdz)
				echo "Force ${2} to immediately enter the low power consumption standby mode, usually causing it to spin down."
				hdparm -y ${2}
				exit 0
			;;
			*)
				echo "HDD name not recognized: exiting."
				exit 1
			;;
			esac
		fi
		;;
	"-u")
		if [ ""$(lshw -class storage -json 2>/dev/null | jq -r '.[]["id"]' | head -n1) = "raid" ] ; then
			ENCLOSURE=$(megacli -EncInfo -aALL -NoLog | awk '/Device ID/ {print $4}')
			case ${2} 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|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48|49|50|51|52|53|54|55|56|57|58|59|60|61|62|63)
				echo "Stop the blinking of the LED of HDD ${2}."
				megacli -PdLocate -stop -PhysDrv [${ENCLOSURE}:${2}] -aall
				exit 0
			;;
			*)
				echo "HDD slot not recognized: exiting."
				exit 1
			;;
			esac
		else
			echo "This is not possible for non-raid config."
			exit 1
		fi
		;;
	*)
		usage
		;;
	esac
fi
