gen_p4dtg_env.sh #1

  • //
  • p4-sdp/
  • dev_rebrand/
  • Server/
  • Unix/
  • p4/
  • common/
  • bin/
  • gen_p4dtg_env.sh
  • View
  • Commits
  • Open Download .zip Download (10 KB)
#!/bin/bash
#------------------------------------------------------------------------------
# gen_p4dtg_env.sh
#
# To see documentation for this script, run:
#   gen_p4dtg_env.sh -man
#------------------------------------------------------------------------------

set -u


# Counters and message helpers.
declare -i ErrorCount=0
declare -i WarningCount=0

function msg () { echo -e "$*"; }
function errmsg () { msg "\\nError: ${1:-Unknown Error}\\n"; ErrorCount+=1; }
function warnmsg () { msg "\\nWarning: ${1:-Unknown Warning}\\n"; WarningCount+=1; }
function bail () { errmsg "${1:-Unknown Error}"; exit "$ErrorCount"; }

# Standard identity vars.
declare ThisScript="${0##*/}"
declare Args="$*"
declare CmdLine="$ThisScript $Args"
declare Version="1.1.2"
declare ThisUser=
declare ThisHost=${HOSTNAME%%.*}

ThisUser="$(id -un 2>/dev/null || echo unknown)"

msg "Starting $ThisScript v$Version as $ThisUser@$ThisHost on $(date) with \\n$CmdLine"

usage() {
  # usage <style> [usageErrorMessage]
  # style: "short"|"man"
  declare style="${1:-short}"
  declare usageErrorMessage="${2:-}"

  [[ -n "$usageErrorMessage" ]] && errmsg "$usageErrorMessage"

  msg "Usage:"
  msg "  $ThisScript -c <P4DTGConfigName> [-i <SDPInstance>] [-u <P4USER>] [-f]"
  msg "  $ThisScript -verify [-i <SDPInstance>] [-e <EnvFile>]"
  msg "  $ThisScript -V|-version|--version"
  msg "  $ThisScript -h|-man"
  msg ""

  if [[ "$style" == "man" ]]; then
    msg "DESCRIPTION"
    msg "  Generates or verifies the systemd EnvironmentFile for a P4DTG instance."
    msg ""
    msg "MODES"
    msg "  Generate mode:"
    msg "    -c <P4DTGConfigName> is required."
    msg "    Writes: \$P4CCFG/p4dtg_<instance>.env"
    msg ""
    msg "  Verify mode:"
    msg "    -verify validates an existing env file."
    msg "    By default it validates: \$P4CCFG/p4dtg_<instance>.env"
    msg "    You can override with: -e <EnvFile>"
    msg ""
    msg "OPTIONS"
    msg "  -i <SDPInstance>"
    msg "        Optional. If omitted, uses \$SDP_INSTANCE; otherwise error."
    msg ""
    msg "  -c <P4DTGConfigName>"
    msg "        Required for generate mode. Sets P4DTG_CFG."
    msg ""
    msg "  -u <P4USER>"
    msg "        Optional. Defaults to 'p4dtg'. Used in generated env file as P4USER."
    msg ""
    msg "  -f"
    msg "        Force overwrite in generate mode."
    msg "        Existing env file moved aside as .bak.YYYY-MM-DD-HHMMSS"
    msg ""
    msg "  -verify"
    msg "        Verify mode."
    msg ""
    msg "  -e <EnvFile>"
    msg "        Optional with -verify. Verify this explicit env file path."
    msg ""
    msg "  -V|-version|--version"
    msg "        Display version and exit."
    msg ""
    msg "  -h|-man"
    msg "        Display help. -man shows extended help."
    msg ""
    msg "NOTES"
    msg "  - Sources SDP environment with: /p4/common/bin/p4_vars <instance>"
    msg "  - P4PORT selection for generated env file:"
    msg "      If /p4/<inst>/bin/p4broker_<inst>_init exists and is executable -> P4PORT=\$P4BROKERPORT"
    msg "      else -> P4PORT=\$P4PORT"
    msg "  - Includes P4CHARSET and P4COMMANDCHARSET only if defined and non-empty."
    msg "  - P4DTG_ROOT is currently hard-coded to /p4/common/dtg."
    msg "  - HOME is set to /home/perforce."
    msg ""
  fi

  exit 2
}

# ----------------------------
# Defaults / inputs
# ----------------------------
declare SDPInstance="${SDP_INSTANCE:-}"
declare P4DTG_CFG=""
declare P4User="p4dtg"
declare Force=0
declare DoVerify=0
declare VerifyEnvFile=""

# ----------------------------
# Command Line Processing.
# ----------------------------
declare shiftArgs=0
while [[ $# -gt 0 ]]; do
  shiftArgs=0
  case "${1}" in
    (-h) usage "short" ;;
    (-man) usage "man" ;;
    (-V|-version|--version)
      msg "$ThisScript v$Version"
      exit 0
      ;;
    (-i) SDPInstance="${2:-}"; shiftArgs=2 ;;
    (-c) P4DTG_CFG="${2:-}"; shiftArgs=2 ;;
    (-u) P4User="${2:-}"; shiftArgs=2 ;;
    (-f) Force=1; shiftArgs=1 ;;
    (-verify) DoVerify=1; shiftArgs=1 ;;
    (-e) VerifyEnvFile="${2:-}"; shiftArgs=2 ;;
    (-*)
      usage "short" "Unknown option: ${1}"
      ;;
    (*)
      usage "short" "Unexpected parameter: ${1}"
      ;;
  esac
  shift "$shiftArgs"
done

# Validate instance presence
[[ -n "${SDPInstance}" ]] || usage "short" "SDP instance not specified. Use -i or set SDP_INSTANCE."

# Conservative sanity for instance name
if [[ ! "$SDPInstance" =~ ^[A-Za-z0-9][A-Za-z0-9_-]*$ ]]; then
  bail "Invalid SDP instance name: '$SDPInstance'"
fi

# ----------------------------
# Source SDP environment
# ----------------------------
declare P4Vars="/p4/common/bin/p4_vars"
[[ -r "$P4Vars" ]] || bail "Missing or unreadable: $P4Vars"

# shellcheck disable=SC1090
source "$P4Vars" "$SDPInstance" || bail "Failed to source SDP environment with: $P4Vars $SDPInstance"

[[ -n "${P4CCFG:-}" ]] || bail "P4CCFG is not set after sourcing p4_vars for instance '$SDPInstance'"

# Compute default env file path now that P4CCFG is known.
declare DefaultEnvFile="${P4CCFG}/p4dtg_${SDPInstance}.env"

# ----------------------------
# Verify mode
# ----------------------------
verify_env_file() {
  declare envFile="${1:-}"
  [[ -n "$envFile" ]] || bail "verify_env_file called with empty path."

  [[ -r "$envFile" ]] || bail "Env file not found or not readable: $envFile"

  # Basic format check: KEY=VALUE lines; ignore comments/blank.
  # Required keys:
  declare -a requiredKeys=(P4DTG_CFG P4DTG_ROOT HOME P4PORT P4USER)
  declare k=""
  for k in "${requiredKeys[@]}"; do
    if ! grep -Eq "^[[:space:]]*${k}=" "$envFile"; then
      bail "Env file missing required key: $k"
    fi
    # Ensure non-empty value (KEY= followed by at least one char)
    if grep -Eq "^[[:space:]]*${k}=[[:space:]]*$" "$envFile"; then
      bail "Env file has empty value for key: $k"
    fi
  done

  # Optional keys should not be present with empty values (if present)
  declare -a optionalKeys=(P4CHARSET P4COMMANDCHARSET P4TICKETS P4TRUST)
  for k in "${optionalKeys[@]}"; do
    if grep -Eq "^[[:space:]]*${k}=[[:space:]]*$" "$envFile"; then
      bail "Env file has empty value for optional key (remove it or set value): $k"
    fi
  done

  # Validate that DTG_ROOT is the expected value (for now, hard-coded requirement).
  if ! grep -Eq '^[[:space:]]*P4DTG_ROOT=/p4/common/dtg[[:space:]]*$' "$envFile"; then
    warnmsg "P4DTG_ROOT is not '/p4/common/dtg' in $envFile (verify whether this is intended)."
  fi

  # Validate broker-port logic consistency (warn only, since admins may override on purpose).
  # Determine expected DTG_P4PORT using the same rule as generation.
  [[ -n "${P4PORT:-}" ]] || bail "P4PORT is not set after sourcing p4_vars for instance '$SDPInstance'"

  declare BrokerInit="/p4/${SDPInstance}/bin/p4broker_${SDPInstance}_init"
  declare ExpectedP4PORT="$P4PORT"
  if [[ -x "$BrokerInit" && -n "${P4BROKERPORT:-}" ]]; then
    ExpectedP4PORT="$P4BROKERPORT"
  fi

  declare ActualP4PORT
  ActualP4PORT="$(grep -E '^[[:space:]]*P4PORT=' "$envFile" | head -1 | sed -E 's/^[[:space:]]*P4PORT=//')"

  if [[ -n "$ExpectedP4PORT" && -n "$ActualP4PORT" && "$ExpectedP4PORT" != "$ActualP4PORT" ]]; then
    warnmsg "P4PORT in env file ('$ActualP4PORT') does not match expected ('$ExpectedP4PORT') for instance '$SDPInstance'."
  fi

  msg "Verified OK: $envFile"
  exit "$ErrorCount"
}

if [[ "$DoVerify" -eq 1 ]]; then
  declare envToVerify="$DefaultEnvFile"
  if [[ -n "$VerifyEnvFile" ]]; then
    envToVerify="$VerifyEnvFile"
  fi
  verify_env_file "$envToVerify"
fi

# ----------------------------
# Generate mode validations
# ----------------------------
[[ -n "${P4DTG_CFG}" ]] || usage "short" "Missing required -c <P4DTGConfigName> for generate mode."

# Expect key vars from sourced env
[[ -n "${P4PORT:-}" ]] || bail "P4PORT is not set after sourcing p4_vars for instance '$SDPInstance'"

# ----------------------------
# Determine DTG P4PORT for generated env file
# ----------------------------
declare BrokerInit="/p4/${SDPInstance}/bin/p4broker_${SDPInstance}_init"
declare DTG_P4PORT="$P4PORT"

if [[ -x "$BrokerInit" ]]; then
  if [[ -n "${P4BROKERPORT:-}" ]]; then
    DTG_P4PORT="$P4BROKERPORT"
  else
    warnmsg "Broker init exists ($BrokerInit) but P4BROKERPORT is not set; falling back to P4PORT='$P4PORT'"
  fi
fi

# ----------------------------
# Output file paths
# ----------------------------
declare OutDir="$P4CCFG"
declare OutFile="$DefaultEnvFile"
declare TmpFile="${OutFile}.tmp.$$"

[[ -d "$OutDir" ]] || bail "Output directory not found: $OutDir"
[[ -w "$OutDir" ]] || bail "Output directory not writable: $OutDir"

# Safety: don't overwrite unless -f
if [[ -e "$OutFile" ]]; then
  if [[ "$Force" -eq 1 ]]; then
    declare Back=
    Back="${OutFile}.bak.$(date +'%Y-%m-%d-%H%M%S')"
    mv -f "$OutFile" "$Back" || bail "Failed to move existing env file aside to: $Back"
    msg "Moved existing env file aside to: $Back"
  else
    bail "Refusing to overwrite existing env file: $OutFile (use -f to force)"
  fi
fi

# Restrictive permissions
umask 077

# ----------------------------
# Generate env file
# ----------------------------
{
  echo "# Generated by $ThisScript v$Version on $(date -u '+%Y-%m-%d %H:%M:%S UTC')"
  echo "# Instance: $SDPInstance"
  echo ""
  echo "P4DTG_CFG=$P4DTG_CFG"
  echo "P4DTG_ROOT=/p4/common/dtg"
  echo "HOME=/home/perforce"
  echo ""
  echo "P4PORT=$DTG_P4PORT"
  echo "P4USER=$P4User"

  # Include only if defined and non-empty
  if [[ -n "${P4CHARSET:-}" ]]; then
    echo "P4CHARSET=$P4CHARSET"
  fi
  if [[ -n "${P4COMMANDCHARSET:-}" ]]; then
    echo "P4COMMANDCHARSET=$P4COMMANDCHARSET"
  fi

  # Pass through if available (optional)
  if [[ -n "${P4TICKETS:-}" ]]; then
    echo "P4TICKETS=$P4TICKETS"
  fi
  if [[ -n "${P4TRUST:-}" ]]; then
    echo "P4TRUST=$P4TRUST"
  fi
} > "$TmpFile" || bail "Failed writing temp env file: $TmpFile"

mv -f "$TmpFile" "$OutFile" || bail "Failed moving $TmpFile to $OutFile"
chmod 600 "$OutFile" 2>/dev/null || true

msg "Wrote: $OutFile"

exit "$ErrorCount"

# Change User Description Committed
#1 32482 C. Thomas Tyler Merge down from //p4-sdp/dev -> //p4-sdp/dev_rebrand.

  This was initiated with 'p4 merge' (no options).
  The 'p4 resolve -as', 'p4 resolve -am' and several interactive resolves were done.
//p4-sdp/dev/Server/Unix/p4/common/bin/gen_p4dtg_env.sh
#1 32480 C. Thomas Tyler Routine merge for SDP from Classic to Streams, done with:

p4 merge -b SDP_Classic_to_Streams
p4 resolve -as

  The automatic-safe resolve handled all files; neither '-am' nor interative resolves were needed.
//guest/perforce_software/sdp/dev/Server/Unix/p4/common/bin/gen_p4dtg_env.sh
#1 32402 C. Thomas Tyler Fixed so the p4dtg_N (P4DTG) service can be managed with systmectl, e.g.

sudo systemctl start p4dtg_1
sudo systemctl status p4dtg_1
sudo systemctl stop p4dtg_1

Also added support for a "force_start" option, similar to that being added for
p4d (per SDP-837).

This change includes:
* Modifiedcation to the temmplate for the p4dtg_N_init script.
* Addition of new template for the systemd p4dtg_N.service file.
* Added a new script to generate a systemctl-compatible environment file from
the standard SDP shell environment mechanism.

See: SDP-552.

#review-32403