#!/bin/bash # # go-xcat - Install xCAT automatically. # # Version 1.0.32 # # Copyright (C) 2016, 2017, 2018 International Business Machines # Eclipse Public License, Version 1.0 (EPL-1.0) # # # 2016-06-16 GONG Jie # - Draft # 2016-06-20 GONG Jie # - Released to the field # 2016-09-20 GONG Jie # - Bug fix # 2018-03-28 GONG Jie # - Use curl when it is available. Otherwise fall back to use wget # - Improved tarball file extension handling # - Disable xCAT-core.repo and xCAT-dep.repo if they exist # 2018-09-28 GONG Jie # - Revised debug log # - xCAT uninstallation # function usage() { local script="${0##*/}" local version="$(version)" while read -r ; do echo "${REPLY}" ; done <<-EOF ${script} version ${version} Usage: ${script} [OPTION]... [ACTION] Install xCAT automatically Options: Mandatory arguments to long options are mandatory for short options too. -h, --help display this help and exit --xcat-core=[URL] use a different URL or path for the xcat-core repository --xcat-dep=[URL] use a different URL or path for the xcat-dep repository -x, --xcat-version=[VERSION] specify the version of xCAT; imply the subdirectory of corresponding xCAT version under http://xcat.org/files/xcat/repos/yum/ or http://xcat.org/files/xcat/repos/apt/ cannot use with --xcat-core -y, --yes answer yes for all questions Actions: install installs all the latest versions of xcat-core and xcat-dep packages from the repository update updates installed xcat-core packages to the latest version from the repository uninstall removes xCAT from this system completely uninstall removes xCAT from this system and cleans up all the traces xCAT made Examples: ${script} ${script} install ${script} update ${script} --yes install ${script} -x 2.12 -y install ${script} --xcat-version=devel install ${script} --xcat-core=/path/to/xcat-core.tar.bz2 \\ --xcat-dep=/path/to/xcat-dep.tar.bz2 install ${script} --xcat-core=http://xcat.org/path/to/xcat-core.tar.bz2 \\ --xcat-dep=http://xcat.org/path/to/xcat-dep.tar.bz2 install ${script} uninstall ${script} completely uninstall xCAT: http://xcat.org/ Full documentation at: http://xcat-docs.readthedocs.io/en/stable EOF } # # verbose_usage This function be will be called when user run # `go-xcat --long-help'. # Including a bunch of secert usage. # function verbose_usage() ( local script="${0##*/}" exec 42< <(usage) function println() { local -i i for (( i = 0 ; i < "$1" ; ++i )) do read -r -u 42 [[ "$?" -ne "0" ]] && break echo "${REPLY}" done } println 7 println 1 >/dev/null # Drop a line while read -r ; do echo "${REPLY}" ; done <<-EOF -h, --help display a simply version of help and exit --long-help display this help and exit EOF println 16 while read -r ; do echo "${REPLY}" ; done <<-EOF check check the version of the installed packages of xCAT and packages in the repository smoke test preform basic tests of the xCAT installation EOF println 11 while read -r ; do echo "${REPLY}" ; done <<-EOF ${script} --xcat-core=/path/to/xcat-core.repo install ${script} --xcat-core=/path/to/xcat-core install ${script} --xcat-core=/path/to/xcat-core.tar install ${script} --xcat-core=/path/to/xcat-core.tar.Z install ${script} --xcat-core=/path/to/xcat-core.tar.gz install ${script} --xcat-core=/path/to/xcat-core.tar.bz2 install ${script} --xcat-core=/path/to/xcat-core.tar.xz install ${script} --xcat-core=http://xcat.org/path/to/xcat-core.repo install ${script} --xcat-core=http://xcat.org/path/to/xcat-core install ${script} --xcat-core=http://xcat.org/path/to/xcat-core.tar.bz2 install ${script} --xcat-core=/path/to/xcat-core.repo \\ --xcat-dep=/path/to/xcat-dep.repo install ${script} --xcat-core=/path/to/xcat-core \\ --xcat-dep=/path/to/xcat-dep install EOF println 4 while read -r ; do echo "${REPLY}" ; done <<-EOF ${script} check ${script} smoke test EOF println 999999 # Print out all the rest of lines exec 42<&- ) # # version Print out the version number. # function version() { # Read the first ten lines of this script for i in {0..9} do read -r [[ ${REPLY} =~ \#\ +[Vv]ersion ]] && echo "${REPLY##* }" && return 0 done <"$0" return 1 } GO_XCAT_DEFAULT_BASE_URL="http://xcat.org/files/xcat/repos" GO_XCAT_DEFAULT_INSTALL_PATH="/install/xcat" # The package list of xcat-core GO_XCAT_CORE_PACKAGE_LIST=() GO_XCAT_DEP_PACKAGE_LIST=() # The package list of all the packages should be installed GO_XCAT_INSTALL_LIST=(perl-xCAT xCAT xCAT-buildkit xCAT-client xCAT-genesis-scripts-ppc64 xCAT-genesis-scripts-x86_64 xCAT-server conserver-xcat elilo-xcat grub2-xcat ipmitool-xcat syslinux-xcat xCAT-genesis-base-ppc64 xCAT-genesis-base-x86_64 xnba-undi yaboot-xcat) # For Debian/Ubuntu, it will need a sight different package list type dpkg >/dev/null 2>&1 && GO_XCAT_INSTALL_LIST=(perl-xcat xcat xcat-buildkit xcat-client xcat-genesis-scripts-amd64 xcat-genesis-scripts-ppc64 xcat-server conserver-xcat elilo-xcat grub2-xcat ipmitool-xcat syslinux-xcat xcat-genesis-base-amd64 xcat-genesis-base-ppc64 xnba-undi) # The package list of all the packages should be installed GO_XCAT_UNINSTALL_LIST=("${GO_XCAT_INSTALL_LIST[@]}" goconserver xCAT-SoftLayer xCAT-confluent xCAT-csm xCAT-openbmc-py xCAT-probe xCAT-test xCAT-vlan xCATsn xCAT-UI-deps) # For Debian/Ubuntu, it will need a sight different package list type dpkg >/dev/null 2>&1 && GO_XCAT_UNINSTALL_LIST=("${GO_XCAT_INSTALL_LIST[@]}" goconserver xcat-confluent xcat-probe xcat-test xcat-vlan xcatsn) PATH="/usr/sbin:/usr/bin:/sbin:/bin" export PATH # # warn_if_bad Put out warning message(s) if $1 has bad RC. # # $1 0 (pass) or non-zero (fail). # $2+ Remaining arguments printed only if the $1 is non-zero. # # Incoming $1 is returned unless it is 0 # function warn_if_bad() { local -i rc="$1" local script="${0##*/}" # Ignore if no problems [ "${rc}" -eq "0" ] && return 0 # Broken shift echo "${script}: $@" >&2 return "${rc}" } # # exit_if_bad Put out error message(s) if $1 has bad RC. # # $1 0 (pass) or non-zero (fail). # $2+ Remaining arguments printed only if the $1 is non-zero. # # Exits with 1 unless $1 is 0 # function exit_if_bad() { warn_if_bad "$@" || exit 1 return 0 } # # check_root_or_exit # # Breaks the script if not running as root. # # If this returns 1, the invoker MUST abort the script. # # Returns 0 if running as root # Returns 1 if not (and breaks the script) # function check_root_or_exit() { [ "${UID}" -eq "0" ] exit_if_bad "$?" "Must be run by UID=0. Actual UID=${UID}." return 0 } # # check_executes Check for executable(s) # # Returns 0 if true. # Returns 1 if not. # function check_executes() { local cmd local all_ok="yes" for cmd in "$@" do if ! type "${cmd}" &>/dev/null then echo "Command \"${cmd}\" not found." >&2 all_ok="no" fi done [ "${all_ok}" = "yes" ] } # # check_exec_or_exit Check for required executables. # # Exits (not returns) if commands listed on command line do not exist. # # Returns 0 if true. # Exits with 1 if not. # function check_exec_or_exit() { check_executes "$@" exit_if_bad "$?" "Above listed required command(s) not found." return 0 } TMP_DIR="" # # internal_setup Script setup # # Returns 0 on success. # Exits (not returns) with 1 on failure. # function internal_setup() { shopt -s extglob # Trap exit for internal_cleanup function. trap "internal_cleanup" EXIT check_exec_or_exit mktemp rm umask 0077 TMP_DIR="$(mktemp -d "/tmp/${0##*/}.XXXXXXXX" 2>/dev/null)" [ -d "${TMP_DIR}" ] exit_if_bad "$?" "Make temporary directory failed." custom_setup } # # internal_cleanup Script cleanup (reached via trap 0) # # Destory any temporarily facility created by internal_setup. # function internal_cleanup() { custom_cleanup [ -d "${TMP_DIR}" ] && rm -rf "${TMP_DIR}" } # # custom_setup # function custom_setup() { check_exec_or_exit awk cat comm grep printf sleep check_root_or_exit debug_log_setup } # # custom_cleanup # function custom_cleanup() { debug_log_cleanup } # # cleanup_n_exec Do the cleanup, then execute the command # # $1+ The command to execute # function cleanup_n_exec() { internal_cleanup exec "$@" } function debug_log_setup() { local script="${0##*/}" local -a argv=() set -- "${BASH_ARGV[@]}" while [ "$#" -gt "0" ] do argv=("$1" "${argv[@]}") shift done GO_XCAT_DEBUG_LOG="${TMP_DIR}/go-xcat.log" GO_XCAT_LOG="/tmp/go-xcat.log" # Global debug log file descriptor : >"${GO_XCAT_DEBUG_LOG}" ln -f "${GO_XCAT_DEBUG_LOG}" "${GO_XCAT_LOG}" # Log all the command line arguments { echo " ." echo " ." echo " . :." echo " .:" echo " ::." echo " :.::" echo " ::::." echo " :::::" echo " :::::" echo " :::::" echo " :::::" echo " :::::" echo "..:::::.." echo " ':::::'" echo " ':'" echo -n "|->" printf " %q" "${script}" "${argv[@]}" echo echo } | debug_logger debug } function debug_log_cleanup() { local rc="$?" local script="${0##*/}" if [[ -n "${GO_XCAT_DEBUG_LOG}" && -n "${GO_XCAT_LOG}" ]] then { printf "\n|-> %-24s ... exited with %s\n" "${script}" "${rc}" echo " ......" echo " :::::" echo " ::::::." echo " ' ':::::." echo " ':::::." echo " '::" echo " '" } | debug_logger debug [[ "${rc}" -eq "0" ]] && rm -f "${GO_XCAT_LOG}" fi } function debug_logger() { local level="$1" while read -r do case "${level}" in "debug") ;; *) echo "${REPLY}" ;; esac echo "${REPLY}" >&2 done 2>>"${GO_XCAT_DEBUG_LOG}" } function debug_trace() { local rc="$?" # Log the function name and all the command line arguments { echo echo -n ".->" printf " %q" "$@" echo echo "'========" } | debug_logger debug # BUG - The command "$@" will be run in a subshell "$@" 2>&1 | debug_logger rc="${PIPESTATUS[0]}" printf ".========\n'-> %-24s ... returned with %s\n" "${1}" "${rc}" | debug_logger debug return "${rc}" } internal_setup # Check operating system function check_os() { case "${OSTYPE}" in "aix"*) # AIX echo "aix" ;; "darwin"*) # OS X echo "darwin" ;; "linux"*) # Linux echo "linux" ;; *) # Unknown echo "${OSTYPE}" ;; esac } # Check instruction set architecture function check_arch() { case "${HOSTTYPE}" in "powerpc64") echo "ppc64" ;; "powerpc64le") echo "ppc64le" ;; "mipsel") echo "mips" ;; "i"?"86") echo "i386" ;; *) echo "${HOSTTYPE}" ;; esac } function check_linux_distro() { local distro="$(source /etc/os-release >/dev/null 2>&1 && echo "${ID}")" [[ -z "${distro}" && -f /etc/redhat-release ]] && distro="rhel" [[ -z "${distro}" && -f /etc/SuSE-release ]] && distro="sles" echo "${distro}" } function check_linux_version() { local ver="$(source /etc/os-release >/dev/null 2>&1 && echo "${VERSION_ID}")" [[ -z "${ver}" && -f /etc/redhat-release ]] && # Need gawk to do this trick ver="$(awk '{ match($0, /([.0-9]+)/, a); print substr($0, a[1, "start"], a[1, "length"]); }' \ /etc/redhat-release)" [[ -z "${ver}" && -f /etc/SuSE-release ]] && ver="$(awk '/VERSION/ { print $NF }' /etc/SuSE-release)" echo "${ver}" } function function_dispatch() { local base="$1" local cmd="" local ret="" shift for cmd in $(compgen -A function "${base}_") do "${cmd}" "$@" ret="$?" [[ "${ret}" -ne "255" ]] && break done [[ "${ret}" -ne "255" ]] exit_if_bad "$?" "${base}: unsupported function" return "${ret}" } # $@ package names function check_package_version_rpm() { type rpm >/dev/null 2>&1 || return 255 local ver="" while read -r ver do if [[ -z "${ver}" || "${ver}" =~ not\ installed ]] then echo "(not installed)" else echo "${ver}" fi done < <(rpm -q --qf '%{version}-%{release}\n' "$@" 2>/dev/null) return 0 } # $@ package names function check_package_version_deb() { type dpkg-query >/dev/null 2>&1 || return 255 local name="" local ver="" while read -r name ver do name+=("${name}") ver+=("${ver}") done < <(dpkg-query --show '--showformat=${Package} ${Version}\n' \ "$@" 2>/dev/null) local -i i while [[ -n "$1" ]] do for i in "${!name[@]}" do if [[ "$1" = "${name[i]}" ]] then if [[ -n "${ver[i]}" ]] then echo "${ver[i]}" else echo "(not installed)" fi unset "name[${i}]" "ver[${i}]" shift && continue 2 fi done echo "(not installed)" shift done return 0 } function check_package_version() { function_dispatch "${FUNCNAME}" "$@" } # $@ package names function check_repo_version_dnf() { type dnf >/dev/null 2>&1 || return 255 local -a name=() local -a ver=() while read -r name ver do name+=("${name}") ver+=("${ver}") done < <(dnf repoquery -q --qf '%{name} %{version}-%{release}' "$@" 2>/dev/null) local -i i while [[ -n "$1" ]] do for i in "${!name[@]}" do if [[ "$1" = "${name[i]}" ]] then echo "${ver[i]}" unset "name[${i}]" "ver[${i}]" shift && continue 2 fi done echo "(not found)" shift done return 0 } # $@ package names function check_repo_version_yum() { type yum >/dev/null 2>&1 || return 255 check_executes repoquery exit_if_bad "$?" "Install the \`yum-utils' package and rerun." local -a name=() local -a ver=() while read -r name ver do name+=("${name}") ver+=("${ver}") done < <(repoquery --qf '%{name} %{version}-%{release}' "$@" 2>/dev/null) local -i i while [[ -n "$1" ]] do for i in "${!name[@]}" do if [[ "$1" = "${name[i]}" ]] then echo "${ver[i]}" unset "name[${i}]" "ver[${i}]" shift && continue 2 fi done echo "(not found)" shift done return 0 } # $@ package names function check_repo_version_zypper() { type zypper >/dev/null 2>&1 || return 255 local -a name=() local -a ver=() while read -r name ver do name+=("${name}") ver+=("${ver}") done < <(zypper --no-gpg-checks -n search --match-exact -C -t package \ -s "$@" 2>/dev/null | awk -F ' +\\| +' '/ package / { if ("(" != substr($6, 0, 1)) print $2, $4 }') local -i i while [[ -n "$1" ]] do for i in "${!name[@]}" do if [[ "$1" = "${name[i]}" ]] then echo "${ver[i]}" unset "name[${i}]" "ver[${i}]" shift && continue 2 fi done echo "(not found)" shift done return 0 } # $@ package names function check_repo_version_apt() { type apt-cache >/dev/null 2>&1 || return 255 local name="" local ver="" while read -r name ver do if [[ "${name}" =~ ^[a-z] ]] then while [[ -n "$1" ]] do [[ "${name}" = "${1}:" ]] && break echo "(not found)" shift done fi if [[ "${name}" = "Candidate:" ]] then echo "$ver" shift fi done < <(apt-cache policy "$@" 2>/dev/null) while [[ -n "$1" ]] do echo "(not found)" shift done return 0 } function check_repo_version() { function_dispatch "${FUNCNAME}" "$@" } # $1 repo id function get_package_list_dnf() { type dnf >/dev/null 2>&1 || return 255 local repo_id="$1" [[ -z "${repo_id}" ]] && return 1 dnf repoquery -q "--repoid=${repo_id}" --qf "%{name}" 2>/dev/null } # $1 repo id function get_package_list_yum() { type yum >/dev/null 2>&1 || return 255 check_executes repoquery exit_if_bad "$?" "Install the \`yum-utils' package and rerun." local repo_id="$1" [[ -z "${repo_id}" ]] && return 1 repoquery -qa "--repoid=${repo_id}" --qf "%{name}" 2>/dev/null } # $1 repo id function get_package_list_zypper() { type zypper >/dev/null 2>&1 || return 255 local repo_id="$1" [[ -z "${repo_id}" ]] && return 1 zypper --no-gpg-checks -n search -r "${repo_id}" 2>/dev/null | awk -F ' +\\| +' '/ package$/ { print $2 }' } # $1 repo id function get_package_list_apt() { [[ -d /var/lib/apt/lists ]] || return 255 local repo_id="$1" [[ -z "${repo_id}" ]] && return 1 local -i rc=0 awk '/^Package: / { print $2 }' \ "/var/lib/apt/lists/"*"_${repo_id}_dists"*"_main_binary-"*"_Packages" \ 2>/dev/null # This is a dirty hack, and use recursion. # For the `devel' branch of the online repo for apt, it has the # subdirectory name of `core-snap' instead of `xcat-core'. rc="$?" if [[ "${rc}" -ne "0" && "${repo_id}" = "xcat-core" ]] then "${FUNCNAME}" "core-snap" rc="$?" fi return "${rc}" } # $1 repo id function get_package_list() { function_dispatch "${FUNCNAME}" "$@" } function download_file_curl() { local script="${0##*/}" local version="$(version)" local user_agent="${script}/${version} (${GO_XCAT_OS}; ${GO_XCAT_ARCH}; ${GO_XCAT_LINUX_DISTRO} ${GO_XCAT_LINUX_VERSION})" type curl >/dev/null 2>&1 || return 255 local url="$1" local local_file="$2" local log_file="${TMP_DIR}/curl.log.${RANDOM}" local -i rc=0 curl -A "${user_agent}" "${url}" -f -o "${local_file}" -S -s >"${log_file}" 2>&1 rc="$?" if [[ "${rc}" -ne "0" ]] then while read -r ; do echo "${REPLY}" ; done <"${log_file}" echo -n "${script}: \`curl' exited with an error: (exit code ${rc}, " case "${rc}" in 1) echo -n "unsupported protocol" ;; 2) echo -n "failed to initialize" ;; 3) echo -n "URL malformed" ;; 4) echo -n "you probably need another build of libcurl!" ;; 5) echo -n "couldn't resolve proxy" ;; 6) echo -n "couldn't resolve host" ;; 7) echo -n "failed to connect to host" ;; 8) echo -n "weird server reply" ;; 9) echo -n "FTP access denied" ;; 10) echo -n "FTP accept failed" ;; 11) echo -n "FTP weird PASS reply" ;; 12) echo -n "During an active FTP session while waiting for the server to connect back to curl, the timeout expired." ;; 13) echo -n "FTP weird PASV reply" ;; 14) echo -n "FTP weird 227 format" ;; 15) echo -n "FTP can't get host" ;; 16) echo -n "HTTP/2 error" ;; 17) echo -n "FTP couldn't set binary" ;; 18) echo -n "Partial file" ;; 19) echo -n "FTP couldn't download/access the given file" ;; 21) echo -n "FTP quote error" ;; 22) echo -n "HTTP page not retrieved" ;; 23) echo -n "write error" ;; 25) echo -n "FTP couldn't STOR file" ;; 26) echo -n "read error" ;; 27) echo -n "out of memory" ;; 28) echo -n "operation timeout" ;; 30) echo -n "FTP PORT failed" ;; 31) echo -n "FTP couldn't use REST" ;; 33) echo -n "HTTP range error" ;; 34) echo -n "HTTP post error" ;; 35) echo -n "SSL connect error" ;; 36) echo -n "bad download resume" ;; 37) echo -n "FILE couldn't read file" ;; 38) echo -n "LDAP cannot bind" ;; 39) echo -n "LDAP search failed." ;; 41) echo -n "function not found" ;; 42) echo -n "aborted by callback" ;; 43) echo -n "internal error" ;; 45) echo -n "interface error" ;; 47) echo -n "too many redirects" ;; 48) echo -n "unknown option specified to libcurl" ;; 49) echo -n "malformed telnet option" ;; 51) echo -n "the peer's SSL certificate or SSH MD5 fingerprint was not OK" ;; 52) echo -n "the server didn't reply anything, which here is considered an error" ;; 53) echo -n "SSL crypto engine not found" ;; 54) echo -n "cannot set SSL crypto engine as default" ;; 55) echo -n "failed sending network data" ;; 56) echo -n "failure in receiving network data" ;; 58) echo -n "problem with the local certificate" ;; 59) echo -n "couldn't use specified SSL cipher" ;; 60) echo -n "peer certificate cannot be authenticated with known CA certificates" ;; 61) echo -n "unrecognized transfer encoding." ;; 62) echo -n "invalid LDAP URL" ;; 63) echo -n "maximum file size exceeded" ;; 64) echo -n "requested FTP SSL level failed" ;; 65) echo -n "sending the data requires a rewind that failed" ;; 66) echo -n "failed to initialise SSL Engine" ;; 67) echo -n "the user name, password, or similar was not accepted and curl failed to log in" ;; 68) echo -n "file not found on TFTP server" ;; 69) echo -n "permission problem on TFTP server" ;; 70) echo -n "out of disk space on TFTP server" ;; 71) echo -n "illegal TFTP operation" ;; 72) echo -n "unknown TFTP transfer ID" ;; 73) echo -n "file already exists (TFTP)" ;; 74) echo -n "no such user (TFTP)" ;; 75) echo -n "character conversion failed" ;; 76) echo -n "character conversion functions required" ;; 77) echo -n "problem with reading the SSL CA cert" ;; 78) echo -n "the resource referenced in the URL does not exist" ;; 79) echo -n "an unspecified error occurred during the SSH session" ;; 80) echo -n "failed to shut down the SSL connection" ;; 82) echo -n "could not load CRL file, missing or wrong format" ;; 83) echo -n "issuer check failed" ;; 84) echo -n "the FTP PRET command failed" ;; 85) echo -n "RTSP: mismatch of CSeq numbers" ;; 86) echo -n "RTSP: mismatch of Session Identifiers" ;; 87) echo -n "unable to parse FTP file list" ;; 88) echo -n "FTP chunk callback reported error" ;; 89) echo -n "no connection available, the session will be queued" ;; 90) echo -n "SSL public key does not matched pinned public key" ;; *) echo -n "unknown error" ;; esac echo ")" echo " ... while downloading \`${url}'" fi >&2 [[ "${rc}" -eq "0" ]] } function download_file_wget() { local script="${0##*/}" local version="$(version)" local user_agent="${script}/${version} (${GO_XCAT_OS}; ${GO_XCAT_ARCH}; ${GO_XCAT_LINUX_DISTRO} ${GO_XCAT_LINUX_VERSION})" type wget >/dev/null 2>&1 || return 255 local url="$1" local local_file="$2" local log_file="${TMP_DIR}/wget.log.${RANDOM}" local -i rc=0 wget -U "${user_agent}" -nv "${url}" -O "${local_file}" -o "${log_file}" rc="$?" if [[ "${rc}" -ne "0" ]] then while read -r ; do echo "${REPLY}" ; done <"${log_file}" echo -n "${script}: \`wget' exited with an error: (exit code ${rc}, " case "${rc}" in 1) echo -n "generic error" ;; 2) echo -n "parse error" ;; 3) echo -n "file I/O error" ;; 4) echo -n "network failure" ;; 5) echo -n "SSL verification failure" ;; 6) echo -n "username/password authentication failure" ;; 7) echo -n "protocol errors" ;; 8) echo -n "server issued an error response" ;; *) echo -n "unknown error" ;; esac echo ")" echo " ... while downloading \`${url}'" fi >&2 [[ "${rc}" -eq "0" ]] } function download_file() { function_dispatch "${FUNCNAME}" "$@" } # $1 repo file # $2 repo id function add_repo_by_file_yum() { [[ -d /etc/yum.repos.d ]] || return 255 local repo_file="$1" local repo_id="$2" [[ -f "${repo_file}" ]] exit_if_bad "$?" "${repo_file}: no such file" [[ -r "${repo_file}" ]] exit_if_bad "$?" "${repo_file}: permission denied" [[ -n "${repo_id}" ]] exit_if_bad "$?" "empty repo id" [[ "${repo_id}" =~ ^[a-zA-Z][0-9a-zA-Z-]*$ ]] exit_if_bad "$?" "${repo_id} illegal character in repo id" local tmp="${TMP_DIR}/tmp_repo_file_${repo_id}.repo" { echo "[${repo_id}]" grep -v '^\[' "${repo_file}" } >"${tmp}" remove_repo_yum "${repo_id}" && cp "${tmp}" "/etc/yum.repos.d/${repo_id}.repo" } # $1 repo file # $2 repo id function add_repo_by_file_zypper() { type zypper >/dev/null 2>&1 || return 255 local repo_file="$1" local repo_id="$2" [[ -f "${repo_file}" ]] exit_if_bad "$?" "${repo_file}: no such file" [[ -r "${repo_file}" ]] exit_if_bad "$?" "${repo_file}: permission denied" [[ -n "${repo_id}" ]] exit_if_bad "$?" "empty repo id" [[ "${repo_id}" =~ ^[a-zA-Z][0-9a-zA-Z-]*$ ]] exit_if_bad "$?" "${repo_id} illegal character in repo id" local tmp="${TMP_DIR}/tmp_repo_file_${repo_id}.repo" { echo "[${repo_id}]" grep -v '^\[' "${repo_file}" } >"${tmp}" remove_repo_zypper "${repo_id}" && zypper addrepo "${tmp}" >/dev/null 2>&1 } # $1 repo file # $2 repo id function add_repo_by_file_apt() { [[ -d /etc/apt/sources.list.d/ ]] || return 255 local repo_file="$1" local repo_id="$2" [[ -f "${repo_file}" ]] exit_if_bad "$?" "${repo_file}: no such file" [[ -r "${repo_file}" ]] exit_if_bad "$?" "${repo_file}: permission denied" [[ -n "${repo_id}" ]] exit_if_bad "$?" "empty repo id" [[ "${repo_id}" =~ ^[a-zA-Z][0-9a-zA-Z-]*$ ]] exit_if_bad "$?" "${repo_id} illegal character in repo id" cp "${repo_file}" "/etc/apt/sources.list.d/${repo_id}.list" } function add_repo_by_file() { function_dispatch "${FUNCNAME}" "$@" } # $1 archive # $2 repo id # $3 install path function extract_archive() { local archive="$1" local repo_id="$2" local install_path="$3" local umask="$(umask)" local -i ret=0 [[ -f "${archive}" ]] warn_if_bad "$?" "${archive}: archive file not found!" || return 1 umask 0022 mkdir -p "${install_path}" 2>/dev/null ret="$?" umask "${umask}" warn_if_bad "${ret}" "Failed to create directory \`${install_path}'" || return 1 case "${archive##*/}" in *".tar.Z") check_executes uncompress tar grep || return 1 uncompress -c "${archive}" | tar -t -f - | grep -v "^${repo_id}/" [[ "${PIPESTATUS[0]}" -eq 0 && "${PIPESTATUS[1]}" -eq 0 && "${PIPESTATUS[2]}" -eq 1 ]] warn_if_bad "$?" "${archive}: bad compressed tarball" || return 1 rm -rf "${install_path}/${repo_id}" uncompress -c "${archive}" | ( cd "${install_path}" && tar -x -f - ) ;; *".tz"|*".tgz"|*".tar.gz") check_executes gzip tar grep || return 1 gzip -d -c "${archive}" | tar -t -f - | grep -v "^${repo_id}/" [[ "${PIPESTATUS[0]}" -eq 0 && "${PIPESTATUS[1]}" -eq 0 && "${PIPESTATUS[2]}" -eq 1 ]] exit_if_bad "$?" "${archive}: bad gzipped tarball" rm -rf "${install_path}/${repo_id}" gzip -d -c "${archive}" | ( cd "${install_path}" && tar -x -f - ) ;; *".tbz"|*".tbz2"|*".tar.bz"|*".tar.bz2") check_executes bzip2 tar grep || return 1 bzip2 -d -c "${archive}" | tar -t -f - | grep -v "^${repo_id}/" [[ "${PIPESTATUS[0]}" -eq 0 && "${PIPESTATUS[1]}" -eq 0 && "${PIPESTATUS[2]}" -eq 1 ]] warn_if_bad "$?" "${archive}: bad bzipped tarball" || return 1 rm -rf "${install_path}/${repo_id}" bzip2 -d -c "${archive}" | ( cd "${install_path}" && tar -x -f - ) ;; *".txz"|*".tar.xz") check_executes xz tar grep || return 1 xz -d -c "${archive}" | tar -t -f - | grep -v "^${repo_id}/" [[ "${PIPESTATUS[0]}" -eq 0 && "${PIPESTATUS[1]}" -eq 0 && "${PIPESTATUS[2]}" -eq 1 ]] warn_if_bad "$?" "${archive}: bad xzed tarball" || return 1 rm -rf "${install_path}/${repo_id}" xz -d -c "${archive}" | ( cd "${install_path}" && tar -x -f - ) ;; *".tar") check_executes tar grep || return 1 tar -t -f "${archive}" | grep -v "^${repo_id}/" [[ "${PIPESTATUS[0]}" -eq 0 && "${PIPESTATUS[1]}" -eq 1 ]] warn_if_bad "$?" "${archive}: bad tarball" || return 1 rm -rf "${install_path}/${repo_id}" ( cd "${install_path}" && tar -x -f - ) <"${archive}" ;; *) warn_if_bad "1" "${archive}: unknown archive file" return 1 ;; esac [[ -d "${install_path}/${repo_id}" ]] warn_if_bad "$?" "${install_path}/${repo_id}: no such directory" } # $1 URL # $2 repo id function add_repo_by_url_yum_or_zypper() { local -a yes=() [[ "$1" = "-y" ]] && yes=("-y") && shift local url="$1" local repo_id="$2" local tmp="" local install_path="${GO_XCAT_DEFAULT_INSTALL_PATH}" case "${url%%://*}" in "ftp"|"http"|"https") case "${url##*/}" in *".repo"|*".tar"|*".tar.Z"|*".tar.bz"|*".tar.bz2"|*".tar.gz"|*".tar.xz"|*".tbz"|*".tbz2"|*".tgz"|*".tz"|*".txz") # an online repo or tarball tmp="${TMP_DIR}/tmp_${url##*/}" download_file "${url}" "${tmp}" warn_if_bad "$?" \ "download ${repo_id} resource failed" || return 1 url="${tmp}" ;; *) # assume it is the base url of the repo tmp="${TMP_DIR}/tmp_repo.repo" while read -r ; do echo "${REPLY}" ; done >"${tmp}" <<-EOF [${repo_id}] name=${repo_id} baseurl=${url%/} enabled=1 gpgcheck=0 gpgkey=${url%/}/repodata/repomd.xml.key EOF add_repo_by_file "${tmp}" "${repo_id}" return "$?" ;; esac ;; "file") url="${url#file://}" ;; esac if [[ -f "${url}" ]] then case "${url##*.}" in "repo") # local repo file add_repo_by_file "${url}" "${repo_id}" return "$?" ;; esac extract_archive "${url}" "${repo_id}" "${install_path}" warn_if_bad "$?" "extract ${repo_id} archive file failed" || return 1 url="${install_path}/${repo_id}" fi if [[ -d "${url}" ]] then # make sure it is an absolute pathname. [[ "${url:0:1}" = "/" ]] || url="${PWD}/${url}" # directory tmp="${TMP_DIR}/tmp_repo.repo" while read -r ; do echo "${REPLY}" ; done >"${tmp}" <<-EOF [${repo_id}] name=${repo_id} baseurl=file://${url%/} enabled=1 gpgcheck=0 gpgkey=file://${url%/}/repodata/repomd.xml.key EOF add_repo_by_file "${tmp}" "${repo_id}" return "$?" fi warn_if_bad "1" "invalid ${repo_id} URL" } # $1 URL # $2 repo id function add_repo_by_url_apt() { [[ -d /etc/apt/sources.list.d/ ]] || return 255 local -a yes=() [[ "$1" = "-y" ]] && yes=("-y") && shift local url="$1" local repo_id="$2" local tmp="" local install_path="${GO_XCAT_DEFAULT_INSTALL_PATH}" local codename="$(source /etc/lsb-release >/dev/null 2>&1 && echo "${DISTRIB_CODENAME}")" [[ -n "${codename}" ]] warn_if_bad "$?" "unknown debian/ubuntu codename" || return 1 case "${url%%://*}" in "ftp"|"http"|"https"|"ssh") case "${url##*/}" in *".tar"|*".tar.Z"|*".tar.bz"|*".tar.bz2"|*".tar.gz"|*".tar.xz"|*".tbz"|*".tbz2"|*".tgz"|*".tz"|*".txz") # an online tarball tmp="${TMP_DIR}/tmp_${url##*/}" download_file "${url}" "${tmp}" warn_if_bad "$?" \ "download ${repo_id} resource failed" || return 1 url="${tmp}" ;; *) # assume it is the base url of the repo tmp="${TMP_DIR}/tmp_repo.list" echo "deb [arch=$(dpkg --print-architecture)] ${url} ${codename} main" >"${tmp}" add_repo_by_file_apt "${tmp}" "${repo_id}" return "$?" ;; esac ;; "file") url="${url#file://}" ;; esac if [[ -f "${url}" ]] then extract_archive "${url}" "${repo_id}" "${install_path}" warn_if_bad "$?" "extract ${repo_id} archive file failed" || return 1 url="${install_path}/${repo_id}" fi if [[ -d "${url}" ]] then # make sure it is an absolute pathname. [[ "${url:0:1}" = "/" ]] || url="${PWD}/${url}" # directory tmp="${TMP_DIR}/tmp_repo.list" echo "deb [arch=$(dpkg --print-architecture)] file://${url} ${codename} main" >"${tmp}" add_repo_by_file_apt "${tmp}" "${repo_id}" return "$?" fi warn_if_bad "1" "invalid ${repo_id} URL" } function add_repo_by_url() { function_dispatch "${FUNCNAME}" "$@" } # $1 repo id function remove_repo_yum() { type yum >/dev/null 2>&1 || return 255 local repo_id="$1" # This deleting method is not good enough. Since there could be more # than one repository definitions in a single repo file. # This is a quick and dirty method. rm -f $(grep -l "^\[${repo_id}\]$" "/etc/yum.repos.d/"*".repo" 2>/dev/null) case "${repo_id}" in "xcat-core") mv /etc/yum.repos.d/xCAT-core.repo{,.nouse} 2>/dev/null ;; "xcat-dep") mv /etc/yum.repos.d/xCAT-dep.repo{,.nouse} 2>/dev/null ;; esac yum clean metadata : } # $1 repo id function remove_repo_zypper() { type zypper >/dev/null 2>&1 || return 255 local repo_id="$1" zypper removerepo "${repo_id}" case "${repo_id}" in "xcat-core") mv /etc/zypp/repos.d/xCAT-core.repo{,.nouse} 2>/dev/null ;; "xcat-dep") mv /etc/zypp/repos.d/xCAT-dep.repo{,.nouse} 2>/dev/null ;; esac : } # $1 repo id function remove_repo_apt() { [[ -d "/etc/apt/sources.list.d" ]] || return 255 local repo_id="$1" rm -f "/etc/apt/sources.list.d/${repo_id}.list" } function remove_repo() { function_dispatch "${FUNCNAME}" "$@" } # $1 URL # $2 version # can be "2.10", "2.11", "2.12", "latest" or "devel" function add_xcat_core_repo_yum_or_zypper() { type yum >/dev/null 2>&1 || type zypper >/dev/null 2>&1 || return 255 local -a yes=() [[ "$1" = "-y" ]] && yes=("-y") && shift local url="$1" local ver="$2" local tmp="" [[ -z "${ver}" ]] && ver="latest" if [[ -z "${url}" ]] then case "${ver}" in "devel") url="${GO_XCAT_DEFAULT_BASE_URL}/yum/devel/core-snap" ;; *) url="${GO_XCAT_DEFAULT_BASE_URL}/yum/${ver}/xcat-core" ;; esac fi add_repo_by_url_yum_or_zypper "${url}" "xcat-core" } # $1 URL # $2 version # can be "2.10", "2.11", "2.12", "latest" or "devel" function add_xcat_core_repo_apt() { [[ -d "/etc/apt/sources.list.d" ]] || return 255 local -a yes=() [[ "$1" = "-y" ]] && yes=("-y") && shift local url="$1" local ver="$2" local tmp="" [[ -z "${ver}" ]] && ver="latest" if [[ -z "${url}" ]] then # get the apt.key local url="${GO_XCAT_DEFAULT_BASE_URL}/apt/apt.key" local tmp="${TMP_DIR}/tmp_xcat.key" download_file "${url}" "${tmp}" warn_if_bad "$?" "download xcat apt key failed" || return 1 apt-key add "${tmp}" >/dev/null 2>&1 warn_if_bad "$?" "import xcat apt key failed" || return 1 case "${ver}" in "devel") url="${GO_XCAT_DEFAULT_BASE_URL}/apt/devel/core-snap" ;; *) url="${GO_XCAT_DEFAULT_BASE_URL}/apt/${ver}/xcat-core" ;; esac fi add_repo_by_url_apt "${url}" "xcat-core" } function add_xcat_core_repo() { function_dispatch "${FUNCNAME}" "$@" } function add_xcat_dep_repo_yum_or_zypper() { type yum >/dev/null 2>&1 || type zypper >/dev/null 2>&1 || return 255 local -a yes=() [[ "$1" = "-y" ]] && yes=("-y") && shift local url="$1" local ver="$2" [[ -z "${ver}" ]] && ver="latest" local tmp="" local install_path="${GO_XCAT_DEFAULT_INSTALL_PATH}" local distro="${GO_XCAT_LINUX_DISTRO}${GO_XCAT_LINUX_VERSION%%.*}" case "${distro}" in "centos"*) distro="rh${distro#centos}" ;; "fedora10"|"fedora11") distro="fedora9" ;; "fedora1"[678]) distro="rh6" ;; "fedora19"|"fedora2"?) distro="rh7" ;; "rhel"*) distro="rh${distro#rhel}" ;; "sles"*) ;; *) warn_if_bad 1 "${distro}: unsupported Linux distro" || return 1 esac [[ -z "${url}" ]] && url="${GO_XCAT_DEFAULT_BASE_URL}/yum/${ver}/xcat-dep" case "${url##*.}" in "repo") # local repo file add_repo_by_url_yum_or_zypper "${url}" "xcat-dep" return "$?" ;; esac case "${url%%://*}" in "ftp"|"http"|"https") case "${url##*/}" in *".tar"|*".tar.Z"|*".tar.bz"|*".tar.bz2"|*".tar.gz"|*".tar.xz"|*".tbz"|*".tbz2"|*".tgz"|*".tz"|*".txz") # an online archive file tmp="${TMP_DIR}/tmp_${url##*/}" download_file "${url}" "${tmp}" warn_if_bad "$?" "download xcat-dep archive file failed" \ || return 1 url="${tmp}" ;; *) url="${url}/${distro}/${GO_XCAT_ARCH}" add_repo_by_url_yum_or_zypper "${url}" "xcat-dep" return "$?" ;; esac ;; "file") url="${url#file://}" ;; esac if [[ -f "${url}" ]] then extract_archive "${url}" "xcat-dep" "${install_path}" warn_if_bad "$?" "extract xcat-dep archive file failed" || return 1 url="${install_path}/xcat-dep" fi if [[ -d "${url}" ]] then # make sure it is an absolute pathname. [[ "${url:0:1}" = "/" ]] || url="${PWD}/${url}" url="${url}/${distro}/${GO_XCAT_ARCH}" add_repo_by_url_yum_or_zypper "${url}" "xcat-dep" return "$?" fi warn_if_bad "1" "invalid xcat-dep URL" } function add_xcat_dep_repo_apt() { [[ -d "/etc/apt/sources.list.d" ]] || return 255 local -a yes=() [[ "$1" = "-y" ]] && yes=("-y") && shift local url="$1" local ver="$2" [[ -z "${ver}" ]] && ver="latest" [[ -z "${url}" ]] && url="${GO_XCAT_DEFAULT_BASE_URL}/apt/${ver}/xcat-dep" add_repo_by_url_apt "${url}" "xcat-dep" } function add_xcat_dep_repo() { function_dispatch "${FUNCNAME}" "$@" } function update_repo_dnf() { type dnf >/dev/null 2>&1 || return 255 dnf --nogpgcheck updateinfo } function update_repo_yum() { type yum >/dev/null 2>&1 || return 255 # Check if `yum' support `updateinfo' command. yum --help 2>/dev/null | grep -q "^updateinfo" >/dev/null 2>&1 warn_if_bad "$?" "Lacking support of \`updateinfo' command for \`yum'." warn_if_bad "$?" "Please rerun after install package \`yum-plugin-security'." exit_if_bad "$?" "And please update package \`yum' to at least version 3.2.29-17." yum --nogpgcheck updateinfo } function update_repo_zypper() { type zypper >/dev/null 2>&1 || return 255 zypper --gpg-auto-import-keys -n refresh } function update_repo_apt() { type apt-get >/dev/null 2>&1 || return 255 apt-get --allow-unauthenticated update } function update_repo() { function_dispatch "${FUNCNAME}" "$@" } function install_packages_dnf() { type dnf >/dev/null 2>&1 || return 255 local -a yes=() [[ "$1" = "-y" ]] && yes=("-y") && shift dnf --nogpgcheck "${yes[@]}" install "$@" } function install_packages_yum() { type yum >/dev/null 2>&1 || return 255 local -a yes=() [[ "$1" = "-y" ]] && yes=("-y") && shift yum --nogpgcheck "${yes[@]}" install "$@" } # Dirty workaround on SLES 11 SP4 function github_issue_5503_workaround() { [[ "${GO_XCAT_LINUX_DISTRO}" = "sles" ]] || return 0 [[ "${GO_XCAT_LINUX_VERSION}" =~ ^11(\.[0-4]){0,1}$ ]] || return 0 rpm -e --allmatches gpg-pubkey-ca548a47-5b2c830b >/dev/null 2>&1 return 0 } function install_packages_zypper() { type zypper >/dev/null 2>&1 || return 255 github_issue_5503_workaround local -a yes=() [[ "$1" = "-y" ]] && yes=("-n") && shift zypper --no-gpg-checks "${yes[@]}" install --force-resolution "$@" } function install_packages_apt() { type apt-get >/dev/null 2>&1 || return 255 local -a yes=() [[ "$1" = "-y" ]] && yes=("-y") && shift apt-get --allow-unauthenticated install "${yes[@]}" "$@" } function install_packages() { function_dispatch "${FUNCNAME}" "$@" } function remove_package_dnf() { type dnf >/dev/null 2>&1 || return 255 local -a yes=() [[ "$1" = "-y" ]] && yes=("-y") && shift dnf --nogpgcheck "${yes[@]}" remove "$@" } function remove_package_yum() { type yum >/dev/null 2>&1 || return 255 local -a yes=() [[ "$1" = "-y" ]] && yes=("-y") && shift yum --nogpgcheck "${yes[@]}" remove "$@" } function remove_package_zypper() { type zypper >/dev/null 2>&1 || return 255 local -a yes=() local ret="" [[ "$1" = "-y" ]] && yes=("-n") && shift zypper --no-gpg-checks "${yes[@]}" remove --force-resolution "$@" ret="$?" case "${ret}" in "104") # ZYPPER_EXIT_INF_CAP_NOT_FOUND ret="0" ;; esac return "${ret}" } function remove_package_apt() { type apt-get >/dev/null 2>&1 || return 255 local -a yes=() [[ "$1" = "-y" ]] && yes=("-y") && shift apt-get --allow-unauthenticated remove "${yes[@]}" "$@" } function remove_package() { function_dispatch "${FUNCNAME}" "$@" } # $1 -y function install_xcat() { install_packages "$@" "${GO_XCAT_INSTALL_LIST[@]}" } # $1 -y function update_xcat() { local -i i=0 local ver="" local -a xcat_core_package_list xcat_core_package_list=($(get_package_list xcat-core)) exit_if_bad "$?" "Failed to get package list from repository \`xcat-core'." local -a install_list=($( comm <(echo "${GO_XCAT_INSTALL_LIST[@]}") \ <(echo "${xcat_core_package_list[@]}") )) for i in "${!install_list[@]}" do read -r ver [[ "${ver}" = "(not installed)" ]] && unset "install_list[${i}]" done < <(check_package_version "${install_list[@]}") [[ "${#install_list[@]}" -gt "0" ]] warn_if_bad "$?" "xCAT is not installed." exit_if_bad "$?" "In order to install xCAT, please rerun with \`${0##*/} install'." install_packages "$@" "${install_list[@]}" } # $1 -y function uninstall_xcat() { remove_package "$@" "${GO_XCAT_UNINSTALL_LIST[@]}" } function kill_xcat() { local f="" for f in /var/run/xcat{d,/{main,udp,install,cmdlog}service}.pid do [[ -f "${f}" ]] && kill -TERM "$(<"${f}")" 2>/dev/null done sleep 1 for f in /var/run/xcat{d,/{main,udp,install,cmdlog}service}.pid do [[ -f "${f}" ]] && kill -KILL "$(<"${f}")" 2>/dev/null done return 0 } # Remove all xCAT related directories and files function trash_xcat() { rm -f /etc/init.d/xcatpostinit1 rm -f /etc/systemd/system/xcatpostinit1.service rm -f /etc/systemd/system/multi-user.target.wants/xcatd.service rm -f /etc/tftpmapfile4xcat.conf rm -f /etc/profile.d/xcat.{c,}sh rm -rf /etc/xcat rm -rf /etc/xcatdockerca rm -f /etc/apt/sources.list.d/xcat-{core,dep}.list rm -f /etc/yum.repos.d/xCAT-{core,dep}.repo{,.nouse} rm -f /etc/yum.repos.d/xcat-{core,dep}.repo rm -f /etc/zypp/repos.d/xCAT-{core,dep}.repo{,.nouse} rm -f /etc/zypp/repos.d/xcat-{core,dep}.repo rm -rf /install/postscripts rm -rf /opt/xcat rm -rf /root/.xcat rm -rf /root/xcat-dbback rm -rf /tftpboot/xcat rm -rf /var/lock/xcat rm -rf /var/log/xcat rm -rf /xcatpost # For goconserver rm -rf /etc/goconserver rm -rf /var/lib/goconserver rm -rf /var/log/goconserver return 0 } function list_xcat_packages() { GO_XCAT_CORE_PACKAGE_LIST=($(get_package_list xcat-core)) GO_XCAT_DEP_PACKAGE_LIST=($(get_package_list xcat-dep)) [ "${#GO_XCAT_CORE_PACKAGE_LIST[@]}" -gt "0" ] warn_if_bad "$?" "Failed to get package list from repository \`xcat-core'." || return 1 [ "${#GO_XCAT_DEP_PACKAGE_LIST[@]}" -gt "0" ] warn_if_bad "$?" "Failed to get package list from repository \`xcat-dep'." || return 1 local -i cols="$(type tput >/dev/null 2>&1 && tput cols)" [[ "${cols}" -lt 80 ]] && cols=80 [[ "${cols}" -gt 90 ]] && cols=90 [[ -t 1 ]] || cols=90 local -i first_col=27 local -i second_col=$(( ( cols - 30 ) / 2 )) local -i third_col=${second_col} local pkg="" echo echo "xCAT Core Packages" echo "==================" echo printf "%-${first_col}s %-${second_col}s %-${third_col}s\n" \ "Package Name" "Installed" "In Repository" printf "%-${first_col}s %-${second_col}s %-${third_col}s\n" \ "------------" "---------" "-------------" for pkg in "${GO_XCAT_CORE_PACKAGE_LIST[@]}" do read -r i_ver && read -u 42 -r r_ver printf "%-${first_col}s %-${second_col}s %-${third_col}s\n" \ "${pkg:0:${first_col}}" \ "${i_ver:0:${second_col}}" \ "${r_ver:0:${third_col}}" done < <(check_package_version "${GO_XCAT_CORE_PACKAGE_LIST[@]}") \ 42< <(check_repo_version "${GO_XCAT_CORE_PACKAGE_LIST[@]}") echo echo "xCAT Dependency Packages" echo "========================" echo printf "%-${first_col}s %-${second_col}s %-${third_col}s\n" \ "Package Name" "Installed" "In Repository" printf "%-${first_col}s %-${second_col}s %-${third_col}s\n" \ "------------" "---------" "-------------" for pkg in "${GO_XCAT_DEP_PACKAGE_LIST[@]}" do read -r i_ver read -u 42 -r r_ver printf "%-${first_col}s %-${second_col}s %-${third_col}s\n" \ "${pkg:0:${first_col}}" \ "${i_ver:0:${second_col}}" \ "${r_ver:0:${third_col}}" done < <(check_package_version "${GO_XCAT_DEP_PACKAGE_LIST[@]}") \ 42< <(check_repo_version "${GO_XCAT_DEP_PACKAGE_LIST[@]}") } # # ask_to_continue Ask to continue # # Exits (not returns) if get negative reply from end user. # This function is intend to read from STDIN. # # $1 -y # $2 Prompt # function ask_to_continue() { [[ "$1" = "-y" ]] && return 0 shift local prompt="$1" echo echo "${prompt}" echo | debug_logger debug echo ".-> ${prompt}" | debug_logger debug while : do read -r -p "Continue? [y/n] " echo "'-> Continue? [y/n] ... ${REPLY}" | debug_logger debug case "${REPLY}" in "Y"*|"y"*) break ;; "N"*|"n"*) echo "Good-bye!" exit 0 ;; *) echo "Invalid response!" ;; esac done return 0 } # Test case 000 # Check if all the xcat-core packages are on the same version function test_case_000_version() { local ver="" local -i ret=0 list_xcat_packages >/dev/null || return 1 while read -r do [[ "${REPLY}" = "(not installed)" ]] && continue [[ -z "${ver}" ]] && ver="${REPLY%%-*}" [[ "${ver}" = "${REPLY%%-*}" ]] (( ret += $? )) done < <(check_package_version "${GO_XCAT_CORE_PACKAGE_LIST[@]}") warn_if_bad "${ret}" "xCAT packages version mismatch" return "${ret}" } # Test case 001 # Check if xcatd is running function test_case_001_xcatd() { local f="" local -i ret=0 for f in /var/run/xcat{d,/{main,udp,install,cmdlog}service}.pid do [ -f "${f}" ] warn_if_bad "$?" "${f}: no such file" || continue kill -0 "$(<"${f}")" >/dev/null 2>&1 warn_if_bad "$?" "Process with an ID $(<${f}) is not running" (( ret += $? )) done return "${ret}" } # Test case 002 # Check if command lsdef can be run function test_case_002_lsdef() { (source /etc/profile.d/xcat.sh && lsdef) >/dev/null 2>&1 warn_if_bad "$?" "Attempt of run \`lsdef' failed" } # Perform basic smoke testing function smoke_testing() { local test_case="" local -i ret=0 for test_case in $(compgen -A function "test_case_") do debug_trace "${test_case}" warn_if_bad "$?" "Something went wrong. :'(" || return 1 done echo echo "It seems everything went well. :-)" return 0 } GO_XCAT_METERS="" function show_progress_meters() { [[ -t 2 ]] || return 0 # Show the progress meters ( declare -i length=0 while : do for bar in \ "...... " \ ".o..o. " \ "oOooOo " \ "OoUUoO " \ "ooUUoo " \ "oOooOo " \ "Oo..oO " \ "o....o " #12345678901234567890123456789012345678901 do msg="${bar}" for (( i = 0; i < length; ++i )) do echo -ne "\b" done length=${#msg} echo -n "${msg}" sleep 0.1 2>/dev/null || sleep 1 kill -0 "$$" >/dev/null 2>&1 || break 2 done done ) >&2 & GO_XCAT_METERS="$!" disown "${GO_XCAT_METERS}" } function stop_progress_meters() { if [[ -t 2 ]] then kill "${GO_XCAT_METERS}" >/dev/null 2>&1 echo -ne "\b\b\b\b\b\b\b" >&2 fi echo -n "...... " } # $1 0 (pass) or non-zero (fail). function boo_boo_if_bad() { local -i rc="$1" # Ignore if no problems [ "${rc}" -eq "0" ] && return 0 debug_logger <<-EOF Boo-boo ======= Something went wrong. :( Please check log file \`${GO_XCAT_LOG}' for more details. EOF exit "${rc}" } # # |\/| _.o._ ._ .__ _ .__.._ _ _ _ _ _ |_ _ .__ # | |(_||| | |_)|(_)(_||(_|| | | (_|(_)(/__> | |(/_|(/_ o # | _| _| # # Main program goes here. declare -a GO_XCAT_YES=() GO_XCAT_ACTION="" GO_XCAT_CORE_URL="" GO_XCAT_DEP_URL="" GO_XCAT_VERSION="latest" while [ "$#" -gt "0" ] do case "$1" in "-h"|"--help") usage exit 0 ;; "--long-help") verbose_usage exit 0 ;; "--xcat-core") shift GO_XCAT_CORE_URL="$1" ;; "--xcat-core="*) GO_XCAT_CORE_URL="${1##--xcat-core=}" ;; "--xcat-dep") shift GO_XCAT_DEP_URL="$1" ;; "--xcat-dep="*) GO_XCAT_DEP_URL="${1##--xcat-dep=}" ;; "-x"|"--xcat-version") shift GO_XCAT_VERSION="$1" ;; "--xcat-version="*) GO_XCAT_VERSION="${1##--xcat-version=}" ;; "-y"|"--yes") GO_XCAT_YES=("-y") ;; "-"*) warn_if_bad 1 "invalid option -- \`$1'" exit_if_bad 1 "Try \`$0 --help' for more information" ;; *) [ "$1" == "--" ] && shift [ -z "${GO_XCAT_ACTION}" ] warn_if_bad "$?" "redundancy action -- \`$1'" exit_if_bad "$?" "Try \`$0 --help' for more information" GO_XCAT_ACTION="$1" case "$1 $2" in "completely uninstall") shift GO_XCAT_ACTION="away" ;; "smoke test") shift GO_XCAT_ACTION="smoke test" ;; esac ;; esac shift done case "${GO_XCAT_ACTION}" in "away"|"check"|"install"|"uninstall"|"update") ;; "smoke test") smoke_testing exit "$?" ;; "") usage exit 1 ;; *) warn_if_bad 1 "invalid action -- \`${GO_XCAT_ACTION}'" exit_if_bad 1 "Try \`$0 --help' for more information" ;; esac # case "${GO_XCAT_ACTION}" in GO_XCAT_OS="$(check_os)" GO_XCAT_ARCH="$(check_arch)" debug_logger <&1)" RET="$?" stop_progress_meters if [[ "${RET}" -ne 0 ]] then echo "failed" echo "${ERR_MSG}" >&2 exit "${RET}" fi echo "done" case "${GO_XCAT_ACTION}" in "check") list_xcat_packages ;; "install"|"update") GO_XCAT_INSTALLER="${GO_XCAT_ACTION}_xcat" ask_to_continue "${GO_XCAT_YES[0]}" "xCAT is going to be ${GO_XCAT_ACTION/%e/}ed." # Use `-y' here. Since the STDOUT is redirected. # `yum' does not display the prompt message properly when # working with redirected I/O. debug_trace "${GO_XCAT_INSTALLER}" -y RET="$?" if [[ "${RET}" -eq "0" ]] then # xCAT has been installed and so far so good smoke_testing >/dev/null 2>&1 RET="$?" fi boo_boo_if_bad "${RET}" case "${GO_XCAT_ACTION}" in "install") # Only print out this message on install debug_logger <<-EOF xCAT has been installed! ======================== If this is the very first time xCAT has been installed, run one of the following commands to set the environment variables. For sh: source /etc/profile.d/xcat.sh For csh: source /etc/profile.d/xcat.csh EOF ;; "update") debug_logger <<-EOF xCAT has been successfully updated! EOF ;; esac ;; *) exit 1 ;; esac # case "${GO_XCAT_ACTION}" in exit 0 # vim: filetype=sh # vim: noautoindent # vim: tabstop=4 shiftwidth=4 softtabstop=4 # End of file