diff --git a/tools/ocft/caselib.in b/tools/ocft/caselib.in index 8c8a45ac0..01b108fab 100644 --- a/tools/ocft/caselib.in +++ b/tools/ocft/caselib.in @@ -1,294 +1,306 @@ # # Copyright (c) 2010-2011 Novell Inc, John Shi # All Rights Reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of version 2 of the GNU General Public License as # published by the Free Software Foundation. # # This program is distributed in the hope that it would be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # # Further, this software is distributed without any warranty that it is # free of the rightful claim of any third person regarding infringement # or the like. Any license provided herein, whether implied or # otherwise, applies only to this software file. Patent licenses, if # any, provided herein do not apply to combinations of this program with # other software, or any other product whatsoever. # # You should have received a copy of the GNU General Public License # along with this program; if not, write the Free Software Foundation, # Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. quit() { local ret ret="$1" while [ $__OCFT__atexit_num -gt 0 ]; do atexit$__OCFT__atexit_num let __OCFT__atexit_num-- done rm -rf $__OCFT__fakebin exit $ret } agent_install() { local pkg if [ $# -eq 0 ]; then return 0 fi for pkg in "$@"; do if [ -e /etc/SuSE-release ]; then if ! rpm -ql "$pkg" >/dev/null 2>&1; then echo "${__OCFT__showhost}Installing $pkg ..." zypper -q install -y "$pkg" >/dev/null 2>&1 if ! rpm -ql "$pkg" >/dev/null 2>&1; then echo echo "${__OCFT__showhost}ERROR: Install '$pkg' failed." quit 2 fi echo "done" echo fi elif [ -e /etc/debian_version ]; then if ! dpkg -L "$pkg" >/dev/null 2>&1; then echo "${__OCFT__showhost}Installing $pkg ..." apt-get -y install "$pkg" >/dev/null 2>&1 if ! dpkg -L "$pkg" >/dev/null 2>&1; then echo echo "${__OCFT__showhost}ERROR: Install '$pkg' failed." quit 2 fi echo "done" echo fi elif [ -e /etc/redhat-release ]; then if ! rpm -ql "$pkg" >/dev/null 2>&1; then echo "${__OCFT__showhost}Installing $pkg ..." yum -y install "$pkg" >/dev/null 2>&1 if ! rpm -ql "$pkg" >/dev/null 2>&1; then echo echo "${__OCFT__showhost}ERROR: Install '$pkg' failed." quit 2 fi echo "done" echo fi else echo "${__OCFT__showhost}ERROR: Cannot detect your OS type." quit 2 fi done } +set_ocf_env() +{ + export OCF_RA_VERSION_MAJOR=1 + export OCF_RA_VERSION_MINOR=0 + export OCF_RESOURCE_TYPE=$1 + export OCF_RESOURCE_INSTANCE=${OCF_RESOURCE_INSTANCE:-"ocft"} +} + agent_run() { local agent cmd timeout pid i ret aroot agent="$1" cmd="$2" timeout="$3" + set_ocf_env $agent + aroot=${__OCFT__MYROOT:-$__OCFT__AGENT_ROOT} setsid $aroot/$agent $cmd >/tmp/.ocft_runlog 2>&1 & pid=$! i=0 while [ $i -lt $timeout ]; do if [ ! -e /proc/$pid ]; then break fi sleep 1 let i++ done if [ $i -ge $timeout ]; then kill -SIGTERM -$pid >/dev/null 2>&1 sleep 3 kill -SIGKILL -$pid >/dev/null 2>&1 echo -n "${__OCFT__showhost}ERROR: The agent was hanging, killed it, " echo "maybe you damaged the agent or system's environment, see details below:" cat /tmp/.ocft_runlog echo quit 1 fi wait $pid } check_success() { local ret msg ret="$1" msg="$2" if [ $ret -ne 0 ]; then echo "${__OCFT__showhost}ERROR: '${msg}' failed, the return code is ${ret}." quit 1 fi } __maxfd() { (echo 0; ls -1 /proc/$$/fd) | sort -rn | head -1 } __getfd() { local host rw fd file host="$1" rw="$2" for fd in /proc/$$/fd/*; do file=$(basename "$(readlink $fd)") if [ "$file" = "${host}_$rw" ]; then basename $fd break fi done } backbash_start() { local host fd rfd wfd host="$1" if [ ! -d "$__OCFT__CASES_DIR" ]; then echo "${__OCFT__showhost}ERROR: Could not found Directory: ${__OCFT__CASES_DIR}." quit 1 fi if lsof $__OCFT__CASES_DIR/${host}_r $__OCFT__CASES_DIR/${host}_w >/dev/null 2>&1; then echo "${__OCFT__showhost}ERROR: Connection exist with $host." quit 1 fi if [ ! -p "$__OCFT__CASES_DIR/${host}_r" ] || [ ! -p "$__OCFT__CASES_DIR/${host}_w" ]; then rm -f $__OCFT__CASES_DIR/${host}_r $__OCFT__CASES_DIR/${host}_w if ! mkfifo $__OCFT__CASES_DIR/${host}_r $__OCFT__CASES_DIR/${host}_w >/dev/null 2>&1; then echo "${__OCFT__showhost}ERROR: Could not create pipe file: $__OCFT__CASES_DIR/${host}_*." quit 1 fi fi ssh root@$host '/bin/bash 2>&1 sed "s/00/001/g" /tmp/.backbash-log echo 000 echo 1' >$__OCFT__CASES_DIR/${host}_r <$__OCFT__CASES_DIR/${host}_w & fd=$(__maxfd) rfd=$(expr $fd + 1) wfd=$(expr $fd + 2) eval "exec ${rfd}<$__OCFT__CASES_DIR/${host}_r ${wfd}>$__OCFT__CASES_DIR/${host}_w" } backbash() { local host rfd wfd ret host="$1" rfd=$(__getfd $host r) wfd=$(__getfd $host w) if [ -z "$rfd" -o -z "$wfd" ]; then echo "${__OCFT__showhost}ERROR: Could not found connection with $host." fi cat >&$wfd <&$wfd cat >&$wfd <&/tmp/.backbash-log sed 's/00/001/g' /tmp/.backbash-log echo 000 echo 0 EOF if [ $? -ne 0 ]; then echo "${__OCFT__showhost}ERROR: Broken connection with $host." quit 1 fi awk -vlive=2 '{ if (sub(/000$/, "")) { if ($0 != "") { gsub("001", "00"); printf("%s", $0); } getline live; exit; } gsub("001", "00"); print; } END { exit(live); }' <&$rfd case $? in 1) quit 1 ;; 2) echo "${__OCFT__showhost}ERROR: Broken connection with $host." quit 1 ;; esac } backbash_stop() { local host rfd wfd host="$1" wfd=$(__getfd $host w) if [ -n "$wfd" ]; then cat >&$wfd <<<'quit 0' fi rm -f $__OCFT__CASES_DIR/${host}_r $__OCFT__CASES_DIR/${host}_w } export OCF_ROOT=@OCF_ROOT_DIR@ export OCF_LIB=@OCF_LIB_DIR@/heartbeat __OCFT__AGENT_ROOT=@OCF_RA_DIR@/heartbeat __OCFT__CASES_DIR=/var/lib/@PACKAGE_NAME@/ocft/cases __OCFT__atexit_num=0 if [ $EUID -ne 0 ]; then echo "${__OCFT__showhost}ERROR: '$0' needs to be run by root." quit 3 fi __OCFT__fakebin=./fakebin mkdir -p $__OCFT__fakebin >/dev/null 2>&1 && ln -sf /bin/true $__OCFT__fakebin/crm_master >/dev/null 2>&1 && ln -sf /bin/true $__OCFT__fakebin/crm_mon >/dev/null 2>&1 if [ $? -ne 0 ]; then echo "${__OCFT__showhost}ERROR: initialize 'fakebin' failed." quit 3 fi export HA_SBIN_DIR=$__OCFT__fakebin . $OCF_LIB/ocf-returncodes || { echo "${__OCFT__showhost}ERROR: $OCF_LIB/ocf-returncodes not found." quit 3 } while read __OCFT__line; do if [ -n "$__OCFT__line" ]; then __OCFT__retn=${__OCFT__line%%=*} __OCFT__reti=$(eval echo \$$__OCFT__retn) __OCFT__retval[__OCFT__reti]=$__OCFT__retn fi done <<<"$(sed 's/#.*//' $OCF_LIB/ocf-returncodes)" + +# vim:ts=2:sw=2:et: diff --git a/tools/ocft/ocft.in b/tools/ocft/ocft.in index b84046098..54124a25a 100644 --- a/tools/ocft/ocft.in +++ b/tools/ocft/ocft.in @@ -1,895 +1,882 @@ #!/bin/bash # Copyright (c) 2010-2013 Novell Inc, John Shi # All Rights Reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of version 2 of the GNU General Public License as # published by the Free Software Foundation. # # This program is distributed in the hope that it would be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # # Further, this software is distributed without any warranty that it is # free of the rightful claim of any third person regarding infringement # or the like. Any license provided herein, whether implied or # otherwise, applies only to this software file. Patent licenses, if # any, provided herein do not apply to combinations of this program with # other software, or any other product whatsoever. # # You should have received a copy of the GNU General Public License # along with this program; if not, write the Free Software Foundation, # Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. die() { local str str="$1" echo "ERROR: $str" >&2 exit 1 } warn() { local str str="$1" echo "WARNING: $str" >&2 } parse_die() { local str str="$1" agent_parse_finish die "${agent}: line ${line_num}: ${str}" } # add quotes to string for Here Documents add_quotes() { local typ str a b typ="$1" str="$2" case "$typ" in 1) a=\'; b=\";; 2) a=\"; b=\';; esac echo "$str" | sed "s/$a/$a$b$a$b$a/g; 1 s/^/$a/; $ s/$/$a/" } # split strings explode() { local str str="$1" echo "$str" | awk -F'"' '{ if (NF > 0 && NF%2 == 0) exit(1); for (i=1; i<=NF; i++) { if (i%2 == 0) print $i; else { len = split($i, str, /[ \t]+/); for (j=1; j<=len; j++) { sb = sub(/#.*/, "", str[j]); if (str[j] != "") print str[j]; if (sb) exit(0); } } } }' } # phase 1: parse the string to 'command' and 'argument collection'. line2trunk() { trunk[0]="${line%%[[:blank:]]*}" trunk[1]="${line#*[[:blank:]]}" } # phase 2: split the argument collection. trunk2branch() { local IFS # Some of statements need one parameter at least. if [ "$line" = "${trunk[0]}" ]; then parse_die "missing parameter." fi IFS=$'\n' branch=($(explode "${trunk[1]}")) if [ $? -ne 0 ]; then parse_die "missing '\"'." fi } preparse_cfg() { local agent line trunk branch macro num host agent="$1" if [ ! -r "$opt_cfgsdir/$agent" ]; then die "${agent}: configuration file not found." fi line_num=0 while read -r line; do let line_num++ num=" $line_num" case "$line" in ""|\#*) continue;; esac line2trunk case "${trunk[0]}" in CASE-BLOCK) trunk2branch macro="$CASES_DIR/${agent}_macro.${branch[0]}" continue ;; Include|Include@*) host=$(echo "${trunk[0]}" | awk -F@ '{print $2}') trunk2branch if [ ! -r "$CASES_DIR/${agent}_macro.${branch[0]}" ]; then parse_die "Macro '${branch[0]}' not found." fi if [ -n "$host" ]; then line="$(sed -e 's/^\([^[:blank:]]*\)@[^[:blank:]]*/\1/' -e "s/^[^[:blank:]]*/&@$host/" "$CASES_DIR/${agent}_macro.${branch[0]}")" else line="$(<"$CASES_DIR/${agent}_macro.${branch[0]}")" fi num= ;; *[!A-Z-]*) : ;; *) macro= ;; esac if [ -n "$macro" ]; then echo "$line$num" >>"$macro" else echo "$line$num" >>"$CASES_DIR/${agent}_preparse" fi done <"$opt_cfgsdir/$agent" } case_parse_finish() { local host if [ -n "$sh" ]; then cat >>$sh <>$sh done echo "quit 0" >>$sh fi atexit_num=0 hosts= sh= } init_cfg_vars() { cfg_agent= cfg_agent_root= cfg_install_package=() cfg_hang_timeout=20 } agent_parse_finish() { local suf for suf in preparse setup cleanup var hosts; do rm -f $CASES_DIR/${agent}_$suf done rm -f $CASES_DIR/${agent}_macro.* init_cfg_vars } need_make() { local src_time obj_time if [ ! -f "$CASES_DIR/0_${agent}.sh" ]; then return 0 fi src_time=$(stat -c '%Y' "$opt_cfgsdir/$agent") obj_time=$(stat -c '%Y' "$CASES_DIR/0_${agent}.sh") test $src_time -ge $obj_time } parse_cfg() { local agents i line stat sh trunk branch atexit_num host hosts if [ $# -eq 0 ]; then agents=($opt_cfgsdir/*) else agents=("$@") fi for agent in "${agents[@]}"; do agent="$(basename "$agent")" if ! need_make; then continue fi agent_obj_clean $agent agent_parse_finish i=0 echo "Making '$agent': " preparse_cfg "$agent" while read -r line; do line_num="${line##* }" line="${line% *}" line2trunk # state switch case "${trunk[0]}" in CONFIG) case_parse_finish stat=1 continue ;; VARIABLE) case_parse_finish stat=2 continue ;; SETUP-AGENT) case_parse_finish stat=3 continue ;; CLEANUP-AGENT) case_parse_finish stat=4 continue ;; CASE) case_parse_finish trunk2branch echo " - case ${i}: ${branch[0]}" sh="$CASES_DIR/${i}_${agent}.sh" cat >$sh <>$CASES_DIR/${agent}_var ;; 3) echo "$line" >>$CASES_DIR/${agent}_setup ;; 4) echo "$line" >>$CASES_DIR/${agent}_cleanup ;; 5) host=$(echo ${trunk[0]} | awk -F@ '{print $2}') if [ -n "$host" ]; then if ! echo "$hosts" | grep -q "$host"; then echo "$host" >>$CASES_DIR/${agent}_hosts hosts=$hosts$'\n'$host cat >>$sh <>$sh if [ -n "$host" ]; then echo "backbash $host <<'CMD'" >>$sh fi case "${trunk[0]}" in Env|Env@*) cat >>$sh <>$sh <>$sh <>$sh <>$sh <>$sh <>$sh <>$sh <>$sh <>$sh fi ;; *) parse_die "unimplemented statement: ${trunk[0]}" ;; esac done <$CASES_DIR/${agent}_preparse if [ -r "$CASES_DIR/${agent}_setup" ]; then cat >$CASES_DIR/setup_${agent}.sh <>$CASES_DIR/setup_${agent}.sh <>$CASES_DIR/setup_${agent}.sh <$CASES_DIR/cleanup_${agent}.sh <>$CASES_DIR/cleanup_${agent}.sh <>$CASES_DIR/cleanup_${agent}.sh </dev/null 2>&1; then die "cases directory not found." fi if [ ! -d logs ]; then mkdir logs fi export __OCFT__VERBOSE=$opt_verbose if [ $# -eq 0 ]; then agents=($(ls -1 *.sh 2>/dev/null | sed 's/.*_\([^_]*\)\.sh$/\1/' | sort | uniq)) else agents=("$@") fi for shs in "${agents[@]}"; do - set_ocf_env $shs if [ -z "$opt_incremental" ]; then testsh="setup_${shs}.sh $(ls -1 [0-9]*_${shs}.sh 2>/dev/null | sort -n) cleanup_${shs}.sh" else testsh="setup_${shs}.sh $(ls -1 [0-9]*_${shs}.retest 2>/dev/null | sed 's/retest$/sh/' | sort -n) cleanup_${shs}.sh" fi if [ -n "$opt_trace_ra" ]; then varlib=${HA_VARLIB:="/var/lib/heartbeat"} export OCF_RESKEY_trace_ra=1 - # not exactly resource type, but for this purpose ... - export OCF_RESOURCE_TYPE="ocft_$shs" - echo "RA trace on, output in $varlib/trace_ra/${OCF_RESOURCE_TYPE}" + echo "RA trace on, output in $varlib/trace_ra" fi for sh in $testsh; do if [ -r "$sh" ]; then if [ -n "$opt_trace_ra" ]; then - OCF_RESOURCE_INSTANCE="`echo $sh | sed 's/_.*//'`" + export OCF_RESOURCE_INSTANCE="`echo $sh | sed 's/_.*//'`" fi ./$sh ret=$? case "$sh" in setup*) if [ $ret -ne 0 ]; then warn "SETUP failed, break all tests of '$shs'." break fi ;; cleanup*) if [ $ret -ne 0 ]; then warn "CLEANUP failed." fi ;; [0-9]*) case $ret in 3) die "core function failed, break all tests." ;; 2) warn "core function failed, break all tests of '$shs'."; break ;; 1) touch ${sh%.*}.retest ;; 0) rm -f ${sh%.*}.retest ;; esac ;; esac fi done 2>&1 | while read -r line; do echo "$line" echo "$(date '+%F %T'): $line" | cat -A | sed -r 's/\^\[\[[0-9]+m|\^I|.$//g' >>logs/$shs.log done done } agent_clean() { local typ ra typ=$1 shift if [ $# -eq 0 ]; then rm -f $CASES_DIR/*.$typ else for ra in "$@"; do rm -f $CASES_DIR/*_${ra}.$typ done fi } agent_retest_clean() { agent_clean retest "$@" } agent_obj_clean() { agent_clean sh "$@" } usage() { cat <