# # Copyright: Martin Fick # Date: 5/29/2007 # Version: 2.1 # License: GNU GPL2 (or greater) # HomePage: http://www.theficks.name/Hacks/Heartbeat-ResourceScripts # usage() { cat - <[m] resource [<+-.=>c colocated_to] [<+-.=>b before] [<+-.=>a after] [<+-.=>l machine] EOF } help() { cat - <[m] shortname [<+-=.>C constraint ...] m (experimental) manual, call an OCF agent directly instead of cibadmin (only usefull for resoures, constraints are ignored) The <+-=.> indicates what to do to the resource or constraint: + add (if manual: OCF start) - delete (if manual: OCF stop) = maintain (no change) (if manual: OCF status) . output the related XML to stdout (if manual: OCF monitor) Note that you must always specify the shortname of the resource, use the = switch when you want to modify an already existing resource's constraints. The current constraints are specified by: C, followed by the constraint argument, the C and its arguments can be: c colocated_to fullname of resource to be colocated to b start_before fullname of resource to start before a start_after fullname of resource to start after l host hostname of the preferred host to run on It is important that fullname be the fullname of the another resource. Resource scripts will generally generate a resource name that is longer than the shortname used above. This requires some knowledge of the of the XML output of your resource scripts to know the fullname that they will generate. Generally top level (outer) resource fullnames will be of the format: _. As a shortcut, arguments which are identical can be held until that last point. I.E. colocation and starting after another resource can be specified like this: +c +a resource Options: -n do not execute any actual cibadmin commands -v verbose, output each cibadmin invocation with its switches and the generated XML -u print the usage --help print this help message EOF } # --- Manual OCF Agents --- # # XML function assumptions: # -one tag per line # -tags are on only one line # -only spaces make whitespace # -no quotes or > inside of quotes # -probably more, this is a very simplistic implementation of XML parsing xml_get_val() { # attr_name < tag sed -e's/^.* '"$1"'="//;s/".*$//' } xml_get_tags() { # tag_name awk '/<'"$1"' +[^>]*>/ || /<'"$1"'\/>/' } xml_get_ftag_with_attval() { # tag_name att value awk '/<\/'"$1"'>/{open=0};/<'"$1"'( +[^>]*)* +'"$2"'="'"$3"'"( +[^>]*)*>/{open=1}; open; /<'"$1"'\/>/{ open=0};' } reverse() # v1.0 { typeset line out='' while read line ; do out=$(echo "$line" ; echo "$out") done echo "$out" } xml_2_manual() { # [-r] RES short typeset SW_r='' xml primitives p_ids p_id res prim provider type nvs name val if [ ."$1" = ."-r" ] ; then SW_r="$1" ; shift ; fi typeset resource="$1" short="$2" typeset OCF=/usr/lib/ocf/resource.d xml=$(resource "$resource" "$short") primitives=$(echo "$xml" | xml_get_tags primitive) p_ids=$(echo "$primitives"| sed -e's/^.* id="//;s/"[ >].*$//') [ ."$SW_r" = ."-r" ] && p_ids=$(echo "$p_ids"|reverse) for p_id in $p_ids ; do res=$(echo "$xml"| xml_get_ftag_with_attval primitive id "$p_id") prim=$(echo "$res"| xml_get_tags primitive) provider=$(echo "$prim"| xml_get_val provider) type=$(echo "$prim"| xml_get_val type) nvs=$(echo "$res"| xml_get_tags nvpair) echo "$nvs" | { while read nv ; do name=$(echo "$nv" | xml_get_val name) val=$(echo "$nv" | xml_get_val value) echo -n "OCF_RESKEY_$name='$val' " done } echo "$OCF/$provider/$type" done } manual_resource() { # short action typeset r='' action="$3" cmd short [ "$action" = "stop" ] && r='-r' xml_2_manual $r "$1" "$2" | { while read cmd ; do short=$(echo "$cmd"|awk '{print $NF}'|sed -es"|^.*/||;s/'//") out=$(eval $cmd $action 2>&1) rtn=$? echo "($rtn) - $short $action" if [ $rtn -ne 0 ] ; then echo $cmd $action echo "$out" | awk '{print " " $0}' fi done } } # --- Constraints --- # colocation() { # RES colocated_to cat - < EOF } after() { # RES starts_after cat - < EOF } before() { # RES starts_before cat - < EOF } # This could really use an optional score! location() { # RES machine cat - < EOF } # --- Parsing Args --- # short_c() { # -+.=c echo "$1"|sed -es/^.// } long_c() { # -+.c case $(short_c "$1") in c) echo colocation ;; b) echo before ;; a) echo after ;; l) echo location ;; esac } cibecho() { typeset stdin=$(cat -) [ ! -z "$SW_V" ] && echo "cibadmin $*" [ ! -z "$SW_V" ] && echo "$stdin" [ -z "$SW_N" ] && { echo "$stdin"| cibadmin "$@" ; } } manual() { # <+-=>m RES ignored.... case "$1" in +m) action=start ;; -m) action=stop ;; =m) action=status ;; .m) action=monitor ;; *) echo "ERR - unknown manual action: $1">2 ; exit ;; esac manual_resource "${PRE}_$2" "$2" "$action" } parse() { PRE=$(basename "$0") if [ "$1" = "-u" ] ; then usage ; exit ; fi if [ "$1" = "--help" ] ; then help ; exit ; fi while [ $# -gt 0 ] ; do case "$1" in -v) SW_V="$1" ;; -n) SW_N="$1" ;; *) break ;; esac ; shift ; done if [ "$1" = "-m" ] ; then manual "$@" ; exit ; fi if [ "$1" = "+m" ] ; then manual "$@" ; exit ; fi if [ "$1" = "=m" ] ; then manual "$@" ; exit ; fi if [ "$1" = ".m" ] ; then manual "$@" ; exit ; fi while [ $# -gt 1 ] ; do o="$1" ; shift a=$(next_arg "$@") shift $? # next_arg returns how many to shift! c=$(short_c "$o") l=$(long_c "$o") case "$o" in +) RES="$a" RESXML=$("$0" . "$RES") || exit # Delayed for later so that we get our constraints first ;; -) RES="$a" XML=$("$0" . "$a") || exit echo "$XML" | cibecho -V -D -o resources -p ;; .) RES="$a" resource "${PRE}_$RES" "$RES" ;; ''|=) RES="$a" ;; +*) XML=$("$0" '' "$RES" ."$c" "$a") || exit echo "$XML" | cibecho -V -D -o constraints -p 2>/dev/null echo "$XML" | cibecho -V -C -o constraints -p ;; -*) XML=$("$0" '' "$RES" ."$c" "$a") || exit echo "$XML" | cibecho -V -D -o constraints -p ;; .*) "$l" "${PRE}_$RES" "$a" ;; =*) ;; *) usage echo "ERROR: Unrecognized argument $1" >&2 exit 2 ;; esac done if [ "$RESXML" != "" ] ; then echo "$RESXML" | cibecho -V -D -o resources -p 2>/dev/null echo "$RESXML" | cibecho -V -C -o resources -p fi if [ $# -gt 0 ] ; then usage echo "ERROR: too few arguments $1" >&2 exit 1 fi } next_arg() { # args ... typeset -i i=1 while [ $# -gt 0 ] ; do case "$1" in +*|-*|.*|=*) shift ; i=0 ;; *) echo "$1" ; return $i ;; esac done usage echo "ERROR: too few arguments" >&2 exit 1 } parse "$@"