#!/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`"

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

# This script will collect sysinfo data from all registered
# tools hosts for a specific group. This is typically called
# at the beginning and end of a benchmark script to capture
# the configurations of all hosts involved in the benchmark.

# Defaults
group=default
dir="/tmp"
# array containing all the possible sysinfo options
sysinfo_opts_default=( block libvirt kernel_config security_mitigations sos topology )
sysinfo_opts_available=( block libvirt kernel_config security_mitigations sos topology ara stockpile insights)
# get comma separated values
sysinfo_opts_default_comma_separated=$(IFS=,; echo "${sysinfo_opts_default[*]}")
sysinfo_opts_available_comma_separated=$(IFS=,; echo "${sysinfo_opts_available[*]}")
check=false

# Display sysinfo options
function display_sysinfo_opts {
	printf "default, none, all"
	for item in ${sysinfo_opts_available[*]}; do printf ", %s" $item ; done
	printf "\n"
}

# Process options and arguments

function usage {
	printf "Usage: $script_name [options] beg|end \n"
	printf "\n"
	printf "Options specified can be one of:\n"
	printf -- "\t-d str --dir=str,     str = a directory where the $script_name\n"
	printf -- "\t                            will store and process data\n"
	printf "\n"
	printf -- "\t-g str --group=str,   str = a tool group used in a benchmark\n"
	printf -- "\t                            (the default group is 'default')\n"
	printf "\n"
	printf -- "\t       --sysinfo=str, str = comma separated values of system information to be collected\n"
	printf -- "\t                            available: $(display_sysinfo_opts)\n"
	printf "\n"
	printf -- "\t       --check,       checks if sysinfo is set to one of the accepted values\n"
}

opts=$(getopt -q -o d:g:h --longoptions "dir:,group:,help,options,sysinfo:,check" -n "getopt.sh" -- "$@");
if [ $? -ne 0 ]; then
	printf "\n"
	printf "$script_name: you specified an invalid option\n\n"
	usage
	exit 1
fi
eval set -- "$opts";
while true; do
	case "$1" in
		-g|--group)
		shift;
		if [ -n "$1" ]; then
			group="$1"
			shift;
		fi
		;;
		-d|--dir)
		shift;
		if [ -n "$1" ]; then
			dir="$1"
			shift;
		fi
		;;
		--options)
		display_sysinfo_opts
		exit 0
		;;
		--sysinfo)
		shift;
		if [ -n "$1" ]; then
			sysinfo="$1"
			shift;
		fi
		;;
		--check)
		check=true
		shift;
		;;
		-h|--help)
		usage
		exit 0
		;;
		--)
		shift;
		break;
		;;
	esac
done

# if unspecified, collect the default sysinfo
if [ -z "$sysinfo" ] ;then
	sysinfo=default
fi

# check if the input sysinfo parameter passed by the user is a valid option or not
if $check; then
	debug_log "[$script_name]: sysinfo option is set to $sysinfo"
	if [ "$sysinfo" == "all" ] || [ "$sysinfo" == "default" ] || [ "$sysinfo" == "none" ]; then
		:
	else
		for item in ${sysinfo//,/ }; do
			if echo "${sysinfo_opts_available[@]}" | grep -q -w "$item"; then
				continue
			else
				if [ "$item" == "all" ] || [ "$item" == "default" ] || [ "$item" == "none" ]; then
					:  # Ignore these options in a list
				else
					error_log "invalid sysinfo option, \"$item\""
					exit 1
				fi
			fi
		done
	fi
	exit 0
fi
# don't collect anything if sysinfo is none
if [ "$sysinfo" == "none" ]; then
	exit 0
fi
# collect everything if sysinfo is all
if [ "$sysinfo" == "all" ]; then
	sysinfo=${sysinfo_opts_available_comma_separated}
fi
if [ "$sysinfo" == "default" ]; then
        sysinfo=${sysinfo_opts_default_comma_separated}
fi

name="$1"
if [ -z "$name" ]; then
	error_log "Missing argument, need a name for this sysinfo collection, either \"beg\" or \"end\""
	exit 1
fi
if [ "$name" != "beg" -a "$name" != "end" ]; then
	error_log "Invalid argument, collection names should be either \"beg\" or \"end\", not \"$name\""
	exit 1
fi

# Make sure that the top-level directory exists no matter what
mkdir -p $dir
if [ ! -d $dir ]; then
	error_log "Unable to create working directory, $dir"
	exit 1
fi

# always notify the user, as collection can sometimes take a while
echo "Collecting system information"

# Ensure we have a tools group directory to work with
if [ -d "$pbench_run/tools-$group" ]; then
	tool_group_dir="$pbench_run/tools-$group"
else
	# Using the default group directory
	tool_group_dir="$pbench_run/tools-default"
	if [ ! -d "$tool_group_dir" ]; then
		error_log "Unable to find default tools group file, $tool_group_dir"
		exit 1
	fi
fi

sysinfo_path="$dir/sysinfo/$name"
if [ -d $sysinfo_path ]; then
	debug_log "Already collected sysinfo-dump data, named: $name; skipping..."
	exit 0
fi
mkdir -p $sysinfo_path
if [ ! -d $sysinfo_path ]; then
	error_log "Unable to create sysinfo-dump directory base path: $sysinfo_path"
	exit 1
fi


function gather_remote_sysinfo_data {
	local remote_host=$1
	local remote_label=$2
	debug_log "[$script_name]running sysinfo-dump on $remote_host"
	cmd="ssh $ssh_opts -n $remote_host pbench-remote-sysinfo-dump $sysinfo_path "$sysinfo" $remote_label"
	debug_log "[$script_name] $cmd > $sysinfo_path/$remote_label$remote_host.tar 2> $sysinfo_path/$remote_label$remote_host.err"
	$cmd > $sysinfo_path/$remote_label$remote_host.tar 2> $sysinfo_path/$remote_label$remote_host.err
	if [ $? -ne 0 ]; then
		error_log "Remote sysinfo-dump failed"
		error_log "$(cat $sysinfo_path/$remote_label$remote_host.err)"
	else
		debug_log "[$script_name]completed: deleting sysinfo-dump data on $remote_host"
		debug_log "$(cat $sysinfo_path/$remote_label$remote_host.err)"
		pushd "$sysinfo_path" >/dev/null
		tar xf $remote_label$remote_host.tar
		tar_status=$?
		popd >/dev/null
		if [ $tar_status -ne 0 ]; then
			error_log "Remote tar ball was bad: $sysinfo_path/$remote_label$remote_host.tar"
		fi
	fi
	rm -f $sysinfo_path/$remote_label$remote_host.tar
	rm -f $sysinfo_path/$remote_label$remote_host.err
}


## Collect the sysinfo-dumps in parallel

lcl_label=""
let lcl_cnt=0
for this_tool_file in `/bin/ls $tool_group_dir`; do
        if [ "$this_tool_file" == "label" ]; then
		lcl_label=`cat $tool_group_dir/label`
		let lcl_cnt=lcl_cnt+1
                continue;
        fi
	if echo "$this_tool_file" | grep -q "^remote"; then
		remote_hostname=`echo "$this_tool_file" | awk -F@ '{print $2}'`
		label=`cat $tool_group_dir/$this_tool_file`
		debug_log "gather_remote_sysinfo_data $remote_hostname $label"
		gather_remote_sysinfo_data $remote_hostname $label &
	elif [ -d $tool_group_dir/$this_tool_file ] ;then
		# skip spurious subdirectory of $tool_group_dir
		warn_log "[$script_name]$this_tool_file is a directory in $tool_group_dir; that should not happen. Please consider deleting it."
		continue
	elif [ ! -e "$pbench_bin/tool-scripts/$this_tool_file" ] ;then
		# skip spurious file - not a tool.
		warn_log "[$script_name]$this_tool_file does not exist in $pbench_bin/tool-scripts; spurious file perhaps? Please consider deleting it."
		continue
	else
		# any other file is assumed to be a local tool
		let lcl_cnt=lcl_cnt+1
	fi
done
if [ $lcl_cnt -gt 0 ]; then
	# We found local tools, or a label, specified in the tools group
	# file, so we should collect sysinfo data locally
	pbench-sysinfo-dump "$sysinfo_path" "$sysinfo" "$lcl_label" &
fi
wait

exit 0
