#!/bin/sh
#
################################################################################
# Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. 
#
# Generate a SunVTS Stress Test Report
# Usage options:
# -a, --append		Append Output to Existing Report"
# -s --summary 		Generates a Summary Test Report
# -v --verbose		Generates a Verbose Test Report
# -o --output <filename> Output to a file instead of stdout
# -h, --help		Usage
################################################################################

[ `uname -s` != SunOS ] && exit 0

# Some globals used through out this script

#Path to VTS logs
VTSLOGDIR=/var/sunvts/logs
VTSINFO="$VTSLOGDIR/sunvts.info"
VTSINFOBKUP="$VTSLOGDIR/sunvts.info.backup"
VTSRPTOUT="$VTSLOGDIR/.sunvts.rpt.part"
VTSRPT="$VTSLOGDIR/sunvts.rpt"
VTSLATEST="$VTSLOGDIR/.sunvts.info.latest"
VTSLTSUMMARY="$VTSLOGDIR/.sunvts.lt.latest"
VTSDATAEXISTS="$VTSLOGDIR/.sunvts.dataexists"

# Report size limit 5MB
VTSRPTLIMIT=5242880

#Syslog messages file
SYSLOG=/var/adm/messages
SYSLOGSESSION="$VTSLOGDIR/.syslog.session"

#LT names
LTs="Disk Environment Ioports Media Memory Interconnect Network Processor HBA Powermanagement Graphics Removable_Disk Power"

# LTs Listed but we we won't report these for now
# Fjio
# Fjmemory
# Fjprocessor


# Path to FMA log information
FMLOG="$VTSLOGDIR/fma_logs.log"

# Set some common paths
PATH="/sbin:/bin:/usr/sbin/:/usr/bin:$PATH"

#Get hostname and domainname
hostName=`hostname`
domainName=`domainname| awk '{i = index($0,".");print substr($0,i+1)}'`

# Help for the user
usage()
{
	echo >&2 "Usage:  vtsreportgenerate [ -a|--append ] [ -s|--summary] [ -v|--verbose ] [ -o|--output <file> ]"
	echo >&2 "      -a, --append		Append Output to Existing Report"
	echo >&2 "      -s, --summary		Summary Report"
	echo >&2 "      -v, --verbose		Verbose Report"
	echo >&2 "      -o, --output		Output to named file"
	echo >&2 "      -h, --help		This usage message"
}

# Print if no valid sessions data is available
noValidSessions()
{
	# No good sessions available, create NULL snapshot
	touch $VTSLATEST $VTSLTSUMMARY
	splitsession=0
}
# Check and get any FMA Faults information into $FMLOG
printFMAInfo()
{

	# Courtesy Paul Webb - Sun Scotland
	# Modified original FMA information gathering script from Paul Webb.
	# Provides fmadm faulty -ai output for vtsreportgenerate
	
	echo "\nFaults Detected\n" >> $VTSRPTOUT
	#Temporary fault check file to see if anything is faulty
	VTSFMTMP="/tmp/vtsfm.f"
	
	# Clear any lingering logs
	rm -f $FMLOG
	
	mename=`uname -n`
	archk=`arch -k`

	# Determine build ( from /etc/release as uname -v does not tell us s10u build )
	build=`uname -v`
	if [ `echo $build | grep -c snv_` -ne 1 ]; then
		# We must be s10update
		build=`head -1 /etc/release | awk '{print $4}' | sed -e 's/s_u/u/' -e 's/x_u/u/' -e 's/wos//g'`
	fi

	if [ `echo $archk | grep -c i86pc` -gt 0 ]; then
		manu=`smbios -i 1 | grep Manufacturer | cut -d: -f2`
		prod=`smbios -i 1 | grep Product | cut -d: -f2`
		if [ `echo $manu | grep -c "Sun Microsystems"` -eq 0 ]; then
			machine="${manu} ${prod}"
		else
			machine=$prod
		fi
	else
		machine=`uname -i | sed -e 's/SUNW,//g'`
	fi

	machine=`echo $machine | sed -e 's/ /_/g' -e 's/[()]/_/g'`
	[ -z "$machine" ] && machine="other"

	fmadm_ignore="snv_96 snv_97 snv_98"

	if [ "`echo $fmadm_ignore | grep -c $build`" -eq 1 ]; then
		echo $$: $0:fmadm hangs in snv_96 snv_97 snv_98, we have $build, no faults can be displayed >> $VTSRPTOUT
		return
	fi
	
	# Check if anything has been flagged by FMA as faulty
	fmadm faulty > $VTSFMTMP
	# Account for the header when determining if anything is faulty
	if [ "`wc -l $VTSFMTMP | awk '{print $1}'`" -lt 3 ]; then
		echo "\tNo Faults or Suspect Hardware Detected by FMA" >> $VTSRPTOUT
		rm -f $VTSFMTMP
		return
	fi

	rm -f $VTSFMTMP
	fmadm faulty -ai >> $VTSRPTOUT
}

# Get a snap shot of the sunvts.info pertaining to the latest completed SunVTS tests
# Creates a temporary file that is parsed for SunVTS test status data

snapShotVTS()
{
	# The variable below is set if the session info is split over sunvts.info and sunvts.info.backup
	splitsession=1

	# Check if there is a good session run anywhere
	if [ -s $VTSINFO ]
	then
		numSessionStarts=`grep -c "Start all tests" $VTSINFO`
		numSessionStops=`grep -c "Stop all tests" $VTSINFO`
	fi

	if [ -s $VTSINFOBKUP ]
	then
		numBkupStarts=`grep -c "Start all tests" $VTSINFOBKUP`
		numBkupStops=`grep -c "Stop all tests" $VTSINFOBKUP`
	fi

	# Tackle common case first
	if [ ${numSessionStops:=0} -gt 0 -a ${numSessionStarts:=0} -gt 0 ]
	then
		# Current info file may have atleast one session
		stop=`grep -n "Stop all tests" $VTSINFO | cut -d ":" -f1 | tail -1`
		start=`grep -n "Start all tests" $VTSINFO | cut -d ":" -f1 | tail -1`
		if [ $start -gt $stop ]
		then
			# A new session is running seek to the previous start
			newstart=$start
			start=`grep -n "Start all tests" $VTSINFO  | cut -d ":" -f1 | tail -2 | head -n 1`
			if [ $newstart -eq $start ]
			then
				noValidSessions
			else
				sed -n "$start,$stop p" $VTSINFO > $VTSLATEST

				# XXX - Solaris sh appears to have a problem substituting for "$", get over it
				if [ ${newstart:=9999999999} -eq 9999999999 ]
				then
					newstart="$"
				fi
				sed -n "$stop,$newstart p" $VTSINFO > $VTSLTSUMMARY
				splitsession=0
				return
			fi
                else
                        # There is a possible window where an oldsession will have stopped and new vtsk started, but start of the new session
                        # not yet registered, check for this window and handle it correctly
                        newvtskstart=`grep -n "starting" $VTSINFO | cut -d ":" -f1 | tail -1`
                        if [ ${newvtskstart:=0} -gt $stop ]
                        then
                                sed -n "$start, $stop p" $VTSINFO > $VTSLATEST
                                sed -n "$stop, $newvtskstart p" $VTSINFO > $VTSLTSUMMARY
				splitsession=0
				return
                        else
                                sed -n "$start,$stop p" $VTSINFO > $VTSLATEST
                                sed -n "$stop,$ p" $VTSINFO > $VTSLTSUMMARY
				splitsession=0
				return
                        fi
		fi
	fi
	if [ ${numBkupStarts:=0} -gt 0 -a $splitsession -gt 0 ]
	then
		# Backup may contain the last session or a split session
		stop=`grep -n "Stop all tests" $VTSINFOBKUP | cut -d ":" -f1 | tail -1`
		start=`grep -n "Start all tests" $VTSINFOBKUP | cut -d ":" -f1 | tail -1`
		if [ $start -gt ${stop:=0} ]
		then
			# Session may have finished in sunvts.info
			newstop=`grep -n "Stop all tests" $VTSINFO | cut -d ":" -f1 | head -1`
			if [ ${newstop:=0} -gt 0 ]
			then
				sed -n "$start,$ p" $VTSINFOBKUP > $VTSLATEST
				sed -n "1,$newstop p" $VTSINFO >> $VTSLATEST
				start=`grep -n "Start all tests" $VTSINFO  | cut -d ":" -f1 | tail -1 `
                               	# XXX - Solaris sh appears to have a problem substituting for "$", get over it
                       		if [ ${start:=9999999999} -eq 9999999999 ]
                       		then
					start="$"
				fi
                               	sed -n "$newstop,$start p" $VTSINFO > $VTSLTSUMMARY
			else
				# Last session in backup and a new session started
				stop=`grep -n "Stop all tests" $VTSINFOBKUP | cut -d ":" -f1 | tail -1`
				start=`grep -n "Start all tests" $VTSINFOBKUP | cut -d ":" -f1 | tail -1`
				if [ $start -gt ${stop:=0} ]
				then
					# A new session is running seek to the previous start
					newstart=$start
					start=`grep -n "Start all tests" $VTSINFOBKUP  | cut -d ":" -f1 | tail -2 | head -n 1`
					if [ $newstart -eq $start ]
					then
						noValidSessions
					else
						sed -n "$start,$stop p" $VTSINFOBKUP > $VTSLATEST
						sed -n "$stop,$newstart p" $VTSINFOBKUP > $VTSLTSUMMARY
						return
					fi
				else
					# Last session ended normally with nothing started after
					sed -n "$start,$stop p" $VTSINFOBKUP > $VTSLATEST
					sed -n "$stop,$ p" $VTSINFOBKUP > $VTSLTSUMMARY
					return
				fi
			fi
		else
			# Last session ended normally with nothing started after
			sed -n "$start,$stop p" $VTSINFOBKUP > $VTSLATEST
			sed -n "$stop,$ p" $VTSINFOBKUP > $VTSLTSUMMARY
			return
		fi
	fi
}
monthDigitToChar()
{
	case $1 in
		'01') newmonth="Jan" ;;
		'02') newmonth="Feb";;
		'03') newmonth="Mar";;
		'04') newmonth="Apr";;
		'05') newmonth="May";;
		'06') newmonth="Jun";;
		'07') newmonth="Jul";;
		'08') newmonth="Aug" ;;
		'09') newmonth="Sep";;
		'10') newmonth="Oct";;
		'11') newmonth="Nov";;
		'12') newmonth="Dec";;
		default) newmonth="";; # Something's wrong, should never get here
	esac
}

# Get a snapshot of the relevant range of syslog
snapShotSyslog()
{
	smonth=$1
	sday=$2
	if [ $sday -lt 10 ]
	then
		sday=".$2"
	fi
	stime=$3
	emonth=$4
	eday=$5
	if [ $eday -lt 10 ]
	then
		eday=".$5"
	fi

	etime=$6

	# Convert numeric month to character month for syslog format
	monthDigitToChar $smonth
	smonth=$newmonth
	monthDigitToChar $emonth
	emonth=$newmonth
	
	startLog=`grep -n "$smonth $sday " $SYSLOG | cut -d ":" -f1 | head -n 1`
	endLog=`grep -n "$emonth $eday " $SYSLOG | cut -d ":" -f1 | tail -1`
	# Check if any syslog exists for VTS session
	if [ ${startLog:=0} -eq 0 -o ${endLog:=0} -eq 0 ]
	then
			touch $SYSLOGSESSION
	elif [ $startLog -eq $endLog ]
		# sed will complain if there is only one line, handle this case
	then
		grep -n "$smonth $sday " $SYSLOG > $SYSLOGSESSION
	else
		# 2 or more syslog messages exist
		sed -n "$startLog,$endLog p" $SYSLOG > $SYSLOGSESSION
	fi
}

# Print summary severity levels of SunVTS messages
printSummarySunVTS()
{
	echo "" >> $VTSRPTOUT
	echo "SunVTS Messages" >> $VTSRPTOUT
	echo ""  >> $VTSRPTOUT

	if [ -s $VTSLATEST ]
	then
		awk '{if (index($7, ".FATAL") > 0) print $0;\
			if (index($7, ".ERROR") > 0) print $0;}'  $VTSLATEST > $VTSDATAEXISTS
		if [ -s $VTSDATAEXISTS ]
		then
			cat $VTSDATAEXISTS >> $VTSRPTOUT
		else
			echo "\tNone"  >> $VTSRPTOUT
		fi
	else
		echo "\tNone"  >> $VTSRPTOUT
	fi
	rm -f $VTSDATAEXISTS
}

# Print verbose severity levels of SunVTS messages
printVerboseSunVTS()
{
	echo "" >> $VTSRPTOUT
	echo "SunVTS Messages" >> $VTSRPTOUT
	echo ""  >> $VTSRPTOUT

	if [ -s $VTSLATEST ]
	then
		awk '{if (index($7, ".FATAL") > 0) print $0;\
			if (index($7, ".ERROR") > 0) print $0;\
			if (index($7, ".ALERT") > 0) print $0;}'  $VTSLATEST > $VTSDATAEXISTS
		if [ -s $VTSDATAEXISTS ]
		then
			cat $VTSDATAEXISTS >> $VTSRPTOUT
		else
			echo "\tNone"  >> $VTSRPTOUT
		fi
	else
		echo "\tNone"  >> $VTSRPTOUT
	fi
	rm -f $VTSDATAEXISTS
}

# Summary report format
printLatestSummary()
{
	echo "" >> $VTSRPTOUT
	echo "SunVTS Summary Test Report" >> $VTSRPTOUT
	echo "" >> $VTSRPTOUT

	if [ -s $VTSLATEST ]
	then
		# There is atleast one session completed
		# SunVTS Version and Build information
		awk '{if (index($0, "*SunVTS daemon vtsk") > 0) printf ("SunVTS Version %s %s %s %s", $13, $14, $15, $16) ; exit}' $VTSLATEST >> $VTSRPTOUT

		# Timestamp and Hostname
		echo "" >> $VTSRPTOUT
		echo "Latest Test Session Start Time: `awk '{if (index($0, \"Start all tests\") > 0)  printf(\"	%s %s\", $1,$2);}' $VTSLATEST`" >> $VTSRPTOUT
		echo "Latest Test Session End   Time: `awk '{if (index($0, \"Stop all tests\") > 0)  printf(\"	%s %s\", $1,$2);}' $VTSLATEST`" >> $VTSRPTOUT
		echo ""  >> $VTSRPTOUT
		echo "Hostname: 	$hostName.$domainName" >> $VTSRPTOUT
		echo "" >> $VTSRPTOUT

		echo "Logical Test Status" >> $VTSRPTOUT
		echo "" >> $VTSRPTOUT
		for lt in $LTs
		do
			# Need the extra escaped spaces for LTs starting with similar names
			grep -i \^$lt\ \ \     $VTSLTSUMMARY > /dev/null 2>&1
			if [ $? -eq 0 ]
			then 
				nopass=0
				pass="`grep -i \^$lt\ \ \    $VTSLTSUMMARY | cut -d: -f2 | cut -d\  -f2`"
				error="`grep -i \^$lt\ \ \    $VTSLTSUMMARY | cut -d: -f3 | cut -d\   -f2`"
				if [ $error -gt 0 ]
				then
					nopass=1
				fi
				if [ $pass -eq 0 ]
				then
					# if LT not enabled in this session, skip
					if [ $error -eq  0 ]
					then
						echo "	$lt: NO RESULT" >> $VTSRPTOUT
						continue
					fi
				fi
				if [ $nopass -gt 0 ]
				then
					echo "	$lt: FAIL" >> $VTSRPTOUT
				else
					echo "	$lt: PASS" >> $VTSRPTOUT
				fi
			fi
		done

	else
		echo "	No SunVTS sessions registered" >> $VTSRPTOUT
	fi

	#Print FMA Faults and Suspects
	printFMAInfo

	# Print high priority VTS messages
	printSummarySunVTS

	#Print syslog(3C) messages higher than LOG_ERR

	echo "\nSyslog Messages\n" >> $VTSRPTOUT
	 awk '{if (index($8, ".error") > 0) print $0;\
		if (index($8, ".alert") > 0) print $0; \
		if (index($8, ".critical") > 0) print $0;}' $SYSLOGSESSION  > $VTSDATAEXISTS
	if [ -s $VTSDATAEXISTS ]
	then
		cat $VTSDATAEXISTS >> $VTSRPTOUT
	else
		echo "\tNone"  >> $VTSRPTOUT
	fi
	echo "End SunVTS Test Report" >> $VTSRPTOUT

}


# Verbose report format
printLatestVerbose()
{
	echo "" >> $VTSRPTOUT
	echo "SunVTS Verbose Test Report" >> $VTSRPTOUT
	echo "" >> $VTSRPTOUT

	if [ -s $VTSLATEST ]
	then
		# There is atleast one session completed
		# SunVTS Version and Build information
		awk '{if (index($0, "*SunVTS daemon vtsk") > 0) printf ("SunVTS Version %s %s %s %s", $13, $14, $15, $16) ; exit}' $VTSLATEST >> $VTSRPTOUT

		# Timestamp and Hostname
		echo "" >> $VTSRPTOUT
		echo "Latest Test Session Start Time: `awk '{if (index($0, \"Start all tests\") > 0)  printf(\"	%s %s\", $1,$2);}' $VTSLATEST`" >> $VTSRPTOUT
		echo "Latest Test Session End   Time: `awk '{if (index($0, \"Stop all tests\") > 0)  printf(\"	%s %s\", $1,$2);}' $VTSLATEST`" >> $VTSRPTOUT
		echo "" >> $VTSRPTOUT
		echo "Hostname:	$hostName.$domainName" >> $VTSRPTOUT
		echo "" >> $VTSRPTOUT

		echo "Logical Test Status" >> $VTSRPTOUT
		echo "" >> $VTSRPTOUT
		for lt in $LTs
		do
			#Need the extra escaped spaces for similar LT names
			grep -i \^$lt\ \ \    $VTSLTSUMMARY > /dev/null 2>&1
			# Check first if there is a result for the LT
			if [ $? -eq 0 ]
			then 
				nopass=0
				pass="`grep -i \^$lt\ \ \    $VTSLTSUMMARY | cut -d: -f2 | cut -d\  -f2`"
				error="`grep -i \^$lt\ \ \    $VTSLTSUMMARY | cut -d: -f3 | cut -d\   -f2`"
				if [ $error -gt 0 ]
				then
					nopass=1
				fi
				if [ $pass -eq 0 ]
				then
					if [ $error -eq 0 ]
					then 
						echo "	$lt: NO RESULT" >> $VTSRPTOUT
						continue
					fi
				fi
				if [ $nopass -gt 0 ]
				then
					echo "	$lt: FAIL" >> $VTSRPTOUT
				else
					echo "	$lt: PASS" >> $VTSRPTOUT
				fi
			fi
		done

		echo "" >> $VTSRPTOUT
		# Print rest of the verbose LT status
		awk '{if ((index($0, "SunVTS") == 0) && (length($0) > 5) && (index ($0, "Elapsed") == 0)) print $0}' $VTSLTSUMMARY >> $VTSRPTOUT

	else
		echo "	No SunVTS sessions registered" >> $VTSRPTOUT
		echo "" >> $VTSRPTOUT
	fi

	#Print FMA Faults and Suspects
	printFMAInfo

	# Print high priority VTS messages
	printVerboseSunVTS

	#Print syslog(3C) messages higher than LOG_ERR
	echo "\nSyslog Messages\n" >> $VTSRPTOUT
	awk '{if (index($8, ".error") > 0) print $0;\
		if (index($8, ".alert") > 0) print $0; \
		if (index($8, ".notice") > 0) print $0; \
		if (index($8, ".warning") > 0) print $0; \
		if (index($8, ".critical") > 0) print $0;}'  $SYSLOGSESSION > $VTSDATAEXISTS
	
	if [ -s $VTSDATAEXISTS ]
	then
		cat $VTSDATAEXISTS >> $VTSRPTOUT
	else
		echo "\tNone" >> $VTSRPTOUT
	fi
	rm -f $VTSDATAEXISTS
	echo "End SunVTS Test Report" >> $VTSRPTOUT
}

# main report flow

# Need super user credentials to run this script
whoami=` id | cut -d\(  -f2 | cut -d\)  -f1`
if [ $whoami != "root" ]
then
	echo "$0: Permission denied. Need root or superuser privileges to execute."
	exit 1
fi

# Summary report by default
summary=1
verbose=0
append=0
nostdout=0
novalid=0

while test $# -ne 0
do
        case "$1" in
                -s | --summary)
			# Protect from conflicting inputs
			summary=1
			verbose=0
                        ;;
                -v | --verbose)
			verbose=1
			summary=0
                        ;;
                -a | --append)
			# Append new report to an existing report
			append=1
                        ;;
                -h | --h*)
                        usage
                        exit 0;;
                -o | --output)
			# Output to specified file instead of stdout
			shift
			VTSRPT=$1
			if [ ${VTSRPT:=".NONE"} = ".NONE" ]
			then
				usage
				exit 2
			fi
			# Disable output to stdout
			nostdout=1
			;;
                -* | --*)
                        echo >&2 "$0: Incorrect Argument passed $1"
                        usage
                        exit 1 ;;
        esac
        shift
done

# Get a snapshot of the latest SunVTS log, this will be the basis for our report
snapShotVTS

if [ -s $VTSLATEST ]
then
	startVTSmon="`awk '{if (index($0, \"Start all tests\") > 0)  if (split($1, a, "/") > 2) 
			print(a[1]) }' $VTSLATEST`"
	startVTSday="`awk '{if (index($0, \"Start all tests\") > 0)  if (split($1, a, "/") > 2) 
			print(a[2]) }' $VTSLATEST`"
	stopVTSmon="`awk '{if (index($0, \"Stop all tests\") > 0)  if (split($1, a, "/") > 2) 
			print(a[1]) }' $VTSLATEST`"
	stopVTSday="`awk '{if (index($0, \"Stop all tests\") > 0)  if (split($1, a, "/") > 2) 
			print(a[2]) }' $VTSLATEST`"
	startVTStime="`awk '{if (index($0, \"Start all tests\") > 0)  printf($2)}' $VTSLATEST`"
	stopVTStime="`awk '{if (index($0, \"Stop all tests\") > 0)  printf($2)}' $VTSLATEST`"

	#snap shot syslog
	snapShotSyslog ${startVTSmon:=0} ${startVTSday:=0} ${startVTStime:=0} ${stopVTSmon:=0} ${stopVTSday:=0}  ${startVTStime:=0}
else
	# There's no vts session to get a range, nothing to do
	touch $SYSLOGSESSION
fi


# Clear any lingering partial reports
rm -f $VTSRPTOUT

# Generate Summary report
if [ $summary -eq 1 ]
then
	printLatestSummary 
fi

# Generate Verbose report
if [ $verbose -eq 1 ]
then
	printLatestVerbose 
fi

# DO all the post-processing
# default report options - vtsreportgenerate, vtsreportgenerate -v
if [ $append -eq 0 -a $nostdout -eq 0 ]
then
	# Display to stdout
	cat $VTSRPTOUT
fi

# Append to an existing report - vtsreportgenerate -a
if [ $append -gt 0 -a $nostdout -eq 0 ]
then
	# Check if report file size limits are exceeded
	RPTSIZE="`ls -l $VTSRPT | cut -d\  -f5`"
	if [ $RPTSIZE -gt $VTSRPTLIMIT ]
	then
		#Report size exceeds 5M limit, copy to a backup first
		mv $VTSRPT $VTSRPTBKUP
	fi

	cat $VTSRPTOUT >> $VTSRPT
fi

# Append to a specifed file - vtsreportgenerate -a -o <filename>
if [ $append -gt 0 -a $nostdout -gt 0 ]
then
	# NOTE: no File size limits apply
	cat $VTSRPTOUT >> $VTSRPT
fi

# Print report to a specifed file - vtsreportgenerate -o <filename>
if [ $append -eq 0 -a $nostdout -gt 0 ]
then
	#NOTE :no File size limits apply
	mv $VTSRPTOUT $VTSRPT
fi

#Cleanup transient files
rm -f $VTSRPTOUT
rm -f $VTSLATEST
rm -f $VTSLTSUMMARY
rm -f $SYSLOGSESSION

exit 0
