#!/bin/bash #============================================================================== set -u #============================================================================== # Declarations and Environment declare -i ErrorCount=0 declare -i ImportUserErrorCount=0 declare -i ImportUserCount=0 declare -i ImportUserOKCount=0 declare -i ImportGroupErrorCount=0 declare -i ImportGroupCount=0 declare -i ImportGroupOKCount=0 declare -i SkipUserByTypeCount=0 declare -i SkipExistingUserCount=0 declare -i NoOp=0 declare -i Debug=0 declare -i i=0 declare ThisScript=${0##*/} declare CmdLine="$0 $*" declare Version=1.2.0 declare ThisUser= declare UserSpecFile= declare GroupSpecFile= declare TmpDir= declare ThisHost="${HOSTNAME%%.*}" declare SDPInstance= declare -A ExistingUsers declare TargetServerPort= declare TmpFile= declare User= declare Type= declare Group= declare FoundUsers= declare FoundGroups= declare P4CBin=/p4/common/bin declare H1="==============================================================================" declare H2="------------------------------------------------------------------------------" declare Log= declare OldLog= #============================================================================== # Local Functions function msg () { echo -e "$*"; } function dbg () { [[ "$Debug" -eq 0 ]] || msg "DEBUG: $*"; } function errmsg () { msg "\\nError: ${1:-Unknown Error}\\n"; ErrorCount+=1; } function bail () { errmsg "${1:-Unknown Error}"; exit "${2:-1}"; } #------------------------------------------------------------------------------ # Function: terminate function terminate { # Disable signal trapping. trap - EXIT SIGINT SIGTERM [[ "$Log" == "off" ]] || msg "Log is: $Log\\n${H1}" # With the trap removed, exit. exit "${ErrorCount}" } #------------------------------------------------------------------------------ # 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 msg "\\n\\nUsage Error:\\n\\n$errorMessage\\n\\n" fi msg "USAGE for $ThisScript v$Version: $ThisScript -t <TargetPort> [-i <SDPInstance>] [-L <log>] [-n] [-D] or $ThisScript [-h|-man|-V] " if [[ $style == -man ]]; then msg " DESCRIPTION: This script targets a designated server and pulls user and group spec data from that, and loads them into the local server. Existing users are skipped. Groups are always re-added to capture any group membership changes. This script might be useful after a perfmerge is done in which the servers to be merged were using a P4AUTH server, and after which the P4AUTH is to be deprected. This script can be used following the perfmerge to target the P4AUTH server running from the environment of the post-perfmerge server. OPTIONS: -t <TargetPort> Specify the target server port. If SSL is enabled, this server must be trusted, with a valid trust enrtry in the P4TRUST file defined for the local SDP environment. A valid login ticket must be available in the P4TICKETS file defined for the local SDP environment. This paraemter is required. -i <SDPInstance> Specify the local SDP instance to which user and group specs will be imported. This is required unless the SDP_INSTANCE environment variable is defined; it will be if the standard SDP shell environment is loaded. -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: /p4/N/logs/${ThisScript%.sh}.log (where N is the SDP instance name). If a log by that name exists from prior runs, it is rotated to: /p4/N/logs/${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.' -n No-Op. Prints commands instead of running them. -d Enable debugging messages. -D Set extreme debugging verbosity. Implies '-d'. HELP OPTIONS: -h Display short help message -man Display man-style help message EXAMPLES: Get a quick usage message: ${ThisScript} -h Get the full manual page: ${ThisScript} -man Normal Usage is with no arguments: ${ThisScript} " fi exit 1 } #============================================================================== # Command Line Processing declare -i shiftArgs=0 set +u while [[ $# -gt 0 ]]; do case $1 in (-h) usage -h;; (-man) usage -man;; (-t) TargetServerPort="$2"; shiftArgs=1;; (-i) SDPInstance="$2"; shiftArgs=1;; (-L) Log="$2"; shiftArgs=1;; (-n) NoOp=1;; (-d) Debug=1;; (-D) Debug=1; set -x;; # Extreme Debug; use bash '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 [[ -n "$TargetServerPort" ]] ||\ usage -h "Missing required '-t <TargetServerPort>' parameter." if [[ -z "$SDPInstance" ]]; then if [[ -n "${SDP_INSTANCE:-}" ]]; then SDPInstance="$SDP_INSTANCE" else bail "The '-i <SDPInstance>' option is required if the SDP shell environmnt s not loaded (and SDP_INSTANCE is not set)." fi fi [[ -z "$Log" ]] && Log="/p4/${SDPInstance}/logs/${ThisScript%.sh}.log" #============================================================================== # Main Program trap terminate EXIT SIGINT SIGTERM if [[ "$Log" != off ]]; then if [[ -e "$Log" ]]; then # shellcheck disable=SC2012 OldLogTimestamp="$(ls -l --time-style +'%Y%m%d-%H%M%S' "$Log" | awk '{print $6}')" OldLog="/p4/${SDPInstance}/logs/${ThisScript%.sh}.$OldLogTimestamp.log" mv -f "$Log" "$OldLog" || bail "Could not do: mv -f \"$Log\" \"$OldLog\"" msg "Rotated $Log to $OldLog" fi touch "$Log" || bail "Couldn't touch log file [$Log]." exec > >(tee "$Log") exec 2>&1 msg "${H1}\\nLog is: $Log\\n" fi ThisUser=$(id -n -u) msg "Started $ThisScript v$Version as $ThisUser@$ThisHost at $(date)\\nCommand Line: $CmdLine" msg "${H2}\\nStarting Preflight Checks." msg "Loading SDP Environment for instance $SDPInstance." # shellcheck disable=SC1091 source "$P4CBin/p4_vars" "$SDPInstance" ||\ errmsg "Failed to load SDP shell environment for instance $SDPInstance." msg "Checking access to target server, P4PORT=$TargetServerPort." if p4 -p "$TargetServerPort" login -s; then msg "Verified: Login to target server is valid." else errmsg "Login to target server could not be verified." fi if p4 login -s; then msg "Verified: Login to local server is valid." else errmsg "Login to local server could be verified." fi if [[ "$ErrorCount" -eq 0 ]]; then msg "Preflight checks OK." else bail "Aborted due to failed preflight checks." fi msg "${H1}\\nImport Users" TmpFile=$(mktemp) dbg "Getting list of local users for instance $SDPInstance with:\\np4 -ztag -F %User% users -a .LT. $TmpFile" if p4 -ztag -F %User% users -a > "$TmpFile"; then if [[ -s "$TmpFile" ]]; then i=0 while read -r User; do ExistingUsers[$User]=1 i+=1 done < "$TmpFile" else bail "Found no existing users on local instance $SDPInstance server." fi else bail "Could not get list of users for local instance $SDPInstance server." fi msg "Found ${#ExistingUsers[@]} existing users on server." dbg "Getting list of users from P4AUTH server with:\\np4 -p $TargetServerPort -ztag -F %Type%:%User% users .GT. $TmpFile" if p4 -p "$TargetServerPort" -ztag -F %Type%:%User% users > "$TmpFile"; then if [[ -s "$TmpFile" ]]; then FoundUsers=$(grep -c '^standard:' "$TmpFile") msg "Found $FoundUsers standard users on target server." else bail "Found no users on target server to import." fi else bail "Could not get list of users and types from target server." fi TmpDir=$(mktemp -d) if [[ ! -d "$TmpDir" ]]; then msg "Creating temp dir [$TmpDir]" mkdir -d "$TmpDir" || bail "Could not create temp dir." fi while read -r TypeAndUser; do Type=${TypeAndUser%%:*} User=${TypeAndUser#*:} if [[ "$Type" != "standard" ]]; then msg "Skipping user $User of non-standard type [$Type]." SkipUserByTypeCount+=1 continue fi if [[ "${ExistingUsers[$User]:-}" == "1" ]]; then msg "Skipping existing user $User." SkipExistingUserCount+=1 continue fi msg "Adding user $User." ImportUserCount+=1 UserSpecFile="$TmpDir/$User.user.p4s" p4 -p "$TargetServerPort" user -o "$User" | grep -E -v '^(#|Access:|Update:)' > "$UserSpecFile" if grep -q ^User: "$UserSpecFile"; then dbg "BEGIN USER SPEC FILE $UserSpecFile:\\n${H2}\\n$(cat "$UserSpecFile")\\n${H2}" if [[ "$NoOp" -eq 0 ]]; then if p4 user -f -i < "$UserSpecFile"; then ImportUserOKCount+=1 else errmsg "Failed to add user $User with this spec:\\nBEGIN USER SPEC FILE $UserSpecFile:\\n${H2}\\n$(cat "$UserSpecFile")\\n${H2}" ImportUserErrorCount+=1 fi else msg "NO_OP: Would add user $User" ImportUserOKCount+=1 fi else errmsg "Could not generate user spec for user $User." fi done < "$TmpFile" dbg "Getting list of groups from P4AUTH server with:\\np4 -p $TargetServerPort -ztag -F %group% groups .GT. $TmpFile" if p4 -p "$TargetServerPort" -ztag -F %group% groups > "$TmpFile"; then if [[ -s "$TmpFile" ]]; then if mv -f "$TmpFile" "${TmpFile}.2"; then if sort -u "${TmpFile}.2" > "$TmpFile"; then FoundGroups=$(wc -l "$TmpFile" | awk '{print $1}') msg "Found $FoundGroups groups on target server." else bail "Could not sort group spec list file with: sort -u ${TmpFile}.2 .GT. $TmpFile" fi else bail "Could not move group spec list file with: mv -f $TmpFile ${TmpFile}.2" fi else bail "Found no groups on target server to import." fi else bail "Could not get list of groups from target server." fi while read -r Group; do msg "Adding group $Group." ImportGroupCount+=1 GroupSpecFile="$TmpDir/$Group.group.p4s" p4 -p "$TargetServerPort" group -o "$Group" | grep -E -v '^(#|Access:|Update:)' > "$GroupSpecFile" if grep -q ^Group: "$GroupSpecFile"; then dbg "BEGIN GROUP SPEC FILE $GroupSpecFile:\\n${H2}\\n$(cat "$GroupSpecFile")\\n${H2}" if [[ "$NoOp" -eq 0 ]]; then if p4 group -i < "$GroupSpecFile"; then ImportGroupOKCount+=1 else errmsg "Failed to add group $Group with this spec:\\nBEGIN USER SPEC FILE $GroupSpecFile:\\n${H2}\\n$(cat "$GroupSpecFile")\\n${H2}" ImportGroupErrorCount+=1 fi else msg "NO_OP: Would add group $Group" ImportGroupOKCount+=1 fi else errmsg "Could not generate group spec for group $Group." fi done < "$TmpFile" rm -rf "$TmpDir" msg "${H2}\\nSummary: User Adds Attempted: $ImportUserCount Users Added OK $ImportUserOKCount User Add Errors: $ImportUserErrorCount Group Updates Attempted: $ImportGroupCount Group Updates Attempted OK: $ImportGroupOKCount Group Update Errors: $ImportGroupErrorCount Total Errors: $ErrorCount Non-standard users skipped: $SkipUserByTypeCount Pre-existing users skipped: $SkipExistingUserCount " if [[ "$ErrorCount" -eq 0 ]]; then msg "All processing completed successfully." else errmsg "Processing complete, but $ErrorCount errors." fi msg "\\nTotal $ThisScript processing took $((SECONDS/3600)) hours $((SECONDS%3600/60)) minutes $((SECONDS%60)) seconds.\\n" exit "${ErrorCount}"
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 29252 | C. Thomas Tyler |
Released SDP 2022.2.29250 (2022/12/08). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
//guest/perforce_software/sdp/dev/Unsupported/Maintenance/import_users_and_groups.sh | |||||
#1 | 29225 | C. Thomas Tyler |
Added script to import users and groups from another Helix Core server. Useful when decomissioning a P4AUTH server. |