#!/bin/bash
# -*- mode: shell-script; indent-tabs-mode: t; sh-basic-offset: 8; sh-indentation: 8; sh-indent-for-case-alt: + -*-

script_path=`dirname $0`
script_name=`basename $0`
pbench_bin="`cd ${script_path}/..; /bin/pwd`"
sysinfo=$2

# source the base script
. "$pbench_bin"/base

dir=$(readlink -f $1 2>/dev/null)
if [[ $? -ne 0 ]]; then
	error_log "You must provide a directory that exists, \"$1\" is not a real path"
	exit 1
fi
if [[ ! -d "$dir" ]]; then
	error_log "You must provide a directory that exists, \"$dir\" does not"
	exit 1
fi

label=$3
if [[ -z "$label" ]]; then
	dir="$dir/$hostname"
else
	dir="$dir/$label:$hostname"
fi
mkdir -p $dir
if [[ ! -d "$dir" ]]; then
	error_log "Failed to create the sysinfo directory, \"$dir\""
	exit 1
fi

# generate inventory file with controller and remotes
export INVENTORY=/tmp/inventory.$$
trap "rm -f $INVENTORY" QUIT INT EXIT

function collect_kernel_config {
	if [[ -e /boot/config-$(uname -r) ]] ;then
		cp /boot/config-$(uname -r) $dir
	fi
}

function collect_mitigation_data {
	# spectre and meltdown

	> $dir/security-mitigation-data.txt
	# check the generic vulnerabilities files first
	if [ -d  /sys/devices/system/cpu/vulnerabilities ] ;then
		grep -Hs . /sys/devices/system/cpu/vulnerabilities/* >> $dir/security-mitigation-data.txt
	fi
	# then check the RHEL-specific flag settings files - only
	# applicable on x86_64
	if [ -d /sys/kernel/debug/x86 ] ;then
		echo >> $dir/security-mitigation-data.txt
		grep -Hs . /sys/kernel/debug/x86/*enabled >> $dir/security-mitigation-data.txt
	fi
}

function collect_libvirt {
	if [[ -e /var/log/libvirt && -e /etc/libvirt ]]; then
		debug_log "[$script_name]collecting libvirt data"
		mkdir -p $dir/libvirt/log
		pushd /var/log/libvirt >/dev/null && find . -name "*.log" | cpio -pdum $dir/libvirt/log/ 2>/dev/null
		mkdir -p $dir/libvirt/etc
		pushd /etc/libvirt >/dev/null && find | cpio -pdum $dir/libvirt/etc/ 2>/dev/null
		debug_log "[$script_name]done collecting libvirt data"
	fi
}

function collect_topology {
	debug_log "[$script_name]collecting system topology"
	if [[ -f /usr/bin/lstopo ]]; then
		lstopo --of txt >$dir/lstopo.txt
	fi
	debug_log "[$script_name]done collecting system topology"
}

function collect_block {
	debug_log "[$script_name]collecting block data"
	for n in  /sys/block/[s,h,v]d\*[a-z]/; do
		find $n  -type f -printf "%p " -exec cat '{}' \;  2>/dev/null
	done >$dir/block-params.log
	debug_log "[$script_name]done collecting block data"
}

function collect_sos {
	read sos_ver sos_ver_minor sos_ver_subminor <<< `rpm -q sos | awk -F- '{print $2}' | awk -F. '{print $1" "$2" "$3}'`
	if [[ "${sos_ver}" -lt 3 ]]; then
		_quiet=""
	else
		_quiet=" --quiet"
	fi

	_sos_report_cmd="sosreport"
	_cksum_suffix="md5"

	if [[ ${sos_ver} -lt 3 || ( ${sos_ver} -eq 3 && ( "${sos_ver_minor}" -lt 5 || ( "${sos_ver_minor}" -eq 5 && -z "${sos_ver_subminor}" ) ) ) ]]; then
		# Pre-v3.5.1+
		_modules="general lsbrelease"
	else
		# date host release plugins in sosreport v3.5.1+
		# ref for plugin refactoring: https://github.com/sosreport/sos/commit/971b9581779da20384f0a4d8de5177c0b87d6892
		_modules="date host release"
	fi
	_modules="${_modules} kernel filesys devicemapper system memory hardware networking"
	if [[ "${sos_ver}" -ge 3 ]]; then
		# block processor plugins in sosreport v3.0+
		# ref for plugin block: https://github.com/sosreport/sos/commit/ae0ed73bc855171b353fd0cf42a6dd75755b8c80
		# ref for plugin processor: https://github.com/sosreport/sos/commit/af5e6f75f8ca7794e34f6b57ced9d2ec683564af
		_modules="${_modules} block processor"
	fi
	if [[ "${sos_ver}" -gt 3 || ( "${sos_ver}" -eq 3 && "${sos_ver_minor}" -ge 4 ) ]]; then
		# collectd plugin in sosreport v3.4+
		# ref for plugin collectd: https://github.com/sosreport/sos/commit/8e63b8e5b1bb907685e2debd169e3e87c360f76b
		_modules="${_modules} collectd"
	fi
	if [[ "${sos_ver}" -gt 3 || ( "${sos_ver}" -eq 3 && "${sos_ver_minor}" -ge 2 ) ]]; then
		# tuned plugin in sosreport v3.2+
		# ref for plugin tuned: https://github.com/sosreport/sos/commit/c55c58cf2dabf93c924c839c8ed045c18e31ba1c
		_modules="${_modules} tuned"
	fi
	if [[ "${sos_ver}" -ge 4 ]]; then
		# the command is now "sos report" in 4.0+
		_sos_report_cmd="sos report"
	fi
	if [[ "${sos_ver}" -gt 4 || ( "${sos_ver}" -eq 4 && "${sos_ver_minor}" -ge 1 )]]; then
		# sos uses sha256 sums, not md5, in 4.1+
		_cksum_suffix="sha256"
	fi

	_name="pbench-$(hostname -f)"
	_cmd="${dir}/sosreport-${_name}.cmd"
	printf -- "%s" "${_sos_report_cmd}" > ${_cmd}
	for mod in ${_modules}; do
		printf -- " -o %s" "${mod}" >> ${_cmd}
	done
	printf -- " --batch%s --tmp-dir=\"%s\" --name \"%s\"" "${_quiet}" "${dir}" "${_name}" >> ${_cmd}
	chmod +x ${_cmd}

	debug_log "[${script_name}]collecting sosreport"
	${_cmd} > ${dir}/sosreport-${_name}.log 2>&1

	# Version of sosreport >= 3.6 generate different names for the
	# sosreport tar balls, inserting a short hostname before the
	# label.  Since older versions of sosreport did not do that,
	# we use a wildcard pattern to capture both names when
	# checking for success.
	_sosreport_tb="${dir}/sosreport-*${_name}-*.tar.xz"
	_sosreport_cksum="${_sosreport_tb}.${_cksum_suffix}"
	ls -1 ${_sosreport_tb} ${_sosreport_cksum} > ${dir}/sosreport-names.lis 2> /dev/null
	if [[ $? -ne 0 ]]; then
		error_log "[$script_name]sosreport collection failed!"
	else
		rm -f ${dir}/sosreport-names.lis
		debug_log "[$script_name]done collecting sosreport"
	fi
}

function collect_ara_data {
	# collect data only when ara is installed
	if python -c "import ara" &>/dev/null; then
		mkdir $dir/ara
		generate_inventory > $INVENTORY
		ansible-playbook -i ${INVENTORY} --extra-vars '{"SYSINFO_DIR":"'$dir'"}' "$pbench_install_dir/ansible/ara/ara.yml"
	else
		debug_log "[$script_name]skipping, $item not installed"
	fi
}

function collect_stockpile_data {
	# parse config
	stockpile_path=$(getconf.py stockpile_path stockpile)
	stockpile_user=$(getconf.py stockpile_user stockpile)
	stockpile_local_remote_user=$(getconf.py local_remote_user stockpile)
	stockpile_host_remote_user=$(getconf.py host_remote_user stockpile)
	stockpile_output_path=$(getconf.py stockpile_output_path stockpile)
	stockpile_log=$(getconf.py stockpile_log stockpile)

	if [[ -z "$stockpile_path" ]]; then
		stockpile_path=$pbench_install_dir
	fi

	# set stockpile log file and output paths
	if [[ -z "$stockpile_log" ]]; then
		stockpile_log=$dir/stockpile.log
	fi
	if [[ -z "$stockpile_output_path" ]]; then
		stockpile_output_path=$dir/stockpile.json
	fi

	# generate inventory and run stockpile
	generate_inventory stockpile > $INVENTORY
	debug_log "[$script_name]Collecting stockpile data"
	stockpile_opts="stockpile_user=$stockpile_user local_remote_user=$stockpile_local_remote_user host_remote_user=$stockpile_host_remote_user stockpile_output_path=$stockpile_output_path"
	stockpile_playbook="$stockpile_path/stockpile/stockpile.yml"
	echo "ansible-playbook -vv --extra-vars '"$stockpile_opts"' -i $INVENTORY $stockpile_playbook" > ${benchmark_run_dir}/stockpile.cmd
	chmod +x ${benchmark_run_dir}/stockpile.cmd
	debug_log "Running stockpile with options: $stockpile_opts"
	${benchmark_run_dir}/stockpile.cmd 2>&1 >$stockpile_log
	if [[ $? != 0 ]]; then
		error_log "[$script_name] Stockpile run failed"
		exit 1
	fi
}

function collect_insights_data {
	debug_log "[$script_name]collecting insights data"
	script -c 'insights-client --offline --logging-file $dir/insights-client.log' /dev/null | sed -n 's/.*\sat\s//p' | tr -d "$'\r" | xargs -I '{}' mv {} $dir
	if [[ $? != 0 ]]; then
		error_log "[$script_name] insights-client run failed"
		exit 1
	else
		debug_log "[$script_name]done collecting insights data"
	fi
}


for item in ${sysinfo//,/ };do
	debug_log "[$script_name]: collecting $item"
	if [[ "$item" == "kernel_config" ]]; then
		collect_kernel_config &
	elif [[ "$item" == "security_mitigations" ]]; then
		collect_mitigation_data &
	elif [[ "$item" == "libvirt" ]]; then
		collect_libvirt &
	elif [[ "$item" == "topology" ]]; then
		collect_topology &
	elif [[ "$item" == "sos" ]]; then
		collect_sos &
	elif [[ "$item" == "block" ]]; then
		collect_block &
	elif [[ "$item" == "ara" ]]; then
		collect_ara_data &> $pbench_log
	elif [[ "$item" == "stockpile" ]]; then
		collect_stockpile_data &
	elif [[ "$item" == "insights" ]]; then
                collect_insights_data &
	else
		error_log "[$script_name]bad sysinfo value, \"${item}\""
	fi
done
wait
chmod -R 775 $dir
