#!/bin/bash #============================================================================== # Copyright and license info is available in the LICENSE file included with # the Helix Management System (HMS), and also available online: # https://swarm.workshop.perforce.com/projects/perforce_software-hms/view/main/LICENSE #------------------------------------------------------------------------------ #============================================================================== # Declarations and Environment # Allow override of P4U_HOME, which is set only when testing P4U scripts. export P4U_HOME=${P4U_HOME:-/p4/common/bin} export P4U_LIB=${P4U_LIB:-/p4/common/lib} export P4U_ENV=$P4U_LIB/p4u_env.sh export P4U_LOG=off export VERBOSITY=${VERBOSITY:-3} # Environment isolation. For stability and security reasons, prepend # PATH to include dirs where known-good scripts exist. # known/tested PATH and, by implication, executables on the PATH. export PATH=$P4U_HOME:$PATH:~/bin:. export P4CONFIG=${P4CONFIG:-.p4config} [[ -r "$P4U_ENV" ]] || { echo -e "\\nError: Cannot load environment from: $P4U_ENV\\n\\n" exit 1 } declare BASH_LIBS=$P4U_ENV BASH_LIBS+=" $P4U_LIB/libcore.sh" BASH_LIBS+=" $P4U_LIB/libp4u.sh" for bash_lib in $BASH_LIBS; do # shellcheck disable=SC1090 source "$bash_lib" ||\ { echo -e "\\nFATAL: Failed to load bash lib [$bash_lib]. Aborting.\\n"; exit 1; } done declare Version=1.5.0 declare -i SilentMode=0 declare TicketExpiration= declare TicketStatus= declare SuperAccessStatus= declare SkipInstanceList=sample declare NewInstanceList= declare -i DoPreflight=1 declare -i PreflightAccessOK=1 declare -i PreflightEnvOK=1 declare -i Skipped=0 declare HTCfgFile=/p4/common/config/HelixTopology.cfg declare SDPEnvFile=/p4/common/bin/p4_vars declare InstanceEnvFile= declare InstanceList= declare Program=Unset declare ProgramPath= declare ProgramArgs= export P4USER= export P4TICKETS=/p4/hms/.p4tickets export P4TRUST=/p4/hms/.p4trust export P4ENVIRO=/dev/null/.p4enviro # shellcheck disable=SC1090 disable=SC2146 disable=SC2116 P4USER=$(echo "$(source "$SDPEnvFile" hms; echo "$P4USER")") unset P4CONFIG export VERBOSITY=3 #============================================================================== # Local Functions #------------------------------------------------------------------------------ # Function: terminate function terminate { # Disable signal trapping. trap - EXIT SIGINT SIGTERM vvmsg "$THISSCRIPT: EXITCODE: $OverallReturnStatus" # Stop logging. [[ "${P4U_LOG}" == off ]] || stoplog # Don't litter. cleanTrash # With the trap removed, exit. exit "$OverallReturnStatus" } #------------------------------------------------------------------------------ # Function: usage (required function) # # Input: # $1 - style, either -h (for short form) or -man (for man-page like format). # The default is -h. # # $2 - error message (optional). Specify this if usage() is called due to # user error, in which case the given message displayed first, followed by the # standard usage message (short or long depending on $1). If displaying an # errror, usually $1 should be -h so that the longer usage message doesn't # obsure the error message. # # Sample Usage: # usage # usage -h # usage -man # usage -h "Incorrect command line usage." #------------------------------------------------------------------------------ function usage { declare style=${1:--h} declare errorMessage=${2:-Unset} if [[ $errorMessage != Unset ]]; then echo -e "\\n\\nUsage Error:\\n\\n$errorMessage\\n\\n" fi echo "USAGE for $THISSCRIPT v$Version: $THISSCRIPT [[-i <instance1>[,<instance2>,...]] [-sk <instance1>[,<instance2>,...]]] [-L <log>] [-si] [-v<n>] [-n] [-D] [<program> [<program arguments ...>]] or $THISSCRIPT [-h|-man|-V] " if [[ $style == -man ]]; then echo -e " DESCRIPTION: This script runs a preflight check, or a command you specify, against all Helix instances defined in the Helix Topology configuration file. If no arguments are supplied, verifies that all instances can be centrally managed with 'p4' commands from the current host. It does this by verifying that a Perforce command can execute with super user access and has a long-term ticket for each instance. The $P4TICKETS and $P4TRUST files are effectively verified with the preflight check. OPTIONS: -i <instance1>[,<instance2>,...] Specify a comma-delimited list of instances to operate on. By default, all instances defined in the Helix Topology configuration file are operated on. -sk <instance1>[,<instance2>,...] Specify a comma-delimited list of instances to ignore for processing purposes. By default, the instance named 'sample' is skipped, the equivalent of specifying '-sk sample'. Specify '-i none' to to process all instances including the 'sample' instance (if defined). -v<n> Set verbosity 1-5 (-v1 = quiet, -v5 = highest). -L <log> Specify the path to a log file, or the special value 'off' to disable logging. By default, output (stdout and stderr) are not captured. When -L is used, this script is self-logging. That is, output displayed on the screen is simultaneously captured in the log file. When -L is used, do not run this script with redirection operators like '> log' or '2>&1', and do not use 'tee.' -si Operate silently. All output (stdout and stderr) is redirected to the log only; no output appears on the terminal. This cannot be used with '-L off'. This is useful when running from cron, as it prevents automatic email from being sent by cron directly, as it does when a script called from cron generates any output. -n No-Op. Prints commands instead of running them. -D Set extreme debugging verbosity. HELP OPTIONS: -h Display short help message -man Display man-style help message -V Dispay version info for this script and its libraries. FILES: Helix Topology Config file: $HTCfgFile Cental tickets file: $P4TICKETS Cental trust file: $P4TRUST EXAMPLES: Example 1: Preflight Chcek With no arguments, do a quick preflight check to ensure that all configured instances can be managed, and that shell envionment files for all instances exist: $THISSCRIPT Example 2: Shell Envionment Check Check the envionment for instance 1: $THISSCRIPT -i 1 p4 set WARNING: This script overrides environment settings for P4PORT, P4TICKETS, P4TRUST, and P4ENVIRO, so settings for these values may not match what is defined by setting the SDP environment in the usual way, i.e.: source $SDPEnvFile N # where N is the instance Example 3: Server Version Check for all instances $THISSCRIPT p4 -ztag -F %serverVersion% info -s Example 4: Server Version Check for all instances, with higher verbosity ('-v4') to display each instance as the command is run: $THISSCRIPT p4 -v4 -ztag -F %serverVersion% info -s " fi exit 1 } #============================================================================== # Command Line Processing declare -i shiftArgs=0 set +u while [[ $# -gt 0 ]]; do case $1 in (-i) InstanceList="${2//,/ }"; shiftArgs=1;; (-sk) SkipInstanceList="${2/,/ }"; shiftArgs=1;; (-h) usage -h;; (-man) usage -man;; (-V) show_versions; exit 1;; (-v1) export VERBOSITY=1;; (-v2) export VERBOSITY=2;; (-v3) export VERBOSITY=3;; (-v4) export VERBOSITY=4;; (-v5) export VERBOSITY=5;; (-L) export P4U_LOG=$2; shiftArgs=1;; (-si) SilentMode=1;; (-n) export NO_OP=1;; (-D) set -x;; # Debug; use 'set -x' mode. (-*) usage -h "Unknown arg ($1).";; (*) Program="$1" shift # shellcheck disable=SC2124 ProgramArgs=$@ break ;; esac # Shift (modify $#) the appropriate number of times. shift; while [[ $shiftArgs -gt 0 ]]; do [[ $# -eq 0 ]] && usage -h "Incorrect number of arguments." shiftArgs=$shiftArgs-1 shift done done set -u #============================================================================== # Command Line Verification [[ $SilentMode -eq 1 && $P4U_LOG == off ]] && \ usage -h "Cannot use '-si' with '-L off'." [[ "$Program" == Unset ]] || DoPreflight=0 # Determine the list of instances to process, accounting for any instances # skipped. [[ -n "$InstanceList" ]] ||\ InstanceList=$(grep '^INSTANCE' "$HTCfgFile" | cut -d '|' -f 2) if [[ $SkipInstanceList != "none" ]]; then NewInstanceList= for i in $InstanceList; do Skipped=0 for s in $SkipInstanceList; do if [[ "$s" == "$i" ]]; then Skipped=1 break fi done # If the instance isn't in the skip list, add it to the list of instances. [[ $Skipped -eq 1 ]] || NewInstanceList+=" $i" done # shellcheck disable=SC2116 InstanceList="$(echo "$NewInstanceList")" vmsg "Instance List: $InstanceList (excluding $SkipInstanceList)" fi #============================================================================== # Main Program trap terminate EXIT SIGINT SIGTERM declare -i OverallReturnStatus=0 declare -i ExitCode=0 if [[ "${P4U_LOG}" != off ]]; then touch "${P4U_LOG}" || bail "Couldn't touch log file [${P4U_LOG}]." # Redirect stdout and stderr to a log file. if [[ $SilentMode -eq 0 ]]; then exec > >(tee "${P4U_LOG}") exec 2>&1 else exec >"${P4U_LOG}" exec 2>&1 fi initlog fi if [[ "$DoPreflight" -eq 1 ]]; then # shellcheck disable=SC2116 msg "${H1}\\nPreflight Check for instances:\\n$(echo "$InstanceList")\\n" msg "Accesss Preflight Check\\n${H2}" printf "%-12s %-24s %-5s %-s\\n" "Instance" "P4PORT" "Super" "Ticket Status" printf "%-12s %-24s %-5s %-s\\n" "------------" "------------------------" "-----" "-----------------------------------------" for i in $InstanceList; do active=$(grep "COMPONENT|$i|p4d-mc|" "$HTCfgFile"|cut -d '|' -f 7) [[ $active == 0 ]] && continue host=$(grep "COMPONENT|$i|p4d-mc|" "$HTCfgFile"|cut -d '|' -f 5) port=$(grep "COMPONENT|$i|p4d-mc|" "$HTCfgFile"|cut -d '|' -f 8) if [[ $port == "ssl:"* ]]; then export P4PORT="ssl:$host:${port#ssl:}" else export P4PORT="$host:$port" fi TicketExpiration=$(p4 -ztag -F %TicketExpiration% -p "$P4PORT" -u "$P4USER" login -s 2>/dev/null) if [[ -n "$TicketExpiration" && "$TicketExpiration" -gt "$((60*60*24*31))" ]]; then TicketStatus="OK with long-term ticket." elif [[ -n "$TicketExpiration" && "$TicketExpiration" -gt "60" ]]; then TicketStatus="OK with short-term ticket ($TicketExpiration seconds)." else TicketStatus="ERROR, ticket not available for $P4USER on $P4PORT." PreflightAccessOK=0 fi if [[ "$TicketStatus" == "OK"* ]]; then ProtectCheck=$(p4 -ztag -F %Protections0% -u "$P4USER" -p "$P4PORT" protect -o 2>/dev/null) if [[ -n "$ProtectCheck" ]]; then SuperAccessStatus="OK" else SuperAccessStatus="Error" PreflightAccessOK=0 fi else SuperAccessStatus="Unknown" PreflightAccessOK=0 fi printf "%-12s %-24s %-5s %-s\\n" "$i" "$P4PORT" "$SuperAccessStatus" "$TicketStatus" done if [[ "$PreflightAccessOK" -eq 1 ]]; then msg "\\nVerified: Access OK. All instances can be accessed as super from this host." else errmsg "Preflight Access check failed. See results above." OverallReturnStatus=1 fi msg "Environment Preflight Check\\n${H2}" for i in $InstanceList; do active=$(grep "COMPONENT|$i|p4d-mc|" "$HTCfgFile"|cut -d '|' -f 7) [[ $active == 0 ]] && continue InstanceEnvFile=/p4/common/config/p4_${i}.vars if [[ ! -r "$InstanceEnvFile" ]]; then errmsg "Missing instance-specific environment file: $InstanceEnvFile" PreflightEnvOK=0 fi done if [[ "$PreflightEnvOK" -eq 1 ]]; then msg "\\nVerified: Environment is OK, all instances have environment files." else errmsg "Preflight Environment check failed. See missing files listed above." OverallReturnStatus=1 fi fi if [[ "$Program" != Unset ]]; then if [[ $Program == /* || $Program == \.* ]]; then # Non-path depedent, absolute or relative path specified. ProgramPath=$Program else # Path-dependent path specified. ProgramPath="$(command -v "$Program")" fi [[ -z "$ProgramPath" ]] && \ bail "The specified program [$Program] cannot be found. Aborting.\\n" [[ ! -r "$ProgramPath" ]] && \ bail "The specified program [$Program] cannot be found. Aborting.\\n" [[ ! -x "$ProgramPath" ]] && \ bail "The specified program [$Program] is not executable. Aborting.\\n" for i in $InstanceList; do active=$(grep "COMPONENT|$i|p4d-mc|" "$HTCfgFile"|cut -d '|' -f 7) [[ $active == 0 ]] && continue vmsg "For instance $i calling $Program $ProgramArgs" InstanceEnvFile=/p4/common/config/p4_${i}.vars if [[ -r "$InstanceEnvFile" ]]; then if [[ $NO_OP -eq 0 ]]; then # shellcheck disable=SC1090 source "$SDPEnvFile" "$i" export P4ENVIRO=/dev/null/.p4enviro export P4CONFIG=FileThatDoesNotExist export P4TICKETS=/p4/hms/.p4tickets export P4TRUST=/p4/hms/.p4trust host=$(grep "COMPONENT|$i|p4d-mc|" "$HTCfgFile"|cut -d '|' -f 5) port=$(grep "COMPONENT|$i|p4d-mc|" "$HTCfgFile"|cut -d '|' -f 8) if [[ $port == "ssl:"* ]]; then export P4PORT="ssl:$host:${port#ssl:}" else export P4PORT="$host:$port" fi $Program $ProgramArgs ExitCode=$? if [[ $ExitCode -ne 0 ]]; then warnmsg "Non-zero exit code returned: $ExitCode" OverallReturnStatus=1 fi else msg "NO_OP: For instance $i, would run: $Program $ProgramArgs" fi else errmsg "Missing instance-specific environment file: $InstanceEnvFile" OverallReturnStatus=1 fi done fi if [[ $OverallReturnStatus -eq 0 ]]; then msg "${H}\\nAll processing completed successfully.\\n" else msg "${H}\\nProcessing completed, but with errors. Scan above output carefully.\\n" fi msg "That took $((SECONDS/3600)) hours $((SECONDS%3600/60)) minutes $((SECONDS%60)) seconds.\\n" # See the terminate() function, which is really where this script exits. exit $OverallReturnStatus
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#2 | 30242 | C. Thomas Tyler | Updated package reference in LICENSE to refer to HMS rather than SDP license. | ||
#1 | 29182 | C. Thomas Tyler |
Moved HMS files from /p4/common/bin -> /p4/common/site/bin. Moved HMS files from /p4/common/lib -> /p4/common/site/lib. Removed dependency on SDP libs so that HMS can be deployed with a wider variety of SDP versions. |
||
//guest/perforce_software/hms/dev/p4/common/bin/irun | |||||
#4 | 27694 | C. Thomas Tyler | Copyright Update; non-functional change. | ||
#3 | 25748 | C. Thomas Tyler | Made irun shellcheck compliant. | ||
#2 | 25683 | C. Thomas Tyler |
Tweaked to honor 'Active' setting for components in the Helix Topology File -- if inactive, ignore it. |
||
#1 | 25682 | C. Thomas Tyler | Added 'irun' (instance run) to simplfy SDP Fleet Management. |