#!/bin/bash
#==============================================================================
# Copyright and license info is available in the LICENSE file included with
# the Server Deployment Package (SDP), and also available online:
# https://swarm.workshop.perforce.com/projects/perforce-software-sdp/view/main/LICENSE
#------------------------------------------------------------------------------
#==============================================================================
# Declarations and Environment
# Allow override of P4U_HOME, which is set only when testing P4U scripts.
export P4U_HOME=${P4U_HOME:-/p4/common/bin}
export P4U_LIB=${P4U_LIB:-/p4/common/lib}
export P4U_ENV=$P4U_LIB/p4u_env.sh
export P4U_LOG=Unset
export VERBOSITY=${VERBOSITY:-3}
# Environment isolation. For stability and security reasons, prepend
# PATH to include dirs where known-good scripts exist.
# known/tested PATH and, by implication, executables on the PATH.
export PATH=$P4U_HOME:$PATH:~/bin:.
export P4CONFIG=${P4CONFIG:-.p4config}
[[ -r "$P4U_ENV" ]] || {
echo -e "\nError: Cannot load environment from: $P4U_ENV\n\n"
exit 1
}
declare BASH_LIBS=$P4U_ENV
BASH_LIBS+=" $P4U_LIB/libcore.sh"
BASH_LIBS+=" $P4U_LIB/libp4u.sh"
for bash_lib in $BASH_LIBS; do
source $bash_lib ||\
{ echo -e "\nFATAL: Failed to load bash lib [$bash_lib]. Aborting.\n"; exit 1; }
done
declare Version=1.0.1
declare SDPInstallDirDefault="/depotdata/sdp"
declare SDPInstallDir=Unset
declare SDPConfigScript=
declare SDPHostsFile=
declare -i Interactive=1
declare -i PreflightOK
declare ActiveInstances
export VERBOSITY=3
#==============================================================================
# Local Functions
#------------------------------------------------------------------------------
# Function: terminate
function terminate
{
# Disable signal trapping.
trap - EXIT SIGINT SIGTERM
# Don't litter.
cleanTrash
vvmsg "$THISSCRIPT: EXITCODE: $OverallReturnStatus"
# Stop logging.
[[ "${P4U_LOG}" == off ]] || stoplog
# With the trap removed, exit.
exit $OverallReturnStatus
}
#------------------------------------------------------------------------------
# Function: usage (required function)
#
# Input:
# $1 - style, either -h (for short form) or -man (for man-page like format).
# The default is -h.
#
# $2 - error message (optional). Specify this if usage() is called due to
# user error, in which case the given message displayed first, followed by the
# standard usage message (short or long depending on $1). If displaying an
# errror, usually $1 should be -h so that the longer usage message doesn't
# obsure the error message.
#
# Sample Usage:
# usage
# usage -h
# usage -man
# usage -h "Incorrect command line usage."
#------------------------------------------------------------------------------
function usage
{
declare style=${1:--h}
declare errorMessage=${2:-Unset}
if [[ $errorMessage != Unset ]]; then
echo -e "\n\nUsage Error:\n\n$errorMessage\n\n"
fi
echo "USAGE for $THISSCRIPT v$Version:
$THISSCRIPT [-y] [-d <sdp_dir>] [-L <log>] [-v<n>] [-n] [-D]
or
$THISSCRIPT [-h|-man|-V]
"
if [[ $style == -man ]]; then
echo -e "
DESCRIPTION:
The HMS \"tight ship\" setup script transforms a standard SDP
installation into a tight-ship style installation on the master
server machine.
A tight ship installation is one in which:
* The key SDP folders, e.g. /p4/common and /p4/N/bin (for
each instance) are versioned locally using SDP.<hostname>
workspaces in a local 'hms' instance, which this script will
create and initialize.
* The crontab for the Perforce user is versioned.
* Any local configuration and/or customizations of the SDP
are versioned.
* The 'hms' instance is aware of The Workshop, a public
Helix server hosted by Perforce Software. It fetches SDP
updates from The Workshop into the local hms instance using
Helix DVCS features.
This simplifies future updates of the SDP, allowing them
to be done with a 'p4 fetch' followed by a 'p4 merge'
on your local server (if the server can reach The
Workshop directly; if not an alternative
approach using an interim personal repo can be used to
bridge 'air gap' networks).
PRE-REQUISITES:
The following are pre-requisites to running $THISSCRIPT:
1. The SDP configuration script, mkdirs.sh must have been
configured and run.
The SDP is expected to exist in /depotdata/sdp (or whatever
diretory is specified with '-d <sdp_dir>'). This may have
been populated via a tar file or workspace pulling files from
The Workshop (P4PORT=workshop.perforce.com:1666),
pulling files from //guest/perforce_software/sdp/main on that
server.
The /depotdata/sdp/Server/Unix/setup/mkdirs.sh must already be
configured correctly, and have been run for at least one
instance. The password stored in the newest of the
/p4/common/config/.p4passwd.*.p4admin files will be used
for the perforce user for the hms instance.
2. The /p4/common/config/sdp_hosts.cfg file is configured to
reference only this current master server machine. If this
file does not exist, a template can be copied from
/depotdata/sdp/Server/Unix/p4/common/config/sdp_hosts.cfg.
3. Perforce crontab initialized.
The crontab for the perforce user must already be configured as
intended.
4. No cruft symlinks in /p4.
In the /p4 directory, and /p4/<N> symlinks which contain a
/p4/<N>/root/server.id file are considered to be valid SDP
instances. This script will attempt to manage any such files.
5. The OSUSER (typically 'perforce') has full sudo privs.
The OSUSER must be able to execute 'sudo su' commands without
a password. This can be accomplished on modern Linux systems
by creating /etc/sudoers.d/perforce, with this one line of
contents:
perforce ALL=(ALL) NOPASSWD: ALL
If configured properly, the following command should execute
without error:
sudo /bin/ls /etc/sudoers.d
6. No hms instancey
There should not (yet) be an hms instance.
ADDITIONAL SETUP:
The following setup is necessary before operating in a tight
ship environment, but are not necessary before running this
script.
1. The SSH keys must be configured enabling the 'perforce' user
to ssh without a password to all machines listed in sdp_hosts.cfg
configured above, including the current host (i.e. it must be
able to ssh to itself using the current hostname).
OPTIONS:
-y Continue past the preflight without an interactive prompt.
-d <sdp_dir>
Specify the root of the directory tree where the SDP package
is available, the directory which contains an already-configured
SDP configuration script, mkdirs.sh
The default is: $SDPInstallDirDefault
-v<n> Set verbosity 1-5 (-v1 = quiet, -v5 = highest).
-L <log>
Specify the path to a log file, or the special value 'off' to disable
logging. By default, all output (stdout and stderr) goes to:
$(dirname ${P4U_LOG}).
NOTE: This script is self-logging. That is, output displayed on the screen
is simultaneously captured in the log file. Do not run this script with
redirection operators like '> log' or '2>&1', and do not use 'tee.'
-n No-Op. Prints commands instead of running them.
-D Set extreme debugging verbosity.
HELP OPTIONS:
-h Display short help message
-man Display man-style help message
-V Dispay version info for this script and its libraries.
FILES:
EXAMPLES:
This is best done immediately after a standard SDP
installation, and must be run on the same master server
machine where the SDP was installed.
SEE ALSO:
"
fi
exit 1
}
#==============================================================================
# Command Line Processing
declare -i shiftArgs=0
set +u
while [[ $# -gt 0 ]]; do
case $1 in
(-d) SDPInstallDir=$2; shiftArgs=1;;
(-y) Interactive=0;;
(-h) usage -h;;
(-man) usage -man;;
(-V) show_versions; exit 1;;
(-v1) export VERBOSITY=1;;
(-v2) export VERBOSITY=2;;
(-v3) export VERBOSITY=3;;
(-v4) export VERBOSITY=4;;
(-v5) export VERBOSITY=5;;
(-L) export P4U_LOG=$2; shiftArgs=1;;
(-n) export NO_OP=1;;
(-D) set -x;; # Debug; use 'set -x' mode.
(*) usage -h "Unknown arg ($1).";;
esac
# Shift (modify $#) the appropriate number of times.
shift; while [[ $shiftArgs -gt 0 ]]; do
[[ $# -eq 0 ]] && usage -h "Incorrect number of arguments."
shiftArgs=$shiftArgs-1
shift
done
done
set -u
#==============================================================================
# Command Line Verification
[[ $P4U_LOG == Unset ]] && \
export P4U_LOG="/tmp/tight_ship_setup.$(date +'%Y%m%d-%H%M%S').log"
[[ $SDPInstallDir == Unset ]] && SDPInstallDir="$SDPInstallDirDefault"
[[ -d "$SDPInstallDir" ]] || \
bail "The SDP install dir [$SDPInstallDir] does not exist. Specify the correct value with '-d <sdp_dir>'."
#==============================================================================
# Main Program
trap terminate EXIT SIGINT SIGTERM
declare -i OverallReturnStatus=0
if [[ "${P4U_LOG}" != off ]]; then
touch ${P4U_LOG} || bail "Couldn't touch log file [${P4U_LOG}]."
# Redirect stdout and stderr to a log file.
exec > >(tee ${P4U_LOG})
exec 2>&1
initlog
fi
#------------------------------------------------------------------------------
msg "Starting Preflight Checklist."
PreflightOK=1
SDPConfigScript="$SDPInstallDir/Server/Unix/setup/mkdirs.sh"
[[ -x "$SDPConfigScript" ]] ||\
{
PreflightOK=0
errmsg "SDP config script not executable: [$SDPConfigScript]."
}
vmsg "Verified: SDP config script is executable: [$SDPConfigScript]."
SDPHostsFile="/p4/common/config/sdp_hosts.cfg"
[[ -f "$SDPHostsFile" ]] ||\
{
PreflightOK=0
errmsg "SDP hosts file missing: [$SDPHostsFile].\nCreate thaat file from this template: $SDPInstallDir/Server/Unix/p4/common/config/sdp_hosts.cfg\n"
}
vmsg "Verified: SDP hosts file exists: [$SDPHostsFile]."
# Extact values already defined in mkdirs.sh.
DD=$(grep "^DD=" $SDPConfigScript|tail -1|cut -d '=' -f 2)
MD=$(grep "^MD=" $SDPConfigScript|tail -1|cut -d '=' -f 2)
LG=$(grep "^LG=" $SDPConfigScript|tail -1|cut -d '=' -f 2)
OSUSER=$(grep "^OSUSER=" $SDPConfigScript|tail -1|cut -d '=' -f 2)
# Removed excess whitespace.
MD=$(echo $MD)
DD=$(echo $DD)
LG=$(echo $LG)
OSUSER=$(echo $OSUSER)
# Find all active SDP Instances.
ActiveInstances=""
for i in /p4/*; do
[[ -L $i ]] || continue
[[ -f $i/root/server.id ]] || continue
ActiveInstances+=" ${i#/p4/}"
done
# Trim excess whitespace.
ActiveInstances=$(echo $ActiveInstances)
if [[ -n "$ActiveInstances" ]]; then
msg "The following active SDP instances were detected: $ActiveInstances."
else
PreflightOK=0
errmsg "No Active SDP Instances Detected."
fi
for dir in "/p4" "/$DD/p4/common/bin" "/$MD/p4" "/$LG/p4"; do
if [[ -d "$dir" ]]; then
vmsg "Verified: SDP directory exists: [$dir]."
else
PreflightOK=0
errmsg "Missing SDP directory: [$dir]."
fi
done
for i in $ActiveInstances; do
for dir in "/$DD/p4/$i/bin" "/$DD/p4/$i/checkpoints" "/$DD/p4/$i/depots" "/$MD/p4/$i/root" "/$LG/p4/$i/logs"; do
if [[ -d "$dir" ]]; then
vmsg "Verified: SDP directory for instance $i exists: [$dir]."
else
PreflightOK=0
errmsg "Missing SDP directory for instance $i: [$dir]."
fi
done
done
for dir in "/$DD/p4/hms" "/$MD/p4/hms" "/$LG/p4/hms"; do
if [[ -d "$dir" ]]; then
PreflightOK=0
errmsg "HMS SDP directory exists but should not: [$dir]."
else
vmsg "Verified: HMS SDP directory doesn't (yet) exist: [$dir]."
fi
done
if [[ $(id -u -n) != $OSUSER ]]; then
PreflightOK=0
errmsg "Must run as $OSUSER, not $(id -u -n)."
else
vmsg "Verified: Running os OSUSER ($OSUSER)."
fi
# Test sudo access. Ignore the NO_OP setting since we want
# to try this preflight check even in no-op mode
run "sudo /bin/ls /etc/sudoers.d > /dev/null" "Testing sudo access. If prompted for a password, do Ctrl-C." 0 1
if [[ $CMDEXITCODE -eq 0 ]]; then
vmsg "Verified: OSUSER ($OSUSER) has sudo privs."
else
PreflightOK=0
errmsg "Could not verify sudo access for OSUSER $OSUSER. Sudo access required."
fi
if [[ $PreflightOK -eq 1 ]]; then
msg "Preflight Checklist Completed OK. Proceeding ..."
else
bail "Aborting due to preflight checklist failures."
fi
if [[ $Interactive -ne 0 ]]; then
input=""
while [[ -z "$input" ]]; do
echo -e "\nProceed [y/Y/n/N]?: "
read -e input
if [[ "${input}" == "Y" || $input == "y" ]]; then
continue
elif [[ "${input}" == "N" || $input == "n" ]]; then
msg "Confirmation to proceed not received. Halting."
exit 1
fi
done
fi
#------------------------------------------------------------------------------
msg "${H2}\nStep 1: Initialize /p4/hms SDP instance."
#------------------------------------------------------------------------------
msg "${H2}\nStep 2: Populate HMS instance with static load data."
#------------------------------------------------------------------------------
msg "${H2}\nStep 3: Fetch SDP from The Workshop."
#------------------------------------------------------------------------------
msg "${H2}\nStep 4: Detect local config changes to mkdirs.sh."
#------------------------------------------------------------------------------
msg "${H2}\nStep 5: Version key in /p4/common and /p4/N/bin dirs."
#------------------------------------------------------------------------------
msg "${H2}\nStep 6: Do initial live checkpoint for new hms instance."
#------------------------------------------------------------------------------
if [[ $OverallReturnStatus -eq 0 ]]; then
msg "${H}\nAll processing completed successfully.\n"
else
msg "${H}\nProcessing completed, but with errors. Scan above output carefully.\n"
fi
# Illustrate using $SECONDS to display runtime of a script.
msg "That took $(($SECONDS/3600)) hours $(($SECONDS%3600/60)) minutes $(($SECONDS%60)) seconds.\n"
# See the terminate() function, which is really where this script exits.
exit $OverallReturnStatus
| # | Change | User | Description | Committed | |
|---|---|---|---|---|---|
| #11 | 25596 | C. Thomas Tyler |
Released SDP 2019.2.25594 (2019/05/02). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
| #10 | 25483 | C. Thomas Tyler |
Released SDP 2019.1.25480 (2019/04/11). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
| #9 | 25245 | C. Thomas Tyler |
Released SDP 2019.1.25238 (2019/03/02). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
| #8 | 22685 | Russell C. Jackson (Rusty) | Update main with current changes from dev. | ||
| #7 | 22185 | C. Thomas Tyler |
Released SDP 2017.2.22177 (2017/05/17). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
| #6 | 21532 | C. Thomas Tyler |
Released SDP 2016.2.21528 (2017/01/14). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
| #5 | 21483 | C. Thomas Tyler |
Released SDP 2016.2.21480 (2017/01/11). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
| #4 | 21338 | C. Thomas Tyler |
Released SDP 2016.2.21328 (2016/12/16). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
| #3 | 21290 | C. Thomas Tyler |
Updated HMS tight ship setiup script; now passes preliminary tests. Bypassing pre-commit review for work-in-progress development of new, unreleased functionality. |
||
| #2 | 21091 | C. Thomas Tyler |
Enhancements to hms_ts_setup.sh and auxiliary files. Enahnced preflight checks to include sudo access check, etc. Enhanced cosmetics. Enhanced doc, adding Additional Setup section. This is still a doc-only verison. Bypassing pre-commit review. #review-21092 |
||
| #1 | 21081 | C. Thomas Tyler |
Added preliminary files in support of automation of the HMS Tight Ship installation. The key file here hs hms_ts_setup.sh, which is currently a 'doc only' script that documents what it is intended to do, although it doesn't currently do anything that affects data. The '-h' and '-man' flags work to convey their intent. This also contains various spec files to be used in the actual implementation. Bypassing pre-commit review since this is only adding new 'doc only' code, not active software. #review-21082 |