#!/bin/bash # Save trace setting _XTRACE_FUNCTIONS_COMMON=$(set +o | grep xtrace) set +o xtrace # Distro Functions # ================ # Determine OS Vendor, Release and Update # # NOTE : For portability, you almost certainly do not want to use # these variables directly! The "is_*" functions defined below this # bundle up compatible platforms under larger umbrellas that we have # determinted are compatible enough (e.g. is_ubuntu covers Ubuntu & # Debian, is_fedora covers RPM-based distros). Higher-level functions # such as "install_package" further abstract things in better ways. # # ``os_VENDOR`` - vendor name: ``Ubuntu``, ``Fedora``, etc # ``os_RELEASE`` - major release: ``16.04`` (Ubuntu), ``23`` (Fedora) # ``os_PACKAGE`` - package type: ``deb`` or ``rpm`` # ``os_CODENAME`` - vendor's codename for release: ``xenial`` #declare -g os_VENDOR os_RELEASE os_PACKAGE os_CODENAME # Make a *best effort* attempt to install lsb_release packages for the # user if not available. Note can't use generic install_package* # because they depend on this! function _ensure_lsb_release { if [[ -x $(command -v lsb_release 2>/dev/null) ]]; then return fi if [[ -x $(command -v apt-get 2>/dev/null) ]]; then sudo apt-get install -y lsb-release elif [[ -x $(command -v zypper 2>/dev/null) ]]; then sudo zypper -n install lsb-release elif [[ -x $(command -v dnf 2>/dev/null) ]]; then sudo dnf install -y redhat-lsb-core elif [[ -x $(command -v yum 2>/dev/null) ]]; then # all rh patforms (fedora, centos, rhel) have this pkg sudo yum install -y redhat-lsb-core else die $LINENO "Unable to find or auto-install lsb_release" fi } # GetOSVersion # Set the following variables: # - os_RELEASE # - os_CODENAME # - os_VENDOR # - os_PACKAGE function GetOSVersion { # We only support distros that provide a sane lsb_release _ensure_lsb_release os_RELEASE=$(lsb_release -r -s) os_CODENAME=$(lsb_release -c -s) os_VENDOR=$(lsb_release -i -s) if [[ $os_VENDOR =~ (Debian|Ubuntu|LinuxMint) ]]; then os_PACKAGE="deb" else os_PACKAGE="rpm" fi typeset -xr os_VENDOR typeset -xr os_RELEASE typeset -xr os_PACKAGE typeset -xr os_CODENAME } # Translate the OS version values into common nomenclature # Sets global ``DISTRO`` from the ``os_*`` values #declare -g DISTRO function GetDistro { GetOSVersion if [[ "$os_VENDOR" =~ (Ubuntu) || "$os_VENDOR" =~ (Debian) || \ "$os_VENDOR" =~ (LinuxMint) ]]; then # 'Everyone' refers to Ubuntu / Debian / Mint releases by # the code name adjective DISTRO=$os_CODENAME elif [[ "$os_VENDOR" =~ (Fedora) ]]; then # For Fedora, just use 'f' and the release DISTRO="f$os_RELEASE" elif [[ "$os_VENDOR" =~ (openSUSE) ]]; then DISTRO="opensuse-$os_RELEASE" elif [[ "$os_VENDOR" =~ (SUSE LINUX) ]]; then # just use major release DISTRO="sle${os_RELEASE%.*}" elif [[ "$os_VENDOR" =~ (Red.*Hat) || \ "$os_VENDOR" =~ (CentOS) || \ "$os_VENDOR" =~ (Scientific) || \ "$os_VENDOR" =~ (OracleServer) || \ "$os_VENDOR" =~ (Virtuozzo) ]]; then # Drop the . release as we assume it's compatible # XXX re-evaluate when we get RHEL10 DISTRO="rhel${os_RELEASE::1}" elif [[ "$os_VENDOR" =~ (XenServer) ]]; then DISTRO="xs${os_RELEASE%.*}" elif [[ "$os_VENDOR" =~ (kvmibm) ]]; then DISTRO="${os_VENDOR}${os_RELEASE::1}" else die $LINENO "Unable to determine DISTRO, can not continue." fi typeset -xr DISTRO } # Utility function for checking machine architecture # is_arch arch-type function is_arch { [[ "$(uname -m)" == "$1" ]] } # Determine if current distribution is a Fedora-based distribution # (Fedora, RHEL, CentOS, etc). # is_fedora function is_fedora { if [[ -z "$os_VENDOR" ]]; then GetOSVersion fi [ "$os_VENDOR" = "Fedora" ] || [ "$os_VENDOR" = "Red Hat" ] || \ [ "$os_VENDOR" = "RedHatEnterpriseServer" ] || \ [ "$os_VENDOR" = "CentOS" ] } # Determine if current distribution is a SUSE-based distribution # (openSUSE, SLE). # is_suse function is_suse { if [[ -z "$os_VENDOR" ]]; then GetOSVersion fi [[ "$os_VENDOR" =~ (openSUSE) || "$os_VENDOR" == "SUSE LINUX" ]] } # Determine if current distribution is an Ubuntu-based distribution # It will also detect non-Ubuntu but Debian-based distros # is_ubuntu function is_ubuntu { if [[ -z "$os_PACKAGE" ]]; then GetOSVersion fi [ "$os_PACKAGE" = "deb" ] } # Package Functions # ================= # Wrapper for ``apt-get update`` to try multiple times on the update # to address bad package mirrors (which happen all the time). function apt_get_update { # only do this once per run if [[ "$REPOS_UPDATED" == "True" && "$RETRY_UPDATE" != "True" ]]; then return fi # bail if we are offline [[ "$OFFLINE" = "True" ]] && return local sudo="sudo" [[ "$(id -u)" = "0" ]] && sudo="env" # time all the apt operations time_start "apt-get-update" local proxies="http_proxy=${http_proxy:-} https_proxy=${https_proxy:-} no_proxy=${no_proxy:-} " local update_cmd="$sudo $proxies apt-get update" if ! timeout 300 sh -c "while ! $update_cmd; do sleep 30; done"; then die $LINENO "Failed to update apt repos, we're dead now" fi REPOS_UPDATED=True # stop the clock time_stop "apt-get-update" } # Wrapper for ``apt-get`` to set cache and proxy environment variables # Uses globals ``OFFLINE``, ``*_proxy`` # apt_get operation package [package ...] function apt_get { local xtrace result xtrace=$(set +o | grep xtrace) set +o xtrace [[ "$OFFLINE" = "True" || -z "$@" ]] && return local sudo="sudo" [[ "$(id -u)" = "0" ]] && sudo="env" # time all the apt operations time_start "apt-get" $xtrace $sudo DEBIAN_FRONTEND=noninteractive \ http_proxy=${http_proxy:-} https_proxy=${https_proxy:-} \ no_proxy=${no_proxy:-} \ apt-get --option "Dpkg::Options::=--force-confold" --assume-yes "$@" < /dev/null result=$? # stop the clock time_stop "apt-get" return $result } # Distro-agnostic package installer # Uses globals ``NO_UPDATE_REPOS``, ``REPOS_UPDATED``, ``RETRY_UPDATE`` # install_package package [package ...] function update_package_repo { NO_UPDATE_REPOS=${NO_UPDATE_REPOS:-False} REPOS_UPDATED=${REPOS_UPDATED:-False} RETRY_UPDATE=${RETRY_UPDATE:-False} if [[ "$NO_UPDATE_REPOS" = "True" ]]; then return 0 fi if is_ubuntu; then apt_get_update fi } function real_install_package { if is_ubuntu; then apt_get install "$@" elif is_fedora; then yum_install "$@" elif is_suse; then zypper_install "$@" else exit_distro_not_supported "installing packages" fi } # Distro-agnostic package installer # install_package package [package ...] function install_package { update_package_repo if ! real_install_package "$@"; then RETRY_UPDATE=True update_package_repo && real_install_package "$@" fi } # Distro-agnostic function to tell if a package is installed # is_package_installed package [package ...] function is_package_installed { if [[ -z "$@" ]]; then return 1 fi if [[ -z "$os_PACKAGE" ]]; then GetOSVersion fi if [[ "$os_PACKAGE" = "deb" ]]; then dpkg -s "$@" > /dev/null 2> /dev/null elif [[ "$os_PACKAGE" = "rpm" ]]; then rpm --quiet -q "$@" else exit_distro_not_supported "finding if a package is installed" fi } # Distro-agnostic package uninstaller # uninstall_package package [package ...] function uninstall_package { if is_ubuntu; then apt_get purge "$@" elif is_fedora; then sudo ${YUM:-yum} remove -y "$@" ||: elif is_suse; then sudo zypper remove -y "$@" ||: else exit_distro_not_supported "uninstalling packages" fi } # Wrapper for ``yum`` to set proxy environment variables # Uses globals ``OFFLINE``, ``*_proxy``, ``YUM`` # yum_install package [package ...] function yum_install { local result parse_yum_result time_start "yum_install" # This is a bit tricky, because yum -y assumes missing or failed # packages are OK (see [1]). We want devstack to stop if we are # installing missing packages. # # Thus we manually match on the output (stack.sh runs in a fixed # locale, so lang shouldn't change). # # If yum returns !0, we echo the result as "YUM_FAILED" and return # that from the awk (we're subverting -e with this trick). # Otherwise we use awk to look for failure strings and return "2" # to indicate a terminal failure. # # [1] https://bugzilla.redhat.com/show_bug.cgi?id=965567 parse_yum_result=' \ BEGIN { result=0 } \ /^YUM_FAILED/ { result=$2 } \ /^No package/ { result=2 } \ /^Failed:/ { result=2 } \ //{ print } \ END { exit result }' (sudo_with_proxies "${YUM:-yum}" install -y "$@" 2>&1 || echo YUM_FAILED $?) \ | awk "$parse_yum_result" && result=$? || result=$? time_stop "yum_install" # if we return 1, then the wrapper functions will run an update # and try installing the package again as a defense against bad # mirrors. This can hide failures, especially when we have # packages that are in the "Failed:" section because their rpm # install scripts failed to run correctly (in this case, the # package looks installed, so when the retry happens we just think # the package is OK, and incorrectly continue on). if [ "$result" == 2 ]; then die "Detected fatal package install failure" fi return "$result" } # zypper wrapper to set arguments correctly # Uses globals ``OFFLINE``, ``*_proxy`` # zypper_install package [package ...] function zypper_install { local sudo="sudo" [[ "$(id -u)" = "0" ]] && sudo="env" $sudo http_proxy="${http_proxy:-}" https_proxy="${https_proxy:-}" \ no_proxy="${no_proxy:-}" \ zypper --non-interactive install --auto-agree-with-licenses "$@" } function install_tendermint_bin { wget https://s3-us-west-2.amazonaws.com/tendermint/binaries/tendermint/v${TM_VERSION}/tendermint_${TM_VERSION}_linux_amd64.zip unzip tendermint_${TM_VERSION}_linux_amd64.zip sudo mv tendermint /usr/local/bin } # Find out if a process exists by partial name. # is_running name function is_running { local name=$1 ps auxw | grep -v grep | grep ${name} > /dev/null local exitcode=$? return $exitcode } # Restore xtrace $_XTRACE_FUNCTIONS_COMMON