#!/bin/bash

#------------------------------------------------------------------------------
# File: eos-rain-test
# Author: Elvin-Alin Sindrilaru - CERN
#------------------------------------------------------------------------------

#/************************************************************************
# * EOS - the CERN Disk Storage System                                   *
# * Copyright (C) 2011 CERN/Switzerland                                  *
# *                                                                      *
# * This program is free software: you can redistribute it and/or modify *
# * it under the terms of the GNU General Public License as published by *
# * the Free Software Foundation, either version 3 of the License, or    *
# * (at your option) any later version.                                  *
# *                                                                      *
# * This program is distributed in the hope that it will be useful,      *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
# * GNU General Public License for more details.                         *
# *                                                                      *
# * You should have received a copy of the GNU General Public License    *
# * along with this program.  If not, see <http://www.gnu.org/licenses/>.*
# ************************************************************************/

#------------------------------------------------------------------------------
# Description: The script is used to test the RAIN-like layouts from EOS.
# Usage:
# eos-rain-test raiddp/raid6/archive/plain dir_test_files root://host//eos_raid_dir tmp_location_dir
#  - first argument is the type of test made 
#  - second arguments specifies the directory from which all files corresponding
#     to the pattern *.rain will be used in the test 
#  - third argument represents the full path to a directory in EOS which has 
#     the proper extended attributes for the type of test specified in the 
#     first argument
#  - fourth argument is a temporary directory in which files read out from EOS
#     are stored. The files put in this directory  will be deleted at the end 
#     of the test. 
#
# The script copies the files in the EOS directories which are using some form
# of RAIN-layout and then tries to read them back and compares the checksum of 
# the initial file put in EOS with the one read back. In the second stage, each
# file system in the EOS configuration is shutdown one by one and the file is 
# read again from EOS to verify if the single stripe recovery mechanism is
# working properly. In the last stage, each two file systems are shutdown and
# again the file is read out of EOS and the match with the original one is tested.
#------------------------------------------------------------------------------

. /etc/init.d/functions

export ERR_MSG1="The provided directory does not have the extended attributes set correctly."

# Set the path to the xrdcp and eos commands, considering it may come from eos-xrootd
export EOS_XROOTSYS=/opt/eos/xrootd/
export LD_LIBRARY_PATH=$EOS_XROOTSYS/lib64/:$LD_LIBRARY_PATH
export PATH=$EOS_XROOTSYS/bin:$PATH
XRDCP=$(command -v xrdcp)
XRDCP="$XRDCP --nopbar"
EOS=$(command -v eos)

if [ "$(whoami)" != "root" ]; then
   SUDO="sudo"
else 
  SUDO=""
fi

#-------------------------------------------------------------------------------
# Write a file to EOS, read it back and compare the checksum
#-------------------------------------------------------------------------------
function write_and_read() 
{
    local SRC=$1
    local DEST=$2
    local FNAME=$3

    echo "Write, read and check test, with file: $FNAME"
    
    # write the file in EOS 
    $XRDCP $SRC/$FNAME $DEST/$FNAME -f 
    
    # read it back in a tmp folder
    $XRDCP $DEST/$FNAME $TMP_LOCATION/$FNAME.tmp -f 
    
    # compute the checksum of initial file and the one read back
    local XSINIT=$(sum $SRC/$FNAME)
    local XSCOPY=$(sum $TMP_LOCATION/$FNAME.tmp)

    # clean up the files in the TMP_LOCATION
    rm -rf $TMP_LOCATION/$FNAME.tmp
    
    test "$XSINIT" = "$XSCOPY" 
    if [[ $? -ne 0 ]]; then
	echo_failure
	exit 1
    fi 
}


#-------------------------------------------------------------------------------
# Read a file from EOS it back and compare the checksum
#-------------------------------------------------------------------------------
function read_and_check() 
{
    local SRC=$1
    local EOS_SRC=$2
    local FNAME=$3

    #echo "Read and check test, with file: $FNAME"
   
    # read it back in a tmp folder
    $XRDCP $EOS_SRC/$FNAME $TMP_LOCATION/$FNAME.tmp -f
    
    # compute the checksum of initial file and the one read back
    local XSINIT=$(sum $SRC/$FNAME)
    local XSCOPY=$(sum $TMP_LOCATION/$FNAME.tmp)

    # clean up the files in the TMP_LOCATION
    rm -rf $TMP_LOCATION/$FNAME.tmp
    
    test "$XSINIT" = "$XSCOPY" 
    if [[ $? -ne 0 ]]; then
	echo_failure
	exit 1
    fi 
}


#-------------------------------------------------------------------------------
# Get the file system ids on which the file has stripes
#-------------------------------------------------------------------------------
function get_file_fs() 
{
    local eos_file=$1
    local rec=$($SUDO $EOS -b file info $eos_file)

    VECT_FS=( $(echo "$rec" | awk '{ if (($6 ~ /booted/) || ($7 ~ /booted/)) print $2 }') )
}



#-------------------------------------------------------------------------------
# Main part
#-------------------------------------------------------------------------------

if [[ $# -eq 0 && $# -gt 5 ]]; 
then 
    echo "Usage: $0 raiddp/raid6/archive/plain dir_test_files root://host//eos_rain_dir tmp_dir"
    exit
fi

# Type of test to be conducted
ARG=$1

# Location where the initial files reside
ROOT_PATH=$2

# EOS directory with the correct RAIN extended attributes
EOS_DEST=$3

# Tmp location where files are saved when read from EOS
TMP_LOCATION=$4

#Extract the EOS directory name 
INDX=`awk -v a="$EOS_DEST" -v b="//eos" 'BEGIN{print index(a,b)}'`
EOS_DIR="${EOS_DEST:$INDX}"

if [ "$ARG" = "raiddp" ]; then
    $SUDO $EOS -b attr ls "$EOS_DIR" | grep -q 'sys.forced.layout="raiddp"' 
    if [ $? -ne 0 ]; then
	echo "$ERR_MSG1"
	echo_failure
	exit 1
    fi
elif [ "$ARG" = "raid6" ];
then
    $SUDO $EOS -b attr ls "$EOS_DIR" | grep -q 'sys.forced.layout="raid6"' 
    if [ $? -ne 0 ]; then
	echo "$ERR_MSG1"
	echo_failure
	exit 1
    fi
elif [ "$ARG" = "archive" ];
then
    $SUDO $EOS -b attr ls "$EOS_DIR" | grep -q 'sys.forced.layout="archive"' 
    if [ $? -ne 0 ]; then
	echo "$ERR_MSG1"
	echo_failure
	exit 1
    fi
elif [ "$ARG" = "plain" ];
then
    $SUDO $EOS -b attr ls "$EOS_DIR" | grep -q 'sys.forced.layout="plain"'
    if [ $? -ne 0 ]; then
	echo "$ERR_MSG1"
	echo_failure
	exit 1
    fi
elif [ "$ARG" = "qrain" ];
then
    $SUDO $EOS -b attr ls "$EOS_DIR" | grep -q 'sys.forced.layout="qrain"'
    if [ $? -ne 0 ]; then
	echo "$ERR_MSG1"
	echo_failure
	exit 1
    fi
else 
    echo "Usage: $0 raiddp/raid6/archive/plain dir_test_files eos_rain_dir tmp_dir"
    exit 1
fi


#...............................................................................
# Check that there are at least 6 FST in the EOS setup so that we can run the test
#...............................................................................
ret=$( $SUDO $EOS -b fs ls | grep booted | wc -l )

if [[ $ret -le 5 ]]; then
    echo "The EOS instance needs at least 6 FST's to run this test."
    exit 1
fi


#...............................................................................
# Do all write-read-check tests in: $EOS_DEST ...
#...............................................................................
echo "Do all write-read-check tests in: $EOS_DEST"
date 
# loop over all files in the pattern and test them in EOS
for file in $ROOT_PATH/*.rain; do
    if [[ -f $file ]]; then
        file=$(basename $file)
	write_and_read $ROOT_PATH $EOS_DEST $file
    fi	
done


#...............................................................................
# Disable one FST and redo the read test...
#...............................................................................
echo "Disable one FST and redo the read test..."
date
date
# loop over all files in the pattern and test them in EOS
for file in $ROOT_PATH/*.rain; do
    if [[ -f $file ]]; then 
        file=$(basename $file)
    	# get the fs on which this files resides
	get_file_fs "$EOS_DIR/$file"
	echo "Process file $file ..."

	for fst in "${VECT_FS[@]}"; do
	    #echo "Disable FST $fst and redo read test..." 
	    
            # disable one FST in EOS and test read
	    $SUDO $EOS -b fs config $fst configstatus=off

	    read_and_check $ROOT_PATH $EOS_DEST $file

            # restore the configuraton in EOS 
	    $SUDO $EOS -b fs config $fst configstatus=rw
	done
    fi
done 


#...............................................................................
# Disable each two FSTs and redo the read tests...
#...............................................................................
echo "Disable each two FSTs and redo the read tests..."
date
# loop over all files in the pattern and test them in EOS
for file in $ROOT_PATH/*.rain; do
    if [[ -f $file ]]; then
	file=$(basename $file)
	# get the filesystems on which this files resides
	get_file_fs "$EOS_DIR/$file"
	echo "Process file $file ..."
	
	for fst1 in "${VECT_FS[@]}"; do
	    for fst2 in "${VECT_FS[@]}"; do
		if [ "$fst1" -ne "$fst2" ]; then
		    #echo "Disable FST $fst1 and $fst2 and redo read test..." 
		    
                    # disable one FST in EOS and test read
		    $SUDO $EOS -b fs config $fst1 configstatus=off
		    $SUDO $EOS -b fs config $fst2 configstatus=off
		    
		    read_and_check $ROOT_PATH $EOS_DEST $file
		    
                    # restore the configuraton in EOS 
		    $SUDO $EOS -b fs config $fst1 configstatus=rw
		    $SUDO $EOS -b fs config $fst2 configstatus=rw
		fi
	    done
	done
    fi
done

#...............................................................................
# Clean up all the files written in EOS
#...............................................................................
echo "Delete files in EOS"
date
# loop over all files in the pattern and test them in EOS
for file in $ROOT_PATH/*.rain; do
    if [[ -f $file ]]; then
        file=$(basename $file)
	$SUDO eos -b rm $EOS_DIR/$file
    fi	
done

echo_success
exit 0
