reset_sdp.sh #158

  • //
  • guest/
  • perforce_software/
  • helix-installer/
  • dev/
  • src/
  • reset_sdp.sh
  • View
  • Commits
  • Open Download .zip Download (90 KB)
#!/bin/bash
#==============================================================================
# Copyright and license info is available in the LICENSE file included with
# this package, and also available online:
# https://swarm.workshop.perforce.com/projects/perforce_software-helix-installer/view/main/LICENSE
#------------------------------------------------------------------------------

#==============================================================================
# Declarations
set -u

declare ThisScript="${0##*/}"
declare Version=4.7.2

# The latest SDP release tarfile has a consistent name, sdp.Unix.tgz,
# alongside the version-named tarball (e.g. sdp.Unix.2019.3.26494.tgz).
# This is best when you want the latest officially released SDP.

# An alternate install method uses Helix native DVCS features to get the very
# latest code from a branch ('dev' by default) using a 'p4 clone' command.
# Alternately, the '-d' flag can be used to copy from a local directory.
declare SDPTar="sdp.Unix.tgz"

# See usage info for the '-d' flag in this script.
declare SDPCopyDir="/sdp"
declare SDPURL="https://swarm.workshop.perforce.com/projects/perforce-software-sdp/download/downloads/$SDPTar"
declare SDPInstallMethod=FTP
declare SDPInstallBranch=Unset
declare FTPURL="https://ftp.perforce.com/perforce"
declare WorkshopPort="public.perforce.com:1666"
declare WorkshopUser=ftp
declare WorkshopRemote=
declare WorkshopBaseURL="https://swarm.workshop.perforce.com"
declare HelixInstallerProjectURL="$WorkshopBaseURL/projects/perforce_software-helix-installer"
declare HelixInstallerBaseURL="$HelixInstallerProjectURL/download"
declare HelixInstallerTarURL="$HelixInstallerBaseURL/downloads/helix_installer.tgz"
declare HelixInstallerBranch="main"
declare HelixInstallerURL="$HelixInstallerBaseURL/$HelixInstallerBranch"
declare HelixInstallerFileURL=
declare HxMetadata1=
declare HxMetadata2=
declare HxLogs=
declare DirList=
declare Hostname=
declare Timezone=
declare UseSystemdOption=
declare -i UseSystemd=1
declare -i CMDEXITCODE

# The values for set here are for use in the usage() function if '-man' is
# used. They are set again further down in the code below, after settings
# are loaded from the config file which might change the values set here.
declare HxDepots="hxdepots"
declare BinDir="/$HxDepots/helix_binaries"
declare ApiArch="linux26x86_64"
declare P4BinRel=r21.1
declare P4APIRel=r21.1
declare RunUser="perforce"
declare ResetHome="/$HxDepots/reset"
declare DownloadsDir="/$HxDepots/downloads"
declare SudoersEntry="$RunUser ALL=(ALL) NOPASSWD: ALL"
declare SudoersFile="/etc/sudoers.d/$RunUser"
declare SudoersDir="${SudoersFile%/*}"
declare BinList=
declare ServerBin=
declare MailSimulator="/p4/common/site/bin/mail"
declare LimitedSudoersTemplate="$ResetHome/perforce_sudoers.t"

# This lists all files needed to operate the Helix Installer, which can be
# acquired during runtime operation in environments where outbound access to
# the public internet is available, or provisioned ahead of time for
# operation when such access is not available.
declare HelixInstallerFiles="NoTicketExpiration.group.p4s admin.user.p4s configure_sample_depot_for_sdp.sh p4broker_N.service.t p4broker_N.xml.t p4d_N.service.t p4d_N.xml.t p4p_N.service.t perforce_bash_profile perforce_bashrc protect.p4s perforce_sudoers.t r"
declare SDPHome=
declare TmpFile=/tmp/tmp.reset_sdp.$$.$RANDOM
declare TmpDir=/tmp/tmp.dir.reset_sdp.$$.$RANDOM
declare ShelvedChange=Unset
declare LocalShelvedChange=Unset
declare CmdLine="${0##*/} $*"
declare -i WarningCount=0
declare -i ErrorCount=0
declare InitMechanism=Unset
declare PackageManager=Unset
declare -A PackageList
declare -A Config ConfigDoc
declare -i BlastDownloadsAndBinaries=0
declare -i StopAfterReset=0
declare -i ExtremeCleanup=0
declare -i InstallDerivedAPIs=0
declare -i LoadSampleDepot=1
declare -i PullFromWebAsNeeded=1
declare -i UseSSL=1
declare -i GenDefaultConfig=0
declare -i LimitedSudoers=0
declare -i MultiRun=0
declare -i SetHostname=0
declare -i SetTimezone=0
declare -i SetServerID=0
declare -i SetServerType=0
declare -i SetSimulateEmail=0
declare -i SetListenPort=0
declare -i SetTargetPort=0
declare -i SetTargetServerID=0
declare -i SimulateEmail=0
declare -i UseBroker=0
declare -i UseConfigFile=0
declare ConfigFile=Unset
declare PreserveDirList=Unset
declare RunUserNewHomeDir=
declare RunUserHomeDir=
declare RunGroup=Unset
declare UserAddCmd=
declare P4YumRepo="/etc/yum.repos.d/perforce.repo"
declare P4AptGetRepo="/etc/apt/sources.list.d/perforce.list"
declare PerforcePackageRepoURL="https://package.perforce.com"
declare PerforcePackagePubkeyURL="$PerforcePackageRepoURL/perforce.pubkey"
declare TmpPubKey=/tmp/perforce.pubkey
declare -i AddPerforcePackageRepo=1
declare -i InstallCrontab=1
declare -i UpdatePackages=1
declare -i RunOSTweaks=1
declare SampleDepotTar=
declare CrontabFileInP4=
declare CrontabFile=
declare ThisArch=
declare ThisHost=
declare ThisOS=
declare ThisOSName=
declare ThisOSDistro=
declare ThisOSMajorVersion=
declare FirewallType=
declare FirewallDir=
declare ThisUser=
declare RunArch="x86_64"
declare CBIN="/p4/common/bin"
declare CCFG="/p4/common/config"
declare -i DoSDPVerify=0
declare SDPVerify="$CBIN/verify_sdp.sh"
declare SDPVerifyCmd=
declare SDPVerifyOptions=
declare SDPVerifySkipTests=
declare SystemdTemplatesDir="/p4/common/etc/systemd/system"
declare SDPSetupDir="/p4/sdp/Server/Unix/setup"
declare SDPUnsupportedSetupDir="/p4/sdp/Unsupported/setup"
declare OSTweaksScript="$SDPSetupDir/os_tweaks.sh"
declare SDPCrontabDir=
declare SDPInstances="1"
declare SDPDefaultInstance=
declare OSTweaksScript=
declare ServerID=
declare ServerType=
declare ListenPort=
declare TargetPort=
declare TargetServerID=
declare MkdirsCmd=

#==============================================================================
# Static Configuration - Package Lists

# The associative array 'PackageList' defines packages required for each
# package manager (yum, apt-get, or zypper).
PackageList['yum']="cronie curl gcc gcc-c++ mailx make openssl openssl-devel rsync tar wget which zlib zlib-devel"
PackageList['apt-get']="build-essential cron libssl-dev make zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev rsync"
PackageList['zypper']="cronie curl gcc gcc-c++ make openssl openssl-devel wget which zlib zlib-devel rsync"

#==============================================================================
# Static Configuration - User Config Data

# User modifiable data is defined in the 'Config' associative array, with
# corresponding user documentation in the 'ConfigDoc' array, corresponding
# to the settings.cfg file the user modifies.

# To add a new setting, define values for both Config['YourNewValue] and
# ConfigDoc['YourNewValue]' in this block. Also, ensure the values are written
# in the appropriate section of the sample config file generated in the
# function gen_default_config().

#------------------------------------------------------------------------------
# Settings Section 1: Localization
# Keep the order that settings are defined here in sync with the 'for c in'
# loop in gen_default_config() for Section 1 below. That defines the desired
# order of appearance in the generated file.

ConfigDoc['SMTPServer']="\\n# Specify email server for the p4review script. Ignore if Helix Swarm is used."
Config['SMTPServer']="smtp.p4demo.com"
ConfigDoc['P4AdminList']="\\n# Specify an email address to receive updates from admin scripts. This may be\\n# a distribution list or comma-separated list of addresses (with no spaces)."
Config['P4AdminList']="P4AdminList@p4demo.com"
ConfigDoc['MailFrom']="\\n# Specify an email address from which emails from admin scripts are sent.\\n# This must be a single email address."
Config['MailFrom']="P4Admin@p4demo.com"
ConfigDoc['DNS_name_of_master_server']="\\n# Specify the DNS alias to refer to he master server, e.g. by end\\n# users. This might be 'perforce' but probably not an actual host name\\n# like 'perforce01', which would be known only to admins."
Config['DNS_name_of_master_server']="helix"
ConfigDoc['SiteTag']="\\n# Specify a geographic site tag for the master server location,\\n# e.g. 'bos' for Boston, MA, USA."
Config['SiteTag']="bos"
ConfigDoc['Hostname']="\\n# Specify the hostname.  This can be left blank. If set on a system that supports\\n# the 'hostnamectl' utility, that utility will be used to set the hostname.  If the\\n# command line parameter '-H <hostname>' is used, that will override this setting."
Config['Hostname']=""
ConfigDoc['Timezone']="\\n# Specify the timezone.  This can be left blank. If set on a system that supports\\n# the 'timedatectl' utility, that utility will be used to set the timezone.  If the\\n# command line parameter '-T <timezone>' is used, that will override this setting."
Config['Timezone']=""

#------------------------------------------------------------------------------
# Settings Section 2: Data Specific
# Keep the order that settings are defined here in sync with the 'for c in'
# loop in gen_default_config() for Section 2 below. That defines the desired
# order of appearance in the generated file.

ConfigDoc['P4_PORT']="\\n# Specify the TCP port for p4d to listen on. Typically this is 1999 if \\n# p4broker is used, or 1666 if only p4d is used."
Config['P4_PORT']="1999"
ConfigDoc['P4BROKER_PORT']="\\n# Specify the TCP port for p4broker to listen on. Must be different\\n# from the P4_PORT."
Config['P4BROKER_PORT']="1666"
ConfigDoc['Instance']="\\n# Specify SDP instance name, e.g. '1' for /p4/1."
Config['Instance']="1"
ConfigDoc['CaseSensitive']="\\n# Helix Core case sensitivity, '1' (sensitive) or '0' (insensitive). If\\n# data from a checkpoint is to be migrated into this instance, set this\\n# CaseSensitive value to match the case handling of the incoming data set\\n# (as shown with 'p4 info')."
Config['CaseSensitive']="1"
ConfigDoc['P4USER']="\\n# Set the P4USER value for the Perforce super user."
Config['P4USER']="perforce"
ConfigDoc['Password']="\\n# Set the password for the super user (see P4USER). If using this Helix Installer to\\n# bootstrap a production installation, replace this default password with your own."
Config['Password']="F@stSCM!"
ConfigDoc['SimulateEmail']="\\n# Specify '1' to avoid sending email from admin scripts, or 0 to send\\n# email from admin scripts."
Config['SimulateEmail']="1"
ConfigDoc['ServerID']="\\n# Specify a ServerID value. Leave this value blank for master/commit servers.\\n# The value for master/commit servers is set automatically."
Config['ServerID']=""
ConfigDoc['ServerType']="\\n# Specify the type of server. Valid values are:\\n# * p4d_master - A master/commit server.\\n# * p4d_replica - A replica with all metadata from the master (not filtered in\\n# any way).\\n# * p4d_filtered_replica - A filtered replica or filtered forwarding replica.\\n# * p4d_edge - An edge server.\\n# * p4d_edge_replica - Replica of an edge server. Also set TargetServerID.\\n# * p4broker - An SDP host running only a broker, with no p4d.\\n# * p4proxy - An SDP host running a proxy (maybe with a broker in front), with\\n# no p4d.\\n#\\n# The ServerID must also be set if the ServerType is any p4d_*\\n# type other than 'p4d_master'."
Config['ServerType']="p4d_master"
ConfigDoc['TargetServerID']="\\n# Set only if ServerType is p4d_edge_replica. The value is the ServerID of\\n# edge server that this server is a replica of, and must match the\\n# 'ReplicatingFrom:' field of the server spec."
Config['TargetServerID']=
ConfigDoc['TargetPort']="\\n# Specify the target port for a p4proxy or p4broker."
Config['TargetPort']=
ConfigDoc['ListenPort']="\\n# Specify the listening port for a p4proxy or p4broker."
Config['ListenPort']=

#------------------------------------------------------------------------------
# Settings Section 3: Deep Customization
# Keep the order that settings are defined here in sync with the code in
# gen_default_config() for Section 3 below. That defines the desired order of
# appearance in the generated file.

ConfigDoc['OSUSER']="\\n# Specify the Linux Operating System account under which p4d and other Helix\\n# services will run as. This user will be created if it does not exist. If\\n# created, the password will match that of the P4USER."
Config['OSUSER']="perforce"
ConfigDoc['OSGROUP']="\\n# Specify the primary group for the Linux Operating System account specified\\n# as OSUSER."
Config['OSGROUP']="perforce"
ConfigDoc['OSUSER_ADDITIONAL_GROUPS']="\\n#Specify a comma-delimited list of any additional groups the OSUSER to be\\n# created should be in.  This is passed to the 'useradd' command the '-G'\\n# flag. These groups must already exist."
Config['OSUSER_ADDITIONAL_GROUPS']=
ConfigDoc['OSUSER_HOME']="\\n# Specify home directory of the Linux account under which p4d and other Helix\\n# services will run as, and the group, in the form <user>:<group>.  This user\\n# and group will be created if they do not exist."
Config['OSUSER_HOME']="/home/perforce"
ConfigDoc['P4BinRel']="\\n# The version of Perforce Helix binaries to be downloaded: p4, p4d, p4broker, and p4p."
Config['P4BinRel']="$P4BinRel"
ConfigDoc['P4APIRel']="\\n# The version of the C++ API to be downloaded, for building dervied APIs such\\n# as P4Perl and P4Python.  This is typically the same as P4BinRel, but\\n# sometimes behind as P4Perl and P4Python can lag behind Helix Core releases."
Config['P4APIRel']="$P4APIRel"
ConfigDoc['HxDepots']="\\n# Define the directory that stores critical digital assets that must be\\n# backed up, including contents of versioned files, metadata checkpoints,\\n# and numbered journal files."
Config['HxDepots']="/hxdepots"
ConfigDoc['HxLogs']="\\n# Define the directory used to store the active journal (P4JOURNAL) and\\n# various logs."
Config['HxLogs']="/hxlogs"
ConfigDoc['HxMetadata1']="\\n# The /HxMetadata1 and /HxMetadata1 settings define two interchangeable\\n# directories that store either active/live metadata databases (P4ROOT) or\\n# offline copies of the same (offline_db). These typically point to the same\\n# directory. Pointing them to the same directory simplifies infrastructure\\n# and enables the fastest recovery options. Using multiple metadata volumes\\n# is typically done when forced to due to capacity limitations for metadata\\n# on a single volume, or to provide operational survivability of the host in\\n# event of loss of a single metadata volume."
Config['HxMetadata1']="/hxmetadata"
ConfigDoc['HxMetadata2']=
Config['HxMetadata2']="/hxmetadata"

#------------------------------------------------------------------------------
# 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}

   msg "USAGE for $ThisScript v$Version:

$ThisScript [-c <cfg>] [-no_ssl] [-no_sd] [-no_cron] [-no_ppr] [-no_systemd] [-no_tweaks] [-ls] [-v] [-fast|-dapi] [-t <ServerType>] [-s <ServerID>] [-ts <TargetServerID>] [-tp <TargetPort>] [-lp <ListenPort>] [-se] [-H <hostname>] [-T <timezone>] [-local|-B] [[-d <sdp_dir>] | [-b <branch>[,@cl]]] [-p <dir1>[,<dir2>,...]>] [-i <helix_installer_branch>] [-D] [-X|-R] [-M]

or

$ThisScript -C > settings.cfg

or

$ThisScript [-h|-man]
"
   if [[ $style == -man ]]; then
      msg "
SAFETY NOTICE:
	This script SHOULD NEVER EXIST on a Production Perforce server.

DESCRIPTION:
	This script simplifies 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.

	It installs the Perforce Helix Core server (P4D) with a P4Broker,
	and installs the Perforce Sample Depot data set used for training
	and PoC installations.

	It is helpful when bootstrapping a demo server with a sample data
	set, complete with broker, and optionally Perl/P4Perl and
	Python/P4Python.

	This script handles many aspects of installation. It does the
	following:
	* Creates the OS user that will run the Helix Core p4d process,
	  the 'perforce' user by default, using the 'useradd' command,
	  unless that account already exists.  If a non-local account
	  is to be used, that should be created first before running this
	  script. If the account is created using 'useradd', the password
	  will be set to match that of the admin P4USER, which is also
	  'perforce' by default (matching the OSUSER).
	* Creates the home directory for the OSUSER user, if needed.
	* Adds OS packages as needed for P4Perl/P4Python local builds
	  (if -dapi is specified).

	Following installation, it also does the following to be more
	convenient for demos, and also give a more production-like feel:
	* Grants the perforce user sudo access (full or limited).
	* Creates default ~perforce/.bash_profile and .bashrc files.
	* Connects to the Perforce Package Repository (APT and YUM only).
	* Adds firewalld rules for Helix server and broker ports ('firewalld'
	only; there is no support for the 'ufw' or other firewalls).
	* Installs crontab for ~perforce user.

PLATFORM SUPPORT:
	This works on Red Hat Enterprise Linux, CentOS, and Mac OSX
	10.10+ thru Mojave platforms.  It works on RHEL/CentOS
	6.4-7.6, SuSE Linux 12, and likely on Ubuntu 18 and other Linux
	distros with little or no modification.

	This script currently supports the bin.linux26x86_64 (Linux) and
	bin.maxosx1010x86_64 (Mac OSX/Darwin) architectures.

	This script recognizes SysV, Systemd, and Launchd init mechanisms,
	though does not currently support Launchd on OSX.

	For Mac OSX, note that this requires bash 4.x, and the default
	bash on Mac OSX remains 3.x as of OSX Mojave.  For operating on
	Mac, the /bin/bash shebang line needs to be adjusted to reference
	a bash 4 version, e.g. /usr/local/bin/bash if installed with
	Homebrew.

REQUIREMENTS:
	The following OS packages are installed (unless '-fast' is
	used):

	* Yum: ${PackageList[yum]}

	* AptGet: ${PackageList[apt-get]}

	* Zypper: ${PackageList[zypper]}

	Development utilities such as 'make', the 'gcc' compiler,
	and 'curl' must be installed and available in the PATH (unless
	running with '-fast').  The package installation as noted
	above ensures these dependencies are available.

OPTIONS:
 -c <cfg>
	Specify a config file.  By default, values for various settings
	such as the email to send script logs to are configure with
	demo values, e.g. ${Config['P4AdminList']}.  Optionally, you can
	specify a config file to define your own values.

	For details on what settings you can define in this way, run:
	$ThisScript -C > setings.cfg

	Then modify the generated config file settings.cfg as desired.
	The generated config file contains documentation on settings and
	values.  If no changes are made to the generated file, running with
	'-c settings.cfg' is the equivalent of running without using '-c' at
	all.

 -C	See '-c <cfg>' above.

 -no_ssl
	By default, the Perforce server is setup SSL-enabled.  Specify
	'-no_ssl' to avoid using SSL feature.

 -no_sd
	By default, the Perforce Sample Depot data set is loaded.
	Specify '-no_sd' to skip loading the Sample Depot.

 -no_cron
	Skip initialization of the crontab.

 -no_ppr
	Skip addition of the Perforce Package Repository for YUM/APT
	repos.  By default, the Package Repository is added.

 -ls	Specify that only limited sudo is to be granted.  By default
 	full sudo access is granted to the OSUSER by adding this file:

	$SudoersFile

	with these contents:

	$SudoersEntry

	If '-ls' is specified, limited sudoers access is provisioned,
	with just enough access to execute commands like:

	systemctl <start|stop|status> p4d_*
	systemctl <start|stop|status> p4dtg_*
	systemctl <start|stop|status> p4broker_*
	systemctl <start|stop|status> p4p_*

	For more detail, see the template file: perforce_sudoers.t

 -v
 	Specify '-v' to run the verify_sdp.sh script after the SDP
	installation is complete. If '-v' is specified and the
	verify_sdp.sh script is available in the SDP, it is executed.
	If the Sample Depot is loaded, the '-online' flag to the
	verify_sdp.sh script is added.  If '-no_cron' is specified,
	the corresponding '-skip cron' option is added verify_sdp.sh.
	If '-no_sd' is specified, the '-skip' tests also exclude
	the offline_db and p4t_files checks in verify_sdp.sh.

 -fast	Specify '-fast' to skip package installation using
	the package manager (yum, apt-get, or zypper).

	The '-fast' flag should not be used if you plan to
	deploy or develop triggers that use P4Python or P4Perl,
	such as the SDP CheckCaseTrigger.py.

 -dapi	Specify '-dapi' (derived API) to attempt install of
	the SDP derived APIs if they are available in the
	SDP package.

	Without the '-dapi' option, installation takes only a
       	few minutes typically.  With '-dapi', expect the
	install to take 20+ minutes due to the time to do
	builds and run automated tests suites for Perl, Python,
	P4Perl, and P4Python.

	The '-fast' and '-dapi' options are mutually exclusive.

	If '-dapi' is not used and a need arises afterward to
	install the derived APIs, that can be done with by running
	the following as the configured OSUSER ('$RunUser' by default):

	cd $SDPSetupDir
	./install_sdp_python.sh
	./install_sdp_perl.sh

	Note: These install_sdp_*.sh scripts may not be available in
	the SDP Package. Also, required packages such as gcc/g++ may
	need to be installed separately

 -local
	By default, various files and binaries are downloaded from
	the Perforce Workshop and the Perforce FTP server as needed.
	If the server machine on which the Helix Installer is to be
	run cannot reach the public internet or if using files from
	external sites is not desired, the '-local' flag can be used.

	With '-local', needed files must be acquired and put in place
	on the server machine on which this script is to be run.  Any
	missing files result in error messages.

	The '-local' argument cannot be used with -B.

	For '-local' to work, the following must exist:

	1. Helix Binaries
	
	Helix binaries must exist in $BinDir:

	* $BinDir/p4
	* $BinDir/p4d
	* $BinDir/p4broker
	* $BinDir/p4p

	2. Server Deployment Package (SDP)

	The SDP tarball must be acquired an put in place here:

	* $DownloadsDir/$SDPTar

	3. Sample Depot Tarball
	
	The Sample Depot appropriate to your platform must exist unless the
	the '-no_sd' ('No Sample Depot') is used.

	* $DownloadsDir/sampledepot.mac.tar.gz (on Mac/OSX if case-insensitive)
	* $DownloadsDir/sampledepot.tar.gz (on UNIX/Linux or case-sensitive Mac)

	4. Helix Installer

	With '-local', the 'reset_sdp.sh' script and all related files must
	be acquired and placed in $ResetHome.

	See EXAMPLES below for sample of acquiring files for use with
	'-local' mode.

 -B	Specify '-B' to blast base SDP dirs, for a clean start.

	Otherwise without '-B', downloaded components from earlier
	runs will be used (which should be fine if they were run
	recently).

	The '-B' flag also replaces files in the $ResetHome
	directory, where this script lives, with those downloaded
	from The Workshop (the versions of which are affected
	by the '-i <helix_installer_branch>' flag, described
	below).

	The '-B' flag also blasts the /tmp/downloads and /tmp/p4perl
	directories, used by install_sdp_python.sh and
	install_sdp_perl.sh, if they exist.

 -no_systemd
	Specify '-no_systemd' to avoid using systemd, even if it
	appears to be available. By default, systemd is used if it
	appears to be available.

	This is helpful in operating in containerized test environments
	where systemd is not available.

 -no_tweaks
 	Skip execution of the SDP operating system tweaks script,
	os_tweaks.sh.

 -t <ServerType>
 
 	Specify the type of server. Valid values are:

	* p4d_master - A master/commit server.
	* p4d_replica - A replica with all metadata from the master (not
	  filtered i any way).
	* p4d_filtered_replica - A filtered replica or filtered forwarding
	  replica.
	* p4d_edge - An edge server.
	* p4d_edge_replica - Replica of an edge server. Also set
	  TargetServerID.
	* p4broker - An SDP host running only a p4broker, with no p4d.
	* p4proxy - An SDP host running only a p4proxy, with no p4d no p4d.
	
 -s <ServerID>
 	Specify the ServerID.  A ServerID is required if the ServerType is
       	any p4d_* type other than p4d_master.

 -ts <TargetServerID>
 	Specify the Target ServerID. Set this only if ServerType is
	p4d_edge_replica. The value is the ServerID of edge server that
	this server is a replica of, and must match the ReplicatingFrom:
	field of the server spec.

 -tp <TargetPort>
 	Specify the target port.  For p4broker and p4proxy only.

 -lp <ListenPort>
 	Specify the port to listen on.  For p4broker and p4proxy only.

 -se
 	Specify -se to simulate email. This generates a mail simlator
	script: $MailSimulator

 -H <hostname>
 	Set the hostname.  This is only supported on systems that
	support the 'hostnamectl' command. The hostname is set by
	doing: hostnamectl set-hostname <hostname>

	If the corresponding 'Hostname' setting is defined in the
	configuration file and this '-H <hostname>' flag is used,
	the command line option will override the config file.

 -T <timezone>
 	Set the timezone.  This is only supported on systems that
	support the 'timedatectl' command. The timezone is set by
	doing: timedatectl set-timezone <timezone>

	If the corresponding 'Timezone' setting is defined in the
	configuration file and this '-T <timezone>' flag is used,
	the command line option will override the config file.

 -p <dir1>[,<dir2>,...]>]
	Specify a comma-delimited list of directories under /p4/common
	to preserve that would otherwise be removed.  Directories must
	be specified as paths relative to /p4/common, and cannot contain
	spaces.

	For example, the value '-p config,bin/triggers' would preserve the
	$CCFG and $CBIN/triggers directories.

	Directories specified are moved aside to a temporary working area
	before the SDP folders are removed.  After installation, they are
	moved back via an 'rsync' command with no '--delete' option.  This
	means any files that overlap with the stock install are replaced
	by ones that originally existed, but non-overlapping files are not
	removed.

	This is intended to be useful for developing test suites that
	install server under $CBIN, e.g. Component Based Development
	scripts which install under $CBIN/cbd would use '-p bin/cbd'.

 -d <sdp_dir>
	Specify a directory on the local host containing the SDP to deploy.

	Use the special value '-d default' to use the /sdp directory (as per
	the Docker-based SDP Test Suite environment).

	The directory specified by '-d' is expected to contain either:
	* an SDP tarball ($SDPTar) file, or
	* an already-extracted SDP directory, which must include the SDP
	Version file.

 -b <branch>[,@cl]
	The default SDP install method is to use the latest released SDP
	tarball representing the main branch in The Workshop ($WorkshopPort).

	The latest tarball can be found on this server, consistently named
	$SDPTar. This file appears alongside a version-tagged file
	named something like sdp.Unix.2019.2.25938.tgz.  These appear here:
	https://swarm.workshop.perforce.com/projects/perforce-software-sdp/files/downloads

	Specify '-b' to use a different branch, typically '-b dev'.  This
	changes the install method from a tarball to using a 'p4 clone'
	command using Helix native DVCS features to fetch the very latest
	unreleased files from the branch at any point in time. This is mainly
	of interest when testing the SDP or previewing specific up and
	coming features.

	If '-b' is specified with the optional @cl syntax, where @cl
	specifies a changelist with files shelved on the given branch,
	a form of unshelving is done, enabling a workflow for testing
	shelved changes with the Helix Installer.  So for example,
	specify '-b dev,@23123' to clone from the dev branch, and then
	followed by a fetch of shelved changelist @23123, which is
	expected to have files shelved in the dev branch.

DEBUGGING OPTIONS:
 -i	<helix_installer_branch>

	Specify the branch of the Helix Installer to use.  This affects the
	URL from which Helix Installer files in $ResetHome are pulled from
	The Workshop.  The default is main; an alternative is '-i dev'.

 -D     Set extreme debugging verbosity.

 -X	Extreme reset. This removes the user account for the configured
	OSUSER ('$RunUser' by default) and blasts all SDP-related directories
	at the start of script operations, including the home directory
	for the configured OSUSER.

	This also clears firewall rules ('firewalld' only).

	Using '-X' does not blast the Helix Installer downloads or
	helix_binaries directories, and thus is compatible with either the
	'-B' or '-local' options.

	This also does not undo the setting of the hostname or the timezone
	with either the command line ('-H <hostname>' and '-T <timezone>')
	or configuration file settings.

 -R	Specify '-R' to reset.  The cleanup logic is the same as with
	-X.  Unlike -X, with -R, processing stops after the cleanup is
	done.

 -M	Specify '-M' to allow multiple runs. This is useful for running
 	a series of tests. This option disables the safety feature that
	self-disables this script after it completes.
	
	to prevent accidentally running this
	script again, e.g. after real data has been migrated to this
	machine after using this script to bootstrap for production.

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

EXAMPLES:
	=== FAST INSTALLATION (skipping package updates) ===

	su -
    	mkdir -p /hxdepots/reset
	cd /hxdepots/reset
	curl -s -O $HelixInstallerURL/src/$ThisScript
	curl -s -O $HelixInstallerURL/src/r
	chmod +x ${ThisScript} r
	./r

	Note that the 'r' wrapper script calls the $ThisScript script with
	a pre-defined of flags optimized for fast operation.  The 'r' wrapper
	also handles log capture, writing to the file '${ThisScript/sh/log}'.

	=== COMPREHENSIVE INSTALLATION ===

	su -
    	mkdir -p /hxdepots/reset
	cd /hxdepots/reset
	curl -s -O $HelixInstallerURL/src/$ThisScript

	chmod +x $ThisScript
	./$ThisScript 2>&1 | tee ${ThisScript/sh/log}

	=== CONFIGURED INSTALLATION ===

	su -
    	mkdir -p /hxdepots/reset
	cd /hxdepots/reset
	curl -s -O $HelixInstallerURL/src/$ThisScript
	chmod +x $ThisScript

 	### Generate a default config file:
	./$ThisScript -C > settings.cfg

 	### Edit settings.cfg, changing the values as desired:
	vi settings.cfg

	./$ThisScript -c settings.cfg 2>&1 | tee log.reset_sdp

	=== LOCAL INSTALL ===

	The following sample commands illustrate how to acquire the
	dependencies for running with '-local' on a machine that can reach
	the public internet.  The resulting file structure, with paths as
	shown, would need to be somehow copied to the machine where the
	this reset_sdp.sh script is to be run.  This can be used to
	facilitate operation on a machine over an \"air gap\" network.

	$ mkdir -p $BinDir
	$ cd $BinDir
	$ curl -s -O $FTPURL/$P4BinRel/bin.$ApiArch/p4
	$ curl -s -O $FTPURL/$P4BinRel/bin.$ApiArch/p4d
	$ curl -s -O $FTPURL/$P4BinRel/bin.$ApiArch/p4broker
	$ curl -s -O $FTPURL/$P4BinRel/bin.$ApiArch/p4p

	$ mkdir $DownloadsDir
	$ cd $DownloadsDir
	$ curl -s -O $FTPURL/tools/$SampleDepotTar
	$ curl -s -O $HelixInstallerTarURL
	$ tar -xzf ${HelixInstallerTarURL##*/}
	$ rsync -a hi/src $ResetHome

	=== SDP DEV BRANCH TESTING ===

	The Helix Installer can be used to test SDP changes shelved to the SDP
	dev branch in The Workshop.  The following example illustrates testing
	a change in shelved changelist 23123:

	su -
    	mkdir -p /hxdepots/reset
	cd /hxdepots/reset
	curl -s -O $HelixInstallerURL/src/reset_sdp.sh

	./reset_sdp.sh -b dev,@23123 2>&1 | tee log.reset_sdp.CL23123

	After the first test, an iterative test cycle may follow on the same
	shelved changelist. For each test iteration, the shelved changelist
	is first updated in the workspace from which the change was originally
	shelved, e.g. with a command like 'p4 shelve -f -c 23123'.

	Then a new test can be done by calling reset_sdp.sh with the same
	arguments. The script will re-install the SDP cleanly, and then
	re-apply the updated shelved changelist.

	=== SDP TEST SUITE SUPPORT ===

	The Helix Installer can install the SDP in the Docker-based SDP
	Test Suite.  In that environment, the directory /sdp appears on
	the test VMs, shared from the host machine.  To deploy that SDP,
	use the '-d <sdp_dir>' flag, something like this:

	./reset_sdp.sh -d /sdp -fast 2>&1 | tee log.reset_sdp.test

"
   fi

   exit 1
}

#------------------------------------------------------------------------------
# Functions msg(), dbg(), and bail().
# Sample Usage:
#    bail "Missing something important. Aborting."
#    bail "Aborting with exit code 3." 3
function msg () { echo -e "$*"; }
function warnmsg () { msg "\\nWarning: ${1:-Unknown Warning}\\n"; WarningCount+=1; }
function errmsg () { msg "\\nError: ${1:-Unknown Error}\\n"; ErrorCount+=1; }
function dbg () { msg "DEBUG: $*" >&2; }
function bail () { errmsg "${1:-Unknown Error}"; exit "${2:-1}"; }

#------------------------------------------------------------------------------
# Functions run($cmd, $desc)
#
# This 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 require dependencies for this
# script).
function run {
   cmd="${1:-echo Testing run}"
   desc="${2:-}"
   [[ -n "$desc" ]] && msg "$desc"
   msg "Running: $cmd"
   $cmd
   CMDEXITCODE=$?
   return $CMDEXITCODE
}

#------------------------------------------------------------------------------
# Function: gen_default_config()
#
# This generates a sample configuration settings file. Output is generated to
# stdout, making it easy for external automation to modify. By convention,
# output is generated to a file named settings.cfg, e.g. with '-C settings.cfg'
# flag with output redirected to that file.
#
# The sample file contains all required settings and reasonable sample values.
# The in-code documentation describes how the settings are used.  Settings
# are enumerated in the Config and ConfigDoc associative arrays, with the
# index of the arrays being the setting name.  For example, if the setting
# is ServerID, it can be referenced as ${Config['ServerID']}.
#
# The sections of the file are delineated by comments, with an description of
# what type of settings are in each section. The sections are Section 1:
# Localization, Section 2: Data Specific, and Section 3: Deep Customization.
# A hand-crafted 'for' loop in each section indicates what section any given
# setting belongs in.
#
# Generate a sample settings.cfg file.
function gen_default_config {
   echo -e "\
#------------------------------------------------------------------------------
# Config file for $ThisScript v$Version.
#------------------------------------------------------------------------------
# This file is in bash shell script syntax.
# Note: Avoid spaces before and after the '=' sign.

# For demo and training installations, usually all defaults in this file
# are fine.

# For Proof of Concept (PoC) installation, Section 1 (Localization) settings
# should all be changed to local values. Some settings in Section 2 (Data
# Specific) might also be changed.

# Changing settings in Section 3 (Deep Customization) is generally
# discouraged unless necessary when bootstrapping a production installation or
# a high-realism PoC.

#------------------------------------------------------------------------------
# Section 1: Localization
#------------------------------------------------------------------------------
# Changing all these is typical and expected, even for PoC installations."

   for c in SMTPServer P4AdminList MailFrom DNS_name_of_master_server SiteTag Hostname Timezone; do
      echo -e "${ConfigDoc[$c]}"
      echo "$c=${Config[$c]}"
   done

echo -e "
#------------------------------------------------------------------------------
# Section 2: Data Specific
#------------------------------------------------------------------------------
# These settings can be changed to desired values, though default values are
# preferred for demo installations."

   for c in P4_PORT P4BROKER_PORT Instance CaseSensitive P4USER Password SimulateEmail ServerID ServerType TargetServerID TargetPort ListenPort; do
      echo -e "${ConfigDoc[$c]}"
      echo "$c=${Config[$c]}"
   done

echo -e "
#------------------------------------------------------------------------------
# Section 3: Deep Customization
#------------------------------------------------------------------------------
# Changing these settings is gently discouraged, but may be necessary for
# bootstrapping some production environments with hard-to-change default values
# for settings such as OSUSER, OSGROUP, Hx*, etc.
#
# Changing these settings is gently discouraged because changing these values
# will cause the configuration to be out of alignment with documentation and
# sample instructions for settings that are typically left as defaults.
# However, there are no functional limitations to changing these settings."

   for c in OSUSER OSGROUP OSUSER_ADDITIONAL_GROUPS OSUSER_HOME P4BinRel P4APIRel; do
      echo -e "${ConfigDoc[$c]}"
      echo "$c=${Config[$c]}"
   done

echo -e "
# The following Hx* settings reference directories that store Perforce
# Helix data.  If configuring for optimal performance and scalability,
# these folders can be mount points for storage volumes.  If so, they must
# be mounted prior to running the $ThisScript script (other than to generate
# this configuration file).
#
# See the Server Deployment Package (SDP) for information and guidance on
# provisioning these volumes."

   for c in HxDepots HxLogs; do
      echo -e "${ConfigDoc[$c]}"
      echo "$c=${Config[$c]}"
   done

   # Special case: The ConfigDoc for HxMetadata1 applies to both HxMetadata1
   # and HxMetadata2 settings, so display it only once.
   echo -e "${ConfigDoc['HxMetadata1']}"
   echo "HxMetadata1=${Config['HxMetadata1']}"
   echo "HxMetadata2=${Config['HxMetadata2']}"
}

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

declare -i shiftArgs=0
set +u

while [[ $# -gt 0 ]]; do
   case $1 in
      (-B) BlastDownloadsAndBinaries=1;;
      (-local) PullFromWebAsNeeded=0;;
      (-no_ssl) UseSSL=0;;
      (-no_sd) LoadSampleDepot=0;;
      (-no_cron) InstallCrontab=0;;
      (-no_ppr) AddPerforcePackageRepo=0;;
      (-no_systemd) UseSystemd=0; UseSystemdOption="-no_systemd";;
      (-no_tweaks) RunOSTweaks=0;;
      (-ls) LimitedSudoers=1;;
      (-v) DoSDPVerify=1;;
      (-fast) UpdatePackages=0;;
      (-dapi) InstallDerivedAPIs=1;;
      (-s) ServerID="$2"; SetServerID=1; shiftArgs=1;;
      (-t) ServerType="$2"; SetServerType=1; shiftArgs=1;;
      (-ts) TargetServerID="$2"; SetTargetServerID=1; shiftArgs=1;;
      (-tp) TargetPort="$2"; SetTargetPort=1; shiftArgs=1;;
      (-lp) ListenPort="$2"; SetListenPort=1; shiftArgs=1;;
      (-se) SimulateEmail=1; SetSimulateEmail=1;;
      (-H) Hostname="$2"; SetHostname=1; shiftArgs=1;;
      (-T) Timezone="$2"; SetTimezone=1; shiftArgs=1;;
      (-C) GenDefaultConfig=1;;
      (-c) ConfigFile="$2"; UseConfigFile=1; shiftArgs=1;;
      (-d)
         SDPInstallMethod=Copy
         [[ "$2" == "default" ]] || SDPCopyDir="$2"
         shiftArgs=1
      ;;
      (-b)
         # If we are pulling from main and not using the ',@' sytnax,
         # stick with tarball installation. Otherwise, switch to cloning
         # from the specified branch (typically dev).
         if [[ "$2" == *",@"* ]]; then
            SDPInstallMethod=DVCS
            SDPInstallBranch=${2%%,@*};
            ShelvedChange=${2##*,@}
         else
            SDPInstallBranch=$2;
            [[ "$SDPInstallBranch" == "main" ]] || SDPInstallMethod=DVCS
         fi
         shiftArgs=1
      ;;
      (-p) PreserveDirList=$2; shiftArgs=1;;
      (-h) usage -h;;
      (-man) usage -man;;
      (-D) set -x;; # Debug; use 'set -x' mode.
      (-X) ExtremeCleanup=1;;
      (-R) ExtremeCleanup=1; StopAfterReset=1;;
      (-M) MultiRun=1;;
      (-i) HelixInstallerBranch="$2"; shiftArgs=1;;
      (*) 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 number of args or flags to args."
      shiftArgs=$shiftArgs-1
      shift
   done
done
set -u

#------------------------------------------------------------------------------
# Command Line Validation

[[ "$UseConfigFile" -eq 1 && "$GenDefaultConfig" -eq 1 ]] && \
   bail "The '-c <cfg>' and '-C' options are mutually exclusive."

[[ "$InstallDerivedAPIs" -eq 1 && "$UpdatePackages" -eq 0 ]] && \
   bail "The '-fast' and '-dapi' options are mutually exclusive."

#------------------------------------------------------------------------------
# Main Program

# Set hostname and timezone early in processing, and bail unless both are
# successful.
if [[ -n "$Hostname" ]]; then
   if command -v hostnamectl > /dev/null; then
      if hostnamectl set-hostname "$Hostname"; then
         msg "Hostname set to $(hostname); short hostname is $(hostname -s)."
      else
         errmsg "Failed to set hostname with: hostnamectl set-hostname $Hostname";
      fi
   else
      errmsg "Not setting hostname due to lack of 'hostnamectl' utility."
   fi
fi

if [[ -n "$Timezone" ]]; then
   if command -v timedatectl > /dev/null; then
      if timedatectl set-timezone "$Timezone"; then
         msg "Timezone is set. Date is: $(date)"
      else
         errmsg "Failed to set timezone with: timedatectl set-timezone $Timezone";
      fi
   else
      errmsg "Not settting timezone due to lack of 'timedatectl' utility."
   fi
fi

[[ "$ErrorCount" -ne 0 ]] && \
   bail "Aborting early due to failure to set hostname and/or timezone."

ThisUser="$(whoami)"
ThisOS="$(uname -s)"
ThisArch="$(uname -m)"
ThisHost="$(hostname -s)"

#------------------------------------------------------------------------------
# Special Mode:  Generate Default Config File
# In this mode, generate a sample config file on stdout, and exit.

if [[ "$GenDefaultConfig" -eq 1 ]]; then
   gen_default_config
   exit 0
fi

#------------------------------------------------------------------------------
# Regular processing mode.

msg "Started $ThisScript v$Version on host $ThisHost as user $ThisUser at $(date), called as:\\n\\t$CmdLine"

if [[ "$UseConfigFile" -eq 1 ]]; then
   [[ -r "$ConfigFile" ]] || \
      bail "Config file specified with '-c $ConfigFile' is not readable."

   msg "Loading configuration data from $ConfigFile."
   for c in "${!Config[@]}"; do
      value=$(grep ^$c= "$ConfigFile")
      value="${value#*=}"
      Config[$c]="$value"
   done
   SDPInstances="${Config['Instance']}"
   RunGroup="${Config['OSGROUP']}"
   RunUserNewHomeDir="${Config['OSUSER_HOME']}"
else
   # We want to know whether RunGroup was set explicitly in the settings.cfg
   # file or not.  If not, we set it to the value of 'Unset', enabling
   # OS-dependent logic to below to supply a platform-specific default.
   # We don't want platform-specific defaults to override values explicitly
   # defined in settings.cfg if that is used.
   RunGroup=Unset

   # Similarly, we want to apply the home directory specified in account
   # creation if it was defined in settings.cfg, but not otherwise.
   RunUserNewHomeDir=Unset
fi

# After the configuration data is loaded, set variables that depend on
# the loaded configuration.
SDPDefaultInstance="${SDPInstances%% *}"
RunUser="${Config['OSUSER']}"
SudoersFile="/etc/sudoers.d/$RunUser"
SudoersDir="${SudoersFile%/*}"
LimitedSudoersTemplate="$ResetHome/perforce_sudoers.t"

HxDepots="${Config['HxDepots']}"
HxMetadata1="${Config['HxMetadata1']}"
HxMetadata2="${Config['HxMetadata2']}"
HxLogs="${Config['HxLogs']}"

# Trim the leading '/' from Hx* settings to be compatible with SDP mkdirs.cfg
HxDepots="${HxDepots#/}"
HxMetadata1="${HxMetadata1#/}"
HxMetadata2="${HxMetadata2#/}"
HxLogs="${HxLogs#/}"

BinDir="/$HxDepots/helix_binaries"
DownloadsDir="/$HxDepots/downloads"
ResetHome="/$HxDepots/reset"
SDPHome="/$HxDepots/sdp"
SDPSetupDir="$SDPHome/Server/Unix/setup"
SDPCrontabDir="$SDPHome/Server/Unix/p4/common/etc/cron.d"
OSTweaksScript="$SDPSetupDir/os_tweaks.sh"
SudoersEntry="$RunUser ALL=(ALL) NOPASSWD: ALL"

#------------------------------------------------------------------------------
# Command Line Overrides
# Configuration settings in this block have corresponding command options.
# Settings from the config file will be overridden if their corresponding
# command line options is set. So if '-t <ServerID>' is given on the command
# line, the ServerID setting from the config file is ignored.
[[ "$SetHostname" -eq 0 ]] && Hostname="${Config['Hostname']}"
[[ "$SetTimezone" -eq 0 ]] && Timezone="${Config['Timezone']}"
[[ "$SetServerID" -eq 0 ]] && ServerID="${Config['ServerID']}"
[[ "$SetServerType" -eq 0 ]] && ServerType="${Config['ServerType']}"
[[ "$SetSimulateEmail" -eq 0 ]] && SimulateEmail="${Config['SimulateEmail']}"
[[ "$SetListenPort" -eq 0 ]] && ListenPort="${Config['ListenPort']}"
[[ "$SetTargetPort" -eq 0 ]] && TargetPort="${Config['TargetPort']}"
[[ "$SetTargetServerID" -eq 0 ]] && TargetServerID="${Config['TargetServerID']}"
#------------------------------------------------------------------------------

# Do some data validations based on data loaded from the configuration file.
if [[ "$UseConfigFile" -eq 1 ]]; then
   msg "Doing sanity checks on data loaded from the config file."

   if [[ "$ServerType" != "p4d_master" ]]; then
      if [[ -z "$ServerID" ]]; then
         if [[ "$ServerType" == "p4broker" || "$ServerType" = "p4proxy" ]]; then
            ServerID="$ServerType"
	    warnmsg "No ServerID defined for server of type $ServerType. Defaulting to $ServerType as the ServerID."
	 else
            errmsg "ServerID is not set. ServerID must be set if ServerType is any p4d_* type other than p4d_master. ServerType is [$ServerType]."
         fi
      fi
   fi

   if [[ -n "$TargetServerID" ]]; then
      [[ "$ServerType" != "p4d_edge_replica" ]] && \
         errmsg "TargetServerID is set (to $TargetServerID), but ServerType is not p4d_edge_replica. TargetServerID can only be set when ServerType is p4d_edge_replica. ServerType [$ServerType]."
   fi

   if [[ "$ErrorCount" -eq 0 ]]; then
      msg "Config file data passed sanity checks."
   else
      bail "Config file data failed sanity checks. Aborting."
   fi
fi

# Valid ServerType.  Based on ServerType, determine binary and services to
# install.
case "$ServerType" in
   (p4d_master)
      BinList="p4d p4broker"
      UseBroker=1
   ;;
   (p4d_replica)
      BinList="p4d p4broker"
      UseBroker=1
   ;;
   (p4d_filtered_replica)
      BinList="p4d p4broker"
      UseBroker=1
   ;;
   (p4d_edge)
      BinList="p4d p4broker"
      UseBroker=1
   ;;
   (p4d_edge_replica)
      BinList="p4d p4broker"
      UseBroker=1
   ;;
   (p4broker)
      BinList="p4broker"
      LoadSampleDepot=0
      UseBroker=1
   ;;
   (p4proxy)
      BinList="p4p"
      LoadSampleDepot=0
      UseBroker=0
   ;;
   (*)
      bail "Invalid ServerType specified [$ServerType]. Run $ThisScript -man to see valid values."
   ;;
esac

# Set the ServerBin to the server binary that will be used to create SSL
# certificates. Use whichever server is available based on the server
# type to be installed; it can be p4d, p4p, or p4broker (but not the 'p4'
# client binary).
ServerBin="/p4/${SDPDefaultInstance}/bin/${BinList%% *}_${SDPDefaultInstance}"

# Get just enough detailed OS info in order to fill in
# details in the Perforce package repository files.
if [[ "$ThisOS" == "Linux" ]]; then
   if [[ -r "/etc/redhat-release" ]]; then
      if grep -q ' 6\.' /etc/redhat-release; then
         ThisOSMajorVersion="6"
      elif grep -q ' 7\.' /etc/redhat-release; then
         ThisOSMajorVersion="7"
      elif grep -q ' 8\.' /etc/redhat-release; then
         ThisOSMajorVersion="8"
      fi
      [[ -n "$ThisOSMajorVersion" ]] || \
         warnmsg "Could not determine OS Major Version from contents of /etc/redhat-release."
   elif [[ -r "/etc/lsb-release" ]]; then
      ThisOSName=$(grep ^DISTRIB_ID= /etc/lsb-release)
      ThisOSName=${ThisOSName#*=}
      ThisOSName=${ThisOSName,,}
      ThisOSDistro=$(grep ^DISTRIB_CODENAME= /etc/lsb-release)
      ThisOSDistro=${ThisOSDistro#*=}

      [[ -n "$ThisOSName" && -n "$ThisOSDistro" ]] || \
         warnmsg "Could not determine OS Name and Distro from contents of /etc/lsb-release."
   fi

   if [[ -r "/etc/firewalld/services" ]]; then
      FirewallType="Firewalld"
      FirewallDir="/etc/firewalld/services"
   elif [[ -r "/etc/sysconfig/iptables" ]]; then
      FirewallType="IPTables"
      FirewallDir="/etc/sysconfig"
   fi
fi

if [[ "$ThisUser" != root ]]; then
   bail "Run as root, not $ThisUser."
else
   msg "Verified: Running as root user."
fi

[[ "$BlastDownloadsAndBinaries" -eq 1 && "$PullFromWebAsNeeded" -eq 0 ]] && \
   bail "The '-B' and '-local' arguments are mutually exclusive."

[[ "$SDPInstallBranch" != "Unset" && "$SDPInstallMethod" == "Copy" ]] && \
   bail "The '-b <branch>' and '-d <sdp_dir>' arguments are mutually exclusive."

[[ "$SDPInstallBranch" == Unset ]] && SDPInstallBranch=main

HelixInstallerURL="$HelixInstallerBaseURL/$HelixInstallerBranch"

#------------------------------------------------------------------------------
# Self-update

cd "$ResetHome" || bail "Could not cd to $ResetHome. Aborting."

msg "\\nEnsuring Helix Installer files are available."

for f in $HelixInstallerFiles; do
   HelixInstallerFileURL="$HelixInstallerURL/src/$f"
   if [[ ! -f "$f" ]]; then
      [[ "$PullFromWebAsNeeded" -eq 0 ]] && \
         bail "Missing Helix Installer file [$f] and '-local' specified. Aborting."
      run "curl -s -O $HelixInstallerFileURL" "Getting file $f." ||\
         bail "Failed to download from [$HelixInstallerFileURL]. Aborting."
   else
      if [[ "$BlastDownloadsAndBinaries" -eq 1 ]]; then
         run "curl -s -O $HelixInstallerFileURL" \
            "Replacing Helix Installer file $f due to '-B'." ||\
            bail "Failed to download file [$PWD/$f]. Aborting."
      else
         msg "Using existing Helix Installer file $PWD/$f."
      fi
   fi

   if [[ ! -x "$f" ]]; then
      if [[ "$f" == *".sh" || "$f" == r ]]; then
         run "chmod +x $f" "chmod +x $f" || bail "Failed to do: chmod +x $f. Aborting."
      fi
   fi
done

# After the self-update, if '-ls' (Limited Sudo) was specified, ensure the
# Limited Sudoers Template file is available.
[[ "$LimitedSudoers" -eq 1 && ! -r "$LimitedSudoersTemplate" ]] && \
   bail "Missing Sudoers template file: $LimitedSudoersTemplate"

#------------------------------------------------------------------------------
# Extreme Cleanup with -X
if [[ "$ExtremeCleanup" -eq 1 ]]; then
   msg "\\nStarted Extreme Cleanup due to -X."
   if id -u "$RunUser" > /dev/null 2>&1; then
      RunUserHomeDir="$(eval echo ~"$RunUser")"
      run "pkill -9 -u $RunUser" "Blasting processes by OS user $RunUser." ||\
         warnmsg "Failed to blast all processes by OS user $RunUser."
      sleep 1
      run "userdel $RunUser" "Removing OS user $RunUser." ||\
         warnmsg "Failed to remove OS user $RunUser."

      run "/bin/rm -rf $RunUserHomeDir" "Removing home dir $RunUserHomeDir" ||\
         warnmsg "Failed to remove $RunUserHomeDir."
   else
      msg "Extreme Cleanup: OS User $RunUser does not exist."
   fi

   if [[ -f "$SudoersFile" ]]; then
      run "/bin/rm -f $SudoersFile" \
         "Extreme Cleanup: Removing sudoers file: $SudoersFile" ||\
         warnmsg "Failed to remove $SudoersFile."
   fi

   if [[ "$HxMetadata1" == "$HxMetadata2" ]]; then
      run "/bin/rm -rf /p4 /$HxDepots/p4 /$HxMetadata1/p4 /$HxLogs/p4" \
         "Extreme Cleanup: Blasting several SDP dirs." ||\
         warnmsg "Failed to blast some SDP dirs."
   else
      run "/bin/rm -rf /p4 /$HxDepots/p4 /$HxMetadata1/p4 /$HxMetadata2/p4 /$HxLogs/p4" \
         "Extreme Cleanup: Blasting several SDP dirs." ||\
         warnmsg "Failed to blast some SDP dirs."
   fi

   if [[ "$FirewallType" == "Firewalld" ]]; then
      cd "$FirewallDir" || bail "Could not cd to: $FirewallDir"
      msg "Extreme Cleanup: Removing p4*.xml firewall rules (if any).\\n"
      for svcFile in p4*.xml; do
         [[ -r "$svcFile" ]] || continue
         svcName="${svcFile%.xml}"
         run "firewall-cmd --permanent --delete-service=$svcName" \
            "Deleting firewall entry for $svcName" ||\
            warnmsg "Deleting firewall entry for $svcName failed."

         # Firewalld renames the *.xml files to *.xml.old upon deletion of the
         # rule.
         if [[ -r "$PWD/${svcFile}.old" ]]; then
            run "rm -f $PWD/${svcFile}.old" "Removing $PWD/${svcFile}.old" ||\
               warnmsg "Deleting file $PWD/${svcFile}.old failed."
         fi
      done
      run "firewall-cmd --reload" "Firewall reload after cleanup." ||\
         warnmsg "Firewall reload failed after cleanup."
   fi

   if [[ "$StopAfterReset" -eq 0 ]]; then
      msg "Extreme Cleanup complete. Continuing.\\n"
   else
      msg "Extreme Cleanup complete. Stopping.\\n"
      exit 0
   fi
fi

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

cd "/$HxDepots" || bail "Could not cd to [/$HxDepots]."

if command -v yum > /dev/null; then
   PackageManager="yum"
elif command -v apt-get > /dev/null; then
   PackageManager="apt-get"
elif command -v zypper > /dev/null; then
   PackageManager="zypper"
fi

if [[ "$UseSystemd" -eq 1 && -d "/etc/systemd/system" ]]; then
   InitMechanism="Systemd"

   if [[ "$ThisOSMajorVersion" == "8" && -r /etc/selinux/config ]]; then
      if [[ $(grep ^SELINUX= /etc/selinux/config) == "SELINUX=enforcing" ]]; then
         errmsg "The OS is RHEL/CentOS/Rocky Linux with major version ${ThisOSMajorVersion}.x,\\nand SELinux is enabled in enforcing mode. The systemd mechanism may not work.\\n\\nSee: https://swarm.workshop.perforce.com/projects/perforce_software-helix-installer/jobs/HI-54.\\n\\nUntil HI-54 is resolved, workarounds are to avoid using system, or to disable SELinux."
      fi
   fi

elif [[ -x "/sbin/launchd" ]]; then
   InitMechanism="Launchd"
elif [[ -d "/etc/init.d" ]]; then
   InitMechanism="SysV"
else
   bail "Could not determine init mechanism. Systemd, SysV, and Launchd aren't available. Aborting."
fi

if [[ "$UpdatePackages" -eq 1 ]]; then
   msg "Ensuring needed packages are installed."

   if [[ "$ThisOS" != "Darwin" ]]; then
      [[ "$PackageManager" == "Unset" ]] && \
         bail "Could not find one of these package managers: ${!PackageList[*]}"

      run "$PackageManager install -y ${PackageList[$PackageManager]}" \
         "Installing these packages with $PackageManager: ${PackageList[$PackageManager]}" ||\
         warnmsg "Not all packages installed successfully.  Proceeding."

      if [[ "$InstallDerivedAPIs" -eq 1 ]]; then
         if ! command -v gcc > /dev/null || ! command -v g++ > /dev/null; then
            msg "Warning: No gcc found in the path.  You may need to install it.  Please\\n check that the gcc and gcc-c++ packages are\\n installed, e.g. with:\\n\\t$PackageManager install -y gcc gcc-c++\\nIgnoring missing gcc/g++ due to '-fast'.\\n"
         else
            msg "Verified: gcc and g++ are available and in the PATH."
         fi
      else
         msg "Skipping package dependency checks in -fast mode."
      fi
   else
      warnmsg "Skipping package handling on Mac OSX/$ThisOS."
   fi
fi

if [[ "$PullFromWebAsNeeded" -eq 1 ]]; then
   if ! command -v curl > /dev/null; then
      bail "No 'curl' found in the path.  You may need to install it or adjust the PATH for the root user to find it.\\n\\n"
   fi
fi

if ! command -v su > /dev/null; then
   bail "No 'su' found in the path.  You may need to install it or adjust the PATH for the root user to find it.\\n\\n"
fi

if [[ "$ThisArch" == "$RunArch" ]]; then
   msg "Verified:  Running on a supported architecture [$ThisArch]."
   ApiArch=UNDEFINED_API_ARCH
   case $ThisOS in
      (Darwin)
         ApiArch="macosx1010x86_64"
         [[ "$RunGroup" == Unset ]] && RunGroup=staff
         SampleDepotTar=sampledepot.mac.tar.gz
      ;;
      (Linux)
         ApiArch="linux26x86_64"
         # Set a platform-specific value for RunGroup if it wasn't defined
         # explicitly in a settings.cfg file.
         if [[ "$RunGroup" == Unset ]]; then
            if [[ -r "/etc/SuSE-release" ]]; then
               RunGroup=users
            else
               # CentOS, RHEL, and Ubuntu default group is same as user name.
               RunGroup=perforce
            fi
         fi
         SampleDepotTar=sampledepot.tar.gz
      ;;
      (*) 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

# In this block, we just check that directories specified to be preserved
# with the '-p' flag actually exist, in which case we abort before further
# processing.
if [[ "$PreserveDirList" != Unset ]]; then
   for d in $(echo "$PreserveDirList" | tr ',' ' '); do
      preserveDir="/$HxDepots/p4/common/$d"
      if [[ -d "$preserveDir" ]]; then
         parentDir=$(dirname "$TmpDir/$d")
         if [[ ! -d "$parentDir" ]]; then
            run "/bin/mkdir -p $parentDir" "Creating parent temp dir [$parentDir]." ||\
               bail "Failed to create parent temp dir [$parentDir]."
         fi
      fi
   done
fi

if [[ "$BlastDownloadsAndBinaries" -eq 1 ]]; then
   if [[ -d "$BinDir" ]]; then
      run "/bin/rm -rf $BinDir" \
         "Blasting helix_binaries dir [$BinDir] due to '-B'." ||\
          warnmsg "Failed to blast helix_binaries dir."

      for d in /tmp/downloads /tmp/p4perl; do
         if [[ -d "$d" ]]; then
            run "/bin/rm -rf $d" \
               "Blasting $d dir due to '-B'." ||\
                warnmsg "Failed to blast dir $d."
         fi
      done
   fi
fi

if [[ ! -d "$BinDir" ]]; then
   [[ "$PullFromWebAsNeeded" -eq 0 ]] && bail "BinDir [$BinDir] is missing and '-local' specified. Aborting."
   run "/bin/mkdir -p $BinDir" ||\
      bail "Could not create dir [$BinDir]."

   cd "$BinDir" || bail "Could not cd to $BinDir."
   msg "Working in [$PWD]."
   run "curl -s -O $FTPURL/${Config['P4BinRel']}/bin.$ApiArch/p4" ||\
      bail "Could not get 'p4' binary."
   run "curl -s -O $FTPURL/${Config['P4BinRel']}/bin.$ApiArch/p4d" ||\
      bail "Could not get 'p4d' binary."
   run "curl -s -O $FTPURL/${Config['P4BinRel']}/bin.$ApiArch/p4p" ||\
      bail "Could not get 'p4p' binary."
   run "curl -s -O $FTPURL/${Config['P4BinRel']}/bin.$ApiArch/p4broker" ||\
      bail "Could not get 'p4broker' binary."

   run "chmod +x p4 p4d p4p p4broker" \
      "Doing chmod +x for downloaded Helix binaries."
else
   msg "Using existing helix_binaries dir [$BinDir]."
fi

#------------------------------------------------------------------------------
# Services Shutdown and Cleanup.

if command -v getent > /dev/null; then
   if getent group "$RunGroup" > /dev/null 2>&1; then
      msg "Verified: Group $RunGroup exists."
   else
      run "groupadd $RunGroup" "Creating group $RunGroup." ||\
         bail "Failed to create group $RunGroup."
   fi
fi

if id -u "$RunUser" > /dev/null 2>&1; then
   msg "Verified: User $RunUser exists."
else
   if command -v useradd > /dev/null; then
      UserAddCmd="useradd -s /bin/bash -g $RunGroup"

      # Specify the home dir only if explicitly defined in settings.cfg;
      # otherwise defer to the useradd default.
      [[ "$RunUserNewHomeDir" != Unset ]] && \
         UserAddCmd+=" -d $RunUserNewHomeDir"

      # Specify the -G value to useradd if and only if values for additional
      # groups were defined in settings.cfg.
      [[ -n "${Config['OSUSER_ADDITIONAL_GROUPS']}" ]] && \
         UserAddCmd+=" -G ${Config['OSUSER_ADDITIONAL_GROUPS']}"

      UserAddCmd+=" $RunUser"
      run "$UserAddCmd" "Creating user $RunUser with command: $UserAddCmd" ||\
         bail "Failed to create user $RunUser."

      msg "Setting OS password for user $RunUser."
      echo "${Config['Password']}" > "$TmpFile"
      echo "${Config['Password']}" >> "$TmpFile"
      msg "Running: passwd $RunUser"
      if passwd "$RunUser" < "$TmpFile"; then
         msg "Verified: Password for user $RunUser set successfully."
      else
         warnmsg "Failed to set password for user $RunUser."
      fi

      RunUserHomeDir="$(eval echo ~"$RunUser")"
      if [[ -d "$RunUserHomeDir" ]]; then
         msg "Verified: Home directory for user $RunUser exists."
      else
         run "mkdir -p $RunUserHomeDir" \
            "Creating home dir for $RunUser" ||\
            bail "Failed to create home directory $RunUserHomeDir for OS user $RunUser."
         run "chown -R $RunUser:$RunGroup $RunUserHomeDir" \
            "Ensuring $RunUser owns home dir $RunUserHomeDir." ||\
            warnmsg "Failed to change ownership of home directory $RunUserHomeDir for OS user $RunUser."
      fi

      run "cp $ResetHome/perforce_bash_profile $RunUserHomeDir/.bash_profile" \
         "Creating $RunUserHomeDir/.bash_profile." ||\
         warnmsg "Failed to copy to $RunUserHomeDir/.bash_profile."

      msg "Creating $RunUserHomeDir/.bashrc."
      sed "s:EDITME_SDP_INSTANCE:$SDPDefaultInstance:g" \
         "$ResetHome/perforce_bashrc" > "$RunUserHomeDir/.bashrc" ||\
         warnmsg "Failed to copy to $RunUserHomeDir/.bashrc."

      run "chown $RunUser:$RunGroup $(eval echo ~"$RunUser")/.bash_profile $(eval echo ~"$RunUser")/.bashrc" "Adjusting perms of .bash_profile and .bashrc." ||\
         warnmsg "Adjusting ownership failed."
   else
      bail "User $RunUser does not exist, and the 'useradd' utility was not found."
   fi
fi

for i in $SDPInstances; do
   if [[ "$ThisOS" == "Linux" || "$ThisOS" == "Darwin" ]]; then
      msg "Stopping Perforce-related services for Instance $i."
      for svc in p4d p4broker p4p p4web p4dtg; do
         processCmd="${svc}_${i}"

         # This 'ps' command should work on Linux and Mac (Yosemite+ at least).
         # shellcheck disable=SC2009
         Pids=$(ps -u "$RunUser" -f | grep -v grep | grep "/$processCmd "| awk '{print $2}')

         if [[ -z "$Pids" && $svc == p4d ]]; then
            msg "$processCmd not found for p4d service; looking for _bin variant instead."
            # For the p4d service, the process command may look like 'p4d_1_bin' or just 'p4d_1', so
            # we check for both.
            processCmd="${svc}_${i}_bin"
            # shellcheck disable=SC2009
            Pids=$(ps -u "$RunUser" -f | grep -v grep | grep "/$processCmd "| awk '{print $2}')
         fi

         if [[ -n "$Pids" ]]; then
            run "kill -9 $Pids" \
               "Killing user $RunUser processes for command $processCmd."
            sleep 1
         else
            msg "Verified: No processes by user $RunUser for command [$processCmd] are running."
         fi
      done
   fi

   if [[ "$InitMechanism" == "SysV" ]]; then
      cd /etc/init.d || bail "Could not cd to /etc/init.d."

      msg "Removing Perforce-related SysV services in $PWD."

      for svc in p4*_init; do
         run "chkconfig --del $svc"
         run "rm -f $svc"
      done
   elif [[ "$InitMechanism" == "Systemd" ]]; then
      cd /etc/systemd/system || bail "Could not cd to /etc/systemd/system."

      msg "Disabling and removing Perforce-related Systemd services in $PWD."
      for svcFile in p4*.service; do
         run "systemctl disable ${svcFile%.service}"
         run "rm -f $svcFile"
      done
      run "systemctl daemon-reload" "Reloading systemd after removing Systemd unit files." ||\
         warnmsg "Failed to reload systemd daemon."
   fi
done

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

if [[ ! -d "$DownloadsDir" ]]; then
   [[ $PullFromWebAsNeeded -eq 0 ]] && bail "DownloadsDir [$DownloadsDir] is missing and '-local' specified. Aborting."
   run "/bin/mkdir -p $DownloadsDir"

   cd "$DownloadsDir" || bail "Could not cd to downloads dir: $DownloadsDir"

   msg "Working in [$PWD]."
   if [[ "$InstallDerivedAPIs" -eq 1 ]]; then
      run "curl -s -O $FTPURL/${Config['P4APIRel']}/bin.$ApiArch/p4api.tgz" ||\
         bail "Could not get file 'p4api.tgz'"
   else
      msg "Skipping download of p4api.tgz '-dapi' not being specified."
   fi

   if [[ "$SDPInstallMethod" == FTP ]]; then
      run "curl -s -O $SDPURL" ||\
         bail "Could not get SDP tar file from [$SDPURL]."
   fi

   if [[ "$LoadSampleDepot" -eq 1 ]]; then
      run "curl -s -O $FTPURL/tools/$SampleDepotTar" ||\
         bail "Could not get file [$SampleDepotTar]. Aborting."

      if [[ "$BlastDownloadsAndBinaries" -eq 1 && -d "PerforceSample" ]]; then
         run "rm -rf "PerforceSample "Blasting dir PerforceSample due to '-B'." ||\
            warnmsg "Failed to cleanly remove Sample Depot dir $PWD/PerforceSample."
      fi

      if [[ ! -d PerforceSample ]]; then
         run "tar -xzpf $SampleDepotTar" "Unpacking $SampleDepotTar in $PWD."
      else
         msg "Using existing extracted Sample Depot dir $PWD/PerforceSample."
      fi

      run "chown -R $RunUser:$RunGroup $DownloadsDir" \
         "Setting ownership on downloads dir." ||\
         bail "Failed to set ownership on downloads dir [$DownloadsDir]. Aborting."
   else
      msg "Skipping download of Sample Depot due to '-no_sd'."
   fi
else
   msg "Using existing downloads dir [$DownloadsDir]."

   cd "$DownloadsDir" || bail "Could not cd to downloads dir: $DownloadsDir"

   if [[ "$SDPInstallMethod" == FTP ]]; then
      if [[ -r "$SDPTar" ]]; then
         msg "Using existing SDP tarfile [$SDPTar]."
      else
         run "curl -s -O $SDPURL" ||\
            bail "Could not get SDP tar file from [$SDPURL]."
      fi
   fi
fi

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

msg "Working in [$PWD]."

if [[ "$HxMetadata1" == "$HxMetadata2" ]]; then
   DirList="/$HxMetadata1 /$HxLogs";
else
   DirList="/$HxMetadata1 /$HxMetadata2 /$HxLogs";
fi

for d in $DirList; do
   if [[ ! -d "$d" ]]; then
      run "/bin/mkdir -p $d" "Initialized empty dir [$d]." ||\
         bail "Failed to create dir [$d]."
   else
      msg "Verified: Dir [$d] exists."
   fi
done

if [[ $PreserveDirList != Unset ]]; then
   run "/bin/mkdir -p $TmpDir" "Creating temp dir [$TmpDir]." ||\
      bail "Failed to create temp dir [$TmpDir]."

   for d in $(echo "$PreserveDirList" | tr ',' ' '); do
      preserveDir="/$HxDepots/p4/common/$d"
      if [[ -d "$preserveDir" ]]; then
         parentDir=$(dirname "$TmpDir/$d")
         if [[ ! -d "$parentDir" ]]; then
            run "/bin/mkdir -p $parentDir" "Creating parent temp dir [$parentDir]." ||\
               bail "Failed to create parent temp dir [$parentDir]."
         fi

         run "/bin/mv $preserveDir $TmpDir/$d" \
            "Moving preserved dir $preserveDir aside for safe keeping."
      else
         bail "Missing expected preserve dir [$preserveDir]. Check that paths specified with '-p' are relative to /$HxDepots/p4/common."
      fi
   done
fi

for i in $SDPInstances; do
   if [[ "$HxMetadata1" == "$HxMetadata2" ]]; then
      DirList="/$HxDepots/p4/$i /$HxMetadata1/p4/$i /$HxLogs/p4/$i"
   else
      DirList="/$HxDepots/p4/$i /$HxMetadata1/p4/$i /$HxMetadata2/p4/$i /$HxLogs/p4/$i"
   fi

   run "/bin/rm -rf $DirList" \
      "Blasting any existing SDP structures." ||\
      bail "Failed to blast existing SDP structures."

   if [[ -L "/p4/$i" ]]; then
      run "/bin/rm -f /p4/$i" "Blasting symlink /p4/$i." ||\
         bail "Failed to remove SDP symlink."
   elif [[ -d "/p4/$i" ]]; then
      run "/bin/rm -rf /p4/$i" "Blasting directory /p4/$i." ||\
         bail "Failed to remove SDP instance directory /p4/$i."
   fi
done

run "/bin/rm -rf /$HxDepots/p4/common" \
   "Blasting SDP common folder." ||\
   bail "Failed to remove SDP common folder."

if [[ -L /p4/common ]]; then
   run "/bin/rm -f /p4/common" "Removing /p4/common symlink." ||\
      bail "Failed to remove /p4/common symlink."
elif [[ -d /p4/common ]]; then
   run "/bin/rm -rf /p4/common" "Removing /p4/common directory." ||\
      bail "Failed to remove /p4/common local directory."
else
   msg "Info: /p4/common did not exist as a directory or symlink."
fi

run "/bin/rm -rf $SDPHome /p4/ssl" \
   "Removing old SDP Home and /p4/ssl." ||\
   bail "Failed to remove old $SDPHome and /p4/ssl."

#------------------------------------------------------------------------------
# SDP Setup
if [[ "$SDPInstallMethod" == FTP ]]; then
   run "tar -xzpf $DownloadsDir/$SDPTar" "Unpacking $DownloadsDir/$SDPTar in $PWD." ||\
      bail "Failed to untar SDP tarfile."
elif [[ "$SDPInstallMethod" == Copy ]]; then
   if [[ -r "$SDPCopyDir/$SDPTar" ]]; then
      if [[ -d "$SDPHome" ]]; then
         run "rm -rf $SDPHome/" \
            "Removing existing SDP directory [$SDPHome]." ||\
            bail "Failed to clean existing SDPHome dir: $SDPHome"
      fi
     
      cd "${SDPHome%/*}" ||\
         bail "Could not cd to parent of SDPHome dir: ${SDPHome%/*}"

      run "tar -xzf $SDPCopyDir/$SDPTar" \
         "Extracting SDP tarball: $SDPCopyDir/$SDPTar" ||\
         bail "Failed to extract SDP tarball."

      cd - > /dev/null || bail "Could not cd back to: $OLDPWD"

   elif [[ -r "$SDPCopyDir/Version" ]]; then
      run "rsync -a --delete $SDPCopyDir/ $SDPHome" "Deploying SDP from: $SDPCopyDir" ||\
         bail "Failed to rsync SDP from $SDPCopyDir."
   else
      bail "The SDP directory [$SDPCopyDir] contains neither an SDP tarball file ($SDPTar) nor a Version file to indicate a pre-extracted SDP tarball. Aborting."
   fi
else
   # SDPInstallMethod is DVCS
   export PATH="$BinDir:$PATH"
   export P4ENVIRO=/dev/null/.p4enviro
   export P4CONFIG=.p4config.local
   run "/bin/mkdir -p $SDPHome" "Creating dir $SDPHome" ||\
      bail "Failed to create dir $SDPHome. Aborting."
   cd "$SDPHome" || bail "Failed to cd to [$SDPHome]."
   WorkshopRemote=perforce_software-sdp_${SDPInstallBranch}

   run "$BinDir/p4 -s -u $WorkshopUser clone -p $WorkshopPort -r $WorkshopRemote" \
      "Cloning SDP $SDPInstallBranch branch from The Workshop." ||\
      bail "Failed to clone SDP from The Workshop."

   run "$BinDir/p4 -s sync -f .p4ignore" \
      "Force-sync .p4ignore file."

   if [[ "$ShelvedChange" != Unset ]]; then
      run "$BinDir/p4 -s fetch -s $ShelvedChange" \
         "Fetching shelved change @$ShelvedChange from The Workshop." ||\
      bail "Failed to fetch shelved change @$ShelvedChange from The Workshop."

      LocalShelvedChange=$("$BinDir"/p4 -ztag -F %change% changes -s shelved -m 1)

      [[ -n "$LocalShelvedChange" ]] || \
         bail "Could not determine local shelved change fetched for shelved change @$ShelvedChange."

      run "$BinDir/p4 -s unshelve -s $LocalShelvedChange" \
         "Unshelving local shelved change @$LocalShelvedChange." ||\
         bail "Failed to unshelve local shelved change @$LocalShelvedChange."
   fi

   unset P4ENVIRO
   unset P4CONFIG
fi

if [[ -r "$SDPHome/Version" ]]; then
   if [[ "$SDPInstallMethod" == DVCS ]]; then
      msg "Version info not displayed as it is unreliable when using DVCS install method to get latest from the dev branch."
   else
      msg "SDP Version in $SDPHome is: $(cat "$SDPHome/Version")"
   fi
else
   bail "Cannot determine SDP Version; file $SDPHome/Version is missing."
fi

run "chown -R $RunUser:$RunGroup $SDPHome $ResetHome" \
   "Changing ownership to $RunUser:$RunGroup for $SDPHome $ResetHome" ||\
   bail "Failed to change ownership to $RunUser:$RunGroup."

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

# To simulate email, generate a faux mail utility in the PATH.
if [[ "$SimulateEmail" -eq 1 ]]; then
   msg "Generating mail simulator."
   echo -e "#!/bin/bash\\necho Simulated Email: $*\\n" > "$MailSimulator"
   chmod +x "$MailSimulator"
   [[ -x "$MailSimulator" ]] || \
      warnmsg "Failed to generate mail simulator script: $MailSimulator"
fi

run "/bin/mv -f mkdirs.cfg mkdirs.cfg.orig" \
   "Generating custom mkdirs.cfg in $PWD."

# The values for the P4MASTERHOST setting in the SDP mkdirs.cfg file can be
# 'DNS_name_of_master_server_for_this_instance' or
# 'DNS_name_of_master_server', depending on SDP version. Support both.
sed -e "s:=DNS_name_of_master_server_for_this_instance:=${Config['DNS_name_of_master_server']}:g" \
   -e "s:=DNS_name_of_master_server:=${Config['DNS_name_of_master_server']}:g" \
   -e "s:^MAILTO=.*:MAILTO=${Config['P4AdminList']}:g" \
   -e "s:^MAILFROM=.*:MAILFROM=${Config['MailFrom']}:g" \
   -e "s:mail.example.com:${Config['SMTPServer']}:g" \
   -e "s:^CASE_SENSITIVE=.*:CASE_SENSITIVE=${Config['CaseSensitive']}:g" \
   -e "s:^DB1=.*:DB1=${HxMetadata1}:g" \
   -e "s:^DB2=.*:DB2=${HxMetadata2}:g" \
   -e "s:^DD=.*:DD=${HxDepots}:g" \
   -e "s:^LG=.*:LG=${HxLogs}:g" \
   -e "s|^P4_PORT=.*|P4_PORT=SeeBelow|g" \
   -e "s|^P4BROKER_PORT=.*|P4BROKER_PORT=SeeBelow|g" \
   -e "s|^P4P_TARGET_PORT=.*|P4P_TARGET_PORT=$TargetPort|g" \
   -e "s|# P4_PORT=1666|P4_PORT=${Config['P4_PORT']}|g" \
   -e "s|# P4BROKER_PORT=1667|P4BROKER_PORT=${Config['P4BROKER_PORT']}|g" \
   -e "s:=adminpass:=${Config['Password']}:g" \
   -e "s:=servicepass:=${Config['Password']}:g" \
   -e "s:ADMINUSER=perforce:ADMINUSER=${Config['P4USER']}:g" \
   -e "s:OSUSER=perforce:OSUSER=$RunUser:g" \
   -e "s:OSGROUP=perforce:OSGROUP=$RunGroup:g" \
   -e "s:REPLICA_ID=replica:REPLICA_ID=p4d_ha_${Config['SiteTag']}:g" \
   -e "s:SVCUSER=service:SVCUSER=svc_p4d_ha_${Config['SiteTag']}:g" \
   mkdirs.cfg.orig > mkdirs.cfg

if [[ $UseSSL -eq 0 ]]; then
   msg "Not using SSL feature due to '-no_ssl'."
   sed "s/SSL_PREFIX=ssl:/SSL_PREFIX=/g" mkdirs.cfg > $TmpFile
   run "mv -f $TmpFile mkdirs.cfg"
fi

chmod +x mkdirs.sh

msg "SDP Localizations in mkdirs.sh:"
diff mkdirs.sh.orig mkdirs.sh

msg "\\nSDP Localizations in mkdirs.cfg:"
diff mkdirs.cfg.orig mkdirs.cfg

# Prior to SDP r20.1, 'p4d', 'p4', and other binaries were placed in
# /<DD>/sdp/p4/common/bin.  Modern SDP uses wrapper shell scripts in
# place of those binaries. If the wrapper script exists, skip the copy
# of the binaries.
if [[ -x "$SDPHome/Server/Unix${CBIN}/p4d" ]]; then
   run "cp -f -p $BinDir/p4* $SDPHome/helix_binaries/." \
      "Copying Perforce Helix binaries to $SDPHome/helix_binaries/." ||\
      errmsg "Failed to copy binaries to $SDPHome/helix_binaries/."
else
   run "cp -p $BinDir/p4* $SDPHome/Server/Unix${CBIN}/." \
      "Copying Perforce Helix binaries to $SDPHome/Server/Unix${CBIN}/." ||\
      errmsg "Failed to copy binaries to $SDPHome/Server/Unix${CBIN}/."
fi

msg "Initializing SDP instances and configuring $InitMechanism services."

for i in $SDPInstances; do
   cd "$SDPSetupDir" || bail "Could not cd to [$SDPSetupDir]."
   MkdirsCmd="$PWD/mkdirs.sh $i"

   if grep -q Version= mkdirs.sh > /dev/null 2>&1; then
      [[ -n "$ServerID" ]] && MkdirsCmd+=" -s $ServerID"
      [[ -n "$ServerType" ]] && MkdirsCmd+=" -t $ServerType"
      [[ -n "$TargetServerID" ]] && MkdirsCmd+=" -S $TargetServerID"
   else
      [[ -n "$ServerID" || "$ServerType" != "p4d_master" || -n "$TargetServerID" ]] && \
         warnmsg "Settings for ServerID, ServerType, and TargetServerID will be ignored due to too-old version of mkdirs.sh. Use SDP r20.1+ to take advantage of these configuration settings."
   fi

   log="$PWD/mkdirs.${i}.log"
   msg "Initializing SDP instance [$i], writing log [$log]."
   msg "Running: $MkdirsCmd"
   $MkdirsCmd > "$log" 2>&1
   cat "$log"

   if [[ "$InitMechanism" == "SysV" ]]; then
      msg "\\nConfiguring $InitMechanism services.\\n"
      cd /etc/init.d || bail "Could not cd to [/etc/init.d]."
      for svc in $BinList; do
         initScript=${svc}_${i}_init
         if [[ -x /p4/${i}/bin/$initScript ]]; then
            run "ln -s /p4/${i}/bin/$initScript"
            run "chkconfig --add $initScript"
            run "chkconfig $initScript on"
         fi
      done
   elif [[ "$InitMechanism" == "Systemd" ]]; then
      msg "\\nConfiguring $InitMechanism services.\\n"
      cd /etc/systemd/system || bail "Could not cd to /etc/systemd/system."
      for binary in $BinList; do
         svcName="${binary}_${i}"
         svcFile="${svcName}.service"

         # If the version of SDP deployed is 2020.1+, it will have templates
         # for systemd unit files. Use those if found, otherwise use the
         # baseline templates that come with the Helix Installer.
         svcTemplate="$SystemdTemplatesDir/${binary}_N.service.t"
         [[ ! -r "$svcTemplate" ]] && \
            svcTemplate="$ResetHome/${binary}_N.service.t"

         sed -e "s:__INSTANCE__:${i}:g" \
            -e "s:__OSUSER__:$RunUser:g" \
            "$svcTemplate" > "$svcFile" ||\
            bail "Failed to generate $PWD/$svcFile from template $svcTemplate."

         run "systemctl enable $svcName" "Enabling $svcName to start on boot." ||\
            warnmsg "Failed to enable $svcName with $InitMechanism."
      done
      run "systemctl daemon-reload" "Reloading systemd after generating Systemd unit files." ||\
         warnmsg "Failed to reload systemd daemon."
   fi

   run "chown $RunUser:$RunGroup /$HxDepots" \
      "Adjusting ownership of /$HxDepots to $RunUser:$RunGroup." ||\
       bail "Failed to adjust ownership of /$HxDepots."

   for d in "/$HxDepots/p4" "$ResetHome" "$BinDir"; do
      if [[ -d "$d" ]]; then
         run "chown -R $RunUser:$RunGroup $d" \
            "Adjusting ownership of $d to $RunUser:$RunGroup." ||\
             bail "Failed to adjust ownership of $d."
      fi
   done

   msg "Apply custom proxy/broker-only host rules."
   iCfg="/p4/common/config/p4_${i}.vars"
   if [[ -r "$iCfg" ]]; then
      iCfgTmp="$(mktemp)"
      if [[ -n "$TargetPort" && "$ServerType" == "p4proxy" ]]; then
         sed -e "s|^export PROXY_TARGET=.*|export PROXY_TARGET=$TargetPort|g" "$iCfg" > "$iCfgTmp"
	 mv -f "$iCfgTmp" "$iCfg"
      fi
      if [[ -n "$TargetPort" && "$ServerType" == "p4broker" ]]; then
         sed -e "s|^export P4PORT=.*|export P4PORT=$TargetPort|g" "$iCfg" > "$iCfgTmp"
	 mv -f "$iCfgTmp" "$iCfg"
      fi
      if [[ -n "$ListenPort" && "$ServerType" == "p4proxy" ]]; then
         sed -e "s|^export PROXY_PORT=.*|export PROXY_PORT=$ListenPort|g" \
            -e "s|^export P4PORT=.*|export P4PORT=$ListenPort|g" \
            "$iCfg" > "$iCfgTmp"
	 mv -f "$iCfgTmp" "$iCfg"
      fi
      if [[ -n "$ListenPort" && "$ServerType" == "p4broker" ]]; then
         sed -e "s|^export P4BROKERPORT=.*|export P4BROKERPORT=$ListenPort|g" \
            "$iCfg" > "$iCfgTmp"
	 mv -f "$iCfgTmp" "$iCfg"
      fi
      chown "$RunUser:$RunGroup" "$iCfg"
   fi

   if [[ "$UseBroker" -eq 1 ]]; then
      msg "\\nGenerating broker config for instance $i.\\n"
      su -l "$RunUser" -c "$CBIN/gen_default_broker_cfg.sh ${i} > $CCFG/p4_${i}.broker.cfg"
   fi

done

if [[ "$UseSSL" -eq 1 ]]; then
   msg "Generating /p4/ssl/config.txt SSL config file for autogen cert."
   sed -e "s/REPL_DNSNAME/helix/g" /p4/ssl/config.txt > "$TmpFile" ||\
      bail "Failed to substitute content in /p4/ssl/config.txt."
   run "mv -f $TmpFile /p4/ssl/config.txt"
   msg "Contents of /p4/ssl/config.txt:\\n$(cat /p4/ssl/config.txt)\\n"

   if [[ -x "$ServerBin" ]]; then
      msg "Generating SSL certificates."
      # If there are multipe SDP Instances, we only generate SSL certificates
      # for one instance.  Any one will do because SSL certs are not
      # instance-specific.
      su -l "$RunUser" -c "/p4/common/bin/p4master_run ${SDPInstances%% *} $ServerBin -Gc" ||\
         warnmsg "Failed to generate SSL Certificates."
   fi
fi

if [[ "$PreserveDirList" != Unset ]]; then
   for d in $(echo "$PreserveDirList" | tr ',' ' '); do
      preserveDir="/$HxDepots/p4/common/$d"
      tempCopyDir="$TmpDir/$d"
      run "rsync -av --exclude=.p4root --exclude=.p4ignore --exclude=.p4config $tempCopyDir/ $preserveDir" \
         "Restoring $preserveDir" ||\
         bail "Failed to restore $preserveDir."
   done

   run "/bin/rm -rf $TmpDir" "Cleanup: Removing temp dir [$TmpDir]." ||\
      bail "Failed to remove temp dir [$TmpDir]."
fi

#------------------------------------------------------------------------------
# Install P4Perl and P4Python if the install scripts are available in the
# SDP Package. If the install_sdp_*.sh scripts are not available, generate
# a warning message.
if [[ "$InstallDerivedAPIs" -eq 1 ]]; then
   if [[ -x "$SDPUnsupportedSetupDir/install_sdp_python.sh" ]]; then
      msg "\\nInstalling P4Python for SDP using: $SDPUnsupportedSetupDir/install_sdp_python.sh"
      su -l "$RunUser" -c "$SDPUnsupportedSetupDir/install_sdp_python.sh" ||\
         errmsg "Failed to install P4Python."
   elif [[ -x "$SDPSetupDir/install_sdp_python.sh" ]]; then
      msg "\\nInstalling P4Python for SDP using: $SDPSetupDir/install_sdp_python.sh"
      su -l "$RunUser" -c "$SDPSetupDir/install_sdp_python.sh" ||\
         errmsg "Failed to install P4Python."
   else
      warnmsg "SDP P4Python installer not available in SDP Package and '-dapi' was used."
   fi

   if [[ -x "$SDPUnsupportedSetupDir/install_sdp_perl.sh" ]]; then
      msg "\\nInstalling P4Perl for SDP using: $SDPUnsupportedSetupDir/install_sdp_perl.sh"
      su -l "$RunUser" -c "$SDPUnsupportedSetupDir/install_sdp_perl.sh" ||\
         errmsg "Failed to install P4Perl."
   elif [[ -x "$SDPSetupDir/install_sdp_perl.sh" ]]; then
      msg "\\nInstalling P4Perl for SDP using: $SDPSetupDir/install_sdp_perl.sh"
      su -l "$RunUser" -c "$SDPSetupDir/install_sdp_perl.sh" ||\
         errmsg "Failed to install P4Perl."
   else
      warnmsg "SDP P4Perl installer not available in SDP Package and '-dapi' was used."
   fi
fi

msg "Preparing to run Sample Depot configuration script."
if [[ ! -d "$ResetHome" ]]; then
   run "/bin/mkdir -p $ResetHome" "Creating reset home dir [$ResetHome]." ||\
      bail "Could not create reset home dir [$ResetHome]. Aborting."
fi

cd "$ResetHome" || bail "Could not cd to $ResetHome. Aborting."

#------------------------------------------------------------------------------
# Add sudoers to /etc/sudoers.d if the directory exists and the user file doesn't.
if [[ -d "$SudoersDir" ]]; then
   msg "Adding $RunUser to sudoers."

   if [[ -e "$SudoersFile" ]]; then
      run "rm -f $SudoersFile" "Removing existing sudoers [$SudoersFile] with these contents:\\n$(cat "$SudoersFile")" ||\
         errmsg "Failed to remove old sudoers file."
   fi

   if [[ "$LimitedSudoers" -eq 1 ]]; then
      if sed -e "s:__OSUSER__:$RunUser:g" -e "s:__HOSTNAME__:$(hostname -s):g" "$LimitedSudoersTemplate" > "$SudoersFile"; then
         run "chmod 0400 $SudoersFile" "Setting perms on sudoers file, $SudoersFile." ||\
            warnmsg "Failed to set perms on $SudoersFile."
      else
         warnmsg "Failed to create $SudoersFile."
      fi
   else
      if echo -e "$SudoersEntry" > "$SudoersFile"; then
         run "chmod 0400 $SudoersFile" "Setting perms on sudoers file, $SudoersFile." ||\
            warnmsg "Failed to set perms on $SudoersFile."
      else
         warnmsg "Failed to create $SudoersFile."
      fi
   fi
else
   warnmsg "Skipping sudoers update; sudoers dir does not exist: $SudoersDir."
fi

#------------------------------------------------------------------------------
# Load the Sample Depot training data set, useful for eval/demo installs,
# PoCs, training, etc.
if [[ "$LoadSampleDepot" -eq 1 ]]; then
   for i in $SDPInstances; do
      msg "Configuring Sample Depot for SDP on Instance $i."
      if su -l "$RunUser" -c "$ResetHome/configure_sample_depot_for_sdp.sh -i $i -d $ResetHome -u $RunUser $UseSystemdOption"; then
         msg "\\nSample Depot configured successfully for instance $i.\\n"
      else
         bail "Failed to load the Sample Depot."
      fi
   done
else
   msg "\\nSkipping configuration of Sample Depot due to '-no_sd'.\\n"
fi

#------------------------------------------------------------------------------
# Add Perforce Package Repository to repo list (YUM and APT only).

if [[ "$AddPerforcePackageRepo" -eq 1 ]]; then
   if [[ -d "${P4YumRepo%/*}" ]]; then
      if [[ -n "$ThisOSMajorVersion" ]]; then
         run "rpm --import $PerforcePackagePubkeyURL" \
            "Adding Perforce's packaging key to RPM keyring." ||\
            warnmsg "Failed to add Perforce packaging key to RPM keyring."

         msg "Generating $P4YumRepo."
         if ! echo -e "[perforce]\\nname=Perforce\\nbaseurl=$PerforcePackageRepoURL/yum/rhel/$ThisOSMajorVersion/x86_64\\nenabled=1\\ngpgcheck=1\\n" > "$P4YumRepo"; then
            warnmsg "Unable to generate $P4YumRepo."
         fi
      else
         warnmsg "Skipping generation of $P4YumRepo due to lack of OS Major Version info."
      fi
   elif [[ -d "${P4AptGetRepo%/*}" ]]; then # /etc/apt/sources.list.d
      if [[ -n "$ThisOSName" && -n "$ThisOSDistro" ]]; then
         msg "Acquiring Perforce's package repository public key."
         if wget -qO - $PerforcePackagePubkeyURL > $TmpPubKey; then
            msg "Public key for Perforce package repo acquired as: $TmpPubKey"

            msg "Adding Perforce's packaging key to APT keyring."
            if apt-key add < /tmp/perforce.pubkey; then
               msg "APT keyring added successfully."
            else
               warnmsg "Failed to add Perforce packaging key to APT keyring."
            fi

            msg "Doing apt-get update after adding the new perforce.list repo."
            if apt-get update; then
               msg "Update completed."
            else
               warnmsg "What if apt-get did not return a zero exit code."
            fi
         else
            warnmsg "Failed to acquire Perforce package repo public key."
         fi

         msg "Generating $P4AptGetRepo."
         if ! echo "deb $PerforcePackageRepoURL/apt/$ThisOSName $ThisOSDistro release" > "$P4AptGetRepo"; then
            warnmsg "Unable to generate $P4AptGetRepo."
         fi
      else
         warnmsg "Skipping generation of $P4AptGetRepo due to lack of OS Name and Distro info."
      fi
   else
      warnmsg "No Perforce supported package repository, RPM or APT, found to add. Skipping."
   fi
else
   msg "Skipping addition of Perforce Package repository due to '-no_ppr'."
fi

#------------------------------------------------------------------------------
# Add Firewall rules (Firewalld only).

if [[ "$FirewallType" == "Firewalld" ]]; then
   msg "\\nConfiguring $FirewallType services.\\n"
   cd "$FirewallDir" || bail "Could not cd to $FirewallDir."
   for i in $SDPInstances; do
      for binary in $BinList; do
         svcName="${binary}_${i}"
         svcFile="${svcName}.xml"
         sed -e "s:__INSTANCE__:${i}:g" \
            -e "s:__P4PORT__:${Config['P4_PORT']}:g" \
            -e "s:__P4BROKER_PORT__:${Config['P4BROKER_PORT']}:g" \
            "$ResetHome/${binary}_N.xml.t" > "$svcFile" ||\
            bail "Failed to generate $PWD/$svcFile."
         run "firewall-cmd --add-service=$svcName" \
            "Adding firewall entry for $svcName" ||\
            warnmsg "Adding firewall entry for $svcName failed."
      done

      run "firewall-cmd --runtime-to-permanent" \
         "Permanently adding firewall entries" ||\
         warnmsg "Adding permanent firewall entries failed."
   done
   run "firewall-cmd --reload" "Firewall reload." ||\
      warnmsg "Firewall reload failed."
   run "iptables-save" "Showing firewall rules." ||\
      warnmsg "Showing firewall failed."
elif [[ "$FirewallType" == "IPTables" ]]; then
   warnmsg "IPtables firewall detected, but not handled."
fi

#------------------------------------------------------------------------------
# Load crontab.
if [[ "$InstallCrontab" -eq 1 ]]; then
   CrontabFile="$SDPCrontabDir/crontab.$RunUser.${HOSTNAME%%.*}"

   # Search for SDP-generated crontab files in a particular order, looking for
   # *.new files first and accounting for an SDP change introducing the
   # SDP instance name info the file.
   for i in $SDPInstances; do
      for f in /p4/p4.crontab.${i}.new /p4/p4.crontab.${i} /p4/p4.crontab.new /p4/p4.crontab; do
         if [[ -r "$f" ]]; then
            CrontabFileInP4="$f"
            break
         fi
      [[ -n "$CrontabFileInP4" ]] && break
      done
   done

   if [[ -n "$CrontabFileInP4" ]]; then
      run "mv $CrontabFileInP4 $CrontabFile" ||\
         errmsg "Failed to move crontab file to $CrontabFile."

      run "crontab -u $RunUser $CrontabFile" "Setting crontab for $RunUser." ||\
         errmsg "Failed to load crontab."
   else
      warnmsg "No SDP-generated crontab file found. Skipping load of crontab."
   fi
else
   msg "Not loading crontab due to '-no_cron'."
fi

if [[ "$DoSDPVerify" -eq 1 && -x "$SDPVerify" ]]; then
   SDPVerifyOptions+=" -L off"
   if [[ "$LoadSampleDepot" -eq 1 ]]; then
      SDPVerifyOptions+=" -online"
   else
      SDPVerifySkipTests="offline_db,p4root,p4t_files"
   fi

   [[ "$InstallCrontab" -eq 0 ]] && SDPVerifySkipTests+=",cron"
   SDPVerifyOptions+=" -skip $SDPVerifySkipTests"

   for i in $SDPInstances; do
      SDPVerifyCmd="$SDPVerify $i $SDPVerifyOptions"
      msg "\\nDoing SDP verification for instance $i."
      if run "$SDPVerifyCmd"; then
         msg "SDP verification for instance $i was OK."
      else
         errmsg "SDP verification for instance $i reported errors."
      fi
   done
else
   msg "No $SDPVerify script found to execute. Skipping it."
fi

#------------------------------------------------------------------------------
# Apply Support-recommended OS Tweaks to Linux kernel parameters.
# (e.g. KHugePage, etc.)
if [[ "$RunOSTweaks" -eq 1 ]]; then
   if [[ "$ThisOS" == "Linux" ]]; then
      if [[ -x "$OSTweaksScript" ]]; then
         run "$OSTweaksScript" "Making recommended Linux OS tweaks." ||\
         warnmsg "Non-zero exit code ($CMDEXITCODE) returned from $SDPSetupDir/os_tweaks.sh"
      else
         msg "Not making OS tweaks, $OSTweaksScript is missing or not executable."
      fi
   else
      msg "Skipping OS tweaks on non-Linux OS."
   fi
else
   msg "Skipping OS tweaks due to '-no_tweaks'."
fi

if [[ "$ErrorCount" -eq 0 ]]; then
   if [[ "$WarningCount" -eq 0 ]]; then
      msg "\\nSUCCESS:  SDP Configuration complete."
   else
      msg "\\nSUCCESS:  SDP Configuration complete with $WarningCount warnings."
   fi

   if [[ "$MultiRun" -eq 0 ]]; then
      run "chmod -x $ResetHome/reset_sdp.sh" \
         "Removing execute permissions from $ThisScript." ||\
         warnmsg "Failed to remove execute permissions from $ResetHome/reset_sdp.sh"

      run "mv $ResetHome/reset_sdp.sh $ResetHome/reset_sdp.sh.txt" \
         "Renamed to clarify this should not be executed again." ||\
         warnmsg "Failed to rename to $ResetHome/reset_sdp.sh.txt"
   else
      msg "Self-disable safety feature ignored due to '-M'."
   fi
else
   msg "\\nSDP Configuration completed, but with $ErrorCount errors and $WarningCount warnings."
fi

exit "$ErrorCount"
# Change User Description Committed
#223 31148 C. Thomas Tyler Changed default Helix Binaries version to r24.2.
#222 30994 C. Thomas Tyler Fixed command determining mkdirs.sh version.
#221 30993 C. Thomas Tyler Improved handling with semanage but without SELinux fully installed.
#220 30992 C. Thomas Tyler Fixed issue with '-no_cron' behavious not exactly matching the doc.

Desired behaviour is that crontab is always generated and always
moved to the correct location in the SDP structure, regardless of
the '-no_cron' option.  The only thing affected by the -no_cron option
is now whether the crontab file is loaded to become active.
#219 30495 C. Thomas Tyler Added config default in case HxCheckpoints isn't defined.
#218 30494 C. Thomas Tyler Added '-m <ShallowCloneRevs>' option.
#217 30493 C. Thomas Tyler Fixed issue with '-v' option to make it more reliable.
#216 30491 C. Thomas Tyler Changed so '-local' implies '-no_ppr'.

#review-30492 @mzinthefer
#215 30489 C. Thomas Tyler Added sos package to yum and zypper package managers; it is not
reliably available on apt.

Added sysstat package to apt, yum, and zypper package managers.

Note that we don't reference 'dnf' (the new 'yum' on RHEL systems)
because 'yum' still works and works across versions.
#214 30488 C. Thomas Tyler Added tuned as a standard package.
#213 30487 C. Thomas Tyler Avoid firewalld errors if firewalld is not running.

This was done in a way as to make it easier to add support
for other firewalls (ufw?) later.
#212 30486 C. Thomas Tyler Pass '-no_systemd' option thru to mkdirs.sh
#211 30470 C. Thomas Tyler Added logic to pass '-no_enable' option thru to mkdirs.sh.
#210 30465 C. Thomas Tyler Improved auditability for getting Helix binaries.
#209 30464 C. Thomas Tyler Typo.
#208 30463 C. Thomas Tyler Fixed regression in 2024.1 where specifying P4BinRel and APIBinRel in
settings.cfg to older-than-default p4d versions did not work as expected;
r24.1 was always pulled.
#207 30462 C. Thomas Tyler Re-added accidentally deleted SDPURL setting.
#206 30461 C. Thomas Tyler More URL adjustments.
#205 30460 C. Thomas Tyler Adjusted URLs, fixed timestamp.
#204 30459 C. Thomas Tyler Change URLs in curl calls in docs and code to avoid Apache redirects.
Also removed '-s' option from curl calls.
#203 30404 C. Thomas Tyler Added support for Rocky 9 in reset_sdp.sh.

Added Rocky 9 to regression test suite.

Changed from using 'yum' to 'dnf' on Rocky, to be trendy.

Changed base OS template to match what SDP uses for Rocky 8.
#202 30399 C. Thomas Tyler Adapted to SDP default value of 'localhost' for DNS name of commit server.
#201 30398 C. Thomas Tyler Add '-no_enable' option to avoid enabling installed services.
#200 30397 C. Thomas Tyler Adjust location of generated crontab file to:
/p4/common/etc/cron.d/crontab.<user>.<short_hostname>.<instance>.
#199 30365 C. Thomas Tyler Added support for separate HxCheckpoints volume.
#198 30364 C. Thomas Tyler Changed default Helix Core version to r24.1.
#197 30332 C. Thomas Tyler Tweaked formatting of log line.
#196 30331 C. Thomas Tyler Added built-in logging.
#195 30330 C. Thomas Tyler More adaptation to SDP 2024.1 changes.
Now deferrring to SDP
for download of derived APIs.
#194 30325 C. Thomas Tyler Adapted to SDP 2024.1, supporting multiple architectures to include aarch64 e.g.
Graviton.
#193 30322 C. Thomas Tyler Fixed inaccuracy in error message if running on unsupported architecture.
#192 30225 C. Thomas Tyler Normalized sed statements to use '|' separator.
#191 30213 C. Thomas Tyler Added '-si <SDPInstance>' as a command line option, so there is one less
reason to need to do the more complex 'Configured' installation, especially
for a proxy or stand-alone broker.

#review-30214
#190 30192 C. Thomas Tyler Adapated to change in SDP default password.
#189 30191 C. Thomas Tyler Typo
#188 30190 C. Thomas Tyler Completed apt repo update for Ubuntu.
#187 30189 C. Thomas Tyler Updated APT keyging magic for Perforce Package Repository for Ubuntu.
#186 30045 C. Thomas Tyler 2023.2 release; changed default version to 2023.2.
#185 29816 C. Thomas Tyler Changed preferred delimeter for sed calls from a mix of ':', '@', and '|'
to always use '|', since there are no values we use for which '|' is
acceptable.

This fixes an issue where certain values, e.g. an SMTP server, might
include a port number, e.g. smtp.p4demo.com:587 -- the ':' would break
when the 'sed' was used.

#review-29817 @will_kreitzmann
#184 29814 C. Thomas Tyler Fixed bug: Wrong/root ownership of 'downloads' dir if '-no_sd' used.

#review-29815
#183 29698 C. Thomas Tyler Changed 'curl' commands referencing Workshop to use '-L'.

Updated stable version numbers in README.md to use new versions
with corrected URLs.
#182 29615 C. Thomas Tyler Set default to r23.1.

Removed '-k' from curl calls.
#181 29447 C. Thomas Tyler Added 'bc' to standard package list.
#180 29389 C. Thomas Tyler Add '--help' alias for '-man' option.
#179 29362 C. Thomas Tyler Updated default Helix Core version from r22.1 -> r22.2.
#178 29339 C. Thomas Tyler Removed superfluous error message.
#177 28887 C. Thomas Tyler reset_sdp.sh v4.11.3:
Fixed bogus message regarding verify_sdp.sh when '-v'
was not specified.

If the '-v' was specified, the scirpt correctly executed the
'verify_sdp.sh' script with the correct "skip test" list to
avoid errors.

However, if '-v' was not specified, a bogus message was
displayed indicating verify_sdp.sh was not available.

With this change:
* If '-v' is not specified, no output about verify_sdp.sh
is displayed at all (as was the original intent).
* If '-v' is specified and verify_sdp.sh is not avaialble,
the message disaplyed about it not being there is now
an error rahter than an informational message.

#review-28888 @rwillyoung
#176 28834 C. Thomas Tyler Updated default P4D version to r22.1.
#175 28833 C. Thomas Tyler reset_sdp.sh v4.11.2:
Fixed issue where -H/-T flags worked but equivalent settings in
settings.cfg did not take.
#174 28769 C. Thomas Tyler Fixed issue with root ownership of mail simulator.
#173 28721 Andy Boutte Adding firewalld template for p4p
#172 28662 C. Thomas Tyler Added support for SELinux in enforcing mode.

Enhanced documentation, including notes about SELinux handling.
#171 28582 C. Thomas Tyler reset_sdp.sh v4.9.0:
Added '-no_sudo' option.
Added '-no_firewall' option.
Fixed minor issue where 'systemctl' commands try to execute when systemctl isn't avail.
Added test coverage in test_hi.sh.
#170 28408 C. Thomas Tyler Refined Blast logic a bit further.
#169 28407 C. Thomas Tyler Minor cleanup of logic blasting 'perforce' user pids.
Fixed formatting issues.
#168 28406 C. Thomas Tyler Adjusted issue with ownership of /p4/ssl/config.txt file.
#167 28405 C. Thomas Tyler Minor code cleanup and refinement of '-B'.
#166 28404 C. Thomas Tyler Tweaked generated email simulator.
#165 28403 C. Thomas Tyler Adjusted placement of email simulator logic.
#164 28402 C. Thomas Tyler Fixed issues with '-B' (blast mode) not cleaning up some dirs.
#163 28401 C. Thomas Tyler Rolled back removal of '-k' to curl for now.
#162 28400 C. Thomas Tyler Fixed logic to generate mail simulator wrapper script.
#161 28399 C. Thomas Tyler Downgraded warning to info re: using ServerType as ServerID for proxy/broker.
#160 28396 C. Thomas Tyler Changed default Helix Core binaries version to r21.2.
#159 28394 C. Thomas Tyler Fail faster if CaseSensitive is set to 0 in the config file and the
Sample Depot data set is to be loaded. The Sample Depot data set is
not supported for a case-insensitive server.
#158 28393 C. Thomas Tyler Added error message if conditions for HI-54 are detected -- i.e.
if OS is RHEL/CentOS/Rocky Linux 8.x and SELinux is enabled.
#157 28392 C. Thomas Tyler Fixed cert generation issue.
#156 28389 C. Thomas Tyler Dropped insecure '-k' option from curl commands.
#155 28388 C. Thomas Tyler Fixed bootstrapping issue with '-ls' (limited sudo) option.
#154 28387 C. Thomas Tyler Corrected issue with generating SSL certificates on proxy-only
or broker-only hosts.
#153 28266 C. Thomas Tyler Improved support for proxy-only hosts.

#review-28267 @rwillyoung
#152 28120 C. Thomas Tyler Added -no_systemd option to avoid using systemd.

This is useful for operating in containerized test environments
where systemd is not available.
#151 28094 C. Thomas Tyler Corrected package list for Ubuntu.
#150 27985 C. Thomas Tyler Added support for running Unsupported (resurrected) SDP
script install_sdp_python.sh if it exists in the SDP package.
#149 27981 C. Thomas Tyler Fixed doc typos.
#148 27980 C. Thomas Tyler Updated default P4D to r21.1 from r20.1.
#147 27930 C. Thomas Tyler Added required 'which' package which is no longer reliably
available on minimal OS installations.
#146 27553 C. Thomas Tyler Spell check only.
Non-functional changes. Docs udpated.
Fixed typos in comments and messages, including generated
settings.cfg files.
#145 27419 C. Thomas Tyler Added '-v' option to run verify_sdp.sh with various options.
Added test and doc for same.
The options to verify_sdp.sh are dependent on options to reset_sdp.sh.

Enabled configure_sample_depot_for_sdp.sh to work with non-default
mount points.
#144 27387 C. Thomas Tyler reset_sdp.sh v4.3.3:
* Updated logic for loading crontab to work with latest SDP, which
changed location of generated SDP crontab files.
#143 27377 C. Thomas Tyler Fixed path to sudoers file.
#142 27376 C. Thomas Tyler Added removal of sudoers file to Extreme Cleanup mode.
#141 27374 C. Thomas Tyler Added '-ls' (limited sudo) option.
#140 27305 C. Thomas Tyler Added rsync package to all platforms.
#139 27299 C. Thomas Tyler Added '-H <hostname>' and '-T <timezone>' options and cfg settings.
#138 27283 C. Thomas Tyler Added '-no_tweaks' option to skip running SDP os_tweaks.sh script.
#137 27282 C. Thomas Tyler Enhanced so ServerID, ServerType, and TargetServerID only apply
if mkdirs.sh is new enough to support them. Added warning message
if those settings are defined and an old SDP is used.

Tweaked 'chown' logic to only chown existing directories.
#136 27259 C. Thomas Tyler reset_sdp.sh v4.0.0:
* Added config settings: ServerID, ServerType, TargetServerType
* Enhanced internal docs.
* Enhanced docs for '-local' flag.
* Added '-dapi' flag to install derived APIs (P4Perl/P4Python).
  If this flag is used, failures to build P4Perl and/or P4Python
  are reported as errors.
* Tweaked '-fast' to now mean "skip package installations," and
  documented as such.
#135 27242 C. Thomas Tyler reset_sdp.sh v3.23.4: Cosmetic changes and fixed typo in config file.
#134 27241 C. Thomas Tyler reset_sdp.sh v3.23.3: No functional change; code cosmetics.
#133 27227 C. Thomas Tyler Refinement for consecutive test runs where owner changes between tests.

The configure_sample_depot_for_sdp.sh will fail with "Permission denied"
errors in regression test suite runs after the first when ownership
changes.
#132 27225 C. Thomas Tyler Refined narrowing logic.
#131 27222 C. Thomas Tyler reset_sdp.sh v3.23.0:
* Narrowed scope of 'chown -R' command to /hxdepots/p4 to avoid
.snapshot/lost+found dirs.
#130 27157 C. Thomas Tyler Adapted to use SDP 2020.1 systemd service file templates if they exist.
#129 27136 C. Thomas Tyler Adjusted to not deploy the systemd unit file for p4p.
#128 27031 C. Thomas Tyler Updated adaptation to SDP r20.1 changes coming soon.
This change has no impact for SDP 2019.3.
#127 26970 C. Thomas Tyler Adjustments to work with SDP r20.1:
* Adapted to new stage area for exes.
* Adapted to changes in mkdirs.cfg.
#126 26969 C. Thomas Tyler Changed Helix Core to r20.2 default release.
#125 26895 C. Thomas Tyler Corrected crontab set command to account for running as root.
#124 26893 C. Thomas Tyler Silently ignore install_sdp_p4<perl,python>.sh if they do not
exist.

Added systemd daemon reload.
#123 26891 C. Thomas Tyler Added loading of crontab for configured OS user.
Added '-no_cron' flag to disable new default crontab loading behavior.
#122 26890 C. Thomas Tyler For '-d <sdp_dir>' flag:
* Adjusted default value to '/sdp' per docs.
* Changed rsync to include '--delete' flag.
#121 26889 C. Thomas Tyler Tweaks to reset_sdp.sh:
* Fixed minor output bug.
* Renamed SDPDir to SDPCopyDir for clarity.
* Improved initialization for SDPCopyDir.
#120 26887 C. Thomas Tyler Fixed typo in comment; non-functional change.
#119 26828 C. Thomas Tyler Adjusted for variation in format of Hx* settings.
#118 26821 C. Thomas Tyler For RHEL/CentOS family, added major OS version detection for RHEL/CentOS 8.
#117 26817 C. Thomas Tyler Fixed '-B' (blast) logic bug when using multiple storage volumes.
#116 26799 C. Thomas Tyler Added '-M' multi-run option to disable the 'run once' safety feature,
to simplify multiple tests.
#115 26784 C. Thomas Tyler reset_sdp.sh v3.17.0:

Made /hx* mount points configurable in settings.cfg, and
updated documentation accordingly.

Added support for configuring /hxmetadata1 and /hxmetadata2
with different values.

Added test coverage for changing /hxdepots from the default.

Enhanced test suite.

TEST FAIL NOTE: As of this change, tests are succeeding on all
platforms except CentOS 6. Failures are in the test suite
infrastructure, not related to this change.
#114 26625 C. Thomas Tyler Fixed bug installing with '-d' install method (mainly used for
Battle School custom installs).
#113 26604 C. Thomas Tyler Non-functional changes to maintain shellcheck compliance.
#112 26576 C. Thomas Tyler Fixed order-of-operations issue due to recent changes in SDP; the logic to
implement 'sudo' as required to call 'systemd' wrappers now requires the
sudo to be called before the call to configure_sample_depot.sh.

Refined firewall handling logic.
#111 26565 C. Thomas Tyler Set password for OSUSER to same as P4USER if OSUSER needs to be created.
#110 26564 C. Thomas Tyler Bumped version id for last change.
#109 26562 C. Thomas Tyler Corrected chmod to be a chown as intended.
#108 26557 C. Thomas Tyler Changed default Helix Core to r20.1.
Updated docs.
#107 26181 C. Thomas Tyler Corrected arg to '-d'.
#106 26180 C. Thomas Tyler Enhanced '-d <sdp_dir>' argument to use an SDP.Unix.tgz tarball in
the specified directory if found, otherwise it reverts to current
behavior of using a pre-extracted sdp directory tree.

Added logic to display the SDP version used unless DVCS method is
used (which case the Version will be unrelaible, as it s the latest
from the dev branch).

Corrected doc inconsistencies.
#105 26179 C. Thomas Tyler Tweaked hardcoded site tag ref to use settings.cfg.
Other cosmetic fixes.
#104 26178 C. Thomas Tyler Doc updates and variable substitutions.
No functional changes.
#103 26177 C. Thomas Tyler Updated Helix binaries to 2019.2.1885864 (2019/11/18)
#102 26020 C. Thomas Tyler Added P4USER setting to settings.cfg to enable super user to
be changed from the default.
#101 26019 C. Thomas Tyler Enabled Sample Depot install with non-default OSUSER.
#100 26016 C. Thomas Tyler Tweaked logic for creation of firewalld files to enable potential future
support of multi-instance handling.
#99 26015 C. Thomas Tyler Follow on to change @26009, removal of bogus extra setting.
#98 26014 C. Thomas Tyler Fix issue with systemd files when OSUSER is not perforce.

Also fixed issue with '-X' mode cleaning up firewalld files.
#97 26009 C. Thomas Tyler Removed bogus extra setting in generated settings.cfg.
#96 26006 C. Thomas Tyler Enhanced format of config file to separate settings that must be
changed, should be changed, and should not be changed for PoC and
production bootstrapping installs, with comments noting that no
changes is needed for demo installs.
#95 26004 C. Thomas Tyler Added more configurable options to settings.cfg:
OSUSER - OS user for p4d to run as, defaults to perforce.
OSGROUP - primary group for OSUSER, w/ platform-specific defaults.
OSUSER_HOME - home dir for OSUSER, default /home/perforce.
OSUSER_ADDITIONAL_GROUPS - Add'l groups for OSUSER, no default.
#94 26003 C. Thomas Tyler Changed default config file referenced in docs to 'settings.cfg',
to better match how it is used in practice and to make things
just a bit easier.
#93 25995 C. Thomas Tyler Changed to use only https (no more http).
All curl commands use '-k' for robustness.

Changed default install method to tarfile using the
consistently named sdp.Unix.tgz file name. Eliminated
'-t' flag; cloning is now done only when '-b' is used.

Removed command attempting to change ownership of
/hxdepots/reset dir to 'perforce' before that user
exists. Better if that folder remains root-owned
in any case, as only root can run it.
#92 25992 C. Thomas Tyler Follow on to change @25915 fixing issue with firewalld conf.
#91 25991 C. Thomas Tyler Added 'mailx' to package list for 'yum' systems.
Did not
added roughly corresponding 'bsd-mailx' to apt-get systems
due to interactive nature. No pacakge changes for zypper
either.
#90 25988 C. Thomas Tyler Updated default SDP tarball packge to install if '-t default' is used.
#89 25915 C. Thomas Tyler Fixed issue with firewalld configuration on RHEL/CentOS 7 systems.

Changed '-X' extreme cleanup to now clear firewalld rules.

Added missing mention of firewalld config in documentation.
#88 25889 C. Thomas Tyler Tweaked 'useradd' command to add explicit '-s /bin/bash' flag, as
needed to ensure the command shell for the 'perforce' user is
bash.  This is to support Ubuntu 18, which seems to default to
/bin/sh for new accounts.
#87 25856 C. Thomas Tyler Fixed bug with 'apt-get' keyring setup on Ubuntu.
Added 'apt-get update' following addition of Perforce package repository.
#86 25854 C. Thomas Tyler Introduced new 'Static Data' internal block in the script, for
configuration of static load data in associative arrays.
#85 25818 C. Thomas Tyler Added '-no_ppr' flag to skip addition of Perforce Package repo.
#84 25817 C. Thomas Tyler Fixed typo in error message.
#83 25815 C. Thomas Tyler Added support for configuring Sample Depot with non-default instance
name.
#82 25813 C. Thomas Tyler Fixed bug with firewall not working for non-default port.
#81 25756 C. Thomas Tyler Minor tweaks to internal variable names.
#80 25753 C. Thomas Tyler Added code to call SDP os_tweaks.sh.

Regenerated command summary file.
#79 25752 C. Thomas Tyler reset_sdp.sh v3.5.0:

Enhanced to support non-default ports in systemd service files.

Enhanced logic handling download of Helix Installer supplemental files.

Skips download of Sample Depot if '-no_sd' is specified. (HI-9).

Skips download of P4API if '-fast' is specified. (HI-9)

Removed redundant check for +x on files.

Enhanced '-B' processing to blast extracted Sample Depot.

Added logic to disable reset_sdp.sh after successful execution. (HI-5)

Tweaked REQUIREMENTS docs.
#78 25728 C. Thomas Tyler Adjustment to Ubuntu public keyring handling.
#77 25726 C. Thomas Tyler Fixed typo bug affecting only Ubuntu 16 distro.
#76 25723 C. Thomas Tyler Updated default Helix Core software version r18.2 -> r19.1.
#75 25638 C. Thomas Tyler Cosmetic changes.
Enhanced doc for password in generated config
file when used to bootstrap production.
#74 25598 C. Thomas Tyler Changed default SDP version for tarball installs.
#73 25497 C. Thomas Tyler Fixed bug where MAILFROM email setting wasn't taking effect.

Added 'MailFrom' setting.
#72 25496 C. Thomas Tyler Added '-R' reset option to stop afer doing reset logic.
#71 25493 C. Thomas Tyler Fixed extra-slash issue.
#70 25492 C. Thomas Tyler Fixed issues with parameterization of the instance.
#69 25491 C. Thomas Tyler Corrected variable name.
#68 25490 C. Thomas Tyler Parameterized case sensitivity setting.
#67 25489 C. Thomas Tyler Enhanced to parameterize SDP instance name.
#66 25488 C. Thomas Tyler Updated version.
#65 25487 C. Thomas Tyler Updated default SDP tarfile version.
#64 25433 C. Thomas Tyler Added '-d <sdp_dir>' flag.
#63 25391 C. Thomas Tyler Updated default SDP release for tarball installs.
#62 25382 C. Thomas Tyler Updated default SDP release for tar installs to
sdp.Unix.2019.1.25374.tgz.
#61 25370 C. Thomas Tyler Added '-c <cfg>' and '-C' flags to use (and with '-C' generate) a
config file (similar to the '-C' and '-c <cfg>' flags with p4broker).

Updated docs accordingly.

Added missing 'chmod +x' step in man page in docs.

Enabled testing on Mac OSX to get past the package manager test,
since yum/apt-get/zypper aren't expected to be on Mac OSX.
#60 25324 C. Thomas Tyler Changed default SDP version for taball installs.
#59 25313 C. Thomas Tyler Changed default SDP version for tar installs.
#58 25308 C. Thomas Tyler Added support for handling firewalld.
#57 25303 C. Thomas Tyler Adjusted to use 'ftp' user for The Workshop.
#56 25302 C. Thomas Tyler Ensure perforce user owns his home directory when the account is
created from scratch.
#55 25285 C. Thomas Tyler Corrected path to Perforce yum repo file.
#54 25282 C. Thomas Tyler Fixed order-of-operations issue for creating ~perforce/.bash* files.
#53 25281 C. Thomas Tyler Updated to latest SDP release.
#52 25277 C. Thomas Tyler Removed download of Swarm tarball, to encourage use of package installer for
Swarm.

Added generation of sudoers file for perforce user.

Added generation of Perforce Package Repository files for RHEL/CentOS and
Ubuntu.
#51 25248 C. Thomas Tyler Filled in SDP 2019.1 changelist number, 25238.
#50 25247 C. Thomas Tyler Additional cleanup.
#49 25240 C. Thomas Tyler Simplified to use a single /hxmetadata volume, as this is the
most common configuration.  Small sites don't need multiple
volumes, and big sites have an array of hardware options, only
some of which require a two-volume solution for metadata to
maintain performance.

Changed default replica ServerID from p4d_fr_bos to p4d_ha_bos,
to promote modern 2018.2 high availability replicas that can
be created with the mkrep.sh in SDP 2019.1+.  The replica is not
actually created with the Helix Installer, just referenced
as a sample ServerID name.

Extended '-B' flag to cleanup temp dir used by install_sdp_python.sh.
Changed behavior to bail on failure to cleanup temp dirs, as this
could result in wasted time building outdated versions of
P4Python, etc.

Added '-i <helix_installer_branch>' debugging flag to support
testing of Helix Installer from the dev branch.  Moved this and
the '-D' flag to a new doc section titled DEBUGGING OPTIONS.

Added '-X' eXtreme reset debugging option.

Updated some internal variable names.
#48 25230 C. Thomas Tyler Added logic to install packages.
#47 25229 C. Thomas Tyler Added wget to zypper package list.
#46 25228 C. Thomas Tyler Updated to generate ~perforce .bash_profile and .bashrc
for fresh-from-scratch installs.

Added warnings mechanism for non-fatal failures.
#45 25226 C. Thomas Tyler Updated to use SDP 2019.1.XXXXX (to be udpated later
with actual value for XXXXX).

Updated to ensure needed OS packages are installed with
various package managers (yum, apt-get, and zypper).

Added support for SuSE Linux.

Updated to create the 'perforce' OS user if needed, and
also create its home directory if needed.

Updated to pass shellcheck v0.60 verification.
#44 25127 C. Thomas Tyler Updated platform for Mac OSX from darwin90x86_64 to
macosx1010x86_64, as needed for r18.2+.
#43 25054 C. Thomas Tyler Updated SDP default tarball to 2018.1.23583.p2.
Corrected Swarm release to 2018.3; there is no 2018.4!
#42 25024 C. Thomas Tyler Updated Helix Swarm to 2018.4.
It's not yet used in this script other
that grabbing the tarball.
#41 25009 C. Thomas Tyler Changed default tarball to 2018.1.p1.
#40 24912 C. Thomas Tyler Added support for sdp_reader login.
#39 24853 C. Thomas Tyler Updating to r18.2 for p4/p4d/p4broker/p4p and r18.3 for Swarm.
#38 23826 C. Thomas Tyler Made more robust in resetting alternlate SDP structures with
/p4/common being a local directory.  Fixed typos in messages.
#37 23825 C. Thomas Tyler Updated to Helix Core 2018.1.
#36 23597 C. Thomas Tyler Updated default SDP to lastest patch.
#35 23512 C. Thomas Tyler Updated default SDP version.
Updated default P4D version to 2017.2.
Updated default Swarm to 2017.4 (though Swarm isn't installed yet).
#34 23363 C. Thomas Tyler reset_sdp.sh v2.9.11:
Tweaked to simplify running a series of installs while re-using
the Downloads dir, acquiring an updated SDP tarfile from the FTP
server if needed.
#33 23359 C. Thomas Tyler Fixed '-t default' processing.
Updated to latest SDP tar file.
#32 23333 C. Thomas Tyler Updated default SDP version to latest just released.
#31 23280 C. Thomas Tyler reset_sdp.sh v2.9.7: Doc enhancements only, no functional change.
#30 23279 C. Thomas Tyler reset_sdp.sh v2.9.6: Doc enhancements only, no functional change.
#29 23243 C. Thomas Tyler Added support for fetching a shelved changelist.
#28 23062 C. Thomas Tyler Routine merge down to dev from main.
#27 23058 C. Thomas Tyler Routine merge down to dev from main.
#26 23011 C. Thomas Tyler Routine merge down to dev from main.
#25 22301 C. Thomas Tyler Routine merge down to dev from main.
#24 22294 C. Thomas Tyler Routine merge down to dev from main.
#23 22289 C. Thomas Tyler Routine merge down to dev from main.
#22 22205 C. Thomas Tyler Routine merge down to dev from main.
#21 22192 C. Thomas Tyler Routine merge down to dev from main.
#20 21827 C. Thomas Tyler Helix Installer, Routine merge down to dev from main.
#19 21541 C. Thomas Tyler Merge Down to dev from main.
#18 21538 C. Thomas Tyler Merge Down to dev from main.
#17 21506 C. Thomas Tyler Routine merge down to dev from main.
#16 21504 C. Thomas Tyler Routine merge down to dev from main.
#15 21502 C. Thomas Tyler Routine merge down to dev from main.
#14 21359 C. Thomas Tyler Merge down to dev from main.
#13 21356 C. Thomas Tyler Merge down to dev from main.
#12 21351 C. Thomas Tyler Merge Down to dev from main.
#11 21247 C. Thomas Tyler Merge Down to Dev from Main.
#10 21044 C. Thomas Tyler Merge Down to dev from main for helix-installer.
#9 20655 C. Thomas Tyler Routine Merge Down to dev from main for the Helix Installer.
#8 20651 C. Thomas Tyler Routine Merge Down to dev from main.
#7 20484 C. Thomas Tyler Routine Merge Down to dev from main.
#6 20053 C. Thomas Tyler Routine Merge Down to dev from main.
#5 19901 C. Thomas Tyler Routine merge down to dev from main.
#4 19894 C. Thomas Tyler Routine merge down to dev from main.
#3 19417 C. Thomas Tyler Merge down to dev from main for Helix Installer.
#2 19315 C. Thomas Tyler Routine Merge Down to dev from main for helix-installer.
#1 19232 C. Thomas Tyler Populate -b perforce_software-helix-installer-dev.
//guest/perforce_software/helix-installer/main/src/reset_sdp.sh
#2 19231 C. Thomas Tyler Adjusted Swarm URL to reflect the Helix Installer move from
//guest/tom_tyler to //guest/perforce_software.
#1 19230 C. Thomas Tyler Populate -o //guest/tom_tyler/helix-installer/...
//guest/perforce_software/helix-installer/....
//guest/tom_tyler/helix-installer/main/src/reset_sdp.sh
#21 18963 C. Thomas Tyler Updated to latest SDP 2016.1.18958.
#20 16837 C. Thomas Tyler Updated to latest SDP tarfile.
#19 16697 C. Thomas Tyler Tweaked to account for cases where 'hostname -i' call returns
more than one IP address.
#18 16671 C. Thomas Tyler reset_sdp.sh v2.6.9:
* Minor optimization to error message when gcc and/or
gcc-c++ packages are missing.
* The '-fast' flag now changes the error relating to
gcc/g++ not being installed to a warning.
* Added confirmation message if gcc/g++ are found.
#17 16670 C. Thomas Tyler reset_sdp.sh v2.6.8:
* Now clones SDP main branch from The Workshop by default, rather
than using a tar file.
* Added '-b' to override default branch (main), e.g. '-b dev'.
* Added '-t <tarfile>' (or '-t default') to use the old tarfile
install method of using a hard-coded tarball, good for when stability
is preferred over using the very latest.
#16 16660 C. Thomas Tyler Added '-p' flag to enable preserving existing directories
under /p4/common.
#15 16642 C. Thomas Tyler Updated default SDP version.
#14 16624 C. Thomas Tyler reset_sdp.sh v2.6.5.
For Linux hosts, optimized to use 'hostname -i' rather than
'hostname -I'.  Added inline comments on IP selection on
Linux and OSX.
#13 16623 C. Thomas Tyler Changed order of commands to fix issue with permissions
when generating SDP broker config file.
#12 16607 C. Thomas Tyler Audit enhancement.
#11 16606 C. Thomas Tyler Improved handling of simulated mail from SDP scripts, so that
live_checkpoint succeeds on all platforms; it had failed
previosuly on Mac/Darwin due to failure sending email.

Improved backup handling.
#10 16602 C. Thomas Tyler Added '-local' option; avoids pulling from Workshop/FTP server.
Updated Swarm to 2015.3.
#9 16567 C. Thomas Tyler Updated SDP Version.
#8 16396 C. Thomas Tyler Rolled back Swarm version.
#7 16395 C. Thomas Tyler Updated to 2015.2 GA for P4D and 2015.3 GA for Swarm.
#6 16393 C. Thomas Tyler Fixed issue with 'sed' call.
Updated to work with new HOSTIP setting in SDP.
#5 16377 C. Thomas Tyler Updated to pick up latest SDP, and made corresponding
adjustments to processing of subsitutions in mkdirs.sh.
#4 16359 C. Thomas Tyler Minor code cleanlup.
#3 16358 C. Thomas Tyler Adjusted base path for Helix Installer.
Updated coypright to reference LICENSE file.
#2 16349 C. Thomas Tyler Updated to latest SDP version.
#1 15829 C. Thomas Tyler Moved Helix Installer to new Workshop Standard
for personal projects.
//guest/tom_tyler/sw/main/hi/src/reset_sdp.sh
#22 15629 C. Thomas Tyler reset_sdp.sh v2.5.0:
* Updated SDP to 2015.1.15607.
* Added '-C' (clean) flag to blast /depotdata/p4/common.
#21 15611 C. Thomas Tyler reset_sdp.sh v2.4.9:
* Updated default Swarm to 2015.2.
* Fixed mostly harmless bug attempting to pull a non-existing file from the web.
#20 15060 C. Thomas Tyler Rollback of Copy Up done with a new utility that apparently needs some work.
#19 15051 C. Thomas Tyler Copy Up using 'p4 copy -r -b tom_tyler-hi-dev'
#18 15007 C. Thomas Tyler Fixed expression.
#17 14987 C. Thomas Tyler Reduced excessive noise from from rsync and tar commands.

Added '--delete' to rsync commands handling the Sample Depot
to force a clean reset.

Added clear completion messages.
#16 14973 C. Thomas Tyler Added -no_ssl flag.
#15 14956 C. Thomas Tyler Fixed 'ps' check.
#14 14954 C. Thomas Tyler Fixed typo in case sensitivity mod.
#13 14953 C. Thomas Tyler Updated various settings to match changes in SDP.
Removed generation of a duplicate broker config file.
#12 14952 C. Thomas Tyler Adjusted case sensitivitiy to be case-sensitive on Linux,
the opposite of the SDP default.
#11 14949 C. Thomas Tyler Enhanced to ensure that 'reset_sdp.sh' is the only script
required.  It now downloads all other scripts and data files as
needed.
#10 14910 C. Thomas Tyler Added initialtion of empty /depotdata /metadata and /logs
dirs.
#9 14903 C. Thomas Tyler Fixed issue running under Vagrant.
#8 14902 C. Thomas Tyler Changed default list of SDP instances to initialize from
"1 12 abc" (illustrating ability to use named rather than
number instances) to just "1", which is mostly all that's
wanted for testing and pilot installations.
#7 14901 C. Thomas Tyler Fixed a typo in 'chmod' call.
#6 14188 C. Thomas Tyler Updated SDP version.
#5 14120 C. Thomas Tyler Moved sample depot checkpoint load to configurator script.
Added '-fast' flag to speed up testing.
Various minor tweaks.
#4 14106 C. Thomas Tyler Implemented Sample Depot SDP configurator script.

Tightened logic around process kill statement, and made it
work for Linux/Mac.
#3 14063 C. Thomas Tyler Added generation of initial live checkpoint for each instance.
Adjusted permissions on downloads folder.
Removed bad code fragements.
Cosmetic enhancement to the password.
#2 14033 C. Thomas Tyler Added script to transform stock Sample Depot data set to be
SDP compliant (mostly a stub at this point).  Various improvements
to reset_sdp.sh and the wrapper r.sh.
#1 13940 C. Thomas Tyler Added my personal reset_sdp test script.
 DO NOT DEPLOY on a live server.