diff --git a/cts/cts.in b/cts/cts.in index 695400c550..7be16576b1 100755 --- a/cts/cts.in +++ b/cts/cts.in @@ -1,264 +1,313 @@ #!@BASH_PATH@ # # Copyright 2012-2023 the Pacemaker project contributors # # The version control history for this file may have further details. # # This source code is licensed under the GNU General Public License version 2 # or later (GPLv2+) WITHOUT ANY WARRANTY. # # e.g. /etc/sysconfig or /etc/default CONFIG_DIR=@CONFIGDIR@ cts_root=`dirname $0` logfile=0 summary=0 verbose=0 watch=0 saved=0 tests="" install=0 clean=0 kill=0 run=0 boot=0 target=rhel-7 cmd="" trace="" custom_log="" patterns="-e CTS:" function sed_in_place_remotely() { cluster-helper -g $cluster_name -- cp -p "\"$1\"" "\"$1.sed\"" \&\& sed -e "\"$2\"" "\"$1\"" \> "\"$1.sed\"" \&\& mv "\"$1.sed\"" "\"$1\"" } helpmsg=$(cat </dev/null if [ $? != 0 ]; then echo $0 needs the cluster-helper script to be in your path exit 1 fi which cluster-clean &>/dev/null if [ $? != 0 ]; then echo $0 needs the cluster-clean script to be in your path exit 1 fi if [ "x$cluster_name" = x ] || [ "x$cluster_name" = xpick ]; then clusters=`ls -1 ~/.dsh/group/[a-z]+[0-9] | sed s/.*group.// | tr '\n' ' ' ` echo "custom) interactively define a cluster" for i in $clusters; do echo "$i) `cluster-helper --list short -g $i`" done read -p "Choose a cluster [custom]: " cluster_name echo fi if [ -z $cluster_name ]; then cluster_name=custom fi case $cluster_name in custom) read -p "Cluster name: " cluster_name read -p "Cluster hosts: " cluster_hosts read -p "Cluster log file: " cluster_log cluster-helper add -g "$cluster_name" -w "$cluster_hosts" ;; *) cluster_hosts=`cluster-helper --list short -g $cluster_name` cluster_log=~/cluster-$cluster_name.log; ;; esac +# NOTES ABOUT THESE AWESOME REGULAR EXPRESSIONS: +# +# * We can't assume GNU sed. Unfortunately, + and * are GNU extensions. Thus, +# we have to use {1,} for + and {0,} for *. +# * You don't need to add an extra set of escaped quotes around the sed expression +# arguments here - sed_in_place_remotely will do that for you. +# * Only literal quotes need the triple backslashes. All other special characters +# are fine with just a single one. +# * sed needs a LOT of characters escaped - \, {, }, (, ), and | at least. + if [ x$cmd != x ]; then config="${CONFIG_DIR}/pacemaker" case $cmd in trace-ls|tls) - cluster-helper -g $cluster_name -- grep PCMK_trace_functions $config + cluster-helper -g $cluster_name -- grep "^[[:space:]]*PCMK_trace_functions" $config ;; trace-add|tadd) echo "Adding $trace to PCMK_trace_functions" - sed_in_place_remotely "$config" "s/.*PCMK_trace_functions=/PCMK_trace_functions=$trace,/" + # Note that this only works if there's already a PCMK_trace_functions line. + # If there isn't one, create it with trace-set first. + # + # Match optional whitespace; then PCMK_trace_functions; then an equals + # surrounded by optional whitespace; then an optional quote; then whatever + # else (presumably, this is the list of previously traced functions with + # an optional trailing quote). Replace the entire line with + # PCMK_trace_functions=, + sed_in_place_remotely "$config" "s/^[ \t]\{0,\}PCMK_trace_functions[ \t]\{0,\}=[ \t]\{0,\}\(\\\"\{0,1\}\)\(.\{1,\}\)/PCMK_trace_functions=\1$trace,\2/" ;; trace-rm|trm) echo "Removing $trace from PCMK_trace_functions" - sed_in_place_remotely "$config" "s/.*PCMK_trace_functions=\\\\\\(.*\\\\\\)$trace,\\\\\\(.*\\\\\\)/PCMK_trace_functions=\\\\\\1\\\\\\2/" - ;; - trace-set|tset) - echo "Setting PCMK_trace_functions to '$trace'" - sed_in_place_remotely "$config" "s/.*PCMK_trace_functions.*/PCMK_trace_functions=$trace/" - ;; + # A bunch of simple regexes are easier to follow than one giant one. + # Look for $trace in the following places on any line containing + # PCMK_trace_functions near the beginning: + # + # (1) At the start of a list - + # Match one of a leading quote, or an equals followed by optional + # whitespace; then $trace; then a comma. Replace $trace with whatever + # came before it. + # (2) In the middle of a list - + # Match a comma; then $trace; then a comma. Replace $trace with a + # single comma. + # (3) At the end of a list - + # Match a comma; then $trace; then one of a quote, whitespace, or + # the EOL. Replace $trace with whatever came after it. + # (4) All by itself - + # Match one of a leading quote, whitespace, or equals followed by + # optional whitespace; then $trace; then one of a trailing quote, + # whitespace, or the EOL. Replace $trace with whatever came before + # and after it. + sed_in_place_remotely "$config" "/^[ \t]\{0,\}PCMK_trace_functions/ { \ + s/\(\\\"\|=\|[ \t]\{1,\}\)$trace,/\1/ ; \ + s/,$trace,/,/ ; \ + s/,$trace\(\\\"\|[ \t]\{1,\}\|$\)/\1/ ; \ + s/\(\\\"\|[ \t]\{1,\}\|=[ \t]\{0,\}\)$trace\(\\\"\|[ \t]\{1,\}\|$\)/\1\2/ }" + ;; + trace-set|tset) + echo "Setting PCMK_trace_functions to '$trace'" + # Do this in two separate sed commands: + # + # (1) Unconditionally remove any existing PCMK_trace_functions= lines. + # (2) Add a new line with $trace after the example line, which therefore + # must exist. Note that GNU sed would support "a PCMK_trace_functions=$trace", + # but that's an extension. For all other seds, we have to put the + # command and the text on separate lines. + sed_in_place_remotely "$config" "/^[ \t]*PCMK_trace_functions/ d ; /^# Example: PCMK_trace_functions/ a\\\ +PCMK_trace_functions=\\\"$trace\\\"" + ;; esac exit 0 fi if [ $run = 1 ]; then install=1 clean=1 fi if [ $clean = 1 ]; then rm -f $cluster_log; cluster-clean -g $cluster_name --kill elif [ $kill = 1 ]; then cluster-clean -g $cluster_name --kill-only exit 0 fi if [ $install = 1 ]; then cluster-helper -g $cluster_name -- yum install -y pacemaker pacemaker-debuginfo pacemaker-cts libqb libqb-debuginfo fi if [ $boot = 1 ]; then $cts_root/cts-lab -r -c -g $cluster_name --boot rc=$? if [ $rc = 0 ]; then echo "The cluster is ready..." fi exit $rc elif [ $run = 1 ]; then $cts_root/cts-lab -r -c -g $cluster_name 500 "$@" exit $? elif [ $clean = 1 ]; then exit 0 fi screen -ls | grep cts-$cluster_name &>/dev/null active=$? if [ ! -z $custom_log ]; then cluster_log=$custom_log fi if [ "x$tests" != x ] && [ "x$tests" != "x " ]; then for t in $tests; do echo "crm_report --cts-log $cluster_log -d -T $t" crm_report --cts-log $cluster_log -d -T $t done elif [ $logfile = 1 ]; then echo $cluster_log elif [ $summary = 1 ]; then files=$cluster_log if [ $saved = 1 ]; then files=`ls -1tr ~/CTS-*/cluster-log.txt` fi for f in $files; do echo $f case $verbose in 0) cat -n $f | grep $patterns | grep -v "CTS: debug:" ;; 1) cat -n $f | grep $patterns | grep -v "CTS:.* cmd:" ;; *) cat -n $f | grep $patterns ;; esac echo "" done elif [ $watch = 1 ]; then case $verbose in 0) tail -F $cluster_log | grep $patterns | grep -v "CTS: debug:" ;; 1) tail -F $cluster_log | grep $patterns | grep -v "CTS:.* cmd:" ;; *) tail -F $cluster_log | grep $patterns ;; esac elif [ $active = 0 ]; then screen -x cts-$cluster_name else touch $cluster_log # . ~/.bashrc export cluster_name cluster_hosts cluster_log screen -S cts-$cluster_name bash fi