#!/usr/bin/env bash
# Copyright (c) 2021 RackN Inc.

set -e

###
#  Installation, upgrade, and removal script for the Digital Rebar Platform (DRP)
#  service.  Use '--help' for Usage information.  Supports online and offline (eg
#  "airgap" installs if the DRP, content, and plugin pieces are local to the installer
#  script, or accessible via an alternate HTTP/S location.
###

# BUMP version on updates
INSTALL_VERSION="v26.05.04-0"
INSTALL_SOURCE=$0

DEFAULT_DRP_VERSION=${DEFAULT_DRP_VERSION:-"stable"}
INSTALLATION_FOLDER=$PWD

SAVE_TMPDIR="yes"
exit_cleanup() {
  # disable trap handler since we're catching the error here
  trap - EXIT
  local _x=$1
  shift
  # if not default TMPDIR, and we had to (try) to create TMPDIR, remove it
  [[ "$TMPDIR" != "/tmp" && -z "$SAVE_TMPDIR" ]] && rm -rf "$TMPDIR" || true
  rm -f rackn-catalog.json
  [[ -n "$*" ]] && echo -e "EXIT MESSAGE: $*"
  exit $_x
} # end exit_cleanup()

trap_exit() {
  local _xit=$?
  if [[ $_xit -ne 0 ]]
  then
    echo ""
    echo -e "${CErr}!!!!!!!!!!!!!!!!!!!!!!! FATAL !!!!!!!!!!!!!!!!!!!!!!!${RCol}"
    echo "The installer script failed with an error.  The last"
    echo -e "command that exited, failed with error code '$CErr$_xit$RCol'."
    echo -e "Please re-run the installer with '$CInfo--debug$RCol' to try and"
    echo "determine what the failure was.  If you are unable to"
    echo "resolve it, please contact RackN Support at"
    echo -e "  ${CInfo}support@rackn.com${RCol}"
    echo "Additional debugging information may be available in"
    echo -e "the debug file '$CInfo$TMPDIR/$DBG_FILE$RCol'"
    echo ""
  fi
} # end trap_exit()

# initial setting, TMPDIR gets updated later and will need to be reset
DRP_DEBUGLOG="$TMPDIR/$DBG_FILE"

COLOR_OK=true
set_color() {
# terminal colors
RCol='\e[0m'    # Text Reset

# Regular           Bold                Underline           High Intensity      BoldHigh Intens     Background          High Intensity Backgrounds
Bla='\e[0;30m';     BBla='\e[1;30m';    UBla='\e[4;30m';    IBla='\e[0;90m';    BIBla='\e[1;90m';   On_Bla='\e[40m';    On_IBla='\e[0;100m';
Red='\e[0;31m';     BRed='\e[1;31m';    URed='\e[4;31m';    IRed='\e[0;91m';    BIRed='\e[1;91m';   On_Red='\e[41m';    On_IRed='\e[0;101m';
Gre='\e[0;32m';     BGre='\e[1;32m';    UGre='\e[4;32m';    IGre='\e[0;92m';    BIGre='\e[1;92m';   On_Gre='\e[42m';    On_IGre='\e[0;102m';
Yel='\e[0;33m';     BYel='\e[1;33m';    UYel='\e[4;33m';    IYel='\e[0;93m';    BIYel='\e[1;93m';   On_Yel='\e[43m';    On_IYel='\e[0;103m';
Blu='\e[0;34m';     BBlu='\e[1;34m';    UBlu='\e[4;34m';    IBlu='\e[0;94m';    BIBlu='\e[1;94m';   On_Blu='\e[44m';    On_IBlu='\e[0;104m';
Pur='\e[0;35m';     BPur='\e[1;35m';    UPur='\e[4;35m';    IPur='\e[0;95m';    BIPur='\e[1;95m';   On_Pur='\e[45m';    On_IPur='\e[0;105m';
Cya='\e[0;36m';     BCya='\e[1;36m';    UCya='\e[4;36m';    ICya='\e[0;96m';    BICya='\e[1;96m';   On_Cya='\e[46m';    On_ICya='\e[0;106m';
Whi='\e[0;37m';     BWhi='\e[1;37m';    UWhi='\e[4;37m';    IWhi='\e[0;97m';    BIWhi='\e[1;97m';   On_Whi='\e[47m';    On_IWhi='\e[0;107m';

# palette
CWarn="$BYel"
CFlag="$IBlu"
CDef="$IBla"
CDef_unset="$IYel"
CFile="$IBla"
CNote="$Yel"
CInfo="$Cya"
CNotice="$IYel"
COk="$IGre"
CErr="$IRed"
} # end set_color()

c_def() { if [[ "$@" == "unset" ]]; then echo -en "$CDef_unset$@$RCol"; else echo -en "$CDef$@$RCol"; fi; }
c_flag() { echo -en "$CFlag$@$RCol"; }
c_warn() { echo -en "$CWarn$@$RCol"; }
c_file() { echo -en "$CFile$@$RCol"; }
c_err() { echo -en "$CErr$@$RCol"; }

# catch any errant exit codes so we can output additional debugging info
# this is called if exit_cleanup() isn't explicitly called
trap "trap_exit" EXIT

usage() {
    [[ "$COLOR_OK" == "true" ]] && set_color
echo -e "
  ${ICya}USAGE:${RCol} ${BYel}$0${RCol} $(c_flag "[ install | upgrade | remove | version ] [ <argument flags: see below> ]")

${CWarn}WARNING${RCol}: '$(c_flag "install")' option will OVERWRITE existing installations

${ICya}OPTIONS${RCol}:
    $(c_flag "install")                 - Sets up an isolated or system 'production' enabled install
    $(c_flag "upgrade")                 - Sets the installer to upgrade an existing 'dr-provision', for upgrade of
                              container; kill/rm the DRP container, then upgrade and reattach data volume
    $(c_flag "remove")                  - Removes the system enabled install.  Requires no other flags
                              optional: '$(c_flag "--remove-data")' to wipe all installed data
    $(c_flag "explode")                 - Only to be used in air-gapped mode. Will explode the contents of the provided
                              script to $DRP_HOME_DIR/airgap, use '$(c_flag "--drp-home-dir=location")' to change
    $(c_flag "extract")                 - Only to be used in air-gapped mode. Will extract the tarball from the script
                              and store it in $DRP_HOME_DIR/airgap, use '$(c_flag "--drp-home-dir=location")' to change
    $(c_flag "build-airgap")            - Builds a 'airgap-install.sh' script which can be moved over to an airgapped system
                              for a drp install.
    $(c_flag "get-drpcli")              - Downloads the latest version of drpcli to the current location. $INSTALLATION_FOLDER
    $(c_flag "version")                 - Show install.sh script version and exit

${ICya}ARGUMENT FLAGS${RCol}:
    $(c_flag "--debug")=$(c_def "[true|false]")    - Enables debug output
    $(c_flag "--force")=$(c_def "[true|false]")    - Forces an overwrite of local install binaries and content
    $(c_flag "--upgrade")=$(c_def "[true|false]")  - Turns on 'force' option to overwrite local binaries/content
    $(c_flag "--tmpdir")=$(c_def "/tmp")           - Temporary directory for installer work
    $(c_flag "--catalog")=$(c_def "<string>")      - Alternate catalog location to use for installing
                              content/plugins; also used for '$(c_flag "--local-ui")' Portal setup
    $(c_flag "--isolated")              - Sets up current directory as install location for drpcli
                              and dr-provision (makes mess in current directory!)
    $(c_flag "--no-content")            - Don't add content to the system
    $(c_flag "--upgrade-content")       - Update content to the latest versions of the same minor version of drp.
                              alias: '$(c_flag "--update-content")'
    $(c_flag "--zip-file")=$(c_def "filename.zip") - Don't download the dr-provision.zip file, instead use
                              the referenced zip file (useful for airgap deployments)
                              NOTE: disables sha256sum checks - do this manually
    $(c_flag "--ipaddr")=$(c_def "<ip>")           - The IP to use for the system identified IP.  The system
                              will attempt to discover the value if not specified
    $(c_flag "--version")=$(c_def "<string>")      - Version identifier if downloading; stable, tip, or
                              specific version label, $(c_def "(defaults to: $DEFAULT_DRP_VERSION)")
    $(c_flag "--remove-data")           - Remove data as well as program pieces
    $(c_flag "--skip-run-check")        - Skip the process check for 'dr-provision' on new install
                              only valid in '$(c_flag "--isolated")' install mode
    $(c_flag "--skip-prereqs")          - Skip OS dependency checks, for testing '$(c_flag "--isolated")' mode
    $(c_flag "--no-sudo")               - Do not use \"sudo\" prefix on commands (assume you're root)
    $(c_flag "--no-colors")             - Installer output will have no terminal colors
    $(c_flag "--fast-downloader")       - (experimental) Use Fast Downloader (uses 'aria2')
    $(c_flag "--keep-installer")        - In Production mode, do not purge the tmp installer artifacts
    $(c_flag "--startup")               - Attempt to start the dr-provision service
    $(c_flag "--systemd")               - Run the systemd enabling commands after installation
    $(c_flag "--systemd-services")      - Additional services for systemd to wait for before starting DRP.
    $(c_flag "--create-self")           - DRP will create a machine that represents itself.
                              Only used with startup/systemd parameters.
    $(c_flag "--start-runner")          - DRP will start a runner for itself. Implies create self.
                              Only used with startup/systemd parameters.
    $(c_flag "--license-file")=$(c_def "<string>")
                            - The license file to initially load into DRP
    $(c_flag "--initial-workflow")=$(c_def "<string>")
                            - Workflow to assign to the DRP's self machine as install finishes
                              Only valid with create-self object, only one Workflow may be specified
    $(c_flag "--initial-profiles")=$(c_def "<string>")
                            - Initial profiles to add to the DRP endpoint before starting the workflow,
                              comma separated list, no spaces, this is only valid with create-self object
    $(c_flag "--initial-contents")=$(c_def "<string>")
                            - Initial content packs to deliver, comma separated with no spaces.
                              A file, URL, or content-pack name
    $(c_flag "--initial-plugins")=$(c_def "<string>")
                            - Initial plugins to deliver, comma separated list with no spaces.
                              A file, URL, or content-pack name
    $(c_flag "--initial-parameters")=$(c_def "<string>")
                            - Initial parameters to set on the system.  Simple parameters
                              as a comma separated list, with no spaces.
    $(c_flag "--initial-subnets")=$(c_def "<string>")
                            - A file or URL containing Subnet definitions in JSON or YAML format,
                              comma separated, no spaces
                              NOTE: Subnets can also be injected in content packs with the
                              '$(c_flag "--initial-contents")' argument
    $(c_flag "--noisofs")               - Do not directly serve isos and uncompressed tarballs (RS_USE_ISOFS)
    $(c_flag "--isofs")                 - EXPERIMENTAL: Directly serve isos and uncompressed tarballs (RS_USE_ISOFS)
    $(c_flag "--bootstrap")             - Store the install image and the install script in the files bootstrap
    $(c_flag "--drp-id")=$(c_def "<string>")       - String to use as the DRP Identifier $(c_def "(only with $(c_flag "--systemd")${CDef})")
    $(c_flag "--drp-user")=$(c_def "<string>")     - DRP user to create after system start $(c_def "(only with $(c_flag "--systemd")${CDef})")
    $(c_flag "--drp-password")=$(c_def "<string>") - DRP user password to set after system start $(c_def "(only with $(c_flag "--systemd")${CDef})")
    $(c_flag "--remove-rocketskates")   - Remove the rocketskates user after system start $(c_def "(only with $(c_flag "--systemd")${CDef})")
    $(c_flag "--local-ui")              - Set up DRP to serve a local Portal/UI instance
                            - Requires that the '--catalog' be set to the UI Catalog source
    $(c_flag "--ha-id")=$(c_def "<string>")        - $(c_err "DEPRECATED pre-v4.6 ONLY"): String to use as the HA Identifier $(c_def "(only with $(c_flag "--systemd")${CDef})")
    $(c_flag "--ha-enabled")            - $(c_err "DEPRECATED pre-v4.6 ONLY"): Indicates that the system is HA enabled
    $(c_flag "--ha-address")=$(c_def "<string>")   - $(c_err "DEPRECATED pre-v4.6 ONLY"): IP Address to use a VIP for HA system
    $(c_flag "--ha-interface")=$(c_def "<string>") - $(c_err "DEPRECATED pre-v4.6 ONLY"): Interface to use for HA traffic
    $(c_flag "--ha-passive")            - $(c_err "DEPRECATED pre-v4.6 ONLY"): Indicates that the system is starting as passive.
    $(c_flag "--ha-token")=$(c_def "<string>")     - $(c_err "DEPRECATED pre-v4.6 ONLY"): The token to use to sync passive to active
    $(c_flag "--client-cert-auth")      - Enable Client Certificate Authentication
    $(c_flag "--client-cert-file")=$(c_def "<string>")
                            - Additional CA Certificate file for client cert validation
    $(c_flag "--system-uid")=$(c_def "<number>")   - System User ID to assign to system user for DRP to run as
    $(c_flag "--system-user")=$(c_def "<string>")  - System user account to create for DRP to run as
    $(c_flag "--system-gid")=$(c_def "<number>")    - System Group ID to assign to system group for DRP to run as
    $(c_flag "--system-group")=$(c_def "<string>") - System group name
    $(c_flag "--drp-home-dir")=$(c_def "<string>") - Use with system-user and system-group to set the home directory
                              for the system-user. This path is where most important drp files live
                              including the tftp root
    $(c_flag "--bin-dir")=$(c_def "<string>")      - Directory where DRP binaries are installed (default: \$DRP_HOME_DIR/bin).
                              Keeping binaries inside DRP_HOME_DIR lets dr-provision self-upgrade
                              without requiring write access to system directories.
    $(c_flag "--symlink-bin-dir")=$(c_def "<string>")
                            - Directory to place symlinks pointing at the installed binaries
                              (default: /usr/local/bin).  Set to empty string to disable.
    $(c_flag "--no-symlinks")              - Skip creating symlinks in --symlink-bin-dir (same as --symlink-bin-dir="")
    $(c_flag "--container")             - Force to install as a container, not zipfile
    $(c_flag "--container-type")=$(c_def "<string>")
                            - Container install type, $(c_def "(defaults to \"$CNT_TYPE\")")
    $(c_flag "--container-name")=$(c_def "<string>")
                            - Set the \"docker run\" container name, $(c_def "(defaults to \"$CNT_NAME\")")
    $(c_flag "--container-restart")=$(c_def "<string>")
                            - Set the Docker restart option, $(c_def "(defaults to \"$CNT_RESTART\")")
                              options are:  no, on-failure, always, unless-stopped
                            * see: https://docs.docker.com/config/containers/start-containers-automatically/
    $(c_flag "--container-volume")=$(c_def "<string>")
                            - Volume name to use for backing persistent storage, $(c_def "(default to \"$CNT_VOL\")")
    $(c_flag "--container-registry")=$(c_def "\"drp.example.com:5000\"")
                            - Alternate registry to get container images from, $(c_def "(default to \"$CNT_REGISTRY\")")
    $(c_flag "--container-env")=$(c_def "\"<string> <string> <string>\"")
                            - Define a space separated list of environment variables to pass to the
                              container on start $(c_def "(eg \"RS_METRICS_PORT=8888 RS_DRP_ID=fred\")")
                              see 'dr-provision --help' for complete list of startup variables
    $(c_flag "--container-netns")=$(c_def "\"<string>\"")
                            - Define Network Namespace to start container in. $(c_def "(defaults to \"$CNT_NETNS\")")
                              If set to empty string (\"\"), then disable setting any network namespace
    $(c_flag "--source-location")=$(c_def "<string>")
                            - Specify a location for catalog and source files for installation.
                              $(c_def "(defaults to \"\")")
    $(c_flag "--disable-dns")           - Disable DNS service (RS_DISABLE_DNS)
    $(c_flag "--disable-dhcp")          - Disable DHCP service (RS_DISABLE_DHCP)
    $(c_flag "--disable-tftp")          - Disable TFTP service (RS_DISABLE_TFTP_SERVER)
    $(c_flag "--disable-pxe")           - Disable PXE service (RS_DISABLE_PXE)
    $(c_flag "--disable-provisioner")   - Disable Static File service (RS_DISABLE_PROVISIONER)
    $(c_flag "--disable-secure-provisioner")
                            - Disable Secure Static File service (RS_DISABLE_SECURE_PROVISIONER)
    $(c_flag "--dns-port")              - Set DNS listen port (defaults to RS_DNS_PORT=53)
    $(c_flag "--dhcp-port")             - Set DHCP listen port (defaults to RS_DHCP_PORT=67)
    $(c_flag "--tftp-port")             - Set TFTP listen port (defaults to RS_TFTP_PORT=69)
    $(c_flag "--binl-port")             - Set PXE listen port (defaults to RS_BINL_PORT=4011)
    $(c_flag "--metrics-port")          - Set Metrics listen port (defaults to RS_METRICS_PORT=8080)
    $(c_flag "--static-port")           - Set Static File listen port (defaults to RS_STATIC_PORT=8090)
    $(c_flag "--static-secure-port")    - Set Secure Static File listen port (defaults to RS_STATIC_SECURE_PORT=8091)
    $(c_flag "--start-wait-time")       - Set the wait time for DRP start up in seconds (defaults to 10)
    $(c_flag "--api-port")              - Set API listen port (defaults to RS_API_PORT=8092)
    $(c_flag "--universal")             - Load the universal components and bootstrap the system.
                              $(c_warn "**This must be first**") all other argument flags must be after this flag;
                              and implies systemd, startup, start-runner, create-self.  Also implies
                              running universal-boostrap and starting discovery.  Subsequent options for
                              '$(c_flag "--initial-workflow")' will be ignored if this is set.
    $(c_flag "--non-interactive")       - Disable any interactive prompts or any sleep/wait pauses
                              for example: if '--universal' is not specified, a sleep wait of $NO_UNI_SLEEP
                              will be imposed, setting this disables the sleep wait

${ICya}DEFAULTS${RCol}:
    |  argument flag:        def. value:      |  argument flag:        def. value:
    |  -------------------   ------------     |  ------------------    ------------
    |  remove-rocketskates = $(c_def "false")            |  version (*)         = $(c_def "$DEFAULT_DRP_VERSION")
    |  isolated            = $(c_def "false")            |  nocontent           = $(c_def "false")
    |  upgrade             = $(c_def "false")            |  force               = $(c_def "false")
    |  debug               = $(c_def "false")            |  skip-run-check      = $(c_def "false")
    |  skip-prereqs        = $(c_def "false")            |  systemd             = $(c_def "false")
    |  create-self         = $(c_def "false")            |  start-runner        = $(c_def "false")
    |  drp-id              = $(c_def "unset")            |  ha-id               = $(c_def "unset")
    |  drp-user            = $(c_def "rocketskates")     |  drp-password        = $(c_def "r0cketsk8ts")
    |  startup             = $(c_def "false")            |  keep-installer      = $(c_def "false")
    |  local-ui            = $(c_def "false")            |  system-user         = $(c_def "root")
    |  system-uid          = $(c_def "unset")            |  system-gid          = $(c_def "unset")
    |  system-group        = $(c_def "root")             |  drp-home-dir        = $(c_def "/var/lib/dr-provision")
    |  bin-dir             = $(c_def "\$DRP_HOME_DIR/bin") |  container           = $(c_def "false")
    |  symlink-bin-dir     = $(c_def "/usr/local/bin")   |  no-symlinks         = $(c_def "false")
    |  container-volume    = $(c_def "$CNT_VOL")         |  container-registry  = $(c_def "$CNT_REGISTRY")
    |  container-type      = $(c_def "$CNT_TYPE")           |  container-name      = $(c_def "$CNT_NAME")
    |  container-netns     = $(c_def "$CNT_NETNS")             |  container-restart   = $(c_def "$CNT_RESTART")
    |  bootstrap           = $(c_def "false")            |  initial-workflow    = $(c_def "unset")
    |  initial-contents    = $(c_def "unset")            |  initial-profiles    = $(c_def "unset")
    |  initial-plugins     = $(c_def "unset")            |  initial-subnets     = $(c_def "unset")
    |  ha-enabled          = $(c_def "false")            |  ha-address          = $(c_def "unset")
    |  ha-passive          = $(c_def "false")            |  ha-interface        = $(c_def "unset")
    |  ha-token            = $(c_def "unset")            |  universal           = $(c_def "unset")
    |  systemd-services    = $(c_def "unset")            |  source-location     = $(c_def "unset")
    |  license-file        = $(c_def "unset")            |  start-wait-time     = $(c_def "10")
    |  tmpdir              = $(c_def "/tmp")             |  catalog             = $(c_def "https://repo.rackn.io/catalog.json")
    |  client-cert-auth    = $(c_def "unset")            |  client-cert-file    = $(c_def "unset")
    |  server-hostname     = $(c_def "unset")            |  non-interactive     = $(c_def "unset")

    * version examples: '$(c_def "tip")', '$(c_def "v4.6.3")', '$(c_def "v4.7.0-beta1.3")', or '$(c_def "stable")'

${ICya}PREREQUISITES${RCol}:
    ${CNote}NOTE: By default, prerequisite packages will be installed if possible.  You must
          ${CNote}manually install these first on a Mac OS X system. Package names may vary
          ${CNote}depending on your operating system version/distro packaging naming scheme.${RCol}

    ${ICya}REQUIRED${RCol}: curl, tar
    ${ICya}OPTIONAL${RCol}: aria2c (if using experimental "fast downloader")

${CWarn}WARNING${RCol}: '$(c_flag "install")' option will OVERWRITE existing installations, use '$(c_flag "update")'
         flag for inplace upgrades.

${ICya}INSTALLER VERSION${RCol}:  $(c_def "$INSTALL_VERSION")
"
} # end usage()

# control flags
DBG_FILE=$(mktemp --dry-run drp-install-script.debug.XXXXXXXXXXX)
TMPDIR=/tmp
ISOLATED=false
NO_CONTENT=false
DBG=false
UPGRADE=false
REMOVE_DATA=false
SKIP_RUN_CHECK=false
SKIP_DEPENDS=false
FAST_DOWNLOADER=false
SYSTEMD=false
START_RUNNER=false
CREATE_SELF=false
STARTUP=false
REMOVE_RS=false
LOCAL_UI=false
KEEP_INSTALLER=false
CONTAINER=false
BOOTSTRAP=false
INITIAL_WORKFLOW=
INITIAL_PROFILES=
INITIAL_PARAMETERS=
INITIAL_CONTENTS=
INITIAL_PLUGINS=
SYSTEMD_ADDITIONAL_SERVICES=
START_LIMIT_INTERVAL=60
START_LIMIT_BURST=5
START_WAIT_TIME=10
RESTART_SECONDS=2
UNIVERSAL=false
NO_UNIVERSAL=false
LICENSE_FILE=

# download URL locations; overridable via ENV variables
URL_BASE=${URL_BASE:-"https://rebar-catalog.s3-us-west-2.amazonaws.com"}
URL_BASE_CONTENT=${URL_BASE_CONTENT:-"$URL_BASE/drp-community-content"}

# set some builtin default values
_sudo="sudo"
BIN_DIR=
DRP_HOME_DIR=/var/lib/dr-provision
SYMLINK_BIN_DIR=/usr/local/bin
CREATE_SYMLINKS=true
CNT_TYPE=docker
CNT_NAME=drp
CNT_VOL=drp-data
CNT_REGISTRY=registry.gitlab.com
CNT_NETNS=host
CNT_ENV=""
CNT_RESTART="always"
CNT_VOL_REMOVE=true
SYSTEM_USER=root
SYSTEM_UID=
SYSTEM_GROUP=root
SYSTEM_GID=
HA_ENABLED=false
HA_ADDRESS=
HA_INTERFACE=
HA_TOKEN=
HA_PASSIVE=false
RS_DNS_PORT="53"
RS_DHCP_PORT="67"
RS_TFTP_PORT="69"
RS_BINL_PORT="4011"
RS_API_PORT="8092"
RS_METRICS_PORT="8080"
RS_STATIC_PORT="8091"
RS_STATIC_SECURE_PORT="8090"
RS_SERVER_HOSTNAME=
RS_CLIENT_CERT_AUTH=false
RS_CA_CERT_FILE=
NO_UNI_SLEEP="20"

###
#  '--universal' must be first argument flag if specified, make it so
###
if [[ "$*" =~ .*--universal.* ]]
then
  set -- "--universal" $(echo "$*" | sed 's/ --universal//g')
fi

original_args=( "$@" )
args=()
while (( $# > 0 )); do
    arg="$1"
    arg_key="${arg%%=*}"
    arg_data="${arg#*=}"
    case $arg_key in
        --help|-h)                      usage; exit_cleanup 0                               ;;
        --debug)                        DBG=true;                                           ;;
        --version|--drp-version)        DRP_VERSION=${arg_data}                             ;;
        --isolated)                     ISOLATED=true                                       ;;
        --tmpdir)                       TMPDIR=${arg_data}                                  ;;
        --skip-run-check)               SKIP_RUN_CHECK=true                                 ;;
        --skip-dep*|--skip-prereq*)     SKIP_DEPENDS=true                                   ;;
        --fast-downloader)              FAST_DOWNLOADER=true                                ;;
        --force)                        force=true                                          ;;
        --remove-data)                  REMOVE_DATA=true                                    ;;
        --upgrade)                      UPGRADE=true; force=true; CNT_VOL_REMOVE=false      ;;
        --nocontent|--no-content)       NO_CONTENT=true; NON_INTERACTIVE=true               ;;
        --update-content|--upgrade-content) UPDATE_CONTENT=true;                             ;;
        --no-sudo)                      _sudo=""                                            ;;
        --no-colors)                    COLOR_OK=false                                      ;;
        --keep-installer)               KEEP_INSTALLER=true                                 ;;
        --startup)                      STARTUP=true; SYSTEMD=true                          ;;
        --catalog)                      DRP_CATALOG="${arg_data}"                           ;;
        --systemd)                      SYSTEMD=true                                        ;;
        --systemd-services)             SYSTEMD_ADDITIONAL_SERVICES="${arg_data}"           ;;
        --create-self)                  CREATE_SELF=true                                    ;;
        --start-runner)                 START_RUNNER=true; CREATE_SELF=true                 ;;
        --bootstrap)                    BOOTSTRAP=true                                      ;;
        --local-ui)                     LOCAL_UI=true                                       ;;
        --remove-rocketskates)          REMOVE_RS=true                                      ;;
        --license-file)                 LICENSE_FILE="${arg_data}"                          ;;
        --initial-workflow)             [[ "$UNIVERSAL" == "false" ]] && INITIAL_WORKFLOW="${arg_data}"
                                                                                            ;;
        --initial-profiles)             INITIAL_PROFILES="${INITIAL_PROFILES}${arg_data}"   ;;
        --initial-parameters)           INITIAL_PARAMETERS="${arg_data}"                    ;;
        --initial-contents)             INITIAL_CONTENTS="${INITIAL_CONTENTS}${arg_data}"   ;;
        --initial-plugins)              INITIAL_PLUGINS="${INITIAL_PLUGINS}${arg_data}"     ;;
        --initial-subnets)              INITIAL_SUBNETS="${arg_data}"                       ;;
        --noisofs)                      RS_USE_ISOFS="false"                                ;;
        --isofs)                        RS_USE_ISOFS="true"                                 ;;
        --drp-user)                     DRP_USER=${arg_data}                                ;;
        --drp-password)                 DRP_PASSWORD="${arg_data}"                          ;;
        --drp-id)                       DRP_ID="${arg_data}"                                ;;
        --ha-id)                        HA_ID="${arg_data}"                                 ;;
        --ha-enabled)                   HA_ENABLED=true                                     ;;
        --ha-address)                   HA_ADDRESS="${arg_data}"                            ;;
        --ha-interface)                 HA_INTERFACE="${arg_data}"                          ;;
        --ha-passive)                   HA_PASSIVE=true                                     ;;
        --ha-token)                     HA_TOKEN="${arg_data}"                              ;;
        --client-cert-auth)             RS_CLIENT_CERT_AUTH=true                            ;;
        --client-cert-file)             RS_CA_CERT_FILE="${arg_data}"                       ;;
        --system-uid)                   SYSTEM_UID="${arg_data}"                            ;;
        --system-user)                  SYSTEM_USER="${arg_data}"                           ;;
        --system-gid)                   SYSTEM_GID="${arg_data}"                            ;;
        --system-group)                 SYSTEM_GROUP="${arg_data}"                          ;;
        --drp-home-dir)                 DRP_HOME_DIR="${arg_data}"                          ;;
        --container)                    CONTAINER=true                                      ;;
        --container-type)               CNT_TYPE="${arg_data}"                              ;;
        --container-name)               CNT_NAME="${arg_data}"                              ;;
        --container-volume)             CNT_VOL="${arg_data}"                               ;;
        --container-restart)            CNT_RESTART="${arg_data}"                           ;;
        --container-registry)           CNT_REGISTRY="${arg_data}"                          ;;
        --container-netns)              CNT_NETNS="${arg_data}"                             ;;
        --container-env)                CNT_ENV="${arg_data}"                               ;;
        --server-hostname)              RS_SERVER_HOSTNAME="${arg_data}"                    ;;
        --disable-dns)                  RS_DISABLE_DNS="true"                               ;;
        --disable-dhcp)                 RS_DISABLE_DHCP="true"                              ;;
        --disable-tftp)                 RS_DISABLE_TFTP_SERVER="true"                       ;;
        --disable-pxe)                  RS_DISABLE_PXE="true"                               ;;
        --disable-provisioner)          RS_DISABLE_PROVISIONER="true"                       ;;
        --disable-secure-provisioner)   RS_DISABLE_SECURE_PROVISIONER="true"                ;;
        --dns-port)                     RS_DNS_PORT="${arg_data}"                           ;;
        --dhcp-port)                    RS_DHCP_PORT="${arg_data}"                          ;;
        --tftp-port)                    RS_TFTP_PORT="${arg_data}"                          ;;
        --binl-port)                    RS_BINL_PORT="${arg_data}"                          ;;
        --metrics-port)                 RS_METRICS_PORT="${arg_data}"                       ;;
        --static-port)                  RS_STATIC_PORT="${arg_data}"                        ;;
        --static-secure-port)           RS_STATIC_SECURE_PORT="${arg_data}"                 ;;
        --api-port)                     RS_API_PORT="${arg_data}"                           ;;
        --skip-port-check)              SKIP_PORT_CHECK="true"                              ;;
        --start-wait-time)              START_WAIT_TIME="${arg_data}"                       ;;
        --source-location)              SOURCE_LOCATION="${arg_data}"                       ;;
        --non-interactive)              NON_INTERACTIVE=true                                ;;
        --universal)                    UNIVERSAL=true; BOOTSTRAP=true;
                                        SYSTEMD=true; STARTUP=true;
                                        CREATE_SELF=true; START_RUNNER=true;
                                        INITIAL_WORKFLOW="universal-bootstrap";
                                        INITIAL_CONTENTS="backup-recovery,universal,eikon,";
                                        INITIAL_PROFILES="bootstrap-drp-endpoint,bootstrap-cloud-wrappers,bootstrap-solidfire," ;;
        --zip-file)
            ZF=${arg_data}
            ZIP_FILE=$(echo "$(cd $(dirname $ZF) && pwd)/$(basename $ZF)")
            ;;
        --bin-dir)                      BIN_DIR="${arg_data}"                              ;;
        --symlink-bin-dir)              SYMLINK_BIN_DIR="${arg_data}"                      ;;
        --no-symlinks)                  CREATE_SYMLINKS=false                              ;;
        --*)
            arg_key="${arg_key#--}"
            arg_key="${arg_key//-/_}"
            # "^^" Paremeter Expansion is a bash v4.x feature; Mac by default is bash 3.x
            #arg_key="${arg_key^^}"
            arg_key=$(echo $arg_key | tr '[:lower:]' '[:upper:]')
            echo -e "$PREF_INFO Overriding $arg_key with $arg_data"
            export $arg_key="$arg_data"
            ;;
        *)
            args+=("$arg");;
    esac
    shift
done

# Default BIN_DIR inside DRP_HOME_DIR so dr-provision can self-upgrade without needing /usr/local/bin write access
BIN_DIR="${BIN_DIR:-${DRP_HOME_DIR}/bin}"

# Airgap stuff
if [[ -f $0 ]] ; then
  AIRGAP_TARBALL_MARKER=$(($(grep -an -m 1 "^-------Begin_tarball-------v2$" "$0" | cut -d: -f1) + 1))
  AIRGAP_DRPCLI_MARKER=$(($(grep -an -m 1 "^-------Begin_drpcli_binary-------v2$" "$0" | cut -d: -f1) + 1))
  AIRGAP_MANIFEST_MARKER=$(($(grep -an -m 1 "^-------Begin_manifest-------v2$" "$0" | cut -d: -f1) + 1))
  AIRGAP_DIR=$DRP_HOME_DIR/airgap
  AIRGAP_TARBALL=airgap.tar.gz
fi

if [[ AIRGAP_DRPCLI_MARKER -gt 1 ]]; then
  echo "Airgap markers found, doing airgap install"
fi

[[ "$COLOR_OK" == "true" ]] && set_color
PREF_OK="$COk>>>$RCol"
PREF_ERR="$CErr!!!$RCol"
PREF_INFO="$CInfo###$RCol"
PREF_WARN="${CWarn}Warning$RCol:"

set -- "${args[@]}"

if [[ "$HA_ENABLED" == "true" ]] ; then
  if [[ "$HA_TOKEN" == "" ]] ; then
    if [[ "$HA_PASSIVE" == "true" ]] ; then
      usage; exit_cleanup 1 "Passive systems must have a token. Specify HA_TOKEN."
    fi
    HA_TOKEN="ACTIVE_NO_TOKEN"
  fi
fi

CLI="${BIN_DIR}/drpcli"
CLI_BKUP="${BIN_DIR}/drpcli.drp-installer.backup"
PROVISION="${BIN_DIR}/dr-provision"
DRBUNDLER="${BIN_DIR}/drbundler"
PATH=$PATH:${BIN_DIR}:${SYMLINK_BIN_DIR}

[[ "$ISOLATED" == "true" ]] && KEEP_INSTALLER=true

[[ $DBG == true ]] && set -x

if [[ $EUID -eq 0 ]]; then
    _sudo=""
else
    if [[ ! -x "$(command -v sudo)" ]]; then
        exit_cleanup 1 "$(c_err "FATAL"): Script is not running as root and sudo command is not found. Please be root"
    fi
    if ! sudo -v 2>/dev/null; then
        exit_cleanup 1 "$(c_err "FATAL"): User '$(id -un)' cannot sudo to root. Root sudo access is required to install system files (binaries, systemd units). Please add this user to sudoers or run as root."
    fi
fi

# When SYSTEM_USER is non-root and running without sudo, validate that BIN_DIR and
# DRP_HOME_DIR are writable by the current user before attempting any install steps.
validate_nonroot_permissions() {
    [[ "${SYSTEM_USER}" == "root" ]] && return
    [[ -n "${_sudo}" || $EUID -eq 0 ]] && return

    if [[ -d "${BIN_DIR}" ]]; then
        if [[ ! -w "${BIN_DIR}" ]]; then
            exit_cleanup 1 "$(c_err "FATAL"): BIN_DIR '${BIN_DIR}' is not writable by '${SYSTEM_USER}' (uid=${SYSTEM_UID:-$(id -u)})." \
                "Use '--bin-dir=<path>' to specify a user-writable directory, or run with sudo."
        fi
    elif [[ ! -w "$(dirname "${BIN_DIR}")" ]]; then
        exit_cleanup 1 "$(c_err "FATAL"): Cannot create BIN_DIR '${BIN_DIR}': parent directory '$(dirname "${BIN_DIR}")' is not writable." \
            "Use '--bin-dir=<path>' to specify a user-writable directory, or run with sudo."
    fi

    local _home_parent
    _home_parent="$(dirname "${DRP_HOME_DIR}")"
    if [[ -d "${DRP_HOME_DIR}" ]]; then
        if [[ ! -w "${DRP_HOME_DIR}" ]]; then
            exit_cleanup 1 "$(c_err "FATAL"): DRP_HOME_DIR '${DRP_HOME_DIR}' is not writable by '${SYSTEM_USER}' (uid=${SYSTEM_UID:-$(id -u)})." \
                "Use '--drp-home-dir=<path>' to specify a user-writable directory, or run with sudo."
        fi
    elif [[ ! -w "${_home_parent}" ]]; then
        exit_cleanup 1 "$(c_err "FATAL"): Cannot create DRP_HOME_DIR '${DRP_HOME_DIR}': parent directory '${_home_parent}' is not writable." \
            "Use '--drp-home-dir=<path>' to specify a user-writable directory, or run with sudo."
    fi
}
validate_nonroot_permissions

# verify the container restart directives
case $CNT_RESTART in
  no|on-failure|always|unless-stopped) true ;;
  *) exit_cleanup 1 "$(c_err "FATAL"): Container restart directive ('$CNT_RESTART') is not valid. See '$(c_flag "--help")${CErr}' for details."
    ;;
esac

# Figure out what Linux distro we are running on.
export OS_TYPE= OS_VER= OS_NAME= OS_FAMILY=

if [[ -f /etc/os-release ]]; then
    . /etc/os-release
    OS_TYPE=${ID,,}
    OS_VER=${VERSION_ID,,}
elif [[ -f /etc/lsb-release ]]; then
    . /etc/lsb-release
    OS_VER=${DISTRIB_RELEASE,,}
    OS_TYPE=${DISTRIB_ID,,}
elif [[ -f /etc/centos-release || -f /etc/fedora-release || -f /etc/redhat-release ]]; then
    for rel in centos-release fedora-release redhat-release; do
        [[ -f /etc/$rel ]] || continue
        OS_TYPE=${rel%%-*}
        OS_VER="$(egrep -o '[0-9.]+' "/etc/$rel")"
        break
    done

    if [[ ! $OS_TYPE ]]; then
        exit_cleanup 1 "$(c_err "FATAL"): Cannot determine Linux version we are running on!"
    fi
elif [[ -f /etc/debian_version ]]; then
    OS_TYPE=debian
    OS_VER=$(cat /etc/debian_version)
elif [[ $(uname -s) == Darwin ]] ; then
    OS_TYPE=darwin
    OS_VER=$(sw_vers | grep ProductVersion | awk '{ print $2 }')
fi
OS_NAME="$OS_TYPE-$OS_VER"

case $OS_TYPE in
    amzn|centos|redhat|fedora|almalinux|rocky|ol)
                            OS_FAMILY="rhel"         ;;
    debian|ubuntu|raspbian) OS_FAMILY="debian"       ;;
    coreos)                 OS_FAMILY="container"    ;;
    opensuse-leap)          OS_FAMILY="opensuse"
                            OS_CODENAME="leap"       ;;
    opensuse-tumbleweed)    OS_FAMILY="opensuse"
                            OS_CODENAME="tumbleweed" ;;
    *)                      OS_FAMILY="$OS_TYPE"     ;;
esac

make_tmpdir() {
    local _parent=$(dirname "$TMPDIR")

    if [[ ! -d "$TMPDIR" ]]; then
        if [[ -w "$_parent" ]]; then
            mkdir --parents "$TMPDIR"
        else
            exit_cleanup 1 "Unable to write to specified temp directory parent folder ('$_parent')."
        fi
    fi

    # reset TMPDIR with a mktemp directory in TMPDIR
    TMPDIR="$(mktemp --dry-run --directory --tmpdir="$TMPDIR")"
    _parent=$(dirname "$TMPDIR")

    if [[ -w "$(dirname $TMPDIR)" ]]; then
        mkdir --parents "$TMPDIR"
    else
        exit_cleanup 1 "FAIL create temp directory '$TMPDIR' write permission error on parent directory ('$_parent')."
    fi
    if [[ "$TMPDIR" != "" ]] ; then
        unset SAVE_TMPDIR
    fi
}

# if TMPDIR is user set, do some basic sanity checks
# if directory doesn't exist, try and create it
if [[ "$TMPDIR" != "/tmp" ]]
then
    # make it a fully qualified path
    TD="$TMPDIR"
    TMPDIR=$(echo "$(cd $(dirname $TD) && pwd)/$(basename $TD)"  | sed 's://:/:g')
    # make sure the directory exists; TMPDIR will be updated in make_tmpdir()
    make_tmpdir "$TMPDIR"
    echo -e "$PREF_OK Alternate temporary directory set to: '${IGre}$TMPDIR${RCol}'${RCol}"
fi
# updated setting with correct TMPDIR
DRP_DEBUGLOG="$TMPDIR/$DBG_FILE"

check_catalog_url() {
  if [[ AIRGAP_DRPCLI_MARKER -gt 1 ]]; then
    _drpcli profiles set global param catalog_url to - <<EOF
${DRP_HOME_DIR}/tftpboot/files/rebar-catalog/rackn-catalog.json
EOF
    _drpcli profiles set global param catalog_urls to - <<EOF
["files/rebar-catalog/rackn-catalog.json", "/files/rebar-catalog/rackn-catalog.json", "{{ .ProvisionerURL }}/files/rebar-catalog/rackn-catalog.json"]
EOF
  fi
}

# Wait until DRP is ready, or exit
check_drp_ready() {
    COUNT=0
    while ! _drpcli info get > /dev/null 2>&1 ; do
        if (( $COUNT == 0 )); then
            echo -e -n "$PREF_INFO Waiting for dr-provision to start ..."
        else
            echo -n "."
        fi
        sleep 2
        # Pre-increment for compatibility with Bash 4.1+
        ((++COUNT))
        if (( $COUNT > $START_WAIT_TIME )) ; then
            exit_cleanup 1 "$(c_err "FATAL"): DRP Failed to start"
        fi
    done
    echo
    INFO=$(_drpcli info get)
    echo -e "${COk}${EP}Digital Rebar $(grep \"version\" <<< "$INFO") started as Endpoint $(grep \"id\" <<< "$INFO")${RCol}"
    echo
    echo -e "$PREF_INFO API is now accessible ${IBlu}https://[host ip]:$RS_API_PORT${RCol} (accept self-signed TLS certificate)"
}

# Set RS_KEY for drpcli authentication using DRP_USER/DRP_PASSWORD with fallback defaults
set_rs_key() {
    local tmp_user="${DRP_USER:-rocketskates}"
    local tmp_passwd="${DRP_PASSWORD:-r0cketsk8ts}"
    export RS_KEY="$tmp_user:$tmp_passwd"
}

# install the EPEL repo if appropriate, and not enabled already
install_epel() {
    if [[ $OS_FAMILY == rhel ]] ; then
        if ( `yum repolist enabled | grep -q "^epel/"` ); then
            echo -e "$PREF_INFO EPEL repository installed already."
        else
            if [[ $OS_TYPE != fedora ]] ; then
                $_sudo yum install -y epel-release
            fi
        fi
    fi
}

# set our downloader GET variable appropriately - supports standard
# (curl) downloader or (experimental) aria2c fast downloader
get() {
    [[ -z "$*" ]] && exit_cleanup 1 "$(c_err "FATAL"): Internal error, get() expects files to get"

    if [[ "$FAST_DOWNLOADER" == "true" ]]; then
        if which aria2c > /dev/null; then
            GET="aria2c --quiet=true --continue=true --max-concurrent-downloads=10 --max-connection-per-server=16 --max-tries=0"
        else
            exit_cleanup 1 "$(c_err "FATAL"): '$(c_flag "--fast-downloader")' specified, but couldn't find tool ('aria2c')."
        fi
    else
        if which curl > /dev/null; then
            GET="curl -k -sfL"
        else
            exit_cleanup 1 "$(c_err "FATAL"): Unable to find downloader tool ('curl')."
        fi
    fi
    for URL in $*; do
        # Replace provisioner URL (this will be the case for airgapped installs)
        if  [[  $URL == "{{.ProvisionerURL}}"* ]] ;
        then
            URL=${URL/"{{.ProvisionerURL}}"/"file://${DRP_HOME_DIR}/tftpboot/files/rebar-catalog"}
        fi
        FILE=${URL##*/}

        # If this is not a proper https:// or file:// url, then prepend the source
        if [[ $URL != https://* ]] && [[ $URL != file://* ]] ;
        then
          echo "URL seems to be relative path, appending source"
          URL=${DRP_CATALOG%/*}/${URL}
        fi

        echo -e "$PREF_OK Downloading file:  ${BWhi}$FILE${RCol} from ${URL}"
        $GET -o $FILE $URL
    done
}

# setup the system user for drp to run as
setup_system_user() {
    if [[ ${SYSTEM_USER} == "root" ]]; then
        return
    fi
    # 0 or 9 here is fine on Deb, RHEL, or OpenSUSE
    # 0 is success 9 means the account already
    # exists which is expected
    RC=0
    if [[ -n $SYSTEM_GID ]]; then
        SYS_GID="--gid $SYSTEM_GID"
    fi
    $_sudo groupadd --system ${SYSTEM_GROUP} ${SYS_GID} || RC=$?
    if [[ ${RC} != 0 && ${RC} != 9 ]]; then
        exit_cleanup ${RC} "$(c_err "FATAL"): Unable to create system group ${SYSTEM_GROUP}"
    fi

    RC=0
    if [[ -n $SYSTEM_UID ]]; then
        SYS_UID="--uid $SYSTEM_UID"
    fi
    if [[ ${OS_FAMILY} == "debian" ]]; then
        $_sudo adduser --system ${SYS_UID} --home ${DRP_HOME_DIR} --quiet --group ${SYSTEM_USER}
        return
    elif [[ ${OS_FAMILY} == "opensuse" ]]; then
        $_sudo useradd ${SYS_UID} --home-dir ${DRP_HOME_DIR} ${SYS_GID} ${SYSTEM_USER} || RC=$?
    elif [[ ${OS_FAMILY} == "rhel" ]]; then
        $_sudo adduser --system ${SYS_UID} -d ${DRP_HOME_DIR} --gid ${SYSTEM_GROUP} -m --shell /sbin/nologin ${SYSTEM_USER} || RC=$?
    fi
    if [[ ${RC} == 0 || ${RC} == 9 ]]; then
        return
    fi

    exit_cleanup ${RC} "$(c_err "FATAL"): Unable to create system user ${SYSTEM_USER}"
}

set_ownership_of_drp() {
    # It is possible for the home directory to not exist if
    # a non-root user was specified but already created.
    # Make sure a directory is created so DRP does not hit
    # permissions errors trying to use the home directory.
    if [ ! -d "${DRP_HOME_DIR}" ]; then
        echo -e "$PREF_OK Creating DRP Home directory $(c_def "(${DRP_HOME_DIR})")"
        $_sudo mkdir -p ${DRP_HOME_DIR}
    fi
    $_sudo chown -R ${SYSTEM_USER}:${SYSTEM_GROUP} ${DRP_HOME_DIR}

    for i in ${PROVISION} ${CLI} ${DRBUNDLER} ${PROVISION}.bak ${CLI}.bak ${DRBUNDLER}.bak ${PROVISION}.new ${CLI}.new ${DRBUNDLER}.new ; do
        [[ -r "$i" ]] && $_sudo chown -R ${SYSTEM_USER}:${SYSTEM_GROUP} $i || true
    done

    # if SELinux add restorecon
    if which restorecon >/dev/null 2>&1; then
        restorecon -Rv ${PROVISION} ${CLI}
    fi
}

setcap_drp_binary() {
    if [[ ${SYSTEM_USER} != "root" ]]; then
        case ${OS_FAMILY} in
            rhel|debian)
                $_sudo setcap "cap_net_raw,cap_net_bind_service=+ep" ${PROVISION}
            ;;
            opensuse)
                if ! $_sudo which setcap 2> /dev/null
                then
                    echo -e "$PREF_WARN Attempting to install 'libcap-progs' for 'setcap' binary from package repositories."
                    $_sudo zypper refresh
                    $_sudo zypper install -y libcap-progs
                fi
                $_sudo setcap "cap_net_raw,cap_net_bind_service=+ep" ${PROVISION}
            ;;
            *)
                echo -e "$PREF_INFO Your OS Family ${OS_FAMILY} does not support setcap" \
                     "  and may not be able to bind privileged ports when" \
                     "  running as non-root user ${SYSTEM_USER}"
            ;;
        esac
    fi
}

check_bins_darwin() {
  local _bin=$1
     case $_bin in
        aria2c)
            if [[ "$FAST_DOWNLOADER" == "true" ]]; then
                _bin="aria2"
                if ! which $_bin > /dev/null 2>&1; then
                    echo -e "$PREF_ERR Must have binary '$_bin' installed."
                    echo "eg:   brew install $_bin"
                    error=1
                fi
            fi
          ;;
        *)
            if ! which $_bin > /dev/null 2>&1; then
                echo -e "$PREF_ERR Must have binary '$_bin' installed."
                echo "eg:   brew install $_bin"
                error=1
            fi
         ;;
     esac
} # end check_bins_darwin()

# handle distro differences; skip 'aria2' if --fast-downloader not requested
check_pkgs_linux() {
    # assumes binary and package name are same
    local _pkg=$1
        if ! which $_pkg &>/dev/null; then
            [[ $_pkg == "aria2" && "$FAST_DOWNLOADER" != "true" ]] && return 0
            echo -e "$PREF_INFO Missing dependency '$_pkg', attempting to install it... "
            if [[ $OS_FAMILY == rhel ]] ; then
                echo $IN_EPEL | grep -q $_pkg && install_epel
                $_sudo yum install -y $_pkg
            elif [[ $OS_FAMILY == opensuse ]] ; then
                $_sudo zypper refresh
                $_sudo zypper install --y $_pkg
            elif [[ $OS_FAMILY == debian ]] ; then
                $_sudo apt-get install -y $_pkg
            fi
        fi
} # end check_pkgs_linux()

ensure_packages() {
    echo -e "$PREF_OK Ensuring required tools are installed"
    case $OS_FAMILY in
        darwin)
            error=0
            BINS="curl aria2c tar"
            for BIN in $BINS; do
                check_bins_darwin $BIN
            done

            if [[ $error == 1 ]]; then
                echo -e "$PREF_ERR After install missing components, restart the terminal to pick"
                echo "  up the newly installed commands, and re-run the installer."
                echo
                exit_cleanup 1
            fi
        ;;
        rhel|debian)
            PKGS="curl aria2 tar"
            IN_EPEL="curl aria2"
            for PKG in $PKGS; do
                check_pkgs_linux $PKG
            done
        ;;
        coreos)
            echo -e "$PREF_INFO CoreOS does not require any packages to be installed.  DRP will be"
            echo "  installed from the Docker Hub registry."
        ;;
        photon)
            if ! which tar > /dev/null 2>&1; then
                echo -e "$PREF_OK Installing packages for Photon Linux..."
                tdnf -y makecache
                tdnf -y install tar
            else
                echo -e "$PREF_INFO 'tar' already installed on Photon Linux..."
            fi
        ;;
        opensuse)
            PKGS="curl aria2 tar"
            for PKG in $PKGS; do
                check_pkgs_linux $PKG
            done
        ;;
        *)
            exit_cleanup 1 "$(c_err "FATAL"): Unsupported OS Family ($OS_FAMILY)."
        ;;
    esac
} # end ensure_packages()

# output a friendly statement on how to download ISOS via fast downloader
show_fast_isos() {
    echo -e "
$PREF_INFO Option '$(c_flag "--fast-downloader")' requested.  You may download the ISO images using
  'aria2c' command to significantly reduce download time of the ISO images.

${CNote} NOTE: The following generated scriptlet should download, install, and enable
      ${CNote}the ISO images.  VERIFY SCRIPTLET before running it.${RCol}

      YOU MUST START 'dr-provision' FIRST! Example commands:

$(c_def "###### BEGIN scriptlet")
  export CMD=\"aria2c --continue=true --max-concurrent-downloads=10 --max-connection-per-server=16 --max-tries=0\"
"

    for BOOTENV in $*
    do
        echo "  export URL=$(${EP}drpcli bootenvs show $BOOTENV | grep 'IsoUrl' | cut -d '"' -f 4)"
        echo "  export ISO=$(${EP}drpcli bootenvs show $BOOTENV | grep 'IsoFile' | cut -d '"' -f 4)"
        echo "  \$CMD -o \$ISO \$URL"
    done
    echo "  # this should move the ISOs to the TFTP directory..."
    echo "  $_sudo mv *.tar *.iso $TFTP_DIR/isos/"
    echo "  $_sudo pkill -HUP dr-provision"
    echo "  echo 'NOTICE:  exploding isos may take up to 5 minutes to complete ... '"
    echo -e $(c_def "###### END scriptlet")

    echo
} # end show_fast_isos()

remove_container() {
    case $CNT_TYPE in
        docker)
            $_sudo docker kill $CNT_NAME > /dev/null && echo -e "$PREF_OK Killed docker container '$CNT_NAME'"
            $_sudo docker rm $CNT_NAME > /dev/null && echo -e "$PREF_OK Removed docker container '$CNT_NAME'"
            if [[ "$CNT_VOL_REMOVE" == "true" ]]; then
                $_sudo docker volume rm $CNT_VOL > /dev/null && echo -e "$PREF_OK Removed backing volume named '$CNT_VOL'"
            else
                echo -e "$PREF_OK Not removing container data volume '$CNT_VOL'"
                if [[ "$MODE" == "remove" ]]; then
                    echo "    To remove: '$_sudo docker volume rm $CNT_VOL'"
                    echo "    or use '--remove-data' next time ... "
                fi
            fi
            ;;
        *)  exit_cleanup 1 "$PREF_ERR Container type '$CNT_TYPE' not supported in installer."
            ;;
    esac
} # end remove_container()

install_container() {
    if [[ -n "$CNT_ENV" ]]; then
        for ENV in $CNT_ENV; do
            OPTS="--env $ENV $OPTS"
        done
        ENV_OPTS=$(echo $OPTS | sed 's/ $//')
    fi
    case $CNT_TYPE in
        docker)
            ! which docker > /dev/null 2>&1 && exit_cleanup 1 "$PREF_ERR Container install requested but no 'docker' in PATH ($PATH)."
            if [[ "$UPGRADE" == "false" ]]; then
                $_sudo docker volume create $CNT_VOL > /dev/null
                VOL_MNT=$($_sudo docker volume inspect $CNT_VOL | grep Mountpoint | awk -F\" '{ print $4 }')
                echo -e "$PREF_OK Created docker volume named '$CNT_VOL' with mountpoint '$VOL_MNT'"
            else
                if $_sudo docker volume inspect $CNT_VOL > /dev/null 2>&1; then
                    echo -e "$PREF_INFO Attempting to reconnect volume '$CNT_VOL'"
                else
                    exit_cleanup 1 "$PREF_ERR No existing volume '$CNT_VOL' found to reconnect."
                fi
            fi
            if [[ -z "$CNT_NETNS" ]]; then
              echo -e "$PREF_WARN No network namespace set - you may have issues with DNS, DHCP, and TFTP depending on your use case."
            else
              NETNS="--net $CNT_NETNS"
            fi
            CMD="$_sudo docker run $ENV_OPTS --restart \"$CNT_RESTART\" --volume $CNT_VOL:/provision/drp-data --name \"$CNT_NAME\" -itd $NETNS ${CNT_REGISTRY}/rackn/containers/dr-provision:$DRP_VERSION"
            echo -e "$PREF_INFO Starting container with following run command:"
            echo "$CMD"
            eval $CMD

            echo ""
            echo -e "$PREF_INFO Digital Rebar container is using backing volume: $CNT_VOL"
            echo "Volume is backed on host filesystem at: $VOL_MNT"
            echo ""
            echo -e "$PREF_INFO Docker container run time information:"
            $_sudo docker ps --filter name=$CNT_NAME
            echo ""
            echo -e "${CNotice}>>>  NOTICE:  If you intend to upgrade this container, record your 'install.sh' options  <<< ${RCol}"
            echo -e "${CNotice}>>>           for the 'upgrade' command - you must reuse the same options to obtain the  <<< ${RCol}"
            echo -e "${CNotice}>>>           same installed results in the upgraded container.  You have been warned!   <<< ${RCol}"
            echo ""
            ;;
        *)  exit_cleanup 1 "$PREF_ERR Container type '$CNT_TYPE' not supported in installer."
            ;;
    esac
} # end install_container()

# Change this to more appropriate space to extract to as per requirement
extract_airgap_manifest() {
  echo "Extracting airgap manifest to $(pwd)"
  tail -n +$((AIRGAP_MANIFEST_MARKER)) "$0" > "$(pwd)/manifest.json"
}

extract_airgap_tarball() {
  echo "Extracting airgap tarball to ${AIRGAP_DIR}"
  $_sudo mkdir -p "$AIRGAP_DIR"
  if [[ "${SYSTEM_USER}" != "root" ]]; then
    $_sudo chown "${SYSTEM_USER}:${SYSTEM_GROUP}" "$AIRGAP_DIR"
  fi
  head -n +$((AIRGAP_DRPCLI_MARKER - 2)) $0 | tail -n +$((AIRGAP_TARBALL_MARKER)) | sed -z '$ s/\n$//' > "${AIRGAP_DIR}"/${AIRGAP_TARBALL}
}

explode_airgap_tarball() {
  extract_airgap_tarball
  # drpcli runs as SYSTEM_USER; ensure DRP_HOME_DIR exists and is writable by that user
  $_sudo mkdir -p "${DRP_HOME_DIR}"
  if [[ "${SYSTEM_USER}" != "root" ]]; then
    $_sudo chown -R "${SYSTEM_USER}:${SYSTEM_GROUP}" "${DRP_HOME_DIR}"
  fi
  echo "Exploding tarball contents.."
  CLEAN_FLAG=""
  if [[ "$MODE" == "install" ]]; then
    CLEAN_FLAG="--clean"
  fi
  "$INSTALLATION_FOLDER"/drpcli airgap explode "${AIRGAP_DIR}"/${AIRGAP_TARBALL} --location="${DRP_HOME_DIR}" $CLEAN_FLAG >> $DRP_DEBUGLOG
  export RS_CATALOG="${DRP_HOME_DIR}/tftpboot/files/rebar-catalog/rackn-catalog.json"
  # Remove the tarball and only keep the exploded contents
  rm -rf "${AIRGAP_DIR}/${AIRGAP_TARBALL}"
}

# main

MODE=$1

if [[ $OS_FAMILY == "container" || $CONTAINER == "true" ]]; then
    RMV_MSG="Remove not supported for container based installer at this time."
    GEN_MSG="Unsupported mode '$MODE'"
    case $MODE in
        install)
            echo -e "$PREF_OK Installing Digital Rebar as a container."
            install_container
            exit_cleanup $?
            ;;
        upgrade)
            echo -e "$PREF_OK Upgrading Digital Rebar as a container."
            UPGRADE=true
            CNT_VOL_REMOVE=false
            remove_container
            install_container
            exit_cleanup $?
            ;;
        remove)  [[ "$REMOVE_DATA" == "true" ]] && CNT_VOL_REMOVE="true" || CNT_VOL_REMOVE="false"
                 remove_container; exit_cleanup $? ;;
        *)       usage; exit_cleanup 1 "$GEN_MSG"  ;;
    esac
fi

arch=$(uname -m)
case $arch in
    x86_64|amd64)  arch=amd64   ;;
    arm64|aarch64) arch=arm64   ;;
    armv7l)        arch=arm_v7  ;;
    ppc64le)       arch=ppc64le ;;
    *)             exit_cleanup 1 "$(c_err "FATAL"): architecture ('$arch') not supported" ;;
esac

case $(uname -s) in
    Darwin)
        os="darwin"
        binpath="bin/darwin/$arch"
        bindest="${BIN_DIR}"
        tar="command tar"
        # Someday, handle adding all the launchd stuff we will need.
        shasum="command shasum -a 256";;
    Linux)
        os="linux"
        binpath="bin/linux/$arch"
        bindest="${BIN_DIR}"
        tar="command tar"
        if [[ -d /etc/systemd/system ]]; then
            # SystemD
            SYSTEMD=true
            initfile="assets/startup/dr-provision.service"
            initdest="/etc/systemd/system/dr-provision.service"
            starter="$_sudo systemctl daemon-reload && $_sudo systemctl start dr-provision"
            stopper="$_sudo systemctl stop dr-provision"
            enabler="$_sudo systemctl daemon-reload && $_sudo systemctl enable dr-provision"
        elif [[ -d /etc/init ]]; then
            # Upstart
            initfile="assets/startup/dr-provision.unit"
            initdest="/etc/init/dr-provision.conf"
            starter="$_sudo service dr-provision start"
            stopper="$_sudo service dr-provision stop"
            enabler="$_sudo service dr-provision enable"
        elif [[ -d /etc/init.d ]]; then
            # SysV
            initfile="assets/startup/dr-provision.sysv"
            initdest="/etc/init.d/dr-provision"
            starter="/etc/init.d/dr-provision start"
            stopper="/etc/init.d/dr-provision stop"
            enabler="/etc/init.d/dr-provision enable"
        else
            echo -e "$PREF_ERR No idea how to install startup stuff -- not using systemd, upstart, or sysv init"
            exit_cleanup 1
        fi
        shasum="command sha256sum";;
    *)
        # Someday, support installing on Windows.  Service creation could be tricky.
        echo -e "$PREF_ERR No idea how to check sha256sums"
        exit_cleanup 1;;
esac

# If a source location has been provided, use the catalog from tftpboot
if [[ $SOURCE_LOCATION != "" ]]; then
  DRP_CATALOG=${DRP_CATALOG:-"$SOURCE_LOCATION/tftpboot/files/rebar-catalog/rackn-catalog.json"}
else
  DRP_CATALOG=${DRP_CATALOG:-"$URL_BASE/rackn-catalog.json"}
fi

# Download and install drpcli, if drpcli is embedded in the script use that
# one else download from catalog

if [[ "$MODE" != "remove" ]] ; then
  if [[ AIRGAP_DRPCLI_MARKER -gt 1 ]]; then
    echo "Airgap mode.. drpcli being extracted from script"
    if [[ AIRGAP_MANIFEST_MARKER -gt 1 ]]; then
      head -n +$((AIRGAP_MANIFEST_MARKER - 2)) "$0" | tail -n +$((AIRGAP_DRPCLI_MARKER)) | sed -z '$ s/\n$//' > "${INSTALLATION_FOLDER}"/drpcli
    else
      tail -n +${AIRGAP_DRPCLI_MARKER} "$0" > "${INSTALLATION_FOLDER}"/drpcli
    fi

    chmod +x "${INSTALLATION_FOLDER}"/drpcli
    ln -sf "${INSTALLATION_FOLDER}"/drpcli "${INSTALLATION_FOLDER}"/jq
  elif [[ "$ZIP_FILE" != "" ]]  ; then
    echo "Try getting drpcli from the zip file"
    $tar -xf "$ZIP_FILE" bin/$os/$arch/drpcli >> $DRP_DEBUGLOG
    if [[ -r ./drpcli ]]; then
      mv ./drpcli ./drpcli.drp-installer.backup
    fi
    mv bin/$os/$arch/drpcli .
    chmod +x drpcli
    ln -sf drpcli jq
  else
    get "$DRP_CATALOG"
    FILE=${DRP_CATALOG##*/}
    mv "${FILE}" rackn-catalog.json.gz
    if ! gunzip rackn-catalog.json.gz >> $DRP_DEBUGLOG ; then
       mv rackn-catalog.json.gz rackn-catalog.json
    fi

    # Only attempting to get tip or stable, not worried about specific version.
    if [ -z ${DRP_VERSION+x} ]; then
      DRPCLI_VERSION="stable"
    elif [[ $DRP_VERSION == "tip" ]] || [[ $DRP_VERSION == *"-"* ]]; then
      DRPCLI_VERSION="tip"
    elif [[ $DRP_VERSION == "stable" ]] || [[ $DRP_VERSION != *"-"* ]]; then
      DRPCLI_VERSION="stable"
    else
      DRPCLI_VERSION="stable"
    fi

    SOURCE=$(grep "drpcli-$DRPCLI_VERSION:::" rackn-catalog.json | awk -F\" '{ print $4 }')
    SOURCE=${SOURCE##*:::}

    if [[ -z "$SOURCE" ]]; then
      echo -e "${CErr}FATAL${RCol} Unable to download '${DRPCLI_VERSION}' of 'drpcli'. Found versions:"
      grep NOJQSource.*drpcli-.*::: ./rackn-catalog.json | egrep "drpcli-sta|drpcli-tip|drpcli-v4" | awk -F'"' ' { print $4 }' | awk -F ':' ' { print $1 } '
      exit_cleanup 1 "Version was not found in the specified catalog."
    fi
    get "$SOURCE"/"$arch"/"$os"/drpcli
    DRPCLI_EXPECTED_SHA="$(grep -A9 "drpcli-$DRPCLI_VERSION:::" rackn-catalog.json | grep "$arch/$os" | awk -F\" '{print $4}')"
    DRPCLI_ACTUAL_SHA="$(sha256sum "$FILE" | awk '{print $1}')"
    if [[ "$DRPCLI_EXPECTED_SHA" != "$DRPCLI_ACTUAL_SHA" ]]; then
      echo -e "$PREF_ERR The sha256sum for $FILE is incorrect."
      exit_cleanup 1
    fi
    chmod +x drpcli
    ln -sf drpcli jq
  fi

  jq=${INSTALLATION_FOLDER}/jq

  if [[ AIRGAP_DRPCLI_MARKER -gt 1 ]]; then
    if [[ "$MODE" == "install" || "$MODE" == "upgrade" ]]
    then
        explode_airgap_tarball
    fi
    DRP_CATALOG="file://$DRP_HOME_DIR/tftpboot/files/rebar-catalog/rackn-catalog.json"
  fi
fi

# Requires catalog item name and version
# If an exact match is found - it returns that so we don't have to worry about
# stable or tip or a full version. If a partial version is found, returns the
# highest matching patch version
# If no matches are found returns nothing
get_latest_patch_version() {
  if [[ ! -e rackn-catalog.json ]] ; then
    get "$DRP_CATALOG" > /dev/null 2>&1
    mv rackn-catalog.json rackn-catalog.json.gz
    if ! gunzip rackn-catalog.json.gz ; then
      mv rackn-catalog.json.gz rackn-catalog.json
    fi
  fi

  # Make a filter to grab all the lines matching our input and sort as needed
  filter='.sections.catalog_items | map(select((.Name==$a1) and (.Version|test($a2))) | .Version | sub("^v"; "")) | map(select(test("-") | not)) | sort_by(.|split(".")|map(tonumber)) | .[-1]'
  if [[ $2 == tip || $2 == stable ]] ; then
    filter='.sections.catalog_items | map(select((.Name==$a1) and (.Version|test($a2))) | .Version | sub("^v"; "")) | .[-1]'
  fi
  version=$($jq -r --arg a1 "$1" --arg a2 "^$2" "$filter" rackn-catalog.json)
  if [[ "${version}" == "null" || "${version}" == "" ]]; then
      echo 0
  elif [[ "${version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
      echo "v$version"
  else
      echo "$version"
  fi
}

_drpcli() {
    RS_TOKEN="" "$INSTALLATION_FOLDER"/drpcli --ignore-unix-proxy "$@"
}

# a system under control of another DRP endpoint may have RS_ENDPOINT set, and
# this will cause various startup check procedures to fail or be wrong
export RS_ENDPOINT="https://127.0.0.1:$RS_API_PORT"

if [[ "$MODE" == "upgrade" ]]
then
    MODE=install
    UPGRADE=true
    force=true
    CNT_VOL_REMOVE=false
fi

case $MODE in
     build-airgap)
             _drpcli airgap build "${original_args[@]:1}"
             ;;
     get-drpcli)
             # Do nothing because once this is run drpcli will have been installed
             echo "drpcli has been installed in $INSTALLATION_FOLDER/drpcli"
             ;;
     extract)
             extract_airgap_tarball
             ;;
     explode)
             explode_airgap_tarball
             ;;
     install)
             DRP_VERSION=${DRP_VERSION:-"$DEFAULT_DRP_VERSION"}

             # Cluster-aware upgrade: all upgrade steps in one place, exits before the install flow.
             # Requires DRP to be running so drpcli system update can reach the API.
             if [[ "$UPGRADE" == "true" && "$ISOLATED" == "false" ]]; then
                 if ! pgrep dr-provision > /dev/null; then
                     echo -e "$PREF_ERR 'dr-provision' is NOT running, CANNOT upgrade ... please start service first"
                     exit_cleanup 9
                 fi
                 echo -e "$PREF_INFO 'dr-provision' is running, proceeding with cluster-aware upgrade ..."

                 # Fetch catalog and resolve the target DRP version
                 if [[ ! -e rackn-catalog.json ]] ; then
                     get $DRP_CATALOG
                     FILE=${DRP_CATALOG##*/}
                     mv ${FILE} rackn-catalog.json.gz
                     if ! gunzip rackn-catalog.json.gz 2>/dev/null >/dev/null ; then
                         mv rackn-catalog.json.gz rackn-catalog.json
                     fi
                 fi
                 DRP_VERSION=$(get_latest_patch_version "drp" "$DRP_VERSION")
                 if [ "${DRP_VERSION}" == 0 ]; then
                     echo "drp with version $DRP_VERSION not in catalog"
                     exit_cleanup 1
                 fi

                 # Obtain the DRP zip (no extraction needed; drpcli system update consumes it directly)
                 if [[ -n "$ZIP_FILE" ]]; then
                     [[ "$ZIP_FILE" != "dr-provision.zip" ]] && cp "$ZIP_FILE" dr-provision.zip
                 else
                     SOURCE=$(grep "drp-$DRP_VERSION:::" rackn-catalog.json | awk -F\" '{ print $4 }')
                     SOURCE=${SOURCE##*:::}
                     if [[ -z "$SOURCE" ]]; then
                         echo -e "${CErr}FATAL${RCol} Unable to download '${DRP_VERSION}' of DRP."
                         exit_cleanup 1 "Version was not found in the specified catalog."
                     fi
                     get $SOURCE || true
                     FILE=${SOURCE##*/}
                     if [[ ! -e $FILE ]] ; then
                         SOURCE=${SOURCE/.zip/.${arch}.${os}.zip}
                         get $SOURCE
                         FILE=${SOURCE##*/}
                     fi
                     mv $FILE dr-provision.zip
                 fi

                 echo -e "$PREF_OK Upgrading DRP binary via drpcli system update (cluster-aware)"
                 set_rs_key
                 check_drp_ready
                 # For HA clusters, point RS_ENDPOINT at the VIP so upgrade targets the active node
                 HA_VIRT_ADDR=$(_drpcli info get | jq -r '.ClusterState.VirtAddr // empty' | cut -d/ -f1)
                 if [[ -n "$HA_VIRT_ADDR" ]] ; then
                     export RS_ENDPOINT="https://$HA_VIRT_ADDR:$RS_API_PORT"
                     echo -e "$PREF_INFO HA cluster detected, using VIP $HA_VIRT_ADDR for upgrade"
                 fi
                 _drpcli system upgrade dr-provision.zip

                 if [[ $UPDATE_CONTENT == "true" ]]; then
                     check_drp_ready
                     check_catalog_url
                     echo -e "$PREF_OK Updating all content to latest compatible versions for drp."
                     _drpcli catalog item update-all --version=$(_drpcli info get | jq -r '.version' | cut -d. -f 1,2)
                 fi

                 exit_cleanup 0 "Upgrade complete"
             fi

             if [[ $NO_CONTENT == false ]]; then
                 DRP_CONTENT_VERSION="${DRP_VERSION}"
                 if [[ "$DRP_VERSION" =~ ^v[0-9]+.[0-9]+.[0-9]+$ ]]; then
                     DRP_CONTENT_VERSION="${DRP_VERSION%.*}"
                 fi
                 DRP_COMMUNITY_CONTENT_VERSION=$(get_latest_patch_version "drp-community-content" "$DRP_CONTENT_VERSION")
                 if [ "${DRP_COMMUNITY_CONTENT_VERSION}" == 0 ]; then
                     echo "drp-community-content with version $DRP_CONTENT_VERSION not in catalog"
                     exit 1
                 fi
                 DRP_FLEXIFLOW_VERSION=$(get_latest_patch_version "flexiflow" "$DRP_CONTENT_VERSION")
                 if [ "${DRP_FLEXIFLOW_VERSION}" == 0 ]; then
                     echo "flexiflow with version $DRP_CONTENT_VERSION not in catalog"
                     exit 1
                 fi
                 DRP_TASK_LIB_VERSION=$(get_latest_patch_version "task-library" "$DRP_CONTENT_VERSION")
                 if [ "${DRP_TASK_LIB_VERSION}" == 0 ]; then
                     echo "task-library with version $DRP_CONTENT_VERSION not in catalog"
                     exit 1
                 fi
                 DRP_VERSION=$(get_latest_patch_version "drp" "$DRP_VERSION")
                 if [ "${DRP_VERSION}" == 0 ]; then
                     echo "drp with version $DRP_CONTENT_VERSION not in catalog"
                     exit 1
                 fi
             fi

             # Check ports before attempting install.  This is tied closely with `drpcli preflight checkports`,
             #  `dr-provision --disable-[service]`, and `dr-provision --[service]-port` and their environment variables.
             if ! $_sudo _drpcli preflight > /dev/null 2>&1; then
                 echo -e "$PREF_WARN drpcli doesn't know how to check service ports.  If service ports are in use,"
                 echo -e "$PREF_WARN installation will fail.  Skipping..."
                 SKIP_PORT_CHECK=true
             fi

             if [[ ! "$SKIP_PORT_CHECK" == "true" ]]; then
                 echo -e "$PREF_INFO Checking service ports."
                 port_status=$(RS_DHCP_PORT=$RS_DHCP_PORT \
                        RS_DNS_PORT=$RS_DNS_PORT \
                        RS_TFTP_PORT=$RS_TFTP_PORT \
                        RS_BINL_PORT=$RS_BINL_PORT \
                        RS_METRICS_PORT=$RS_METRICS_PORT \
                        RS_STATIC_PORT=$RS_STATIC_PORT \
                        RS_STATIC_SECURE_PORT=$RS_STATIC_SECURE_PORT \
                        RS_API_PORT=$RS_API_PORT \
                        $_sudo _drpcli preflight checkports)
                 warnings=$(echo $port_status | $jq '.Warnings[]')
                 services=$(echo $port_status | $jq '.Services[]')
                 if [[ "$RS_DISABLE_DHCP" == "true" ]]; then
                     services=$(echo $services | $jq '. | del(select(.Service == "DHCP" ))' | $jq '. | select(. != null)')
                 fi
                 if [[ "$RS_DISABLE_DNS" == "true" ]]; then
                     services=$(echo $services | $jq '. | del(select(.Service == "DNS" ))' | $jq '. | select(. != null)')
                 fi

                 if [[ "$RS_DISABLE_TFTP_SERVER" == "true" ]]; then
                     services=$(echo $services | $jq '. | del(select(.Service == "TFTP" ))' | $jq '. | select(. != null)')
                 fi

                 if [[ "$RS_DISABLE_PXE" == "true" ]]; then
                     services=$(echo $services | $jq '. | del(select(.Service == "BINL" ))' | $jq '. | select(. != null)')
                 fi

                 if [[ "$RS_DISABLE_PROVISIONER" == "true" ]]; then
                     services=$(echo $services | $jq '. | del(select(.Service == "Static" ))' | $jq '. | select(. != null)')
                 fi

                 if [[ "$RS_DISABLE_SECURE_PROVISIONER" == "true" ]]; then
                     services=$(echo $services | $jq '. | del(select(.Service == "SecureStatic" ))' | $jq '. | select(. != null)')
                 fi

                 if [[ $warnings != "" ]]; then
                     echo -e "$PREF_WARN The following ports could not be checked."
                     echo "$warnings"
                 fi

                 if [[ $services != "" ]] && [[ $services != "null" ]]; then
                     echo -e "$PREF_ERR The following ports are in use.  Please correct before continuing."
                     echo "$services"
                     exit 57
                 fi
             fi
             # If Airgap markers are present, explode airgap contents and also get catalog
             if [[ AIRGAP_DRPCLI_MARKER -gt 1 ]]; then
               get "$DRP_CATALOG"
               FILE=${DRP_CATALOG##*/}
               set +e
               mv "${FILE}" rackn-catalog.json.gz
               if ! gunzip rackn-catalog.json.gz 2>/dev/null >/dev/null ; then
                  mv rackn-catalog.json.gz rackn-catalog.json
               fi
               set -e
             fi

             if [[ "$ISOLATED" == "false" || "$SKIP_RUN_CHECK" == "false" ]]; then
                 if pgrep dr-provision > /dev/null; then
                     echo -e "$PREF_ERR 'dr-provision' service is running, CANNOT install ... please stop service or container first"
                     echo -e "  Run ${IYel}$stopper${RCol}"
                     exit_cleanup 9
                 else
                     echo -e "$PREF_INFO 'dr-provision' service is not running, beginning install process ... "
                 fi
             else
                 echo -e "$PREF_INFO Skipping 'dr-provision' service run check as requested ..."
             fi

             [[ "$SKIP_DEPENDS" == "false" ]] && ensure_packages || echo -e "$PREF_INFO Skipping dependency checks as requested ... "

             if [[ "$ISOLATED" == "false" ]]; then
                 TMP_INSTALLER_DIR=$(mktemp -d ${TMPDIR}/drp.installer.XXXXXX)
                 echo -e "$PREF_INFO Using temp directory to extract artifacts to and install from ('$(c_file "$TMP_INSTALLER_DIR")')."
                 OLD_PWD=$(pwd)
                 cd $TMP_INSTALLER_DIR
                 TMP_INST=$TMP_INSTALLER_DIR/tools/install.sh
             fi

             # Are we in a build tree
             if [ -e server ] ; then
                 if [ ! -e bin/linux/amd64/drpcli ] ; then
                     echo "It appears that nothing has been built."
                     echo -e "Please run $(c_flag "tools/build.sh") and then rerun this command".
                     exit_cleanup 1
                 fi
             else
                 if [[ $UNIVERSAL == true ]]; then
                     echo -e "$PREF_INFO Universal Install Mode (will automatically bootstrap endpoint)"
                 else
                     # allow overriding the sleep timer with --non-interactive flag, for automation of DRP
                     # Endpoints that intentionally should not get any content (eg MSM managed Endpoints)
                     if [[ $NON_INTERACTIVE == false ]]; then
                         echo -e "$PREF_WARN Legacy Install Mode - operator will need to manage initial content"
                         echo -e "$PREF_WARN RECOMMENDED ACTION: Hit 'Ctrl-C' and install with '--universal' flag"
                         N=0; while (( N < $NO_UNI_SLEEP )); do printf "."; sleep 1; (( N++ )); done; echo
                     fi
                 fi

                 # We aren't a build tree, but are we extracted install yet?
                 # If not, get the requested version.
                 if [[ ! -e sha256sums || $force ]] ; then
                     echo -e "$PREF_OK Installing Version ${IGre}$DRP_VERSION${RCol} of ${ICya}Digital Rebar${RCol} (dr-provision) with $(c_def "$INSTALL_VERSION") install.sh"
                     if [[ $DRP_ID ]] ; then
                        echo -e "$PREF_INFO Using Endpoint ID ${IGre}$DRP_ID${RCol}."
                     else
                        echo -e "$PREF_INFO Using MAC based Endpoint ID.  Consider using '$(c_flag "--drp-id")' to set during installation."
                     fi
                     ZIP="dr-provision.zip"
                     SHA="dr-provision.sha256"
                     if [[ -n "$ZIP_FILE" ]]
                     then
                       [[ "$ZIP_FILE" != "dr-provision.zip" ]] && cp "$ZIP_FILE" dr-provision.zip
                       echo -e "$PREF_WARN  No sha256sum check performed for '$(c_flag "--zip-file")' mode."
                       echo "          We assume you've already verified your download file."
                       $tar -xf dr-provision.zip >> $DRP_DEBUGLOG
                     else
                       if [[ ! -e rackn-catalog.json ]] ; then
                         get $DRP_CATALOG
                         FILE=${DRP_CATALOG##*/}
                         mv ${FILE} rackn-catalog.json.gz
                         if ! gunzip rackn-catalog.json.gz 2>/dev/null >/dev/null ; then
                           mv rackn-catalog.json.gz rackn-catalog.json
                         fi
                       fi
                       SOURCE=$(grep "drp-$DRP_VERSION:::" rackn-catalog.json | awk -F\" '{ print $4 }')
                       SOURCE=${SOURCE##*:::}

                       if [[ -z "$SOURCE" ]]; then
                         echo -e "${CErr}FATAL${RCol} Unable to download '${DRP_VERSION}' of DRP. Found versions:"
                         grep NOJQSource.*drp-.*::: ./rackn-catalog.json | egrep "drp-sta|drp-tip|drp-v4" | awk -F'"' ' { print $4 }' | awk -F ':' ' { print $1 } '
                         exit_cleanup 1 "Version was not found in the specified catalog."
                       fi

                       get $SOURCE || true
                       FILE=${SOURCE##*/}
                       # if we couldn't find dr-provision.zip, then try os/arch based zip
                       if [[ ! -e $FILE ]] ; then
                           SOURCE=${SOURCE/.zip/.${arch}.${os}.zip}
                           get $SOURCE
                           FILE=${SOURCE##*/}
                       fi
                       mv $FILE $ZIP
                       $tar -xf dr-provision.zip >> $DRP_DEBUGLOG
                       $shasum -c sha256sums >> $DRP_DEBUGLOG || exit_cleanup 1
                     fi
                 fi
             fi

             if [[ $NO_CONTENT == false ]]; then
                 if [[ ! -e rackn-catalog.json ]] ; then
                   get $DRP_CATALOG
                   mv rackn-catalog.json rackn-catalog.json.gz
                   if ! gunzip rackn-catalog.json.gz ; then
                     mv rackn-catalog.json.gz rackn-catalog.json
                   fi
                 fi
                 echo -e "$PREF_OK Installing Version ${IGre}${DRP_COMMUNITY_CONTENT_VERSION}${RCol} of ${ICya}Digital Rebar Community Content${RCol}"
                 if [[ -n "$ZIP_FILE" ]]; then
                   echo -e "$PREF_WARN '$(c_flag "--zip-file")' specified, still trying to download community content..."
                   echo "         (specify '$(c_flag "--no-content")' to skip download of community content"
                 fi

                 SOURCE=$(grep "drp-community-content-$DRP_COMMUNITY_CONTENT_VERSION:::" rackn-catalog.json | awk -F\" '{ print $4 }')
                 SOURCE=${SOURCE##*:::}

                 get $SOURCE
                 FILE=${SOURCE##*/}
                 COMMUNITY_EXPECTED_SHA="$($jq -r ".sections.catalog_items.\"drp-community-content-$DRP_COMMUNITY_CONTENT_VERSION\".Shasum256.\"any/any\"" rackn-catalog.json)"
                 COMMUNITY_ACTUAL_SHA="$(sha256sum "$FILE" | awk '{print $1}')"
                 if [[ "$COMMUNITY_EXPECTED_SHA" == "$COMMUNITY_ACTUAL_SHA" ]]; then
                   mv "$FILE" drp-community-content.json
                 else
                   echo -e "$PREF_ERR The sha256sum for $FILE is incorrect."
                   exit_cleanup 1
                 fi
             fi

             if [[ $ISOLATED == false ]]; then
                 setup_system_user

                 if [[ $initfile ]]; then
                     if [[ -r $initdest ]]
                     then
                         echo -e "$PREF_WARN"
                         echo -e "${CWarn}  initfile ('$initfile') exists already, not overwriting it${RCol}"
                         echo -e "${CWarn}  please verify 'dr-provision' startup options are correct${RCol}"
                         echo -e "${CWarn}  for your environment and the new version .. ${RCol}"
                         echo
                         echo -e "${CWarn}  specifically verify: '${CFlag}--file-root=$(c_def "<tftpboot directory>${CWarn}'")"
                     else
#                         $_sudo bash -c { sed "s:/usr/local/bin/dr-provision:$PROVISION:g" "${TMP_INSTALLER_DIR}/${initfile}" > "$initdest" }
                         echo "sed 's:/usr/local/bin/dr-provision:$PROVISION:g' \"${TMP_INSTALLER_DIR}/${initfile}\" > \"$initdest\"" | $_sudo bash

                         if grep -q WorkingDirectory "$initdest"; then
                            $_sudo sed "s:^WorkingDirectory.*:WorkingDirectory=$DRP_HOME_DIR:" "$initdest" > i2
                         else
                            $_sudo sed "s:^ExecStart.*:WorkingDirectory=$DRP_HOME_DIR\n&:" "$initdest" > i2
                         fi

                         $_sudo cp -f i2 "$initdest"

                         if command -v restorecon &> /dev/null; then
                           $_sudo restorecon -v "$initdest"
                         fi

                     fi
                     # output our startup helper messages only if SYSTEMD isn't specified
                     if [[ "$SYSTEMD" == "false" || "$STARTUP" == "false" ]]; then
                        echo
                        echo -e "$PREF_INFO Tips for ${BIYel}systemd${RCol} management of ${ICya}Digital Rebar${RCol} service:"
                        echo -e "  Enable: ${IYel}$enabler${RCol}"
                        echo -e "  Start:  ${IYel}$starter${RCol}"
                        echo -e "  Stop:   ${IYel}$stopper${RCol}"
                        echo -e "  Status: ${IYel}$_sudo systemctl status dr-provision${RCol}"
                        echo -e "  Logs:   ${IYel}$_sudo journalctl -u dr-provision${RCol}"
                    else
                        echo -e "$PREF_INFO Will attempt to execute startup procedures ('$(c_flag "--startup")' specified)"
                        echo -e "  ${IYel}$starter${RCol}"
                        echo -e "  ${IYel}$enabler${RCol}"
                    fi
                 fi

                 if [[ ! -e ${DRP_HOME_DIR}/digitalrebar/tftpboot && -e /var/lib/tftpboot ]] ; then
                     echo -e "$PREF_OK Moving $(c_file "/var/lib/tftpboot") to $(c_file "$DRP_HOME_DIR/tftpboot") location ... "
                     $_sudo mv /var/lib/tftpboot ${DRP_HOME_DIR}
                 fi

                 # Make sure bindest exists
                 $_sudo mkdir -p "$bindest"

                 # move aside/preserve an existing drpcli - this machine might be under
                 # control of another DRP Endpoint, and this will break the installer (text file busy)
                 if [[ -f "$CLI" ]]; then
                     echo -e "$PREF_OK Saving '$(c_file "${BIN_DIR}/drpcli")' to backup file ($(c_file "$CLI_BKUP"))"
                     $_sudo mv "$CLI" "$CLI_BKUP"
                 fi

                 INST="${BIN_DIR}/drp-install.sh"
                 $_sudo cp $TMP_INST $INST && $_sudo chmod 755 $INST
                 echo -e  "$PREF_INFO Install script saved to '$(c_file "$INST")'"
                 echo -e "$PREF_INFO To ${BIYel}uninstall${RCol} DRP use '${IRed}$_sudo $INST remove${RCol}' (must be ${IYel}root${RCol}, use '${IRed}--remove-data${RCol}' to remove all data)"

                 TFTP_DIR="${DRP_HOME_DIR}/tftpboot"
                 $_sudo cp "$binpath"/* "$bindest"

                 if [[ "$CREATE_SYMLINKS" == "true" ]] && [[ -n "$SYMLINK_BIN_DIR" ]] && [[ "$SYMLINK_BIN_DIR" != "$bindest" ]]; then
                     echo -e "$PREF_OK Creating symlinks in $(c_file "$SYMLINK_BIN_DIR") -> $(c_file "$bindest")"
                     $_sudo mkdir -p "$SYMLINK_BIN_DIR"
                     for _bin in dr-provision drpcli drbundler drpjoin dr-waltool drpjq drp-install.sh; do
                         [[ -f "$bindest/$_bin" ]] && $_sudo ln -sf "$bindest/$_bin" "$SYMLINK_BIN_DIR/$_bin" || true
                     done
                 fi

                 setcap_drp_binary

                 set_ownership_of_drp

                 if [[ $SYSTEMD == true ]] ; then
                 # dr-provision now supports configuring itself using systemd.
                   if grep -q "config-service" <<<$($PROVISION --help); then
                     # Use dr-provision to configure systemd.
                     # To make sure everything is properly passed, export all the things.
                     [[ $RESTART_SECONDS ]] && export RESTART_SECONDS="$RESTART_SECONDS"
                     [[ $START_LIMIT_INTERVAL ]] && export START_LIMIT_INTERVAL="$START_LIMIT_INTERVAL"
                     [[ $START_LIMIT_BURST ]] && export START_LIMIT_BURST="$START_LIMIT_BURST"
                     [[ $SYSTEMD_ADDITIONAL_SERVICES ]] && export SYSTEMD_ADDITIONAL_SERVICES="$SYSTEMD_ADDITIONAL_SERVICES"
                     [[ $DRP_HOME_DIR ]] && export RS_BASE_ROOT="$DRP_HOME_DIR"
                     [[ $SYSTEM_USER ]] && export SYSTEM_USER="$SYSTEM_USER"
                     [[ $SYSTEM_GROUP ]] && export SYSTEM_GROUP="$SYSTEM_GROUP"
                     [[ $RS_SERVER_HOSTNAME ]] && export RS_SERVER_HOSTNAME="$RS_SERVER_HOSTNAME"
                     [[ $DRP_ID ]] && export RS_DRP_ID="$DRP_ID"
                     [[ $HA_ID ]] && export RS_HA_ID="$HA_ID"
                     [[ $HA_ENABLED ]] && export RS_HA_ENABLED="$HA_ENABLED"
                     [[ $HA_INTERFACE ]] && export RS_HA_INTERFACE="$HA_INTERFACE"
                     [[ $HA_ADDRESS ]] && export RS_HA_ADDRESS="$HA_ADDRESS"
                     [[ $HA_PASSIVE ]] && export RS_HA_PASSIVE="$HA_PASSIVE"
                     [[ $HA_TOKEN ]] && export RS_HA_TOKEN="$HA_TOKEN"
                     [[ $IPADDR ]] && IPADDR="${IPADDR///*}" && export RS_STATIC_IP="$IPADDR"
                     if [[ $LOCAL_UI == "true" ]]; then
                       export RS_LOCAL_UI="tftpboot/files/ux"
                       export RS_UI_URL="/ux"
                     fi
                     [[ $CREATE_SELF == "true" ]] && export RS_CREATE_SELF=true
                     [[ $START_RUNNER == "true" ]] && export RS_START_RUNNER=true
                     [[ $RS_DISABLE_TFTP_SERVER ]] && export RS_DISABLE_TFTP_SERVER=true
                     [[ $RS_DISABLE_PROVISIONER ]] && export RS_DISABLE_PROVISIONER=true
                     [[ $RS_DISABLE_SECURE_PROVISIONER ]] && export RS_DISABLE_SECURE_PROVISIONER=true
                     [[ $RS_DISABLE_DNS ]] && export RS_DISABLE_DNS=true
                     [[ $RS_DISABLE_DHCP ]] && export RS_DISABLE_DHCP=true
                     [[ $RS_DISABLE_PXE ]] && export RS_DISABLE_PXE=true
                     [[ $RS_METRICS_PORT ]] && export RS_METRICS_PORT="$RS_METRICS_PORT"
                     [[ $RS_STATIC_PORT ]] && export RS_STATIC_PORT="$RS_STATIC_PORT"
                     [[ $RS_STATIC_SECURE_PORT ]] && export RS_STATIC_SECURE_PORT="$RS_STATIC_SECURE_PORT"
                     [[ $RS_TFTP_PORT ]] && export RS_TFTP_PORT="$RS_TFTP_PORT"
                     [[ $RS_API_PORT ]] && export RS_API_PORT="$RS_API_PORT"
                     [[ $RS_DNS_PORT ]] && export RS_DNS_PORT="$RS_DNS_PORT"
                     [[ $RS_DHCP_PORT ]] && export RS_DHCP_PORT="$RS_DHCP_PORT"
                     [[ $RS_BINL_PORT ]] && export RS_BINL_PORT="$RS_BINL_PORT"
                     [[ $RS_CLIENT_CERT_AUTH == "true" ]] && export RS_CLIENT_CERT_AUTH=true
                     [[ $RS_CA_CERT_FILE ]] && export RS_CA_CERT_FILE="$RS_CA_CERT_FILE"

                     ${_sudo:+${_sudo} -E} $PROVISION --config-service --force-config
                   else
                     # The version of dr-provision isn't able to configure systemd.
                     if [[ ${SYSTEMD_ADDITIONAL_SERVICES} != "" ]] ; then
                         sed -i "s/^After=network.target\$/After=network.target,${SYSTEMD_ADDITIONAL_SERVICES}/" /etc/systemd/system/dr-provision.service
                     fi

                     $_sudo mkdir -p /etc/systemd/system/dr-provision.service.d
                     $_sudo bash -c "cat > /etc/systemd/system/dr-provision.service.d/user.conf <<EOF
[Service]
Restart=always
RestartSec=${RESTART_SECONDS}
StartLimitInterval=${START_LIMIT_INTERVAL}
StartLimitBurst=${START_LIMIT_BURST}
User=${SYSTEM_USER}
Group=${SYSTEM_GROUP}
Environment=RS_BASE_ROOT=${DRP_HOME_DIR}
EOF"
                     if command -v restorecon > /dev/null 2>&1 ; then
                       rs=$(command -v restorecon)
                       $_sudo bash -c "cat > /etc/systemd/system/dr-provision.service.d/selinux.conf <<EOF
[Service]
ExecStartPre=-$rs -v $PROVISION
EOF"
                     else
                       echo -e "$PREF_WARN restorecon command not found, systemd will not be able to set selinux label on dr-provision binary."
                     fi

                     if [[ ${SYSTEM_USER} != "root" ]]; then
                       if command -v setcap > /dev/null 2>&1 ; then
                         sc=$(command -v setcap)
                         $_sudo bash -c "cat > /etc/systemd/system/dr-provision.service.d/setcap.conf <<EOF
[Service]
PermissionsStartOnly=true
ExecStartPre=-$sc \"cap_net_raw,cap_net_bind_service=+ep\" $PROVISION
Environment=RS_EXIT_ON_CHANGE=true
Environment=RS_PLUGIN_COMM_ROOT=pcr
EOF"
                       else
                         echo -e "$PREF_WARN setcap command not found, systemd will not be able to set capabilities on dr-provision binary."
                       fi
                     fi

                     if [[ $RS_SERVER_HOSTNAME ]] ; then
                       $_sudo bash -c "cat > /etc/systemd/system/dr-provision.service.d/hostname.conf <<EOF
[Service]
Environment=RS_SERVER_HOSTNAME=$RS_SERVER_HOSTNAME
EOF"
                     fi
                     if [[ $DRP_ID ]] ; then
                       $_sudo bash -c "cat > /etc/systemd/system/dr-provision.service.d/drpid.conf <<EOF
[Service]
Environment=RS_DRP_ID=$DRP_ID
EOF"
                     fi
                     if [[ $HA_ID ]] ; then
                       $_sudo bash -c "cat > /etc/systemd/system/dr-provision.service.d/haid.conf <<EOF
[Service]
Environment=RS_HA_ID=$HA_ID
EOF"
                     fi
                     if [[ "$HA_ENABLED" == "true" ]] ; then
                       $_sudo bash -c "cat > /etc/systemd/system/dr-provision.service.d/ha.conf <<EOF
[Service]
Environment=RS_HA_ENABLED=true
Environment=RS_HA_INTERFACE=$HA_INTERFACE
Environment=RS_HA_ADDRESS=$HA_ADDRESS
Environment=RS_HA_PASSIVE=$HA_PASSIVE
Environment=RS_HA_TOKEN=$HA_TOKEN
EOF"
                     fi
                     if [[ $IPADDR ]] ; then
                       IPADDR="${IPADDR///*}"
                       $_sudo bash -c "cat > /etc/systemd/system/dr-provision.service.d/ipaddr.conf <<EOF
[Service]
Environment=RS_STATIC_IP=$IPADDR
Environment=RS_FORCE_STATIC=true
EOF"
                     fi
                     if [[ $LOCAL_UI == true ]] ; then
                       $_sudo bash -c "cat > /etc/systemd/system/dr-provision.service.d/local-ui.conf <<EOF
[Service]
Environment=RS_LOCAL_UI=tftpboot/files/ux
Environment=RS_UI_URL=/ux
EOF"
                     fi
                     if [[ $CREATE_SELF == true ]] ; then
                       $_sudo bash -c "cat > /etc/systemd/system/dr-provision.service.d/create-self.conf <<EOF
[Service]
Environment=RS_CREATE_SELF=$CREATE_SELF
EOF"
                     fi
                     if [[ $START_RUNNER == true ]] ; then
                       $_sudo bash -c "cat > /etc/systemd/system/dr-provision.service.d/start-runner.conf <<EOF
[Service]
Environment=RS_START_RUNNER=$START_RUNNER
EOF"
                     fi
                    if [[ $RS_DISABLE_TFTP_SERVER == true ]] ; then
                        $_sudo bash -c "cat > /etc/systemd/system/dr-provision.service.d/disable-tftp.conf <<EOF
[Service]
Environment=RS_DISABLE_TFTP_SERVER=true
EOF"
                    fi
                    if [[ $RS_DISABLE_PROVISIONER == true ]] ; then
                        $_sudo bash -c "cat > /etc/systemd/system/dr-provision.service.d/disable-provisioner.conf <<EOF
[Service]
Environment=RS_DISABLE_PROVISIONER=true
EOF"
                    fi
                    if [[ $RS_DISABLE_SECURE_PROVISIONER == true ]] ; then
                        $_sudo bash -c "cat > /etc/systemd/system/dr-provision.service.d/disable-secure-provisioner.conf <<EOF
[Service]
Environment=RS_DISABLE_SECURE_PROVISIONER=true
EOF"
                    fi
                    if [[ $RS_DISABLE_DNS == true ]] ; then
                        $_sudo bash -c "cat > /etc/systemd/system/dr-provision.service.d/disable-dns.conf <<EOF
[Service]
Environment=RS_DISABLE_DNS=true
EOF"
                    fi
                    if [[ $RS_DISABLE_DHCP == true ]] ; then
                        $_sudo bash -c "cat > /etc/systemd/system/dr-provision.service.d/disable-dhcp.conf <<EOF
[Service]
Environment=RS_DISABLE_DHCP=true
EOF"
                    fi
                    if [[ $RS_DISABLE_PXE == true ]] ; then
                        $_sudo bash -c "cat > /etc/systemd/system/dr-provision.service.d/disable-pxe.conf <<EOF
[Service]
Environment=RS_DISABLE_PXE=true
EOF"
                    fi
                    if [[ "$RS_METRICS_PORT" != "" ]] ; then
                        $_sudo bash -c "cat > /etc/systemd/system/dr-provision.service.d/metrics-port.conf <<EOF
[Service]
Environment=RS_METRICS_PORT=$RS_METRICS_PORT
EOF"
                    fi
                    if [[ "$RS_STATIC_PORT" != "" ]] ; then
                       $_sudo bash -c "cat > /etc/systemd/system/dr-provision.service.d/static-port.conf <<EOF
[Service]
Environment=RS_STATIC_PORT=$RS_STATIC_PORT
EOF"
                    fi
                    if [[ "$RS_STATIC_SECURE_PORT" != "" ]] ; then
                        $_sudo bash -c "cat > /etc/systemd/system/dr-provision.service.d/static-secure-port.conf <<EOF
[Service]
Environment=RS_STATIC_SECURE_PORT=$RS_STATIC_SECURE_PORT
EOF"
                    fi
                    if [[ "$RS_TFTP_PORT" != "" ]] ; then
                        $_sudo bash -c "cat > /etc/systemd/system/dr-provision.service.d/tftp-port.conf <<EOF
[Service]
Environment=RS_TFTP_PORT=$RS_TFTP_PORT
EOF"
                    fi
                    if [[ "$RS_API_PORT" != "" ]] ; then
                        $_sudo bash -c "cat > /etc/systemd/system/dr-provision.service.d/api-port.conf <<EOF
[Service]
Environment=RS_API_PORT=$RS_API_PORT
EOF"
                    fi
                    if [[ "$RS_DNS_PORT" != "" ]] ; then
                        $_sudo bash -c "cat > /etc/systemd/system/dr-provision.service.d/dns-port.conf <<EOF
[Service]
Environment=RS_DNS_PORT=$RS_DNS_PORT
EOF"
                    fi
                    if [[ "$RS_DHCP_PORT" != "" ]] ; then
                        $_sudo bash -c "cat > /etc/systemd/system/dr-provision.service.d/dhcp-port.conf <<EOF
[Service]
Environment=RS_DHCP_PORT=$RS_DHCP_PORT
EOF"
                    fi
                    if [[ "$RS_BINL_PORT" != "" ]] ; then
                        $_sudo bash -c "cat > /etc/systemd/system/dr-provision.service.d/binl-port.conf <<EOF
[Service]
Environment=RS_BINL_PORT=$RS_BINL_PORT
EOF"
                     fi
                    if [[ $RS_USE_ISOFS ]] ; then
                        $_sudo bash -c "cat > /etc/systemd/system/dr-provision.service.d/isofs.conf <<EOF
[Service]
Environment=RS_USE_ISOFS=$RS_USE_ISOFS
EOF"
                    fi
                    if [[ $RS_CLIENT_CERT_AUTH == true ]] ; then
                        $_sudo bash -c "cat > /etc/systemd/system/dr-provision.service.d/client-cert-auth.conf <<EOF
[Service]
Environment=RS_CLIENT_CERT_AUTH=true
EOF"
                    fi
                  fi
                     eval "$enabler"
                     eval "$starter"

                    if [[ $RS_CA_CERT_FILE ]] ; then
                      echo -e "$PREF_OK Uploading client cert file: $RS_CA_CERT_FILE"
                      $_sudo _drpcli system certs client set "$RS_CA_CERT_FILE"
                    fi

                         check_drp_ready

                         if [[ "$LICENSE_FILE" != "" ]] ; then
                             echo -e "$PREF_OK Uploading license file: $LICENSE_FILE"
                             if [[ -f "${OLD_PWD}/$LICENSE_FILE" ]] ; then
                                 _drpcli contents upload "${OLD_PWD}/$LICENSE_FILE" >/dev/null
                             elif [[ -f "$LICENSE_FILE" ]] ; then
                                 _drpcli contents upload "$LICENSE_FILE" >/dev/null
                             else
                                 echo -e "$(c_err "FATAL"): license file, $LICENSE_FILE, not found"
                                 exit 1
                             fi
                         fi

                         # Check catalog url, in case of airgap point to the right catalog
                         check_catalog_url

                         if [[ $NO_CONTENT == false ]] ; then
                             _drpcli catalog item install drp-community-content --version=${DRP_COMMUNITY_CONTENT_VERSION}  >> $DRP_DEBUGLOG
                             _drpcli catalog item install flexiflow --version=${DRP_FLEXIFLOW_VERSION}  >> $DRP_DEBUGLOG
                             _drpcli catalog item install task-library --version=${DRP_TASK_LIB_VERSION}  >> $DRP_DEBUGLOG

                             if [[ "$INITIAL_CONTENTS" != "" ]] ; then
                                 OLD_IFS="${IFS}" # nosemgrep: ifs-tampering -- saved here, restored as IFS="${OLD_IFS}" below
                                 IFS=',' read -ra contents_array <<< "$INITIAL_CONTENTS"
                                 for i in "${contents_array[@]}" ; do
                                     echo -e "$PREF_OK Installing content item '$i'"
                                     if [[ -f ${OLD_PWD}/$i ]] ; then
                                         _drpcli contents upload ${OLD_PWD}/${i}  >> $DRP_DEBUGLOG
                                     elif [[ -f "$i" ]] ; then
                                         _drpcli contents upload ${i}  >> $DRP_DEBUGLOG
                                     elif [[ $i == http* ]] ; then
                                         _drpcli contents upload ${i} >> $DRP_DEBUGLOG
                                     else
                                         _drpcli catalog item install ${i} --version=${DRP_CONTENT_VERSION} -c $DRP_CATALOG  >> $DRP_DEBUGLOG
                                     fi
                                 done
                                 IFS="${OLD_IFS}"
                             fi

			     if [[ "$LOCAL_UI" == "true" ]] ; then
                                 if _drpcli catalog item show drp-ux -c $DRP_CATALOG > /dev/null 2>&1 ; then
                                     echo -e "$PREF_INFO Install Local UI from catalog: '$(c_flag "$DRP_CATALOG")'"
                                     _drpcli catalog item install drp-ux --version=${DRP_CONTENT_VERSION} -c $DRP_CATALOG  >> $DRP_DEBUGLOG
			         else

                                     echo -e "$PREF_ERR ${IRed}NOTICE:${RCol} Portal/UX/UI content not found in specified catalog"
                                     echo -e "    Current Catalog Location: '$DRP_CATALOG'"
                                     echo -e "    Specify correct Catalog; or contact RackN for the UX Catalog source location."
			         fi
                             fi

                             if [[ "$INITIAL_PLUGINS" != "" ]] ; then
                                 OLD_IFS="${IFS}" # nosemgrep: ifs-tampering -- saved here, restored as IFS="${OLD_IFS}" below
                                 IFS=',' read -ra plugins_array <<< "$INITIAL_PLUGINS"
                                 for i in "${plugins_array[@]}" ; do
                                     echo -e "$PREF_OK Installing plugin item '$i'"
                                     if [[ -f ${OLD_PWD}/$i ]] ; then
                                         _drpcli plugin_providers upload ${OLD_PWD}/${i} >> $DRP_DEBUGLOG
                                     elif [[ $i == http* ]] ; then
                                         _drpcli plugin_providers upload ${i} >> $DRP_DEBUGLOG
                                     else
                                         _drpcli catalog item install ${i} --version=${DRP_CONTENT_VERSION} -c $DRP_CATALOG  >> $DRP_DEBUGLOG
                                     fi
                                 done
                                 IFS="${OLD_IFS}"
                             fi

                             if [[ "$INITIAL_PROFILES" != "" ]] ; then
                                 if [[ $CREATE_SELF == true ]] ; then
                                     echo -e "$PREF_OK Installing initial profiles..."
                                   cp $INSTALLATION_FOLDER/drpcli ${TMPDIR}/jq
                                   chmod +x ${TMPDIR}/jq
                                   ID=$(_drpcli info get | ${TMPDIR}/jq .id -r | sed -r 's/:/-/g')
                                   rm ${TMPDIR}/jq
                                   # create-self registers the machine asynchronously; wait for it
                                   _MCOUNT=0
                                   while ! _drpcli machines exists "Name:$ID" >/dev/null 2>&1 ; do
                                     (( ++_MCOUNT ))
                                     if (( _MCOUNT > $START_WAIT_TIME )) ; then
                                       echo -e "$PREF_WARN Machine Name:$ID not found after waiting; skipping initial profile assignment"
                                       break
                                     fi
                                     sleep 2
                                   done
                                   OLD_IFS="${IFS}" # nosemgrep: ifs-tampering -- saved here, restored as IFS="${OLD_IFS}" below
                                   IFS=',' read -ra profiles_array <<< "$INITIAL_PROFILES"
                                   if _drpcli machines exists "Name:$ID" >/dev/null 2>&1 ; then
                                     for i in "${profiles_array[@]}" ; do
                                       if ! _drpcli profiles exists "$i" >/dev/null 2>/dev/null ; then
                                         echo -e "$PREF_WARN Profile $i doesn't exist - skipping"
                                         continue
                                       fi
                                       _drpcli machines addprofile "Name:$ID" "$i" >> $DRP_DEBUGLOG
                                     done
                                   fi
                                   IFS="${OLD_IFS}"
                                 fi
                             fi

                             if [[ "$INITIAL_PARAMETERS" != "" ]] ; then
                                 if [[ $CREATE_SELF == true ]] ; then
                                   echo -e "$PREF_OK Installing initial parameters..."
                                   cp $INSTALLATION_FOLDER/drpcli ${TMPDIR}/jq
                                   chmod +x ${TMPDIR}/jq
                                   ID=$(_drpcli info get | ${TMPDIR}/jq .id -r | sed -r 's/:/-/g')
                                   rm ${TMPDIR}/jq
                                   OLD_IFS="${IFS}" # nosemgrep: ifs-tampering -- saved here, restored as IFS="${OLD_IFS}" below
                                   IFS=',' read -ra param_array <<< "$INITIAL_PARAMETERS"
                                   for i in "${param_array[@]}" ; do
                                     IFS="=" read -ra data_array <<< "$i"
                                     _drpcli machines set "Name:$ID" param "${data_array[0]}" to "${data_array[1]}" >> $DRP_DEBUGLOG
                                   done
                                   IFS="${OLD_IFS}"
                                 fi
                             fi

                             if [[ "$INITIAL_WORKFLOW" != "" ]] ; then
                                 if [[ $CREATE_SELF == true ]] ; then
                                     cp $INSTALLATION_FOLDER/drpcli ${TMPDIR}/jq
                                     chmod +x ${TMPDIR}/jq
                                     ID=$(_drpcli info get | ${TMPDIR}/jq .id -r | sed -r 's/:/-/g')
                                     rm ${TMPDIR}/jq
                                     echo -e "$PREF_OK Setting initial workflow to '$INITIAL_WORKFLOW' for Machine '$ID'"
                                     _drpcli machines update "Name:$ID" "{ \"Workflow\": \"$INITIAL_WORKFLOW\", \"WorkOrderMode\": false, \"Locked\": false }" >/dev/null
                                 fi
                             fi

                             if [[ "$INITIAL_SUBNETS" != "" ]] ; then
                                 if [[ $CREATE_SELF == true ]] ; then
                                     OLD_IFS="${IFS}" # nosemgrep: ifs-tampering -- saved here, restored as IFS="${OLD_IFS}" below
                                     IFS=',' read -ra subnet_array <<< "$INITIAL_SUBNETS"
                                     for i in "${subnet_array[@]}" ; do
                                       if [[ $i == http* ]] ; then
                                         echo -e "$PREF_OK Creating subnet from URL '$i'"
                                         _drpcli subnets create ${i} >> $DRP_DEBUGLOG
                                       elif [[ -f ${OLD_PWD}/$i ]] ; then
                                         echo -e "$PREF_OK Creating subnet from file '${OLD_PWD}/$i'"
                                         _drpcli subnets create ${OLD_PWD}/${i} >> $DRP_DEBUGLOG
                                       elif [[ -f "$i" ]] ; then
                                         echo -e "$PREF_OK Creating subnet from file '${i}'"
                                         _drpcli subnets create ${i} >> $DRP_DEBUGLOG
                                       else
                                         echo -e "$PREF_WARN unable to read subnet file '$i' or '${OLD_PWD}/$i'; no SUBNET created"
                                       fi
                                     done
                                     IFS="${OLD_IFS}"
                                 fi
                             fi
                         fi

                    if [[ $DRP_USER || $DRP_PASSWORD ]]; then
                      user="rocketskates"
                      pass="r0cketsk8ts"
                      [[ "$DRP_USER" ]] && user="$DRP_USER"
                      [[ "$DRP_PASSWORD" ]] && pass="$DRP_PASSWORD"
                      if [[ "$user" != "rocketskates" ]]; then
                        if _drpcli users exists "$user" >/dev/null 2>&1; then
                          echo -e "$PREF_OK Updating DRP_USER..."
                          _drpcli users update "$user" "{ \"Name\": \""$user"\", \"Roles\": [ \"superuser\" ] }" >> $DRP_DEBUGLOG
                        else
                          echo -e "$PREF_OK Creating DRP_USER..."
                          _drpcli users create "{ \"Name\": \""$user"\", \"Roles\": [ \"superuser\" ] }" >> $DRP_DEBUGLOG
                        fi
                      fi
                      echo -e "$PREF_OK Changing DRP_PASSWORD..."
                      _drpcli users password "$user" "$pass" >> $DRP_DEBUGLOG
                      export RS_KEY="$user:$pass"
                      if ! _drpcli -x info check >/dev/null 2>&1; then
                        echo -e "$(c_err "FATAL"): Newly created user/pass not working - bailing out."
                        exit 1
                      fi
                      if [[ "$REMOVE_RS" == "true" && "$user" != "rocketskates" ]] ; then
                        echo -en "$PREF_INFO Removing default DRP_USER..."
                        _drpcli users destroy rocketskates >> "$DRP_DEBUGLOG"
                      fi
                    fi

                     if [[ "$BOOTSTRAP" == "true" ]] ; then
                         _drpcli files upload dr-provision.zip as bootstrap/dr-provision.zip >> $DRP_DEBUGLOG
                         _drpcli files upload $TMP_INST as bootstrap/install.sh >> $DRP_DEBUGLOG
                     fi
                     # If the catalog contains ux, then install it
                     if [[ -d "${DRP_HOME_DIR}/tftpboot/files/rebar-catalog/drp-ux" ]]; then
                        _drpcli catalog item install drp-ux --version=${DRP_CONTENT_VERSION} >> $DRP_DEBUGLOG
                     fi
                 else
                     if [[ "$STARTUP" == "true" ]]; then
                         echo -e "$PREF_INFO Attempting startup of 'dr-provision' ('$(c_flag "--startup")' specified)"
                         eval "$enabler"
                         eval "$starter"

                         check_drp_ready
                         # Check catalog url, in case of airgap point to the right catalog
                         check_catalog_url

                         if [[ "$NO_CONTENT" == "false" ]] ; then
                             _drpcli catalog item install task-library --version=${DRP_CONTENT_VERSION} -c $DRP_CATALOG >> $DRP_DEBUGLOG

                             if [[ "$INITIAL_CONTENTS" != "" ]] ; then
                                 IFS=',' read -ra contents_array <<< "$INITIAL_CONTENTS"
                                 for i in "${contents_array[@]}" ; do
                                     if [[ -f ${OLD_PWD}/$i ]] ; then
                                         _drpcli contents upload ${OLD_PWD}/${i} >> $DRP_DEBUGLOG
                                     elif [[ $i == http* ]] ; then
                                         _drpcli contents upload ${i} >> $DRP_DEBUGLOG
                                     else
                                         _drpcli catalog item install ${i} --version=${DRP_CONTENT_VERSION} -c $DRP_CATALOG >> $DRP_DEBUGLOG
                                     fi
                                 done
                             fi

                             if [[ "$INITIAL_PLUGINS" != "" ]] ; then
                                 IFS=',' read -ra plugins_array <<< "$INITIAL_PLUGINS"
                                 for i in "${plugins_array[@]}" ; do
                                     if [[ -f ${OLD_PWD}/$i ]] ; then
                                         _drpcli plugin_providers upload ${OLD_PWD}/${i} >> $DRP_DEBUGLOG
                                     elif [[ $i == http* ]] ; then
                                         _drpcli plugin_providers upload ${i} >> $DRP_DEBUGLOG
                                     else
                                         _drpcli catalog item install ${i} --version=${DRP_CONTENT_VERSION} -c $DRP_CATALOG >> $DRP_DEBUGLOG
                                     fi
                                 done
                             fi

                             if [[ "$INITIAL_PROFILES" != "" ]] ; then
                                 if [[ $CREATE_SELF == true ]] ; then
                                   cp $INSTALLATION_FOLDER/drpcli ${TMPDIR}/jq
                                   chmod +x ${TMPDIR}/jq
                                   ID=$(_drpcli info get | ${TMPDIR}/jq .id -r | sed -r 's/:/-/g')
                                   rm ${TMPDIR}/jq
                                   _MCOUNT=0
                                   while ! _drpcli machines exists "Name:$ID" >/dev/null 2>&1 ; do
                                     (( ++_MCOUNT ))
                                     if (( _MCOUNT > $START_WAIT_TIME )) ; then
                                       echo -e "$PREF_WARN Machine Name:$ID not found after waiting; skipping initial profile assignment"
                                       break
                                     fi
                                     sleep 2
                                   done
                                   IFS=',' read -ra profiles_array <<< "$INITIAL_PROFILES"
                                   if _drpcli machines exists "Name:$ID" >/dev/null 2>&1 ; then
                                     for i in "${profiles_array[@]}" ; do
                                       _drpcli machines addprofile "Name:$ID" "$i" >> $DRP_DEBUGLOG
                                     done
                                   fi
                                 fi
                             fi

                             if [[ "$INITIAL_PARAMETERS" != "" ]] ; then
                                 if [[ $CREATE_SELF == true ]] ; then
                                   cp $INSTALLATION_FOLDER/drpcli ${TMPDIR}/jq
                                   chmod +x ${TMPDIR}/jq
                                   ID=$(_drpcli info get | ${TMPDIR}/jq .id -r | sed -r 's/:/-/g')
                                   rm ${TMPDIR}/jq
                                   IFS=',' read -ra param_array <<< "$INITIAL_PARAMETERS"
                                   for i in "${param_array[@]}" ; do
                                     IFS="=" read -ra data_array <<< "$i"
                                     _drpcli machines set "Name:$ID" param "${data_array[0]}" to "${data_array[1]}" >> $DRP_DEBUGLOG
                                   done
                                 fi
                             fi

                             if [[ "$INITIAL_WORKFLOW" != "" ]] ; then
                                 if [[ $CREATE_SELF == true ]] ; then
                                     cp $INSTALLATION_FOLDER/drpcli ${TMPDIR}/jq
                                     chmod +x ${TMPDIR}/jq
                                     ID=$(_drpcli info get | ${TMPDIR}/jq .id -r)
                                     rm ${TMPDIR}/jq
                                     _drpcli machines workflow "Name:$ID" "$INITIAL_WORKFLOW" >> $DRP_DEBUGLOG
                                 fi
                             fi
                         fi
                         if [[ "$BOOTSTRAP" == "true" ]] ; then
                             _drpcli files upload dr-provision.zip as bootstrap/dr-provision.zip >> $DRP_DEBUGLOG
                             _drpcli files upload $TMP_INST as bootstrap/install.sh >> $DRP_DEBUGLOG
                         fi
                     fi
                 fi

                 cd $OLD_PWD
                 if [[ "$KEEP_INSTALLER" == "false" ]]; then
                     rm -rf $TMP_INSTALLER_DIR
                 else
                     echo ""
                     echo -e "$PREF_INFO Installer artifacts are in '$(c_file "$TMP_INSTALLER_DIR")' - to purge:"
                     echo -e "  ${IYel}$_sudo rm -rf $TMP_INSTALLER_DIR${RCol}"
                 fi

             # do an "isolated" mode install
             else
                 mkdir -p drp-data
                 TFTP_DIR="`pwd`/drp-data/tftpboot"

                 # Make local links for execs
                 rm -f drpcli dr-provision drpjoin
                 ln -s $binpath/drpcli drpcli
                 ln -s $binpath/dr-provision dr-provision
                 if [[ -e $binpath/drpjoin ]] ; then
                     ln -s $binpath/drpjoin drpjoin
                 fi

                 if [[ "$STARTUP" == "false" ]]; then
                     echo
                     echo -e "${CInfo}********************************************************************************"
                     echo
                     echo -e "$PREF_INFO Run the following commands to start up dr-provision in a local isolated way."
                     echo -e "$PREF_INFO The server will store information and serve files from the drp-data directory."
                     echo
                 else
                     echo
                     echo -e "${CInfo}********************************************************************************"
                     echo
                     echo -e "$PREF_INFO Will attempt to startup the 'dr-provision' service ... "
                 fi

                 if [[ $IPADDR == "" ]] ; then
                     if [[ $OS_FAMILY == darwin ]]; then
                         ifdefgw=$(netstat -rn -f inet | grep default | awk '{ print $6 }')
                         if [[ $ifdefgw ]] ; then
                                 IPADDR=$(ifconfig en0 | grep 'inet ' | awk '{ print $2 }')
                         else
                                 IPADDR=$(ifconfig -a | grep "inet " | grep broadcast | head -1 | awk '{ print $2 }')
                         fi
                     else
                         gwdev=$(/sbin/ip -o -4 route show default |head -1 |awk '{print $5}')
                         if [[ $gwdev ]]; then
                             # First, advertise the address of the device with the default gateway
                             IPADDR=$(/sbin/ip -o -4 addr show scope global dev "$gwdev" |head -1 |awk '{print $4}')
                         else
                             # Hmmm... we have no access to the Internet.  Pick an address with
                             # global scope and hope for the best.
                             IPADDR=$(/sbin/ip -o -4 addr show scope global |head -1 |awk '{print $4}')
                         fi
                     fi
                 fi

                 if [[ $IPADDR ]] ; then
                     IPADDR="${IPADDR///*}"
                 fi

                 if [[ $OS_FAMILY == darwin ]]; then
                     bcast=$(netstat -rn | grep "255.255.255.255 " | awk '{ print $6 }')
                     if [[ $bcast == "" && $IPADDR ]] ; then
                             echo -e "$PREF_INFO No broadcast route set - this is required for Darwin < 10.9."
                             echo -e "  ${IYel}$_sudo route add 255.255.255.255 $IPADDR${RCol}"
                             echo -e "$PREF_INFO No broadcast route set - this is required for Darwin > 10.9."
                             echo -e "  ${IYel}$_sudo route -n add -net 255.255.255.255 $IPADDR${RCol}"
                     fi
                 fi

                 STARTER="$_sudo ./dr-provision --base-root=`pwd`/drp-data > drp.log 2>&1 &"
                 if [[ "$STARTUP" == "false" ]]; then
                   echo -e "$PREF_INFO Digital Rebar can be started with the following command:"
                   echo -e "  ${IYel}$STARTER${RCol}"
                fi
                 if [[ "$STARTUP" == "true" ]]; then
                     eval $STARTER
                     echo -e "$PREF_INFO 'dr-provision' running processes:"
                     ps -eo pid,args -o comm  | grep -v grep | grep dr-provision
                     echo

                     if [[ "$BOOTSTRAP" == "true" ]] ; then
                         _drpcli files upload dr-provision.zip as bootstrap/dr-provision.zip >> $DRP_DEBUGLOG
                         _drpcli files upload tools/install.sh as bootstrap/install.sh >> $DRP_DEBUGLOG
                     fi
                 fi

                 EP="./"
             fi

             echo -e "$PREF_INFO With Digital Rebar started, complete the setup using the ${ICya}System Install Wizard${RCol}"
             if [[ $IPADDR ]] ; then
                 echo -e "  open ${IBlu}https://$IPADDR:$RS_API_PORT${RCol} (accept self-signed TLS certificate)"
             else
                 echo -e "  open ${IBlu}https://[host ip]:$RS_API_PORT${RCol} (accept self-signed TLS certificate)"
             fi
             echo
             if [[ $UNIVERSAL == false ]] ; then
                 echo -e "$PREF_INFO Or, use the CLI to setup for basic system discovery:"
                 echo -e "  ${IYel}${EP}drpcli bootenvs uploadiso sledgehammer${RCol}"
                 echo -e "  ${IYel}${EP}drpcli prefs set defaultWorkflow discover-base unknownBootEnv discovery defaultBootEnv sledgehammer defaultStage discover${RCol}"
             else
                 echo -e "$PREF_INFO Remember to wait for bootstrapping to complete by watching the self-runner machine."
             fi
             if [[ $NO_CONTENT == true ]] ; then
                 echo
                 echo -e "$PREF_INFO Add common utilities (sourced from RackN) using drpcli"
                 echo -e "  ${IYel}${EP}drpcli contents upload catalog:task-library-$DRP_TASK_LIB_VERSION${RCol}"
             fi
             [[ "$FAST_DOWNLOADER" == "true" ]] && show_fast_isos "ubuntu-20.04-install" "centos-8-install" "sledgehammer"

         ;;
     remove)
         if [[ $ISOLATED == true ]] ; then
             echo -e "$PREF_INFO Remove the directory that the initial isolated install was done in."
             exit_cleanup 0
         fi
         if pgrep dr-provision; then
             echo -e "$PREF_ERR 'dr-provision' service is running and CANNOT be removed. Please stop service or container first."
             echo -e "  Run ${IYel}$_sudo systemctl stop dr-provision${RCol}"
             exit_cleanup 9
         else
             echo -e "$PREF_INFO 'dr-provision' service is not running, beginning removal process..."
         fi
         if [[ -f "$CLI_BKUP" ]]
         then
           echo -e "$PREF_INFO Restoring original 'drpcli'."
           $_sudo mv "$CLI_BKUP" "$CLI"
           RM_CLI=""
         else
           RM_CLI="$bindest/drpcli"
           echo -e "$PREF_INFO No 'drpcli' backup file found ('$(c_file "$CLI_BKUP")')."
         fi
         echo -e "$PREF_OK Removing program and service files"
         $_sudo rm -f "$bindest/dr-provision" "$RM_CLI" "$bindest/drbundler" "$bindest/drpjoin" "$bindest/dr-waltool" "$bindest/drpjq" "$initdest" "$INSTALLATION_FOLDER/drpcli"
         # We might not own jq.
         [[ -L "$bindest/jq" ]] && [[ $(readlink "$bindest/jq") = "$bindest/drpcli" ]] && $_sudo rm -f "$bindest/jq"
         # Remove any symlinks we created in SYMLINK_BIN_DIR pointing into bindest
         if [[ -n "$SYMLINK_BIN_DIR" ]] && [[ "$SYMLINK_BIN_DIR" != "$bindest" ]]; then
             for _bin in dr-provision drpcli drbundler drpjoin dr-waltool drpjq drp-install.sh; do
                 [[ -L "$SYMLINK_BIN_DIR/$_bin" ]] && [[ "$(readlink "$SYMLINK_BIN_DIR/$_bin")" == "$bindest/$_bin" ]] && $_sudo rm -f "$SYMLINK_BIN_DIR/$_bin" || true
             done
         fi
         [[ -d /etc/systemd/system/dr-provision.service.d ]] && $_sudo rm -rf /etc/systemd/system/dr-provision.service.d
         [[ -f ${BIN_DIR}/drp-install.sh ]] && $_sudo rm -f ${BIN_DIR}/drp-install.sh
         if [[ $REMOVE_DATA == true ]] ; then
             echo -e "$PREF_OK Removing data files and directories ... "
             [[ -d "/usr/share/dr-provision" ]] && RM_DIR="/usr/share/dr-provision " || true
             [[ -d "/etc/dr-provision" ]] && RM_DIR+="/etc/dr-provision " || true
             [[ -d "${DRP_HOME_DIR}" ]] && RM_DIR+="${DRP_HOME_DIR}" || true
             echo -e "$(c_file "$RM_DIR")"

             for _dir in $RM_DIR
             do
                 # 'mountpoint' requires sysvinit or utils-linux (etc...) pkg, use more portable method
                 if cat /proc/mounts | cut -d ' ' -f 2 | grep -q "^${_dir}$"
                 then
                     echo -e "$(c_file "'$_dir' is a mount point, only removing contents")"
                     $_sudo rm -rf "$_dir"/*
                 else
                     $_sudo rm -rf "$_dir"
                 fi
             done

         fi
         echo -e "${COk}${EP}Digital Rebar has been removed.${RCol}"
         ;;
     version) echo -e "Installer Version: $(c_def "$INSTALL_VERSION")" ;;
     *) echo -e "Unknown action \"$1\". Please use '$(c_flag "install")', '$(c_flag "upgrade")', '$(c_flag "explode")', '$(c_flag "extract")', '$(c_flag "build-airgap")', '$(c_flag "get-drpcli")', or '$(c_flag "remove")'";;
esac

exit_cleanup 0
