[Pacemaker] how to determin crm version / features from within a RA

Lars Ellenberg lars.ellenberg at linbit.com
Thu Jun 11 13:57:44 UTC 2009


attaching revised generic shell level version compare scriptlet
plus cib/crm detection logic.

hopefully it is more less instransparent what is going on now,
and clear why the eval for the cibadmin -Ql | sed thingy is ok.

the shell version compare may be useful for inclusion into the
"ocf" shell function library -- if it turns out to even work on
non-linux shell, sed and sort ;)
whatever it is good for.

-- 
: Lars Ellenberg
: LINBIT | Your Way to High Availability
: DRBD/HA support and consulting http://www.linbit.com

DRBD® and LINBIT® are registered trademarks of LINBIT, Austria.
-------------- next part --------------
#!/bin/sh

# two parameters
# version1 version2
# return value:
# 0: version1 = version2 by string compare
# 1: version1 < version2 by "version compare"
# 2: version1 > version2 by "version compare"
# 3: something in that funny little tr + sed + sort construct went wrong
version_cmp()
{
	# make both version parameters start non-numeric
	local v1="$1" v2="$2" result l sed_script sort_keys

	# short cut
	if [ "x$v1" = "x$v2" ]; then
		return 0
	fi

	# strip leading and trailing spaces.
	# all embeded spaces to underscores.
	# versions should not contain spaces!
	# insert spaces separators around numeric values
	sed_script="s/^ *//; s/ *$//;s/ /_/g; s/[0-9]\+/ & /g"
	# tr to strip newlines in arguments, even though you should not call
	# this function with embeded newlines in arguments!

	v1=$(echo "$v1" | tr '\n' ' ' | sed -e "$sed_script")
	v2=$(echo "$v2" | tr '\n' ' ' | sed -e "$sed_script")
	set -- $v1 x
	l=$#
	set -- $v2 x
	if [ $l -lt $# ] ; then l=$#; fi
	# $v1 and $v2 contain space separated alternating non-numeric and
	# numeric parts, starting with a non-numeric one, which possibly
	# is empty; therefore the extra 'x' on the set -- lines above.
	# $l now contains the maximum "column" number.
	# generate that many sort key arguments:
	# -k1,1 -k2,2n -k3,3 -k4,4n -k5,5 ...
	sort_keys=$(seq $l | sed -e 's/.*/ -k&,&/;2~2 s/$/n/')

	# capture which value sort places in the first line.
	# the -s is "stabilize", and should actually not be neccessary
	result=$( ( echo "$v1" ; echo "$v2" ) |
		LANG=C LC_ALL=C sort -t " " -s $sort_keys |
		head -n1)
	case "$result" in
	"$v1")
		return 1;; # v1 < v2
	"$v2")
		return 2;; # v2 < v1
	*)
		return 3;; # oops, what happened here?
	esac
}

# for those that rather have a boolean result
# three parameters
# compare_version $v1 $op $v2
# where op is one of lt|le|eq|ge|gt
# return value:
# 0: requested relation evaluates to true
# 1: requested relation evaluates to false
# anything else: problem evaluating expression
compare_versions()
{
	local v1="$1" op="$2" v2="$3" rc

	case "$op" in
	lt|le|eq|ge|gt)
		:;;
	*)
		echo >&2 "bad relation '$op'"
		return 2
		;;
	esac

	version_cmp "$v1" "$v2"
	rc=$?
	case $rc in
	0)
		case "$op" in
		eq|[lg]e)
			return 0;;
		*)
			return 1;;
		esac;;
	1)
		case "$op" in
		l[te])
			return 0;;
		*)
			return 1;;
		esac ;;
	2)
		case "$op" in
		g[te])
			return 0;;
		*)
			return 1;;
		esac ;;
	*)
		return $rc ;;
	esac
}

#### excercise it:
# version_cmp "$1" "$2"
# case $? in
# 	0) echo "'$1' = '$2'" ;;
# 	1) echo "'$1' < '$2'" ;;
# 	2) echo "'$1' > '$2'" ;;
# 	*) echo "something went wrong: '$1' =?= '$2'" ;;
# esac
################# version compare ends

# now use it.
# does not yet evaluate _CIB_VALIDATE_WITH, but we could trigger on it.
#
_DC_VERSION=""
_CIB_VALIDATE_WITH=""
eval $(cibadmin -Ql |
    sed -n -e '/^<cib/ {
	# capture the value of the validate-with attribute of the cib tag.
	s/^.*\bvalidate-with="\([^"]*\)".*$/\1/;
	# shell-escape it
	s/[^-%+.\/0-9:=@A-Z_a-z]/\\&/g;
	# prepend the variable name, and print
	s/^/_CIB_VALIDATE_WITH=/;p;}' \
	-e '
	# delete everything but the cluster_property_set
	# to avoid possible uninteressting nvpairs with name="dc-version"
	1,/<cluster_property_set\b/d;
	/<\/cluster_property_set>/q;' \
	-e '
	# find the right nvpair,
	# capture the first part of its value into a variable assignment
	# no need to quote [0-9.:]
	/^[[:space:]]*<nvpair .*\bname="dc-version"/ s/^.*\bvalue="\([0-9.:]*\).*$/_DC_VERSION=\1/p'
)

# add some "epoch" prefix (only if not present already)
case $_DC_VERSION in
"")
	echo >&2 "problem reading cib :("
	exit 1;;
2.*)	_DC_VERSION=0:$_DC_VERSION;;
1.*)	_DC_VERSION=1:$_DC_VERSION;;
esac

required_crm_version=0:2.1.3
if compare_versions $_DC_VERSION lt $required_crm_version ; then
	echo "sorry, I need a $required_crm_version crm"
	exit 1
else
	echo "fine, $_DC_VERSION is newer than required $required_crm_version crm version"
fi


More information about the Pacemaker mailing list