#!/bin/bash
declare Version=2.3.1

#------------------------------------------------------------------------------
# Copyright (c) Perforce Software, Inc., 2007-2015. All rights reserved
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1  Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#
# 2.  Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PERFORCE
# SOFTWARE, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
# DAMAGE.
#------------------------------------------------------------------------------

set -u

#------------------------------------------------------------------------------
# Declarations
declare SDPTar=sdp.Unix.2015.1.13934.tgz
declare SDPURL=http://swarm.workshop.perforce.com/projects/perforce-software-sdp/download/downloads/$SDPTar
declare ResetTarget=/depotdata
SDPHome=$ResetTarget/sdp
declare Password=G00dP@ssw0rd
declare ExesDir=$ResetTarget/exes
declare DownloadsDir=$ResetTarget/downloads
declare -i BlastDepotdataDir=0
declare DataDir=$ResetTarget/data
declare P4ExeRel=r15.1
declare P4DExeRel=$P4ExeRel
declare P4PExeRel=$P4ExeRel
declare P4BrokerExeRel=$P4ExeRel
declare P4SwarmRel=r15.1
declare P4Rel=r15.1
declare RunUser=perforce
declare RunGroup=
declare Arch=x86_64
declare ApiArch=
declare ThisArch=
declare RunArch=x86_64
declare ThisOS=
declare CBIN=/p4/common/bin
declare SDPSetupDir=$SDPHome/Server/Unix/setup
declare ThisScript=$(basename $0)
declare SDPInstances="1 12 abc"

#------------------------------------------------------------------------------
# Function: usage (required function)
#
# Input:
# $1 - style, either -h (for short form) or -man (for man-page like format).
#------------------------------------------------------------------------------
function usage
{
   declare style=${1:--h}

   echo "USAGE for $ThisScript v$Version:

$THISSCRIPT [-B] [-D]

or

$THISSCRIPT [-h|-man]
"
   if [[ $style == -man ]]; then
      echo -e "
DESCRIPTION:
	This script SHOULD NEVER EXIST on a Production Perforce server.

	It is designed simplify the process of testing an SDP installation,
	repetitively blasting all process by the 'perforce' user and resetting
	the SDP from the ground up, blasting typical SDP folders each time.
	This could be helpful bootstrapping a demo server with a sample data set.

PLATFORM SUPPORT:
	This works on Red Hat Linux, CentOS, and Mac OSX (Mavericks or
	Yosemitie) platforms.  It works on CentOS 6.4 and 6.5 and
	likely on other Linux derivatives with little or no modification.

	It currently supports only the bin.linux26x86_64 (Linux) and
	bin.darwin90x86_64 (Mac OSX/Darwin) architectures.

REQUIREMENTS:
	Development utilities such as 'make' and the 'gcc' compiler
	must be installed and available in the PATH.

	The 'wget' utility must be installed and available in the
	PATH.  Mac OSX users:  'wget' is not installed with Mac OSX
	by default, at least not os of OSX 10.10/Yosemite.  It can be
	acquired and compiled.  For example, see:
	http://osxdaily.com/2012/05/22/install-wget-mac-os-x/

OPTIONS:
 -B	Specify '-B' to blast base SDP dirs, for a clean start.
	Otherwise, downloaded components from earlier runs will
	be used (which should be fine if they were run recently).
 
 -D     Set extreme debugging verbosity.

HELP OPTIONS:
 -h	Display short help message
 -man	Display man-style help message

EXAMPLES:
	Typical usage:
	su - root
	cd /where/this/script/is
	./reset_sdp.sh -B 2>&1 | tee log.reset_sdp
"
   fi

   exit 1
}

#------------------------------------------------------------------------------
# Function bail().
# Sample Usage:
#    bail "Missing something important. Aborting."
#    bail "Aborting with exit code 3." 3
function bail () { echo -e "\nError: ${1:-Unknown Error}\n"; exit ${2:-1}; }

#------------------------------------------------------------------------------
# Functions.  The runCmd() function is similar to functions defined in SDP core
# libraries, but we need to duplicate them here since this script runs before
# the SDP is available on the machine (and we want no dependencies for this
# script.
function runCmd {
   cmd=${1:-echo Testing runCmd}
   desc=${2:-""}
   [[ -n "$desc" ]] && echo $desc
   echo Running: $cmd
   $cmd
   return $?
}

#==============================================================================
# Command Line Processing

declare -i NoOp=0
declare -i shiftArgs=0

set +u

while [[ $# -gt 0 ]]; do
   case $1 in
      (-B) BlastDepotdataDir=1;;
      (-h) usage -h;;
      (-man) usage -man;;
      (-D) set -x;; # Debug; use 'set -x' mode.
      (*) bail "Usage Error: Unknown arg ($1).";;
   esac

   # Shift (modify $#) the appropriate number of times.
   shift; while [[ $shiftArgs -gt 0 ]]; do
      [[ $# -eq 0 ]] && bail "Usage Error: Wrong numbers of args or flags to args."
      shiftArgs=$shiftArgs-1
      shift
   done
done
set -u

#------------------------------------------------------------------------------
# Usage Validation
if [[ $USER != root ]]; then
   bail "Run as root, not $USER."
else
   echo Verified: Running as user $USER.
fi

#------------------------------------------------------------------------------
# Digital asset acquisition and availability checks.
[[ ! -d $ResetTarget ]] && runCmd "/bin/mkdir -p $ResetTarget"

cd $ResetTarget || bail "Could not cd to [$ResetTarget]."

echo Verifying dependencies.

[[ -z "$(which gcc 2>/dev/null)" || -z "$(which g++ 2>/dev/null)" ]] && \
   bail "No gcc found in the path.  You may need to install it.  Please\n check that the gcc.x86_64 and gcc-c++.x86_64 packages are\n installed, e.g. with:\n\tyum install -y gcc.x86_64 gcc-c++.x86_64\n\n"

[[ -z "$(which wget 2>/dev/null)" ]] && \
   bail "No 'wget' found in the path.  You may need to install it.  Please check that the wget.x86_64 packages is installed, e.g. with:\n\tyum install -y wget.x86_64\n\n"

[[ -z "$(which su 2>/dev/null)" ]] && \
   bail "No 'su' found in the path.  You may need to install it or add it to the path for the root user.\n\n"

ThisArch=$(uname -m)
ThisOS=$(uname -s)

if [[ $ThisArch == $RunArch ]]; then
   echo Verified:  Running on a supported architecture [$ThisArch].
   ApiArch=UNDEFINED_API_ARCH
   case $ThisOS in
      (Darwin) ApiArch="darwin90x86_64"; RunGroup=staff;;
      (Linux) ApiArch="linux26x86_64"; RunGroup=perforce;;
      (*) bail "Unsupported value returned by 'uname -m': $ThisOS. Aborting.";;
   esac
else
   bail "Running on architecture $ThisArch.  Run this only on hosts with '$RunArch' architecture. Aborting."
fi

if [[ -d $ExesDir && $BlastDepotdataDir -eq 1 ]]; then
   runCmd "/bin/rm -r -f $ExesDir" \
      "Blasting exes dir [$ExesDir] due to '-B'."
fi

if [[ ! -d $ExesDir ]]; then
   runCmd "/bin/mkdir -p $ExesDir" ||\
      bail "Could not create dir [$ExesDir]."

   cd $ExesDir || exit 1
   echo Working in [$PWD].
   runCmd "wget -q ftp://ftp.perforce.com/perforce/$P4ExeRel/bin.$ApiArch/p4" ||\
      bail "Could not get 'p4' executable."
   runCmd "wget -q ftp://ftp.perforce.com/perforce/$P4DExeRel/bin.$ApiArch/p4d" ||\
      bail "Could not get 'p4d' executable."
   runCmd "wget -q ftp://ftp.perforce.com/perforce/$P4PExeRel/bin.$ApiArch/p4p" ||\
      bail "Could not get 'p4p' executable."
   runCmd "wget -q ftp://ftp.perforce.com/perforce/$P4BrokerExeRel/bin.$ApiArch/p4broker" ||\
      bail "Could not get 'p4broker' executable."

   runCmd "chmod +x p4 p4d p4p p4broker" \
      "Doing chmod +x for downloaded executables."
else
   echo Using existing exes dir [$ExesDir].
fi

if [[ -d /depotdata && $BlastDepotdataDir -eq 1 ]]; then
   echo "Blasting base SDP dirs due to -B."
   runCmd "/bin/rm -r -f /depotdata/p4 /depotdata/sdp"
   runCmd "/bin/rm -f /p4/common"
   for i in $SDPInstances; do
      runCmd "/bin/rm -f /p4/$i"
   done
fi

if [[ -d $DownloadsDir && $BlastDepotdataDir -eq 1 ]]; then
   runCmd "/bin/rm -r -f $DownloadsDir" \
      "Blasting downloads dir [$DownloadsDir] due to '-B'."
fi

if [[ ! -d $DownloadsDir ]]; then
   runCmd "/bin/mkdir -p $DownloadsDir"

   cd $DownloadsDir || bail "Could not cd to [$DownloadsDir]."

   echo Working in [$PWD].
   runCmd "wget -q ftp://ftp.perforce.com/perforce/$P4Rel/bin.$ApiArch/p4api.tgz" ||\
      bail "Could not get file 'p4api.tgz'"
   runCmd "wget -q ftp://ftp.perforce.com/perforce/$P4SwarmRel/bin.multiarch/swarm.tgz" ||\
      bail "Could not get file 'swarm.tgz'"
   runCmd "wget -q $SDPURL" ||\
      bail "Could not get SDP tar file from [$SDPURL]."
else
   echo Using existing downloads dir [$DownloadsDir].
fi

if [[ ! -d $DataDir ]]; then
   runCmd "/bin/mkdir -p $DataDir"
   cd $DataDir || bail "Could not cd to [$DataDir]."
   echo Working in [$PWD].

   case $ThisOS in
      (Darwin) SampleDepotTar=sampledepot.mac.tar.gz;;
      (Linux) SampleDepotTar=sampledepot.tar.gz;;
      (*) bail "Unsupported value returned by 'uname -m': $ThisOS. Aborting.";;
   esac

   runCmd "wget -q ftp://ftp.perforce.com/perforce/tools/$SampleDepotTar" ||\
      bail "Could not get file '$SampleDepotTar'"
else
   echo Using existing data dir [$DataDir].
fi

#------------------------------------------------------------------------------
# Services Managment

if [[ $ThisOS == Linux ]]; then
   cd /etc/init.d

   echo -e "Stopping and removing Perforce-related servcies.\nWorking in [$PWD]."

   for svc in $(/bin/ls p4*); do
      runCmd "service $svc stop"
      sleep 1
      runCmd "chkconfig --del $svc"
      runCmd "rm -f $svc"
   done

   sleep 1
fi

PerforcePids=$(ps -u $RunUser -o pid=)
if [[ -n "$PerforcePids" ]]; then
   runCmd "kill $PerforcePids" \
      "Killing all processes by user $RunUser."
   sleep 1
else
   echo "Verified: No processes by user $RunUser are running."
fi


#------------------------------------------------------------------------------
# Cleanup
cd "$ResetTarget" || bail "Could not cd to [$ResetTarget]. Aborting."

echo -e "Working in [$PWD]."

runCmd "/bin/rm -rf /depotdata/p4 /depotdata/sdp /metadata/p4 /logs/p4 /p4 /tmp/p4" \
   "Blasting any existing SDP structures due to -B."

#------------------------------------------------------------------------------
# SDP Setup
runCmd "tar -xzvpf $DownloadsDir/$SDPTar" "Unpacking $DownloadsDir/$SDPTar in $PWD."

cd $SDPSetupDir ||\
   bail "Could not cd to [$SDPSetupDir]."

echo "Localizing mkdirs.sh in [$PWD]."

runCmd "/bin/mv -f mkdirs.sh mkdirs.sh.orig"
runCmd "chmod 444 mkdirs.sh.orig"

echo "Generating custom mkdirs.sh."
sed "s:=p4admin:=perforce:g"  mkdirs.sh.orig |\
   sed "s:DNS_name_of_master_server:p4d01.p4bsw.com:g" |\
   sed "s:DNS_name_of_replica_server:p4d02.p4bsw.com:g" |\
   sed "s:DNS_name_of_proxy_server:p4proxy01:g" |\
   sed "s:P4PORT_END=666:P4PORT_END=999:g" |\
   sed "s:P4BROKER_PORT_END=667:P4BROKER_PORT_END=666:g" |\
   sed "s:=adminpass:=$Password:g" |\
   sed "s:=servicepass:=$Password:g" |\
   sed "s:OSGROUP=perforce:OSGROUP=$RunGroup:g" |\
   sed "s:REPLICANAME=replica:REPLICANAME=HA_Master:g" > mkdirs.sh

chmod +x mkdirs.sh

echo "SDP Localizations."
diff mkdirs.sh.orig mkdirs.sh

runCmd "cp -p $ExesDir/p4* $SDPHome/Server/Unix/p4/common/bin/." \
   "Copying perforce executables."

echo "Initializing SDP instances and configuring /etc/init.d services."

for i in $SDPInstances; do
   cd $SDPSetupDir || bail "Could not cd to [$SDPSetupDir]."
   log=$PWD/mkdirs.${i}.log
   echo "Initializing SDP instance [$i], writing log [$log]."
   $PWD/mkdirs.sh $i > $log 2>&1
   cat $log

   brokerCfg=/p4/${i}/bin/p4broker.cfg
   $CBIN/gen_default_broker_cfg.sh ${i} > $brokerCfg
   runCmd "chown $RunUser:$RunGroup $brokerCfg"

   if [[ $ThisOS == Linux ]]; then
      echo -e "\nConfiguring Linux init scripts.\n"
      cd /etc/init.d || bail "Could not cd to [/etc/init.d]."
      for svc in p4broker p4d p4p; do
         initScript=${svc}_${i}_init
         if [[ -x /p4/${i}/bin/$initScript ]]; then
            runCmd "ln -s /p4/${i}/bin/$initScript"
            runCmd "chkconfig --add $initScript"
            runCmd "chkconfig $initScript on"
         fi
      done
   fi

   echo -e "\nGenerating SSH Certificates for instance $i.\n"
   su -l $RunUser -c "source /p4/common/bin/p4_vars $i; /p4/${i}/bin/p4d_${i} -Gc"

   echo -e "\nGenerating broker config for instance $i.\n"
   su -l $RunUser -c "/p4/common/bin/gen_default_broker_cfg.sh ${i} > /p4/common/config/p4_${i}.broker.cfg"

   for svc in p4broker p4d p4p; do
      initScript=${svc}_${i}_init
      if [[ $ThisOS == Linux ]]; then
         runCmd "service $initScript start"
         runCmd "service $initScript status"
      else
         runCmd "/p4/$i/bin/$initScript start"
         runCmd "/p4/$i/bin/$initScript status"
      fi
   done

   sleep 1

   # Note: Automating a 'p4 trust -y' is INAPPROPRIATE in a production environment, as it defeats
   # the purpose of the Open SSL trust mechanism.  But for our purposes here for seting scripts to
   # spin up and tear down a throw-away data set for testing purposes, it's just dandy.
   echo -e "Trusting the server."
   su -l $RunUser -c "source /p4/common/bin/p4_vars $i; /p4/$i/bin/p4_$i trust -y"
   echo -e "Logging the super user in."
   su -l $RunUser -c "source /p4/common/bin/p4_vars $i; /p4/common/bin/p4login"
done

#------------------------------------------------------------------------------
#
echo -e "\nInstalling P4Python for SDP.\n"
su -l $RunUser -c '/depotdata/sdp/Server/Unix/setup/install_sdp_python.sh -L /p4/1/logs/install_sdp_python.log'

echo -e "\nInstalling P4Perl for SDP.\n"
su -l $RunUser -c '/depotdata/sdp/Server/Unix/setup/install_sdp_perl.sh -L /p4/1/logs/install_sdp_perl.log'

echo -e "\nPlaceholder for Installing P4Ruby for SDP (Not yet implemented in the SDP).\n"
