#!/bin/bash #------------------------------------------------------------------------------ ### WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ### THIS SCRIPT SHOULD BE USED WITH GREAT CAUTION. #------------------------------------------------------------------------------ set -u # This script loads a specified checkpoint simultaneously into /p4/N/root # and /p4/N/offline_db. #============================================================================== # Declarations and Environment # Allow override of P4U_HOME, which is set only when testing P4U scripts. export P4U_HOME="${P4U_HOME:-/p4/common/bin}" export P4U_LIB="${P4U_LIB:-/p4/common/lib}" export P4U_ENV="$P4U_LIB/p4u_env.sh" export P4U_LOG=Unset export VERBOSITY=${VERBOSITY:-5} # 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=2.1.1 declare -i SilentMode=0 declare Checkpoint=Unset declare SDPInstance= declare SDPInstanceVarsFile= declare OfflineDB= declare OfflineDBUsableFile= declare CaseMode= declare CaseFlag= declare CompressFlag= declare ExcludedTables= declare P4DInitScript= declare P4DSystemdServiceFile= declare P4BrokerInitScript= declare P4BrokerSystemdServiceFile= declare P4BrokerCfg= declare P4DPids= declare ThisHost=${HOSTNAME%%.*} #============================================================================== # Local Functions function user_confirmation_and_warning () { local interactive=${1:-1} local input="" msg "\\n ============================================================================== WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING\\n This script will remove files in P4ROOT and the offline_db folder, including db.* files, state* files, and others. It is STRONGLY recommended that these files be preseved first unless it is absolutely certain they will never potentially be useful in any recovery scenario. This is being run on host $HOSTNAME at $(date). WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ============================================================================== \\n\\n" if [[ $interactive -eq 0 ]]; then msg "Bypassing interactive confirmation due to -y on command line." return 0 fi while [[ -z "$input" ]]; do echo -e -n "\\nEnter Y to proceed, N to stop [y/Y/n/N]: " read -r -e input if [[ "${input^^}" == "Y" ]]; then continue elif [[ "${input^^}" == "N" ]]; then msg "Confirmation to proceed not received." return 1 else input= fi done return 0 } #------------------------------------------------------------------------------ # 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 <checkpoint> [-i <instance>] [-r] [-b] [-y] [-L <log>] [-si] [-v<n>] [-D] or $THISSCRIPT [-h|-man|-V] " if [[ $style == -man ]]; then echo -e " DESCRIPTION: This script loads a specified checkpoint into /p4/N/root and /p4/N/offline_db. ARGUMENTS AND OPTIONS: <checkpoint> Specify the path to the checkpoint file to load. The file may be a compressed or uncompressed checkpoint. This positional paremter is required. -i <instance> Specify the SDP instance. This can be omitted if SDP_INSTANCE is already defined. -r Specify '-r' to replay only to P4ROOT. By default, this script replays both to P4ROOT and the offline_db. -b Specify '-b' to start the a p4broker process (if configured). By default the p4d process is started after loading the checkpoint, but the p4broker process is not. This can be useful to ensure the human administrator has an opportunity to do sanity checks before enabling the broker to allow access by end users (if the broker is deployed for this usage). -y Use the '-y' flag to bypass an interactive warning and confirmation prompt. -v<n> Set verbosity 1-5 (-v1 = quiet, -v5 = highest). The default is 5. -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: ${LOGS:-/tmp}/${THISSCRIPT%.sh}.<timestamp>.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.' -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'. -D Set extreme debugging verbosity. HELP OPTIONS: -h Display short help message -man Display man-style help message -V Dispay version info for this script and its libraries. FILES: EXAMPLES: Sample Usage (bash syntax): nohup $P4CBIN/load_checkpoint.sh /p4/1/checkpoints/p4_1.ckp.4025.gz -i 1 -y -si < /dev/null > /dev/null 2>&1 & Then, monitor with: tail -f \$(ls -t \$LOGS/load_checkpoint.*.log|head -1)\\n " fi exit 1 } #============================================================================== # Command Line Processing declare -i LoadOfflineDB=1 declare -i StartBrokerWhenDone=0 declare -i Interactive=1 declare -i shiftArgs=0 set +u while [[ $# -gt 0 ]]; do case $1 in (-r) LoadOfflineDB=0;; (-b) StartBrokerWhenDone=1;; (-y) Interactive=0;; (-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 u4U_LOG="$2"; shiftArgs=1;; (-si) SilentMode=1;; (-D) set -x;; # Debug; use 'set -x' mode. (-*) usage -h "Unknown flag ($1).";; (*) if [[ "$Checkpoint" == Unset ]]; then Checkpoint="$1" else usage -h "Only one checkpoint file can be specified." fi ;; 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'." [[ "${P4U_LOG:-Unset}" == Unset ]] && \ P4U_LOG="${LOGS:-/tmp}/${THISSCRIPT%.sh}.$(date +'%Y%m%d-%H%M%S').log" if [[ -z "$SDPInstance" ]]; then if [[ "${SDP_INSTANCE:-Unset}" != Unset ]]; then SDPInstance="$SDP_INSTANCE" else usage -h "SDP Instance parameter is missing and SDP_INSTANCE is undefined." fi fi #============================================================================== # Main Program trap terminate EXIT SIGINT SIGTERM declare -i OverallReturnStatus=0 if [[ "${P4U_LOG}" != off ]]; then touch "${P4U_LOG}" || bail "Couldn't touch log file [${P4U_LOG}]." # Redirect stdout and stderr to a log file. if [[ "$SilentMode" -eq 0 ]]; then exec > >(tee "${P4U_LOG}") exec 2>&1 else exec >"${P4U_LOG}" exec 2>&1 fi initlog fi msg "Started ${0##*/} v$Version on $ThisHost at $(date)" # shellcheck disable=SC2153 P4DInitScript="$P4HOME/bin/p4d_${SDPInstance}_init" P4DSystemdServiceFile="/etc/systemd/system/p4d_${SDPInstance}.service" P4BrokerInitScript="$P4HOME/bin/p4broker_${SDPInstance}_init" P4BrokerSystemdServiceFile="/etc/systemd/system/p4broker_${SDPInstance}.service" SDPInstanceVarsFile="/p4/common/config/p4_${SDPInstance}.vars" [[ "$Checkpoint" == Unset ]] && usageError "Missing checkpoint parameter." [[ -r "$SDPInstanceVarsFile" ]] ||\ bail "Missing SDP instance vars file. Typo in instance name? Expected: $SDPInstanceVarsFile" [[ -r "$Checkpoint" ]] ||\ bail "Specified checkpoint file does not exist: $Checkpoint" # shellcheck disable=SC1091 source /p4/common/bin/p4_vars "$SDPInstance" # shellcheck disable=SC1091 source /p4/common/bin/ps_functions.sh ||\ bail "Failed to load ps_functions.sh." #shellcheck disable=SC1091 source /p4/common/bin/edge_vars ||\ bail "Failed to load edge_vars." declare CheckpointMD5= [[ -n "$ExcludedTables" ]] ||\ bail "Value for \$ExcludedTables not defined in $P4CBIN/edge_vars." user_confirmation_and_warning "$Interactive" ||\ bail "User confirmation not verified. Aborting." cd "$P4ROOT" || bail "Could not cd to P4ROOT [$P4ROOT]." [[ "$PWD" == "/p4/${SDPInstance}/root" ]] || bail "Unexpected P4ROOT value of: $P4ROOT" CheckpointMD5="${Checkpoint}.md5" if [[ -r "$CheckpointMD5" ]]; then msg "Verified: MD5 file for checkpoint exists: $CheckpointMD5" else CheckpointMD5="${Checkpoint/.gz/.md5}" if [[ -r "$CheckpointMD5" ]]; then msg "Verified: MD5 file for checkpoint exists: $CheckpointMD5" else bail "Could not find MD5 file for checkpoint. Tried ${Checkpoint}.md5 and ${Checkpoint/.gz/.md5}" fi fi if [[ "$P4PORT" == "ssl:"* && ! -r "$P4SSLDIR/certificate.txt" ]]; then bail "P4PORT has SSL is enabled, but there is no certificate file [$P4SSLDIR/certificate.txt].\\nPerhaps try:\\n\\t$P4DBIN -Gc\\n\\n" fi [[ -x "$P4DInitScript" ]] || bail "Aborting: P4D Init script is missing or not executable: $P4DInitScript" if [[ -r "/p4/common/config/p4_${SDPInstance}.broker.${ThisHost}.cfg" ]]; then P4BrokerCfg="/p4/common/config/p4_${SDPInstance}.broker.${ThisHost}.cfg" else P4BrokerCfg="/p4/common/config/p4_${SDPInstance}.broker.cfg" fi if [[ -x "$P4BrokerInitScript" && -r "$P4BrokerCfg" ]]; then msg "Checking p4broker status." if $P4BrokerInitScript status; then msg "Shutting down p4broker." if [[ -r "$P4BrokerSystemdServiceFile" ]]; then sudo systemctl stop "${P4BROKERBIN##*/}" ||\ bail "Failed to execute: sudo systemctl stop ${P4BROKERBIN##*/}" else $P4BrokerInitScript stop fi else msg "Verified: p4broker is down." fi fi msg "Checking p4d status." P4DPids=$(get_pids "$P4DBIN") if [[ -n "$P4DPids" ]]; then msg "Shutting down p4d." if [[ -r "$P4DSystemdServiceFile" ]]; then sudo systemctl stop "${P4DBIN##*/}" ||\ bail "Failed to execute: sudo systemctl stop ${P4DBIN##*/}" else $P4DInitScript stop fi else msg "Verified: No processes are running for: $P4DBIN" fi # Remove db.* and state* files, but not server.id or license files. Cmd="/bin/rm -f db.* state*" msg "Cleaning up databases with this command in $PWD:\\n$Cmd" $Cmd || bail "Failed to clean up old databases and state files in $P4ROOT" # Move P4LOG and P4JOURAL aside if they exist. if [[ -r "$P4LOG" ]]; then Cmd="mv $P4LOG $P4LOG.moved.$(date +'%Y%m%d-%H%M')" msg "Moving P4LOG aside with this command:\\n$Cmd" $Cmd || bail "Failed to move P4LOG aside." fi if [[ -r "$P4JOURNAL" ]]; then Cmd="mv $P4JOURNAL $P4JOURNAL.moved.$(date +'%Y%m%d-%H%M')" msg "Moving P4JOURNAL aside with this command:\\n$Cmd" $Cmd || bail "Failed to move P4JOURNAL aside." fi # For checkpoint replay operations, determine whether case sensitivity # flag is needed, and whether '-z' is needed. if [[ "$Checkpoint" == *".gz" ]]; then CaseMode=$(zcat "$Checkpoint" | head -1 | grep -E '^@nx@ (0|2) ' | cut -d ' ' -f5) if [[ "$CaseMode" == "2" ]]; then CaseFlag='-C1' msg "Case-insensitive checkpoint detected." else msg "Case-sensitive checkpoint detected." fi # In P4D 2018.1, the '-z' flag should be dropped, as the need for # compression/decompression is determined by P4D when replying, # and thus '-z' should not be used (though it is supported by P4D # for backward compatibility, and we use it here if using an older # server. # shellcheck disable=SC2072 [[ "$P4D_VERSION" < "2018.1" ]] && CompressFlag='-z' else CaseMode=$(head -1 "$Checkpoint"| grep -E '^@nx@ (0|2) ' | cut -d ' ' -f5) if [[ "$CaseMode" == "2" ]]; then CaseFlag='-C1' msg "Case-insensitive checkpoint detected." else msg "Case-sensitive checkpoint detected." fi fi if [[ "${SERVERID^^}" == "P4D_EDGE_"* ]]; then Cmd="$P4DBIN -r $P4ROOT -K $ExcludedTables $CompressFlag $CaseFlag -jr $Checkpoint" else Cmd="$P4DBIN -r $P4ROOT $CompressFlag $CaseFlag -jr $Checkpoint" fi msg "Replaying checkpoint to P4ROOT with this command:\\n$Cmd" $Cmd || bail "Checkpoint replay to P4ROOT failed." Cmd="$P4DBIN -r $P4ROOT -xu" msg "Ensuring databases are upgraded with this command:\\n$Cmd" $Cmd || bail "Database upgrade in P4ROOT failed." if [[ "$LoadOfflineDB" -eq 1 ]]; then OfflineDB=${P4ROOT/root/offline_db} OfflineDBUsableFile="$OfflineDB/offline_db_usable.txt" cd "$OfflineDB" || bail "Could not cd to offline_db dir [$OfflineDB]." [[ "$PWD" == "/p4/${SDPInstance}/offline_db" ]] || bail "Unexpected OfflineDB value of: $OfflineDB" # Remove db.* and state* files, but not server.id or license files. Cmd="/bin/rm -f db.* state* $OfflineDBUsableFile" msg "Cleaning up databases and offline_db_usable.txt file with this command in $PWD:\\n$Cmd" $Cmd || bail "Failed to clean up old databases and state files in $OfflineDB" if [[ "${SERVERID^^}" == "P4D_EDGE_"* ]]; then Cmd="$P4DBIN -r $OfflineDB -K $ExcludedTables $CompressFlag $CaseFlag -jr $Checkpoint" else Cmd="$P4DBIN -r $OfflineDB $CompressFlag $CaseFlag -jr $Checkpoint" fi msg "Replaying checkpoint to offline_db with this command:\\n$Cmd" $Cmd || bail "Checkpoint replay to offline_db failed." Cmd="$P4DBIN -r $OfflineDB -xu" msg "Ensuring databases in offline_db are upgraded with this command:\\n$Cmd" $Cmd || bail "Database upgrade in offline_db failed." echo "Database restored successfully." > "$OfflineDBUsableFile" ||\ bail "Failed to write this filfe: $OfflineDBUsableFile" fi msg "Starting p4d." if [[ -r "$P4DSystemdServiceFile" ]]; then sudo systemctl start "${P4DBIN##*/}" ||\ bail "Failed to execute: sudo systemctl start ${P4DBIN##*/}" else $P4DInitScript start fi sleep 1 msg "Logging in." "$P4CBIN/p4login" -v # Now that we have loaded a checkpoint, re-load the shell environment to # ensure that P4REPLICA is set correctly, as some db.config settings are # determined dynamically. # shellcheck disable=SC1091 source /p4/common/bin/p4_vars "$SDPInstance" if [[ "$P4REPLICA" == TRUE ]]; then msg "Logging in service user." p4login -v -service sleep 3 Cmd="$P4BIN -s pull -lj" msg "Checking replication status with this command:\\n$Cmd" $Cmd || bail "Replica is not replicating properly." fi msg "\\nAll processing completed successfully.\\n" if [[ -x "$P4BrokerInitScript" && -r "$P4BrokerCfg" ]]; then if [[ "$StartBrokerWhenDone" -eq 1 ]]; then if [[ -r "$P4BrokerSystemdServiceFile" ]]; then sudo systemctl start "${P4BROKERBIN##*/}" ||\ bail "Failed to execute: sudo systemctl start ${P4BROKERBIN##*/}" else $P4BrokerInitScript start fi else if [[ -r "$P4BrokerSystemdServiceFile" ]]; then msg "NOT starting broker. Start it manually when ready with:\\n\\tsudo systemctl start ${P4BROKERBIN##*/}\\n" else msg "NOT starting broker. Start it manually when ready with:\\n\\t$P4BrokerInitScript start\\n" fi fi fi msg "Checkpoint load processing took $((SECONDS/3600)) hours $((SECONDS%3600/60)) minutes $((SECONDS%60)) seconds.\\n"
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#17 | 30388 | C. Thomas Tyler |
Released SDP 2024.1.30385 (2024/06/11). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#16 | 30297 | C. Thomas Tyler |
Released SDP 2023.2.30295 (2024/05/08). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#15 | 29954 | C. Thomas Tyler |
Released SDP 2023.1.29949 (2023/12/01). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#14 | 29891 | C. Thomas Tyler |
Released SDP 2023.1.29699 (2023/07/11). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#13 | 29401 | C. Thomas Tyler |
Released SDP 2022.2.29399 (2023/02/06). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#12 | 29205 | C. Thomas Tyler |
Released SDP 2022.1.29203 (2022/11/22). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#11 | 28858 | C. Thomas Tyler |
Released SDP 2022.1.28855 (2022/05/27). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#10 | 28651 | C. Thomas Tyler |
Released SDP 2021.2.28649 (2022/03/03). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#9 | 28240 | C. Thomas Tyler |
Released SDP 2021.1.28238 (2021/11/12). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#8 | 27761 | C. Thomas Tyler |
Released SDP 2020.1.27759 (2021/05/07). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#7 | 27331 | C. Thomas Tyler |
Released SDP 2020.1.27325 (2021/01/29). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#6 | 26470 | C. Thomas Tyler |
Released SDP 2019.3.26468 (2020/04/10). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#5 | 26403 | C. Thomas Tyler |
Released SDP 2019.3.26400 (2020/03/28). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#4 | 25951 | C. Thomas Tyler |
Released SDP 2019.2.25949 (2019/08/12). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#3 | 25940 | C. Thomas Tyler |
Released SDP 2019.2.25938 (2019/08/05). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#2 | 25933 | C. Thomas Tyler |
Released SDP 2019.2.25923 (2019/08/05). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#1 | 25245 | C. Thomas Tyler |
Released SDP 2019.1.25238 (2019/03/02). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
//guest/perforce_software/sdp/dev/Server/Unix/p4/common/bin/load_checkpoint.sh | |||||
#6 | 24602 | C. Thomas Tyler | Fixed a few obvious typos. | ||
#5 | 24599 | C. Thomas Tyler | Fixed obvious typo. | ||
#4 | 24482 | C. Thomas Tyler |
Fixed obvious typo. Removed redundant time as it clutters the output and introduces an unnecessary dependency. Change to new/unreleased script, bypassing review. |
||
#3 | 24374 | C. Thomas Tyler | Added actual file content. | ||
#2 | 24368 | C. Thomas Tyler |
load_checkpoint.sh v1.0.6: * Added safety warning and interactive confirmation. * Supports systemd init mechanism rather than SysV init scripts if systemd *.service files are configured. Uses 'sudo systemctl start/stop' calls for p4d and p4broker. Use SysV init scripts on other systems. * Fixed bug with cleanup steps not executing. TO DO: Normalize into template.sh style with auto-logging and standard command line flags. |
||
#1 | 24198 | C. Thomas Tyler |
Added utility script to load a specified checkpoint into both /p4/N/root and /p4/N/offline_db, including logic to managing p4d/p4broker processes, ensure no db.* files exist prior to replaying the checkoint, managing the offline_db_usable.txt file, etc. |