#!/bin/bash #============================================================================== # Copyright and license info is available in the LICENSE file included with # the Server Deployment Package (SDP), and also available online: # https://swarm.workshop.perforce.com/projects/perforce-software-sdp/view/main/LICENSE #------------------------------------------------------------------------------ #============================================================================== # Declarations and Environment # Allow override of P4U_HOME, which is set only when testing P4U scripts. export P4U_HOME="${P4U_HOME:-/p4/common/bin}" export P4U_LIB="${P4U_LIB:-/p4/common/lib}" export P4U_ENV="$P4U_LIB/p4u_env.sh" export 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.1.3 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 # error, usually $1 should be -h so that the longer usage message doesn't # obscure 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 <instance>] [-L <log>] [-v<n>] [-p|-n] [-D] or $THISSCRIPT [-h|-man|-V] " if [[ $style == -man ]]; then echo -e " DESCRIPTION: This script obsoletes the SetDefaultDepotSpecMapField.py trigger. It does so by following a series of steps. First, it ensures that the configurable server.depot.root is set correctly, setting it if it is not already set. Next, the Triggers table is checked to ensure the call to the SetDefaultDepotSpecMapField.py is not called; it is deleted from the Triggers table if found. Last, it resets the 'Map:' field of depot specs for depot types where that is appropriate, setting it to the default value of '<DepotName>/...', so that it honors the server.depot.root configurable. This is done for depots of these types: * stream * local * spec * unload but not these: * unload * remote * graph If an unknown depot type is encountered, the 'Map:' field is reset as well if it is set. This script does a preflight check first, reporting any cases where the starting conditions are not as expected. These conditions are treated as Errors, and will abort processing: * Depot Map field set to something other than the default. * Configurable server.depot.root is set, but to something other than what it should be. The following are treated as Warnings, and will be reported but will not prevent processing. * Configurable server.depot.root is already set. * SetDefaultDepotSpecMapField.py not found in triggers. * Depot already has 'Map:' field set to the default value: <DepotName>/... OPTIONS: -v<n> Set verbosity 1-5 (-v1 = quiet, -v5 = highest). -L <log> Specify the path to a log file, or the special value 'off' to disable logging. By default, all output (stdout and stderr) goes to EDITME_DEFAULT_LOG NOTE: This script is self-logging. That is, output displayed on the screen is simultaneously captured in the log file. Do not run this script with redirection operators like '> log' or '2>&1', and do not use 'tee.' -p Run preflight checks only, and then stop. By default, actual changes occur if preflight checks find no issues. -n No-Op. No actions are taken that would affect data significantly; instead commands are displayed rather than executed. -D Set extreme debugging verbosity. HELP OPTIONS: -h Display short help message -man Display man-style help message -V Display version info for this script and its libraries. EXAMPLES: A typical flow for this script is to do a preflight first, and then a live run, for any given instance: $THISSCRIPT -i 1 -p $THISSCRIPT -i 1 Note that if using '-n', the '-v5' flag should also be used. " fi exit 1 } #============================================================================== # Command Line Processing declare SDPInstance=Unset declare SDPEnvFile="/p4/common/bin/p4_vars" declare SDPInstanceCfgFile= declare -i PreflightOnly=0 declare -i RemoveOldTrigger=1 declare -i SetSDRConfigurable=1 declare -i shiftArgs=0 set +u while [[ $# -gt 0 ]]; do case $1 in (-i) SDPInstance="$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;; (-p) PreflightOnly=1;; (-n) export NO_OP=1;; (-D) set -x;; # Debug; use 'set -x' mode. (*) usage -h "Unknown arg ($1).";; esac # Shift (modify $#) the appropriate number of times. shift; while [[ $shiftArgs -gt 0 ]]; do [[ $# -eq 0 ]] && usage -h "Incorrect number of arguments." shiftArgs=$shiftArgs-1 shift done done set -u #============================================================================== # Command Line Verification # If not set on the command line with -i, default SDPInstance to the # $SDP_INSTANCE environment variable, if defined. [[ "$SDPInstance" == "Unset" ]] && SDPInstance="${SDP_INSTANCE:-Unset}" [[ "$SDPInstance" == "Unset" ]] && \ bail "The '-i <SDP_Instance>' argument is required unless \$SDP_INSTANCE is defined in the environment." SDPInstanceCfgFile="/p4/common/config/p4_${SDPInstance}.vars" [[ -r "$SDPInstanceCfgFile" ]] || \ bail "Missing SDP instance config file: $SDPInstanceCfgFile" # Load the standard SDP shell environment for the given instance. # shellcheck disable=SC1090 source "$SDPEnvFile" "$SDPInstance" [[ "${P4U_LOG:-Unset}" == Unset ]] && \ P4U_LOG="${LOGS:-/tmp}/${THISSCRIPT%.sh}.$(date +'%Y%m%d-%H%M%S').log" #============================================================================== # Main Program trap terminate EXIT SIGINT SIGTERM declare -i OverallReturnStatus=0 declare DepotType= declare Depot= declare ActualMapFieldValue= declare ExpectedMapFieldValue= declare SDRExpectedValue="/p4/$SDPInstance/depots" declare SDRActualValue= declare TmpFile1="$P4TMP/tmp1.$$.$RANDOM" declare TmpFile2="$P4TMP/tmp2.$$.$RANDOM" declare TmpPrefix="$P4TMP/${THISSCRIPT/.sh/.tmp}" declare -i ErrorCount=0 declare -i WarningCount=0 if [[ "${P4U_LOG}" != off ]]; then touch "${P4U_LOG}" || bail "Couldn't touch log file [${P4U_LOG}]." # Redirect stdout and stderr to a log file. exec > >(tee "${P4U_LOG}") exec 2>&1 initlog fi msg "Started $THISSCRIPT v$Version at $(date)." msg "${H2}\\nPreflight Check for super access." [[ "$("$P4BIN" protects -m)" == "super" ]] || \ bail "Super access for $P4USER could not be verified. Aborting." msg "Super user access for user $P4USER verified." msg "${H2}\\nPreflight Check for server.depot.root configurable." SDRActualValue=$("$P4BIN" -ztag -F "%Value%" configure show server.depot.root) if [[ -z "$SDRActualValue" ]]; then msg "The configurable server.depot.root is not (yet) set, as expected." elif [[ "$SDRActualValue" == "$SDRExpectedValue" ]]; then warnmsg "The configurable server.depot.root is already set to the intended value." WarningCount+=1 SetSDRConfigurable=0 else errmsg "The configurable server.depot.root is set to an unexpected value [$SDRActualValue], expected value is [$SDRExpectedValue]." WarningCount+=1 fi msg "${H2}\\nPreflight Checks for Depot Spec Map Fields:" # Note: graph depots aren't reported by 'p4 depots' with flags # given here, so we don't need any special processing to ignore them # (as server.depot.root does not apply to them). for data in $("$P4BIN" -ztag -F "%name%:%type%" depots); do vvmsg "d=[$data]" [[ "$data" == *":"* ]] || bail "Unexpected output. Bailing." Depot="${data%%:*}" DepotType="${data##*:}" vvmsg "D=[$Depot] T=[$DepotType]" case "$DepotType" in (archive|remote) vmsg "Skipping depot $Depot of type $DepotType." continue ;; (stream|local|spec|unload) vmsg "Processing depot $Depot of type $DepotType." ;; (*) warnmsg "Processing depot $Depot of UKNOWN type $DepotType." WarningCount+=1 ;; esac ExpectedMapFieldValue="/p4/$SDPInstance/depots/$Depot/..." DefaultMapFieldValue="$Depot/..." ActualMapFieldValue=$("$P4BIN" -ztag -F "%Map%" depot -o "$Depot") if [[ "$ActualMapFieldValue" == "$DefaultMapFieldValue" ]]; then warnmsg "Depot $Depot already has default map field value of $DefaultMapFieldValue." WarningCount+=1 else echo "$ActualMapFieldValue" > "$TmpFile1" echo "$ExpectedMapFieldValue" > "$TmpFile2" if ! diff -q "$TmpFile1" "$TmpFile2"; then echo "DBG AV=[$ActualMapFieldValue]" errmsg "Depot $Depot has unexpected map field value of: $ActualMapFieldValue" ErrorCount+=1 else msg "Depot $Depot has expected Map field value of: $ActualMapFieldValue" fi fi done msg "${H2}\\nPreflight Check for trigger script SetDefaultDepotSpecMapField.py." "$P4BIN" triggers -o > "$TmpFile1" if grep -i -q SetDefaultDepotSpecMapField.py "$TmpFile1"; then msg "Trigger SetDefaultDepotSpecMapField.py detected, as expected." else warnmsg "Missing trigger SetDefaultDepotSpecMapField.py (which was about to be deleted anyway)." WarningCount+=1 RemoveOldTrigger=0 fi msg "Preflight checks discovered $ErrorCount errors and $WarningCount warnings." [[ "$ErrorCount" -gt 0 ]] && \ bail "Preflight checks FAILED.\\nAborting due to errors found in preflight checks." msg "Preflight checks PASSED." if [[ "$PreflightOnly" -eq 1 ]]; then msg "Exiting after preflight checks due to '-p'." exit "$OverallReturnStatus" fi msg "${H2}\\nUpdating configurable server.depot.root." # Set the configurable server.depot.root. If this fails, we bail. This # is the first change to actual data in our processing, an so we can # bail here without foregoing idempotency. if [[ "$SetSDRConfigurable" -eq 1 ]]; then run "$P4BIN configure set server.depot.root=$SDRExpectedValue" \ "Setting configurable server.depot.root to: $SDRExpectedValue" ||\ bail "Failed to set server.depot.root configurable." else msg "Configurable server.depot.root is already set to the expected value." fi msg "${H2}\\nUpdating triggers table." if [[ "$RemoveOldTrigger" -eq 1 ]]; then "$P4BIN" triggers -o | grep -v '^#' | grep -i -v SetDefaultDepotSpecMapField.py > "$TmpFile1" ||\ bail "Failed to get triggers table." run "$P4BIN -s triggers -i < $TmpFile1" \ "Loading updated table with SetDefaultDepotSpecMapField.py removed." if [[ "$CMDEXITCODE" -ne 0 ]]; then errmsg "Failed to update triggers table." ErrorCount+=1 OverallReturnStatus=1 fi else msg "Triggers table update not required, SetDefaultDepotSpecMapField.py not found." fi msg "${H2}\\nUpdating depot spec Map fields." # Failures in this next block updating depot spec Map fields, will be # reported but will not cause an abort. Manual post-processing would be # required if there are failures here. for data in $("$P4BIN" -ztag -F "%name%:%type%" depots); do vvmsg "d=[$data]" [[ "$data" == *":"* ]] || bail "Unexpected output. Bailing." Depot="${data%%:*}" DepotType="${data##*:}" case "$DepotType" in (archive|remote) continue ;; (stream|local|spec|unload) true;; (*) warnmsg "Processing depot $Depot of UKNOWN type $DepotType." WarningCount+=1 ;; esac ExpectedMapFieldValue="/p4/$SDPInstance/depots/$Depot/..." DefaultMapFieldValue="$Depot/..." ActualMapFieldValue=$("$P4BIN" -ztag -F "%Map%" depot -o "$Depot") if [[ "$ActualMapFieldValue" == "$DefaultMapFieldValue" ]]; then msg "Skipping update of depot $Depot; it is already correct." else # Get the current depot spec, sans the 'Map:' field value. "$P4BIN" depot -o "$Depot" | grep -v '^#' | grep -v '^Map:' \ > "$TmpPrefix.$Depot.p4s" # Append the correct Map field value to the end of the spec file. echo "Map: $DefaultMapFieldValue" >> "$TmpPrefix.$Depot.p4s" # Load the updated spec. run "$P4BIN -s depot -i < $TmpPrefix.$Depot.p4s" \ "Updating depot spec for depot $Depot." if [[ "$CMDEXITCODE" -ne 0 ]]; then errmsg "Failed to load this updated depot spec:$(cat "$TmpPrefix.$Depot.p4s")" ErrorCount+=1 OverallReturnStatus=1 fi fi done # Be tidy for f in "$TmpFile1" "$TmpFile2" "$TmpPrefix"*; do GARBAGE+="$f"; done if [[ "$OverallReturnStatus" -eq 0 ]]; then msg "${H}\\nAll processing completed successfully.\\n" else msg "${H}\\nProcessing completed, but with errors. Scan above output carefully.\\n" fi # Illustrate using $SECONDS to display runtime of a script. msg "That took $((SECONDS/3600)) hours $((SECONDS%3600/60)) minutes $((SECONDS%60)) seconds.\\n" # See the terminate() function, which is really where this script exits. exit "$OverallReturnStatus"
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#4 | 27805 | C. Thomas Tyler |
Added support for graph depots to clear_depot_Map_fields.sh. Fixed doc issue re: unload depots. #review-27806 |
||
#3 | 27722 | C. Thomas Tyler |
Refinements to @27712: * Resolved one out-of-date file (verify_sdp.sh). * Added missing adoc file for which HTML file had a change (WorkflowEnforcementTriggers.adoc). * Updated revdate/revnumber in *.adoc files. * Additional content updates in Server/Unix/p4/common/etc/cron.d/ReadMe.md. * Bumped version numbers on scripts with Version= def'n. * Generated HTML, PDF, and doc/gen files: - Most HTML and all PDF are generated using Makefiles that call an AsciiDoc utility. - HTML for Perl scripts is generated with pod2html. - doc/gen/*.man.txt files are generated with .../tools/gen_script_man_pages.sh. #review-27712 |
||
#2 | 27534 | C. Thomas Tyler |
Doc refinements for clear_depot_Map_fields.sh. Non-funcitonal change. |
||
#1 | 26157 | C. Thomas Tyler |
Added script to deprecate the SetDefaultDepotSpecMapField.py, useful when upgrading from older SDP environments. This will be deployed in into a new /p4/common/upgrade_sdp directory, separate from /p4/common/bin, as is a one-time-per-data set script only done as part of the SDP upgrade process. Actually getting this deployed will require a tweak to mkdirs.sh, which will be coming later. |