From 01ad6cd6a612dd3f7e24923bf2b89d12d0d21c60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=E1=B4=8F=C9=B4=C9=A2=20Jie?= Date: Thu, 25 Oct 2018 13:24:15 +0800 Subject: [PATCH] Uninstall xCAT with go-xcat (#5674) * [go-xcat] Revise debug log, in order to make debugging go-xcat and bug reporting easier. * [go-xcat] Revise the prompt messages * [go-xcat] In yum/zypper repo file, use gpgcheck=1 * [go-xcat] Bump version number * [go-xcat] Revise the help messages * [go-xcat] xCAT uninstallation * [go-xcat] Fix kill command error messages * [go-xcat] Simplify command line argument processing * [go-xcat] When do a `check', only run update_repo * Update document of xCAT uninstallation - use `go-xcat uninstall` * [go-xcat] Handle goconserver in trash_xcat() * [go-xcat] Add goconserver to the uninstallation package list * Add goconserver to the uninstallation package list * [go-xcat] Fix debug_logger * [go-xcat] xCAT can be completely uninstalled --- .../maintenance/uninstall_xcat.rst | 19 +- xCAT-server/share/xcat/tools/go-xcat | 525 +++++++++++++----- 2 files changed, 406 insertions(+), 138 deletions(-) diff --git a/docs/source/guides/install-guides/maintenance/uninstall_xcat.rst b/docs/source/guides/install-guides/maintenance/uninstall_xcat.rst index c3e84774b..b31b1a79d 100644 --- a/docs/source/guides/install-guides/maintenance/uninstall_xcat.rst +++ b/docs/source/guides/install-guides/maintenance/uninstall_xcat.rst @@ -46,18 +46,25 @@ Stop xCAT Service Remove xCAT Files ----------------- -1. Remove the xCAT RPMs +1. Remove xCAT Packages - There is no easy way to identify all xCAT packages. For packages shipped by xCAT, you can remove them by using the commands below. + To automatically remove all xCAT packages, run the following command :: - [RHEL and SLES] :: + /opt/xcat/share/xcat/tools/go-xcat uninstall - yum remove '*xcat*' - yum remove '*xCAT*' + There is no easy way to identify all xCAT packages. For packages shipped by xCAT, you can manually remove them by using one of the commands below. + + [RHEL] :: + + yum remove conserver-xcat elilo-xcat goconserver grub2-xcat ipmitool-xcat perl-xCAT syslinux-xcat xCAT xCAT-SoftLayer xCAT-buildkit xCAT-client xCAT-confluent xCAT-csm xCAT-genesis-base-ppc64 xCAT-genesis-base-x86_64 xCAT-genesis-scripts-ppc64 xCAT-genesis-scripts-x86_64 xCAT-openbmc-py xCAT-probe xCAT-server xnba-undi yaboot-xcat + + [SLES] :: + + zypper remove conserver-xcat elilo-xcat goconserver grub2-xcat ipmitool-xcat perl-xCAT syslinux-xcat xCAT xCAT-SoftLayer xCAT-buildkit xCAT-client xCAT-confluent xCAT-csm xCAT-genesis-base-ppc64 xCAT-genesis-base-x86_64 xCAT-genesis-scripts-ppc64 xCAT-genesis-scripts-x86_64 xCAT-openbmc-py xCAT-probe xCAT-server xnba-undi yaboot-xcat [Ubuntu] :: - dpkg -l | awk '/xcat/ { print $2 }' + apt-get remove conserver-xcat elilo-xcat goconserver grub2-xcat ipmitool-xcat perl-xcat syslinux-xcat xcat xcat-buildkit xcat-client xcat-confluent xcat-genesis-base-amd64 xcat-genesis-base-ppc64 xcat-genesis-scripts-amd64 xcat-genesis-scripts-ppc64 xcat-probe xcat-server xcat-test xcat-vlan xcatsn xnba-undi To do an even more thorough cleanup, use links below to get a list of RPMs installed by xCAT. Some RPMs may not to be installed in a specific environment. diff --git a/xCAT-server/share/xcat/tools/go-xcat b/xCAT-server/share/xcat/tools/go-xcat index add91c1af..80a888362 100755 --- a/xCAT-server/share/xcat/tools/go-xcat +++ b/xCAT-server/share/xcat/tools/go-xcat @@ -2,7 +2,7 @@ # # go-xcat - Install xCAT automatically. # -# Version 1.0.29 +# Version 1.0.30 # # Copyright (C) 2016, 2017, 2018 International Business Machines # Eclipse Public License, Version 1.0 (EPL-1.0) @@ -18,6 +18,9 @@ # - 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() @@ -50,6 +53,9 @@ function usage() 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} @@ -62,8 +68,10 @@ function usage() --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 + xCAT: http://xcat.org/ Full documentation at: http://xcat-docs.readthedocs.io/en/stable EOF } @@ -96,16 +104,13 @@ function verbose_usage() -h, --help display a simply version of help and exit --long-help display this help and exit EOF - println 12 + 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 - EOF - println 2 - while read -r ; do echo "${REPLY}" ; done <<-EOF smoke-test preform basic tests of the xCAT installation EOF - println 10 + 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 @@ -122,6 +127,11 @@ function verbose_usage() ${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<&- @@ -159,6 +169,14 @@ 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 @@ -295,8 +313,10 @@ function internal_cleanup() # function custom_setup() { - check_exec_or_exit awk cat comm grep printf sleep tee + check_exec_or_exit awk cat comm grep printf sleep check_root_or_exit + + debug_log_setup } # @@ -304,7 +324,7 @@ function custom_setup() # function custom_cleanup() { - : + debug_log_cleanup } # @@ -319,6 +339,101 @@ function cleanup_n_exec() exec "$@" } +function debug_log_setup() +{ + local script="${0##*/}" + + 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}" "${BASH_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 @@ -960,9 +1075,10 @@ function add_repo_by_url_yum_or_zypper() while read -r ; do echo "${REPLY}" ; done >"${tmp}" <<-EOF [${repo_id}] name=${repo_id} - baseurl=${url} + baseurl=${url%/} enabled=1 - gpgcheck=0 + gpgcheck=1 + gpgkey=${url%/}/repodata/repomd.xml.key EOF add_repo_by_file "${tmp}" "${repo_id}" return "$?" @@ -995,9 +1111,10 @@ function add_repo_by_url_yum_or_zypper() while read -r ; do echo "${REPLY}" ; done >"${tmp}" <<-EOF [${repo_id}] name=${repo_id} - baseurl=file://${url} + baseurl=file://${url%/} enabled=1 - gpgcheck=0 + gpgcheck=1 + gpgkey=file://${url%/}/repodata/repomd.xml.key EOF add_repo_by_file "${tmp}" "${repo_id}" return "$?" @@ -1351,6 +1468,52 @@ 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() { @@ -1381,6 +1544,62 @@ function update_xcat() 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)) @@ -1438,12 +1657,55 @@ function list_xcat_packages() 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 + while read -r do [[ "${REPLY}" = "(not installed)" ]] && continue @@ -1451,6 +1713,7 @@ function test_case_000_version() [[ "${ver}" = "${REPLY%%-*}" ]] (( ret += $? )) done < <(check_package_version "${GO_XCAT_CORE_PACKAGE_LIST[@]}") + return "${ret}" } @@ -1460,17 +1723,13 @@ function test_case_001_xcatd() { local f="" local -i ret=0 - for f in /var/run/xcat/{main,install,udp}service.pid + + for f in /var/run/xcat{d,/{main,udp,install,cmdlog}service}.pid do - kill -0 "$(<"${f}")" - (( ret += $? )) - done - for f in /var/run/xcat/cmdlogservice.pid - do - [[ -f "${f}" ]] || continue - kill -0 "$(<"${f}")" + kill -0 "$(<"${f}")" 2>/dev/null (( ret += $? )) done + return "${ret}" } @@ -1481,32 +1740,24 @@ function test_case_002_lsdef() (source /etc/profile.d/xcat.sh && lsdef) } -# Perform basic smoke test -function perform_smoke_test() +# Perform basic smoke tests +function perform_smoke_tests() { local test_case="" local -i ret=0 + for test_case in $(compgen -A function "test_case_") do - "${test_case}" >"${TMP_DIR}/${test_case}.stdout" \ - 2>"${TMP_DIR}/${test_case}.stderr" + debug_trace "${test_case}" ret="$?" - if [[ "${ret}" -ne "0" || -s "${TMP_DIR}/${test_case}.stderr" ]] + + if [[ "${ret}" -ne "0" ]] then - # Something went wrong - echo "-- 8< -- -- -- -- -- -- -- -- -- -- -- -- -- -- --" - echo "==== ${test_case} failed with exit code ${ret} ====" - echo "-- 8< ${test_case} stdout -- --" - while read -r ; do echo "${REPLY}" ; done \ - <"${TMP_DIR}/${test_case}.stdout" - echo "-- 8< ${test_case} stderr -- --" - while read -r ; do echo "${REPLY}" ; done \ - <"${TMP_DIR}/${test_case}.stderr" - echo "-- 8< -- -- -- -- -- -- -- -- -- -- -- -- -- -- --" - # skip all the remain test cases return "${ret}" - fi >&2 + fi done + + echo echo "It seems everything went well. :)" return 0 } @@ -1559,6 +1810,27 @@ function stop_progress_meters() 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 @@ -1583,7 +1855,7 @@ do verbose_usage exit 0 ;; - "--xcat-core") + "-x"|"--xcat-core") shift GO_XCAT_CORE_URL="$1" ;; @@ -1604,10 +1876,6 @@ do "--xcat-version="*) GO_XCAT_VERSION="${1##--xcat-version=}" ;; - "-x") - shift - GO_XCAT_VERSION="$1" - ;; "-y"|"--yes") GO_XCAT_YES=("-y") ;; @@ -1621,16 +1889,21 @@ do warn_if_bad "$?" "redundancy action -- \`$1'" exit_if_bad "$?" "Try \`$0 --help' for more information" GO_XCAT_ACTION="$1" + if [ "$1 $2" == "completely uninstall" ] + then + shift + GO_XCAT_ACTION="away" + fi ;; esac shift done case "${GO_XCAT_ACTION}" in -"check"|"install"|"update") +"away"|"check"|"install"|"uninstall"|"update") ;; "smoke-test") - perform_smoke_test + perform_smoke_tests exit "$?" ;; "") @@ -1641,13 +1914,12 @@ case "${GO_XCAT_ACTION}" in warn_if_bad 1 "invalid action -- \`${GO_XCAT_ACTION}'" exit_if_bad 1 "Try \`$0 --help' for more information" ;; -esac +esac # case "${GO_XCAT_ACTION}" in GO_XCAT_OS="$(check_os)" GO_XCAT_ARCH="$(check_arch)" -while read -r ; do echo "${REPLY}" ; echo "${REPLY}" >&2 - done 2>"${TMP_DIR}/go-xcat.log.000" <&2 - done 2>"${TMP_DIR}/go-xcat.log.001" <&1)" @@ -1716,95 +2041,31 @@ case "${GO_XCAT_ACTION}" in ;; "install"|"update") GO_XCAT_INSTALLER="${GO_XCAT_ACTION}_xcat" - if [[ "${#GO_XCAT_YES[@]}" -eq "0" ]] - then - echo - echo "xCAT is going to be ${GO_XCAT_ACTION/%e/}ed." - while true; do - - read -r -p "Continue? [y/n] " - case "${REPLY}" in - "Y"*|"y"*) - break - ;; - "N"*|"n"*) - echo "Good-bye!" - exit 0 - ;; - *) - echo "Invalid response!" - ;; - esac - done - fi - # Use `-y' here. Since the STDOUT is redirect to tee. + 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 tee. - "${GO_XCAT_INSTALLER}" -y \ - > >(tee "${TMP_DIR}/${GO_XCAT_INSTALLER}.stdout") \ - 2> >(tee "${TMP_DIR}/${GO_XCAT_INSTALLER}.stderr" >&2) + # working with redirected I/O. + debug_trace "${GO_XCAT_INSTALLER}" -y RET="$?" - { - # Creating logs - echo "-- 8< -- -- -- -- -- -- -- -- -- -- -- -- -- -- --" - echo "==== ${GO_XCAT_INSTALLER} exited with exit code ${RET} ====" - echo "-- 8< ${GO_XCAT_INSTALLER} stdout -- --" - while read -r ; do echo "${REPLY}" ; done \ - <"${TMP_DIR}/${GO_XCAT_INSTALLER}.stdout" - echo "-- 8< ${GO_XCAT_INSTALLER} stderr -- --" - while read -r ; do echo "${REPLY}" ; done \ - <"${TMP_DIR}/${GO_XCAT_INSTALLER}.stderr" - echo "-- 8< -- -- -- -- -- -- -- -- -- -- -- -- -- -- --" - } >"${TMP_DIR}/go-xcat.log.005" - if [[ "${RET}" -eq "0" && ! -s "${TMP_DIR}/${GO_XCAT_INSTALLER}.stderr" ]] + if [[ "${RET}" -eq "0" ]] then # xCAT has been installed and so far so good - perform_smoke_test >"${TMP_DIR}/perform_smoke_test.stdout" \ - 2>"${TMP_DIR}/perform_smoke_test.stderr" + perform_smoke_tests >/dev/null 2>&1 RET="$?" - if [[ "${RET}" -ne "0" || -s "${TMP_DIR}/perform_smoke_test.stderr" ]] - then - # Smoke test failed - echo "-- 8< -- -- -- -- vv -- -- -- vv -- -- -- -- 8< --" - echo "==== perform_smoke_test failed with exit code ${RET} ====" - echo "-- 8< perform_smoke_test stdout -- --" - while read -r ; do echo "${REPLY}" ; done \ - <"${TMP_DIR}/perform_smoke_test.stdout" - echo "-- 8< perform_smoke_test stderr -- --" - while read -r ; do echo "${REPLY}" ; done \ - <"${TMP_DIR}/perform_smoke_test.stderr" - echo "-- 8< -- -- -- -- ^^ -- -- -- ^^ -- -- -- -- 8< --" - fi - fi >"${TMP_DIR}/go-xcat.log.008" - - if [[ "${RET}" -ne "0" ]] - then - GO_XCAT_LOG="/tmp/go-xcat.log" - cat "${TMP_DIR}/go-xcat.log."* >"${GO_XCAT_LOG}" 2>/dev/null - while read -r ; do echo "${REPLY}" ; done >&2 <<-EOF - - - Boo-boo - ======= - - Something went wrong. :( - - Please check log file \`${GO_XCAT_LOG}' for more details. - EOF - - exit "${RET}" fi + boo_boo_if_bad "${RET}" + case "${GO_XCAT_ACTION}" in "install") # Only print out this message on install - while read -r ; do echo "${REPLY}" ; done <<-EOF + debug_logger <<-EOF xCAT has been installed! ======================== - If this is the very first time xCAT has been installed, run the following - commands to set environment variables into your PATH: + 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 @@ -1814,7 +2075,7 @@ case "${GO_XCAT_ACTION}" in EOF ;; "update") - while read -r ; do echo "${REPLY}" ; done <<-EOF + debug_logger <<-EOF xCAT has been successfully updated! EOF