#!/bin/bash
#
# Copyright (C) 2000-2015 Kern Sibbald
# License: BSD 2-Clause; see file LICENSE-FOSS
#

#
# Attempt to backup and restore kubernetes  where contains postgresql pods
# 
#
# Assumes:
#   - You have a working K8S cluster avaialable
#   - You can create storage class with any local-storage provider

#
# The k8s cluster status:

# $ kubectl apply -f scripts/kubernetes/kubernetes-plugin-test-0003.yaml
# namespace/testing-ns-0003-1 created
# configmap/test-secret-0003-1 created
# persistentvolumeclaim/test-pvc-0003-1 created
# pod/test-pod-0003-1 created
#
#
#
# $ kubectl -n testing-ns-0003-1 get pods -o wide
# NAME              READY   STATUS    RESTARTS   AGE   IP           NODE                      NOMINATED NODE   READINESS GATES
# test-pod-0003-1   1/1     Running   0          58m   10.85.2.50   am-u20-k8s-worker03-bck   <none>           <none>
#
# $ kubectl -n testing-ns-0003-1 get pvc -o wide 
# NAME              STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE   VOLUMEMODE
# test-pvc-0003-1   Bound    pvc-cf505dcc-46e9-448f-b403-33c66a4cd91f   1Gi        RWO            local-path     58m   Filesystem

TEST_ID=0003
TestName="kubernetes-plugin-test-${TEST_ID}"
JobNameBase="Test-K8S-${TEST_ID}"
FileSetName="Test-K8S-Set-${TEST_ID}-"

# Variables in tests
K8S_SCRIPT_YAML_FILE="scripts/kubernetes/kubernetes-plugin-test-${TEST_ID}.yaml"
K8S_NAMESPACE_1="testing-ns-0003-1"
K8S_NAMESPACE_2="testing namespace in progress"
PVC_N1_0003_1="test-pvc-0003-1"
# PVC_N1_0003_2="test-pvc-0003-2"
# PVC_N2_0003_3="test-pvc-0003-3"
POD_N1_0003_1="test-pod-0003-1"
# POD_N1_0003_2="test-pod-0003-2"
# POD_N2_0003_3="test-pod-0003-3"
PVC_PATH_IN_POD="/var/lib/postgresql/data"

POD_N1_0003_1_TABLE="test_table"

. scripts/functions
. scripts/regress-utils.sh

. tests/kubernetes/k8s-utils.sh

printf "\nInit test: ${TestName}\n"

CONNECTION_ARGS=""
if [ ! -z $KUBE_FD_CERT_FILE ]
then
   setup_self_signed_cert $KUBE_FD_CERT_DIR $KUBE_FD_CERT_NAME
   CONNECTION_ARGS=" fdkeyfile=$KUBE_FD_KEY_FILE fdcertfile=$KUBE_FD_CERT_FILE "
fi

if [ ! -z "$KUBE_PROXY_POD_PLUGIN_HOST" ]
then
   CONNECTION_ARGS="${CONNECTION_ARGS} pluginhost=${KUBE_PROXY_POD_PLUGIN_HOST} "
fi

if [ ! -z "$KUBE_BACULA_IMAGE" ]
then
   CONNECTION_ARGS="${CONNECTION_ARGS} baculaimage=${KUBE_BACULA_IMAGE} imagepullpolicy=ifNotPresent "
fi

export debug=2
scripts/cleanup
scripts/copy-kubernetes-plugin-confs ${TEST_ID}

printf "\n ... Preparing ...\n"

# export requires variables
setup_plugin_param "kubernetes:"
if [ "x$KUBECONFIG" != "x" ]
then
   export KUBECONFIG
   LPLUG="${LPLUG} config='$KUBECONFIG' ${CONNECTION_ARGS}"
fi

KSTORAGECLASS=`${KUBECTL} get storageclass | grep local | wc -l`
if [ $KSTORAGECLASS -eq 0 ]
then
   echo "Do you need a local storage class. It is to simplify the errors!"
   exit 1
fi

tmp="${tmp}/test-${TEST_ID}"

mkdir -p ${tmp}

# check the requirements
KNODES=`${KUBECTL} get nodes | grep Ready | wc -l`
if [ $KNODES -eq 0 ]
then
   echo "A working Kubernetes cluster required!"
   exit 1
fi

# check if K8S_NAMESPACE_1 or K8S_NAMESPACE_2 exist
KPLUGTEST_1=`${KUBECTL} get ns | grep "^${K8S_NAMESPACE_1} " | wc -l`
# KPLUGTEST_2=`${KUBECTL} get ns | grep "^${K8S_NAMESPACE_2} " | wc -l`
if [ $KPLUGTEST_1 -ne 0 ] && [ "x$1" != "xforce" ];
then
   echo "Namespace \"${K8S_NAMESPACE_1}\" exist on cluster and no force option specified!"
   exit 1
fi
# if [ $KPLUGTEST_2 -ne 0 ] && [ "x$1" != "xforce" ];
# then
#    echo "Namespace \"${K8S_NAMESPACE_2}\" exist on cluster and no force option specified!"
#    exit 1
# fi


# prepare data
printf "\n ... Apply data ... \n"
reset_k8s_env() {
   if [ $KPLUGTEST_1 -ne 0 ]
   then
      printf "Removing namespaces: ${K8S_NAMESPACE_1} and ${K8S_NAMESPACE_2}\n"
      ${KUBECTL} delete ns ${K8S_NAMESPACE_1} 2>&1 > ${tmp}/kube.log
      # ${KUBECTL} delete ns ${K8S_NAMESPACE_2} 2>&1 >> ${tmp}/kube.log
      printf "Removed namespaces: ${K8S_NAMESPACE_1} and ${K8S_NAMESPACE_2}\n"
   fi
   ${KUBECTL} apply -f ${K8S_SCRIPT_YAML_FILE} 2>&1 >> ${tmp}/kube.log

   i=0
   SPIN=('-' '\\' '|' '/')
   printf "\n ... Waiting to ready ... \n"
   while true
   do
      # TODO: Check also the pods in namespace_2 are running
      kstat=`${KUBECTL} -n ${K8S_NAMESPACE_1} get pods -o go-template='{{range .items}}{{.status.phase}}{{"\n"}}{{end}}' | grep -v Running | wc -l`
      if [ $kstat -eq 0 ]
      then
         break
      fi;
      w=1
      printf "\b${SPIN[(($i % 4))]}"
      if [ $i -eq 600 ]
      then
         echo "Timeout waiting for test data to populate. Cannot continue!"
         exit 1
      fi
      ((i++))
      sleep 1
   done
   sleep 10 # Wait to ready pods

   # Command to create a file inside pvc
   printf "\n ... Refill data in pvcs ...\n"
   SIZE_MB=10
   DD_CMD="dd if=/dev/urandom of=${PVC_PATH_IN_POD}/file${SIZE_MB}MB bs=1M count=${SIZE_MB}"
   # Exec command inside pod to create a random file
   ${KUBECTL} exec -it $POD_N1_0003_1 -n ${K8S_NAMESPACE_1} -- /bin/bash -c "$DD_CMD"
   # Exec command to create table and insert values in database
   printf "\n ... Inserting values in database ... \n"
   printf "... Command executed ... \n"
   echo "${KUBECTL} exec -ti $POD_N1_0003_1 -n ${K8S_NAMESPACE_1} -- env PGPASSWORD=postgres psql -h localhost -U postgres postgres -c \"CREATE TABLE IF NOT EXISTS ${POD_N1_0003_1_TABLE} (id INT, name VARCHAR(255)); INSERT INTO test_table(id,name) VALUES (1, 'value1'), (2, 'value2'), (3, 'value3');\""
   printf "\n"
   ${KUBECTL} exec -ti $POD_N1_0003_1 -n ${K8S_NAMESPACE_1} -- env PGPASSWORD=postgres psql -h localhost -U postgres postgres -c "CREATE TABLE IF NOT EXISTS ${POD_N1_0003_1_TABLE} (id INT, name VARCHAR(255)); INSERT INTO test_table(id,name) VALUES (1, 'value1'), (2, 'value2'), (3, 'value3');"
}

reset_k8s_env


# wait a bit to objects to populate.
sleep 3


# get variables
printf "\n ... Get Environment Variables ...\n"
${KUBECTL} get ns -o name > ${tmp}/allns.log
${KUBECTL} get pv -o name > ${tmp}/allpv.log


# Prepare bacula dir configuration
printf "\n ... Preparing Bacula-dir configuration ...\n"
export PLUGIN_WORKING=${cwd}/working

out_sed="${tmp}/sed_tmp"
echo "s%@LPLUG@%${LPLUG}%" > ${out_sed}
echo "s%@K8S_NAMESPACE_1@%${K8S_NAMESPACE_1}%" >> ${out_sed}
echo "s%@K8S_NAMESPACE_2@%${K8S_NAMESPACE_2}%" >> ${out_sed}
echo "s%@PVC_N1_0003_1@%${PVC_N1_0003_1}%" >> ${out_sed}
echo "s%@PVC_N1_0003_2@%${PVC_N1_0003_2}%" >> ${out_sed}
echo "s%@PVC_N2_0003_3@%${PVC_N2_0003_3}%" >> ${out_sed}

echo "s%@CONNECTION_ARGS@%${CONNECTION_ARGS}%" >> ${out_sed}
echo "s%@BACKUP_PROXY_WITHOUT_PVC@%${BACKUP_PROXY_WITHOUT_PVC}%" >> ${out_sed}
echo "s%@BACKUP_ONLY_PVC@%${BACKUP_ONLY_PVC}%" >> ${out_sed}
printf "\nCommand launched:\n"
echo "sed -i -f ${out_sed} ${conf}/bacula-dir.conf"

sed -i -f ${out_sed} ${conf}/bacula-dir.conf

printf "\n ... Done ...\n"

## Variables to restore from other jobs
JOB_ID_TO_RESTORE_1=0
JOB_ID_TO_RESTORE_2=0


start_test

# We must put the bconsole command in ${cwd}/tmp/bconcmds
cat <<END_OF_DATA >${tmp}/bconcmds
@output /dev/null
messages
@$out ${tmp}/log.out
label storage=File1 pool=Default volume=TestVolume001
@setdebug dir level=500 trace=1
quit
END_OF_DATA

run_bacula


#############
## BTEST 1 ##
#############
btest1 () {
   # Test 1
   TEST=1
   OUTPUT_FILE=${tmp}/blog${TEST}.out
   JOB_ID_TO_RESTORE_1=${JOBID}
   do_regress_backup_test ${TEST}
   check_regress_backup_statusT ${TEST}
   F=$?
   # Check pvc1 is backup once
   F_1=0
   RET=`grep "@kubernetes" ${OUTPUT_FILE} | grep "${PVC_N1_0003_1}.tar" | wc -l`
   RES=1
   if [ $RET -ne $RES ]
   then
      F_1=1
      ((bstat++))
   fi
   
   printf "\n%s\n" "--------"
   printf "Results backup test ${TEST}:\n"
   printf "%s%s\n" " -> StatusT: " $(regress_test_result ${F})
   printf "%s%s\n" " -> The pvc data of '${PVC_N1_0003_1}' is backup once: " $(regress_test_result ${F_1}) 
   printf "%s\n" "--------"
}



#############
## RTEST 1 ##
#############
rtest1 () {
   TEST=1
   if [ "${JOB_ID_TO_RESTORE_1}" -eq 0 ]; then
      printf "%s\n" "--------------"
      printf "%s\n" "The job id to restore ${TEST} was not assigned."
      printf "%s\n" "--------------"
      exit 1
   fi
   # Before delete
   echo "---> Before delete the pvc:" 2>&1 > ${tmp}/rlog${TEST}.out
   ${KUBECTL} -n ${K8S_NAMESPACE_1} get pvc/${PVC_N1_0003_1} 2>&1 >> ${tmp}/rlog${TEST}.out
   ${KUBECTL} -n ${K8S_NAMESPACE_1} get pod/${POD_N1_0003_1} 2>&1 >> ${tmp}/rlog${TEST}.out
   echo "---> Deleting the pvc and pod:" 2>&1 >> ${tmp}/rlog${TEST}.out
   ${KUBECTL} -n ${K8S_NAMESPACE_1} delete pod/${POD_N1_0003_1} 2>&1 >> ${tmp}/rlog${TEST}.out
   ${KUBECTL} -n ${K8S_NAMESPACE_1} delete pvc/${PVC_N1_0003_1} 2>&1 >> ${tmp}/rlog${TEST}.out
   echo "---> Deleted the pvc(${PVC_N1_0003_1}) and pod (${POD_N1_0003_1})" 2>&1 >> ${tmp}/rlog${TEST}.out
   actions=(
      "" # Always starts with empty line. I don't know why is neccesary.
      "mark *"
   )
   do_regress_restore_test_jobid ${TEST} ${JOB_ID_TO_RESTORE_1} "/" $actions
   check_regress_restore_statusT ${TEST}
   F=$?
   # check if object restored on kubernetes
   sleep 5
   echo "---> After restore the pod and pvc:" 2>&1 >> ${tmp}/rlog${TEST}.out
   ${KUBECTL} -n ${K8S_NAMESPACE_1} get pod/${POD_N1_0003_1} 2>&1 >> ${tmp}/rlog${TEST}.out
   RET=`${KUBECTL} -n ${K8S_NAMESPACE_1} get pod/${POD_N1_0003_1} -o go-template='{{.metadata.name}}{{"\n"}}' 2>/dev/null | wc -l`
   ${KUBECTL} -n ${K8S_NAMESPACE_1} get pvc/${PVC_N1_0003_1} 2>&1 >> ${tmp}/rlog${TEST}.out
   RET_1=`${KUBECTL} -n ${K8S_NAMESPACE_1} get pvc/${PVC_N1_0003_1} -o go-template='{{.metadata.name}}{{"\n"}}' 2>/dev/null | wc -l`
   ${KUBECTL} exec -ti $POD_N1_0003_1 -n ${K8S_NAMESPACE_1} -- timeout 10 env PGPASSWORD=postgres psql -h localhost -U postgres postgres -c "SELECT * FROM test_table;" 2>&1 > ${tmp}/rlog${TEST}-sql.out
   RET_2=`grep "value1" ${tmp}/rlog${TEST}-sql.out | wc -l`

   F_1=0 F_2=0 F_3=0
   rets=($RET $RET_1 $RET_2)
   fs=("F_1" "F_2" "F_3")

   for i in ${!rets[@]}; do
      echo "RET: ${rets[i]}" >> ${tmp}/rlog${TEST}.out
      if [ ${rets[i]} -ne 1 ]; then
         eval ${fs[i]}=1
         rstat=$((rstat+1))
      fi
   done

   printf "\n%s\n" "--------"
   printf "Result restore test ${TEST}:"
   printf "%s%s\n" " -> StatusT: " $(regress_test_result ${F})
   printf "%s%s\n" " -> The pod ${POD_N1_0003_1} was restored: " $(regress_test_result ${F_1})
   printf "%s%s\n" " -> The pvc ${PVC_N1_0003_1} was restored: " $(regress_test_result ${F_2})
   printf "%s%s\n" " -> The database data of postgres was restored correctly: " $(regress_test_result ${F_3})
   printf "%s\n" "--------"
}

estat=0

bstat=0
JOBID=1
# This job is the base of all backup jobs names
JobName=${JobNameBase}-

btest1

rstat=0
rtest1

stop_bacula
end_test