#!/bin/sh prog="ctdb" # Print a message and exit. die () { echo "$1" >&2 ; exit ${2:-1} } not_implemented_exit_code=1 usage () { cat >&2 <&2 exit $not_implemented_exit_code } # Don't set $POSIXLY_CORRECT here. _temp=$(getopt -n "$prog" -o "Xvhn:" -l help -- "$@") || \ usage eval set -- "$_temp" verbose=false machine_readable=false nodespec="" args="$*" while true ; do case "$1" in -X) machine_readable=true ; shift ;; -v) verbose=true ; shift ;; -n) nodespec="$2" ; shift 2 ;; --) shift ; break ;; -h|--help|*) usage ;; # * shouldn't happen, so this is reasonable. esac done [ $# -ge 1 ] || usage setup_tickles () { # Make sure tickles file exists. tickles_file="$EVENTSCRIPTS_TESTS_VAR_DIR/fake-ctdb/tickles" mkdir -p $(dirname "$tickles_file") touch "$tickles_file" } ctdb_killtcp () { while read _src _dst ; do sed -i -e "/^$_dst $_src\$/d" "$FAKE_NETSTAT_TCP_ESTABLISHED_FILE" done } parse_nodespec () { if [ "$nodespec" = "all" ] ; then nodes="$(seq 0 $((FAKE_CTDB_NUMNODES - 1)) )" elif [ -n "$nodespec" ] ; then nodes="$(echo $nodespec | sed -e 's@,@ @g')" else _t=$(ctdb_pnn) nodes="${_t#PNN:}" fi } # For testing backward compatibility... for i in $CTDB_NOT_IMPLEMENTED ; do if [ "$i" = "$1" ] ; then not_implemented "$i" fi done ctdb_pnn () { # Defaults to 0 echo "PNN:${FAKE_CTDB_PNN:-0}" } ###################################################################### FAKE_CTDB_NODE_STATE="$FAKE_CTDB_STATE/node-state" FAKE_CTDB_NODES_DISABLED="$FAKE_CTDB_NODE_STATE/0x4" ###################################################################### # NOTE: all nodes share $CTDB_PUBLIC_ADDRESSES FAKE_CTDB_IP_LAYOUT="$FAKE_CTDB_STATE/ip-layout" ip_reallocate () { touch "$FAKE_CTDB_IP_LAYOUT" ( flock 0 _pa="${CTDB_PUBLIC_ADDRESSES:-${CTDB_BASE}/public_addresses}" if [ ! -s "$FAKE_CTDB_IP_LAYOUT" ] ; then sed -n -e 's@^\([^#][^/]*\)/.*@\1 -1@p' \ "$_pa" >"$FAKE_CTDB_IP_LAYOUT" fi _t="${FAKE_CTDB_IP_LAYOUT}.new" _flags="" for _i in $(seq 0 $((FAKE_CTDB_NUMNODES - 1)) ) ; do if ls "$FAKE_CTDB_STATE/node-state/"*"/$_i" >/dev/null 2>&1 ; then # Have non-zero flags _this=0 for _j in "$FAKE_CTDB_STATE/node-state/"*"/$_i" ; do _tf="${_j%/*}" # dirname _f="${_tf##*/}" # basename _this=$(( $_this | $_f )) done else _this="0" fi _flags="${_flags}${_flags:+,}${_this}" done CTDB_TEST_LOGLEVEL=2 \ "ctdb_takeover_tests" \ "ipalloc" "$_flags" <"$FAKE_CTDB_IP_LAYOUT" | sort >"$_t" mv "$_t" "$FAKE_CTDB_IP_LAYOUT" ) <"$FAKE_CTDB_IP_LAYOUT" } ctdb_ip () { # If nobody has done any IP-fu then generate a layout. [ -f "$FAKE_CTDB_IP_LAYOUT" ] || ip_reallocate _mypnn=$(ctdb_pnn | sed -e 's@PNN:@@') if $machine_readable ; then if $verbose ; then echo "|Public IP|Node|ActiveInterface|AvailableInterfaces|ConfiguredInterfaces|" else echo "|Public IP|Node|" fi else echo "Public IPs on node ${_mypnn}" fi # Join public addresses file with $FAKE_CTDB_IP_LAYOUT, and # process output line by line... _pa="${CTDB_PUBLIC_ADDRESSES:-${CTDB_BASE}/public_addresses}" sed -e 's@/@ @' "$_pa" | sort | join - "$FAKE_CTDB_IP_LAYOUT" | while read _ip _bit _ifaces _pnn ; do if $verbose ; then # If more than 1 interface, assume all addresses are on the 1st. _first_iface="${_ifaces%%,*}" # Only show interface if address is on this node. _my_iface="" if [ "$_pnn" = "$_mypnn" ]; then _my_iface="$_first_iface" fi if $machine_readable ; then echo "|${_ip}|${_pnn}|${_my_iface}|${_first_iface}|${_ifaces}|" else echo "${_ip} node[${_pnn}] active[${_my_iface}] available[${_first_iface}] configured[[${_ifaces}]" fi else if $machine_readable ; then echo "|${_ip}|${_pnn}|" else echo "${_ip} ${_pnn}" fi fi done } ctdb_moveip () { _ip="$1" _target="$2" ip_reallocate # should be harmless and ensures we have good state ( flock 0 _t="${FAKE_CTDB_IP_LAYOUT}.new" while read _i _pnn ; do if [ "$_ip" = "$_i" ] ; then echo "$_ip $_target" else echo "$_ip $_pnn" fi done | sort >"$_t" mv "$_t" "$FAKE_CTDB_IP_LAYOUT" ) <"$FAKE_CTDB_IP_LAYOUT" } ###################################################################### ctdb_enable () { parse_nodespec for _i in $nodes ; do rm -f "${FAKE_CTDB_NODES_DISABLED}/${_i}" done ip_reallocate } ctdb_disable () { parse_nodespec for _i in $nodes ; do mkdir -p "$FAKE_CTDB_NODES_DISABLED" touch "${FAKE_CTDB_NODES_DISABLED}/${_i}" done ip_reallocate } ###################################################################### ctdb_shutdown () { echo "CTDB says BYE!" } ###################################################################### # This is only used by the NAT gateway code at the moment, so use a # hack. Assume that $CTDB_NATGW_NODES contains all nodes in the # cluster (which is what current tests assume). Use the PNN to find # the address from this file. The NAT gateway code only used the # address, so just mark the node healthy. ctdb_nodestatus () { echo '|Node|IP|Disconnected|Banned|Disabled|Unhealthy|Stopped|Inactive|PartiallyOnline|ThisNode|' _line=$(( $FAKE_CTDB_PNN + 1 )) _ip=$(sed -e "${_line}p" "$CTDB_NATGW_NODES") echo "|${FAKE_CTDB_PNN}|${_ip}|0|0|0|0|0|0|0|Y|" } ###################################################################### ctdb_setvar () { shift _var="$1" for _i in $FAKE_CTDB_TUNABLES_OK ; do if [ "$_var" = "$_i" ] ; then return 0 fi done for _i in $FAKE_CTDB_TUNABLES_OBSOLETE ; do if [ "$_var" = "$_i" ] ; then echo "Setting obsolete tunable variable '${_var}'" return 0 fi done echo "Unable to set tunable variable '${_var}'" return 1 } ###################################################################### _t_setup () { _t_dir="$EVENTSCRIPTS_TESTS_VAR_DIR/fake-ctdb/fake-tdb/$1" mkdir -p "$_t_dir" } _t_put () { echo "$2" >"${_t_dir}/$1" } _t_get () { cat "${_t_dir}/$1" } _t_del () { rm -f "${_t_dir}/$1" } ctdb_pstore () { _t_setup "$2" _t_put "$3" "$4" } ctdb_pdelete () { _t_setup "$2" _t_del "$3" } ctdb_pfetch () { _t_setup "$2" _t_get "$3" >"$4" 2>/dev/null } ctdb_ptrans () { _t_setup "$2" while IFS="" read _line ; do _k=$(echo "$_line" | sed -n -e 's@^"\([^"]*\)" "[^"]*"$@\1@p') _v=$(echo "$_line" | sed -e 's@^"[^"]*" "\([^"]*\)"$@\1@') [ -n "$_k" ] || die "ctdb ptrans: bad line \"${line}\"" if [ -n "$_v" ] ; then _t_put "$_k" "$_v" else _t_del "$_k" fi done } ctdb_catdb () { _t_setup "$2" # This will break on keys with spaces but we don't have any of # those yet. _count=0 for _i in "${_t_dir}/"* ; do [ -r "$_i" ] || continue _k="${_i##*/}" # basename _v=$(_t_get "$_k") _kn=$(echo -n "$_k" | wc -c) _vn=$(echo -n "$_v" | wc -c) cat <>"$tickles_file" ;; deltickle) setup_tickles _t=$(grep -F -v "$2 $3" "$tickles_file") echo "$_t" >"$tickles_file" ;; pstore) ctdb_pstore "$@" ;; pdelete) ctdb_pdelete "$@" ;; pfetch) ctdb_pfetch "$@" ;; ptrans) ctdb_ptrans "$@" ;; catdb) ctdb_catdb "$@" ;; ifaces) # Assume -Y. echo "|Name|LinkStatus|References|" _f="${CTDB_PUBLIC_ADDRESSES:-${CTDB_BASE}/public_addresses}" if [ -r "$_f" ] ; then while read _ip _iface ; do case "_$ip" in \#*) : ;; *) _status=1 # For now assume _iface contains only 1. if [ -f "{FAKE_CTDB_IFACES_DOWN}/${_iface}" ] ; then _status=0 fi # Nobody looks at references echo "|${_iface}|${_status}|0|" esac done <"$_f" | sort -u fi ;; setifacelink) # Existence of file means CTDB thinks interface is down. _f="${FAKE_CTDB_IFACES_DOWN}/$2" case "$3" in up) rm -f "$_f" ;; down) touch "$_f" ;; *) echo "ctdb setifacelink: unsupported interface status $3" exit 1 esac ;; checktcpport) for _i in $FAKE_TCP_LISTEN ; do if [ "$2" = "${_i##*:}" ] ; then exit 98 fi done exit 0 ;; scriptstatus) $machine_readable || not_implemented "$1, without -X" [ "$2" != "all" ] || not_implemented "scriptstatus all" # For now just assume everything is good. echo "|Type|Name|Code|Status|Start|End|Error Output...|" for _i in "$CTDB_BASE/events.d/"*.* ; do _d1=$(date '+%s.%N') _b="${_i##*/}" # basename _f="$FAKE_CTDB_SCRIPTSTATUS/$_b" if [ -r "$_f" ] ; then read _code _status _err_out <"$_f" else _code="0" _status="OK" if [ ! -x "$_i" ] ; then _status="DISABLED" _code="-8" fi _err_out="" fi _d2=$(date '+%s.%N') echo "|${2:-monitor}|${_b}|${_code}|${_status}|${_d1}|${_d2}|${_err_out}|" done ;; gratiousarp) : ;; # Do nothing for now killtcp) ctdb_killtcp "$@" ;; ip) ctdb_ip "$@" ;; pnn|xpnn) ctdb_pnn ;; enable) ctdb_enable "$@";; disable) ctdb_disable "$@";; moveip) ctdb_moveip "$@";; shutdown) ctdb_shutdown "$@";; setvar) ctdb_setvar "$@" ;; nodestatus) ctdb_nodestatus "$@" ;; *) not_implemented "$1" ;; esac