#!/bin/bash

# @@@ START COPYRIGHT @@@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
#
# @@@ END COPYRIGHT @@@


#==========================================
# Backup all Trafodion tables
#==========================================

source ${0%/*}/backup_restore_functions.sh

usage()
{
  echo "The $0 script performs full offline backup of all Trafodion tables"
  echo "and copies the backup files to an HDFS location"
  echo "The command to use the script is as follows:"
  echo "$0 -b backup_folder -b backup_dir -u trafodion_user -h hbase_user -d hdfs_user -m mappers -l 10 -n -o"
  echo "where"
  echo "-b backup_folder"
  echo "     (Optional) HDFS path where all the Trafodion object are exported and saved"
  echo "     The HDFS path needs to have a format like hdfs://<host>:<port>/<folder>/..."
  echo "     If the path is not provided the script generates a path with a format like"
  echo "     hdfs://<host>:<port>/trafodion-backups/backup_<timestamp> and unless -n"
  echo "     is specified the user is asked whether to confirm the use of the generated"
  echo "     path."
  echo "-u trafodion user"
  echo "     (Optional) The user under which Trafodion server runs. If not provided and"
  echo "     if -n option is not specified the user is asked whether the default"
  echo "     trafodion user 'trafodion' can be used or not. If the answer is yes then the"
  echo "      default trafodion user is used otherwise the script exits."
  echo "-h hbase user"
  echo "     (Optional) The user under which HBase server runs. If not provided the script"
  echo "     tries to compute it and if it does not succeed it considers using the default"
  echo "     hbase user 'hbase'. Unless the -n option is specified, the user is asked to"
  echo "     confirm the selection afterwards."
  echo "-d hdfs user"
  echo "     (Optional) The user under which HDFS server runs. If not provided the script"
  echo "     tries to compute it and if it does not succeed it considers using the default"
  echo "     HDFS user 'hdfs'. Unless the -n option is specified, the user is asked to"
  echo "     confirm the selection afterwards."
  echo "-m mappers"
  echo "     (Optional) Number of mappers. If unspecified each snapshot will use a number suitable for its size."
  echo "-n"
  echo "     (Optional) Non interactive mode. With this option the script does not prompt"
  echo "     the user to confirm the use of computed or default values when a parameter"
  echo "     like trafodion user, hbase user, hdfs user or backup path is not provided."
  echo "-o"
  echo "     (Optional) offline. With this option trafodion will not be restarted after"
  echo "     snapshots are taken."
  echo "-l"
  echo "     (Optional) Snapshot size limit in MB above which map reduce is used for copy. Snapshots with size below this value will be copied using HDFS FileUtil.copy. Default value is 100 MB. FileUtil.copy is invoked through a class provided by Trafodion. Use 0 for this option to use HBase' ExportSnaphot class instead."
  echo " Example: $0  -b hdfs://<host>:<port>/<hdfs-path>  -m 4"
  exit 1
}

hdfs_backup_location=
snap_suffix=SNAP
snapshot_name=

backup_run_dir=${PWD}
tmp_dir=$backup_run_dir/tmp
log_dir=$backup_run_dir/logs
log_file=${log_dir}/run_traf_backup_${date_str}.log
tmp_log_file=${tmp_dir}/tmp_log.log

#hbase shell scripts
hbase_create_snapshots=$tmp_dir/bckp_create_snapshots_${date_str}.hbase
hbase_delete_snapshots=$tmp_dir/bckp_delete_snapshots_${date_str}.hbase
hbase_disable_tables=$tmp_dir/bckp_disable_tables_${date_str}.hbase
hbase_drop_tables=$tmp_dir/bckp_drop_tables_${date_str}.hbase
hbase_trafodion_table_list=${tmp_dir}/bckp_trafodion_table_list_${date_str}.hbase

trafodion_table_list_file=$tmp_dir/bckp_trafodion_table_list_${date_str}.txt
tmp_trafodion_table_list_file=${tmp_dir}/bckp_tmp_trafodion_table_list_${date_str}.txt
trafodion_snapshot_list_file=trafodion_snapshot_list.txt
trafodion_snapshot_list_path=$tmp_dir/${trafodion_snapshot_list_file}



#
trafodion_user=
hbase_user=
hdfs_user=
confirm=1
stay_offline=0
mr_limit=100

while getopts b:u:m:h:d:l:no arguments
do
  case $arguments in
  b)  hdfs_backup_location=$OPTARG;;
  m)  mappers=$OPTARG;;
  u)  trafodion_user=$OPTARG;;
  h)  hbase_user=$OPTARG;;
  d)  hdfs_user=$OPTARG;;
  l)  mr_limit=$OPTARG;;
  o)  stay_offline=1;;
  n)  confirm=0;;
  *)  usage;;
  esac
done

#check the HBase compatiblity if TrafExportSnapshot is able to be used
java org.trafodion.utility.backuprestore.TrafExportSnapshot -t
if [[ $? -ne 0 ]]; then
  echo 'not able to use TrafExportSnapshot'
  mr_limit=0
else
  echo 'able to use TrafExportSnapshot'
fi

echo "logging output to: ${log_file}"

#create tmp and log folders if they don't exist
create_tmp_and_log_folders
if [[ $? -ne 0 ]]; then
  exit 1
fi

#validate the environmet and users --
validate_environment_and_users
if [[ $? -ne 0 ]]; then
  exit 1
fi

#get the hdfs uri
hdfs_uri=$(get_hdfs_uri)
echo "hdfs_uri: ${hdfs_uri}"
echo "hdfs_backup_location:${hdfs_backup_location}"
# if hdfs backup location is empty generate one
if [[ -z "$hdfs_backup_location" ]] ; then
  new_path=${hdfs_uri}/user/trafodion/trafodion_backups/backup_${date_str}
  confirm_choice "Would you like to use this path as the backup folder: ${new_path} ?"
  if [[ $? -ne 0 ]]; then
    echo "***[ERROR]: New path ${new_path} could not be validated."    | tee -a  ${log_file}
    exit 1
   else
     hdfs_backup_location=${new_path}
  fi
fi

echo "hdfs_backup_location  ${hdfs_backup_location}"

#verify that the hdfs backup location is valid and exists. create it if not there
verify_or_create_folder ${hdfs_backup_location} "create"
ret_code=$?
if [[ $ret_code -ne 0  ]]; then
   exit $ret_code
fi

#verify backup folder has no contents
var_count=$($(get_hadoop_cmd) fs -ls ${hdfs_backup_location} | wc -l)
if [  $var_count -ne 0 ]; then
   echo "***[ERROR]: The HDFS backup location ${hdfs_backup_location} is not empty. "  | tee -a $log_file
   echo "***[ERROR]: Please provide an empty HDFS location for the backup."  | tee -a $log_file
   exit 1
fi

echo "Backup Folder: ${hdfs_backup_location} ." | tee -a $log_file

#verify that the hbase home dir exist. ExportSnapshot fails if it does not exist
verify_or_create_folder "${hdfs_uri}/user/${hbase_user}" "create"
ret_code=$?
if [[ $ret_code -ne 0  ]] ; then
   exit $ret_code
fi

###get list of trafodion tables
echo "hbase_trafodion_table_list: ${hbase_trafodion_table_list}" | tee -a $log_file
cat <<EOF > ${hbase_trafodion_table_list}
list  'TRAFODION\..*\..*'
exit
EOF
if [[ ! -f "${hbase_trafodion_table_list}" ]]; then
 echo "***[ERROR]: Cannot create the ${hbase_trafodion_table_list} file. Exiting ..."   | tee -a $log_file
 exit 1;
fi

echo "Getting list of Trafodion tables from HBase "  | tee -a  $log_file
$(get_hbase_cmd) shell ${hbase_trafodion_table_list} | tee  ${tmp_trafodion_table_list_file}   | tee -a  $log_file
echo "grep for trafodion tables"      | tee -a  $log_file
#filter out anything other than Trafodion tables from the list
grep 'TRAFODION.*'   ${tmp_trafodion_table_list_file} | tee  ${trafodion_table_list_file}    | tee -a  $log_file


###Generate HBase shell scripts
> $hbase_create_snapshots
> $hbase_delete_snapshots
> $hbase_disable_tables
> $hbase_drop_tables
> ${trafodion_snapshot_list_path}
#
while read line
do
  table_name=$line
  snapshot_name=${table_name}_${snap_suffix}_${date_str}

  echo "Generating hbase scripts for table: ${table_name}"
  # hbase shell scripts - create snapshot
  echo "snapshot	'${table_name}'	, '${snapshot_name}'" >>	$hbase_create_snapshots
  # hbase shell script - delete snapshot
  echo "delete_snapshot	'${snapshot_name}'" >>	$hbase_delete_snapshots
  # hbase shell script - disable table
  echo "disable	'${table_name}'" >> $hbase_disable_tables
  # hbase shell script - drop table
  echo "drop	'${table_name}'" >> $hbase_drop_tables
  # make a list of the snapshots.
  echo ${snapshot_name} >> ${trafodion_snapshot_list_path}
done < ${trafodion_table_list_file}

echo "exit" >>  $hbase_create_snapshots
echo "exit" >>  $hbase_disable_tables
echo "exit" >>  $hbase_drop_tables
echo "exit" >>  $hbase_delete_snapshots


## Do create the snapshots
echo "Creating hbase snapshots ..."  | tee  -a  ${log_file}
cat ${hbase_create_snapshots}  | tee  -a  ${log_file}
hbase_cmd="$(get_hbase_cmd) shell ${hbase_create_snapshots}"
echo "${hbase_cmd}"  | tee  -a  ${log_file}
${hbase_cmd}   2>&1 |  tee $tmp_log_file | tee -a  ${log_file}
## check if there are errors. exit on error.
grep ERROR $tmp_log_file
if  [[ $? -eq 0 ]]; then
    echo "***[ERROR]: Error encountered while creating snapshots"     | tee -a $log_file
    echo "For more information please check the logs at ${log_file}. "     | tee -a $log_file
    exit 1;
fi

## Restart Trafodion
if [[ ${stay_offline} -ne 1 ]]; then
 start_trafodion $trafodion_user 
else
 echo "Trafodion can now be restarted at your convinience. Backup script does not need for it to be offline anymore."
fi

while read line
do
  snapshot_name=$line
  echo "********************************************************************"
  echo "Exporting ${snapshot_name} ..."
  if [[ ${mr_limit} -eq 0 ]]; then
     hbase_cmd="$(get_hbase_cmd) org.apache.hadoop.hbase.snapshot.ExportSnapshot"
  else 
     hbase_cmd="$(get_hbase_cmd) org.trafodion.utility.backuprestore.TrafExportSnapshot"
  fi
  hbase_cmd+=" -snapshot ${snapshot_name}"
  hbase_cmd+=" -copy-to ${hdfs_backup_location}/${snapshot_name}"
  hbase_cmd+=" -mappers $mappers"
  if [[ ${mr_limit} -ne 0 ]]; then
     hbase_cmd+=" -mr-lowlimit-mb ${mr_limit}"
  fi
  echo "${hbase_cmd}" | tee -a ${log_file}

  do_sudo ${hbase_user} "${hbase_cmd}" 2>&1 | tee -a  ${log_file}
  ##check for errors
  if [[ ${PIPESTATUS[0]} -ne 0 ]]; then
      echo "***[ERROR]: Error while exporting snapshot: ${snapshot_name}."   | tee -a $log_file
      echo "For more information please check the logs at ${log_file}."    | tee -a $log_file
      exit 1;
  fi
done < ${trafodion_snapshot_list_path}

#copy the generated snapshot list to the hdfs backup location
#first copy the list to /tmp because in some cases hadoop fs -copyFromLocal gives error
#message when using the local path -- permission issue
cp ${trafodion_snapshot_list_path} /tmp/${trafodion_snapshot_list_file}

hbase_cmd="$(get_hadoop_cmd) fs -copyFromLocal /tmp/${trafodion_snapshot_list_file}  ${hdfs_backup_location}"
echo "${hbase_cmd}"   | tee -a  ${log_file}
do_sudo  ${hbase_user}  "${hbase_cmd}"  2>&1   | tee -a  ${log_file}
if [[ ${PIPESTATUS[0]} -ne 0 ]] ; then
   echo "***[ERROR]: Error occurred while copying the ${trafodion_snapshot_list_path} file to hdfs backup location ${hdfs_backup_location}."   | tee -a $log_file
   echo "For more information please check the logs at ${log_file}. "   | tee -a $log_file
   exit 1;
fi

## do delete the snapshots after export is done
echo "Deleting hbase snapshots ..."  | tee  -a  ${log_file}
cat ${hbase_delete_snapshots}  | tee  -a  ${log_file}
echo "$(get_hbase_cmd) shell ${hbase_delete_snapshots} "   | tee -a  ${log_file}
$(get_hbase_cmd) shell ${hbase_delete_snapshots}   2>&1 | tee  $tmp_log_file | tee -a  ${log_file}
## check if there are errors. exit on error.
grep ERROR $tmp_log_file
if [ $? -eq 0 ]; then
    echo "***[ERROR]: An Error occurred while deleting snapshots"
    echo "They can be deleted manually using the ${hbase_delete_snapshots} script after the backup is done."
    #exit 1;
fi

###Verifications
#echo "cat ./${trafodion_table_list_file} | wc -l"
#echo "$(get_hadoop_cmd) fs -ls $hdfs_backup_location | grep -v ./${trafodion_snapshot_list_path}"
#echo "$(get_hadoop_cmd) fs -cat $hdfs_backup_location/${trafodion_snapshot_list_path} | wc -l"
traf_table_count=$(cat ${trafodion_table_list_file} | wc -l )
echo    "traf_table_count: ${traf_table_count} " | tee -a $log_file

hbase_cmd="$(get_hadoop_cmd) fs -ls -d ${hdfs_backup_location}/TRAFODION.*.*"
var_backup_snapshot_count=$(do_sudo ${hbase_user}  "$hbase_cmd" | grep 'TRAFODION.\.*\.*' | wc -l)

echo "var_backup_snapshot_count: ${var_backup_snapshot_count}" | tee -a $log_file

hbase_cmd="$(get_hadoop_cmd) fs -cat ${hdfs_backup_location}/${trafodion_snapshot_list_file}"
var_snapshot_file_count=$(do_sudo ${hbase_user} "${hbase_cmd} " | wc -l)
echo "var_snapshot_file_count: ${var_snapshot_file_count} "  | tee -a $log_file
if [[  ${traf_table_count} -ne ${var_backup_snapshot_count} ]]
then
   echo "***[ERROR]: the number of snapshots in backup location ${hdfs_backup_location} does not match the number of trafodion tables."  | tee -a $log_file
   exit 1
fi

if [[  ${traf_table_count} -ne ${var_snapshot_file_count} ]]
then
   echo "***[ERROR]: the number of snapshots listed in ${hdfs_backup_location}/${trafodion_snapshot_list_file} does not match the number of trafodion tables."  | tee -a $log_file
   exit 1
fi


echo "Backup complete."  | tee -a $log_file
exit 0
