diff --git a/cts/Makefile.am b/cts/Makefile.am
index c902f6945e..a26ff35276 100644
--- a/cts/Makefile.am
+++ b/cts/Makefile.am
@@ -1,61 +1,62 @@
#
# Copyright 2001-2022 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.
#
MAINTAINERCLEANFILES = Makefile.in
# Test commands and globally applicable test files should be in $(testdir),
# and command-specific test data should be in a command-specific subdirectory.
testdir = $(datadir)/$(PACKAGE)/tests
test_SCRIPTS = cts-cli \
cts-exec \
cts-fencing \
cts-regression \
cts-scheduler
dist_test_DATA = README.md \
valgrind-pcmk.suppressions
ctsdir = $(testdir)/cts
cts_SCRIPTS = lxc_autogen.sh
clidir = $(testdir)/cli
dist_cli_DATA = cli/constraints.xml \
cli/crmadmin-cluster-remote-guest-nodes.xml \
cli/crm_diff_new.xml \
cli/crm_diff_old.xml \
cli/crm_mon.xml \
cli/crm_mon-partial.xml \
cli/crm_mon-unmanaged.xml \
cli/crm_resource_digests.xml \
cli/regression.acls.exp \
cli/regression.crm_mon.exp \
cli/regression.dates.exp \
cli/regression.rules.exp \
cli/regression.tools.exp \
cli/regression.upgrade.exp \
- cli/regression.validity.exp
+ cli/regression.validity.exp \
+ cli/regression.access_render.exp
scheduler-list:
@for T in "$(srcdir)"/scheduler/xml/*.xml; do \
echo $$(basename $$T .xml); \
done
CLEANFILES = $(builddir)/.regression.failed.diff
clean-local:
rm -f scheduler/*/*.pe
SUBDIRS = benchmark lab scheduler support
cts-support-install:
$(MAKE) $(AM_MAKEFLAGS) -C support cts-support
$(builddir)/support/cts-support install
cts-support-uninstall:
$(MAKE) $(AM_MAKEFLAGS) -C support cts-support
$(builddir)/support/cts-support uninstall
diff --git a/cts/cli/regression.access_render.exp b/cts/cli/regression.access_render.exp
new file mode 100644
index 0000000000..37f093ddb4
--- /dev/null
+++ b/cts/cli/regression.access_render.exp
@@ -0,0 +1,133 @@
+Created new pacemaker configuration
+Setting up shadow instance
+A new shadow instance was created. To begin using it paste the following into your shell:
+ CIB_shadow=cts-cli ; export CIB_shadow
+=#=#=#= Begin test: Configure some ACLs =#=#=#=
+=#=#=#= Current cib after: Configure some ACLs =#=#=#=
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+=#=#=#= End test: Configure some ACLs - OK (0) =#=#=#=
+* Passed: cibadmin - Configure some ACLs
+=#=#=#= Begin test: Enable ACLs =#=#=#=
+=#=#=#= Current cib after: Enable ACLs =#=#=#=
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+=#=#=#= End test: Enable ACLs - OK (0) =#=#=#=
+* Passed: crm_attribute - Enable ACLs
+=#=#=#= Begin test: An instance of ACLs render (into color) =#=#=#=
+
+\x1b[34m
+ \x1b[34m
+ \x1b[34m
+ \x1b[34m
+ \x1b[34m[0m
+ \x1b[34m[0m
+ \x1b[34m[0m
+ \x1b[34m[0m
+ \x1b[34m[0m
+ \x1b[34m[0m
+ \x1b[31m
+ \x1b[31m
+ \x1b[31m[0m
+ \x1b[31m[0m
+ \x1b[31m[0m
+ \x1b[31m
+ \x1b[31m[0m
+ \x1b[31m[0m
+ \x1b[31m[0m
+ \x1b[34m[0m
+ \x1b[34m[0m
+\x1b[34m[0m
+=#=#=#= End test: An instance of ACLs render (into color) - OK (0) =#=#=#=
+* Passed: cibadmin - An instance of ACLs render (into color)
+=#=#=#= Begin test: An instance of ACLs render (into namespacing) =#=#=#=
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+=#=#=#= End test: An instance of ACLs render (into namespacing) - OK (0) =#=#=#=
+* Passed: cibadmin - An instance of ACLs render (into namespacing)
+=#=#=#= Begin test: An instance of ACLs render (into text) =#=#=#=
+
+vvv---[ READABLE ]---vvv
+
+
+
+
+
+
+
+
+
+
+
+ vvv---[ ~DENIED~ ]---vvv
+
+
+
+
+
+
+
+
+
+
+
+
+=#=#=#= End test: An instance of ACLs render (into text) - OK (0) =#=#=#=
+* Passed: cibadmin - An instance of ACLs render (into text)
diff --git a/cts/cts-cli.in b/cts/cts-cli.in
index 7c90f75364..9ae374fee3 100755
--- a/cts/cts-cli.in
+++ b/cts/cts-cli.in
@@ -1,1977 +1,2027 @@
#!@BASH_PATH@
#
# Copyright 2008-2022 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.
#
# Set the exit status of a command to the exit code of the last program to
# exit non-zero. This is bash-specific.
set -o pipefail
#
# Note on portable usage of sed: GNU/POSIX/*BSD sed have a limited subset of
# compatible functionality. Do not use the -i option, alternation (\|),
# \0, or character sequences such as \n or \s.
#
USAGE_TEXT="Usage: cts-cli []
Options:
--help Display this text, then exit
-V, --verbose Display any differences from expected output
-t 'TEST [...]' Run only specified tests (default: 'dates tools crm_mon acls validity upgrade rules')
-p DIR Look for executables in DIR (may be specified multiple times)
-v, --valgrind Run all commands under valgrind
-s Save actual output as expected output"
# If readlink supports -e (i.e. GNU), use it
readlink -e / >/dev/null 2>/dev/null
if [ $? -eq 0 ]; then
test_home="$(dirname "$(readlink -e "$0")")"
else
test_home="$(dirname "$0")"
fi
: ${shadow=cts-cli}
shadow_dir=$(mktemp -d ${TMPDIR:-/tmp}/cts-cli.shadow.XXXXXXXXXX)
num_errors=0
num_passed=0
verbose=0
tests="dates tools crm_mon acls validity upgrade rules"
do_save=0
XMLLINT_CMD=
VALGRIND_CMD=
VALGRIND_OPTS="
-q
--gen-suppressions=all
--show-reachable=no
--leak-check=full
--trace-children=no
--time-stamp=yes
--num-callers=20
--suppressions=$test_home/valgrind-pcmk.suppressions
"
# These constants must track crm_exit_t values
CRM_EX_OK=0
CRM_EX_ERROR=1
CRM_EX_INVALID_PARAM=2
CRM_EX_UNIMPLEMENT_FEATURE=3
CRM_EX_INSUFFICIENT_PRIV=4
CRM_EX_USAGE=64
CRM_EX_CONFIG=78
CRM_EX_OLD=103
CRM_EX_DIGEST=104
CRM_EX_NOSUCH=105
CRM_EX_UNSAFE=107
CRM_EX_EXISTS=108
CRM_EX_MULTIPLE=109
CRM_EX_EXPIRED=110
CRM_EX_NOT_YET_IN_EFFECT=111
reset_shadow_cib_version() {
local SHADOWPATH
SHADOWPATH="$(crm_shadow --file)"
# sed -i isn't portable :-(
cp -p "$SHADOWPATH" "${SHADOWPATH}.$$" # preserve permissions
sed -e 's/epoch="[0-9]*"/epoch="1"/g' \
-e 's/num_updates="[0-9]*"/num_updates="0"/g' \
-e 's/admin_epoch="[0-9]*"/admin_epoch="0"/g' \
"$SHADOWPATH" > "${SHADOWPATH}.$$"
mv -- "${SHADOWPATH}.$$" "$SHADOWPATH"
}
# A newly created empty CIB might or might not have a rsc_defaults section
# depending on whether the --with-resource-stickiness-default configure
# option was used. To ensure regression tests behave the same either way,
# delete any rsc_defaults after creating or erasing a CIB.
delete_shadow_resource_defaults() {
cibadmin --delete --xml-text ''
# The above command might or might not bump the CIB version, so reset it
# to ensure future changes result in the same version for comparison.
reset_shadow_cib_version
}
create_shadow_cib() {
local VALIDATE_WITH
local SHADOW_CMD
VALIDATE_WITH="$1"
export CIB_shadow_dir="${shadow_dir}"
SHADOW_CMD="$VALGRIND_CMD crm_shadow --batch --force --create-empty"
if [ -z "$VALIDATE_WITH" ]; then
$SHADOW_CMD "$shadow" 2>&1
else
$SHADOW_CMD "$shadow" --validate-with="${VALIDATE_WITH}" 2>&1
fi
export CIB_shadow="$shadow"
delete_shadow_resource_defaults
}
function _test_assert() {
target=$1; shift
validate=$1; shift
cib=$1; shift
app=`echo "$cmd" | sed 's/\ .*//'`
printf "* Running: $app - $desc\n" 1>&2
printf "=#=#=#= Begin test: $desc =#=#=#=\n"
export outfile=$(mktemp ${TMPDIR:-/tmp}/cts-cli.output.XXXXXXXXXX)
eval $VALGRIND_CMD $cmd 2>&1 | tee $outfile
rc=$?
if [ x$cib != x0 ]; then
printf "=#=#=#= Current cib after: $desc =#=#=#=\n"
CIB_user=root cibadmin -Q
fi
# Do not validate if running under valgrind, even if told to do so. Valgrind
# will output a lot more stuff that is not XML, so it wouldn't validate anyway.
if [ "$validate" = "1" ] && [ "$VALGRIND_CMD" = "" ] && [ $rc = 0 ] && [ "$XMLLINT_CMD" != "" ]; then
# The sed command filters out the "- validates" line that xmllint will output
# on success. grep cannot be used here because "grep -v 'validates$'" will
# return an exit code of 1 if its input consists entirely of "- validates".
$XMLLINT_CMD --noout --relaxng "$PCMK_schema_directory/api/api-result.rng" "$outfile" 2>&1 | sed -n '/validates$/ !p'
rc=$?
if [ $rc = 0 ]; then
printf "=#=#=#= End test: %s - $(crm_error --exit $rc) (%d) =#=#=#=\n" "$desc" $rc
else
printf "=#=#=#= End test: %s - Failed to validate (%d) =#=#=#=\n" "$desc" $rc
fi
else
printf "=#=#=#= End test: %s - $(crm_error --exit $rc) (%d) =#=#=#=\n" "$desc" $rc
fi
rm -f "$outfile"
if [ $rc -ne $target ]; then
num_errors=$(( $num_errors + 1 ))
printf "* Failed (rc=%.3d): %-14s - %s\n" $rc $app "$desc"
printf "* Failed (rc=%.3d): %-14s - %s\n" $rc $app "$desc (`which $app`)" 1>&2
return
exit $CRM_EX_ERROR
else
printf "* Passed: %-14s - %s\n" $app "$desc"
num_passed=$(( $num_passed + 1 ))
fi
}
function test_assert() {
_test_assert $1 0 $2
}
function test_assert_validate() {
_test_assert $1 1 $2
}
function test_crm_mon() {
local TMPXML
export CIB_file="$test_home/cli/crm_mon.xml"
desc="Basic text output"
cmd="crm_mon -1"
test_assert $CRM_EX_OK 0
desc="XML output"
cmd="crm_mon --output-as=xml"
test_assert_validate $CRM_EX_OK 0
desc="Basic text output without node section"
cmd="crm_mon -1 --exclude=nodes"
test_assert $CRM_EX_OK 0
desc="XML output without the node section"
cmd="crm_mon --output-as=xml --exclude=nodes"
test_assert_validate $CRM_EX_OK 0
desc="Text output with only the node section"
cmd="crm_mon -1 --exclude=all --include=nodes"
test_assert $CRM_EX_OK 0
# The above test doesn't need to be performed for other output formats. It's
# really just a test to make sure that blank lines are correct.
desc="Complete text output"
cmd="crm_mon -1 --include=all"
test_assert $CRM_EX_OK 0
# XML includes everything already so there's no need for a complete test
desc="Complete text output with detail"
cmd="crm_mon -1R --include=all"
test_assert $CRM_EX_OK 0
# XML includes detailed output already
desc="Complete brief text output"
cmd="crm_mon -1 --include=all --brief"
test_assert $CRM_EX_OK 0
desc="Complete text output grouped by node"
cmd="crm_mon -1 --include=all --group-by-node"
test_assert $CRM_EX_OK 0
# XML does not have a brief output option
desc="Complete brief text output grouped by node"
cmd="crm_mon -1 --include=all --group-by-node --brief"
test_assert $CRM_EX_OK 0
desc="XML output grouped by node"
cmd="crm_mon -1 --output-as=xml --group-by-node"
test_assert_validate $CRM_EX_OK 0
desc="Complete text output filtered by node"
cmd="crm_mon -1 --include=all --node=cluster01"
test_assert $CRM_EX_OK 0
desc="XML output filtered by node"
cmd="crm_mon --output-as xml --include=all --node=cluster01"
test_assert_validate $CRM_EX_OK 0
desc="Complete text output filtered by tag"
cmd="crm_mon -1 --include=all --node=even-nodes"
test_assert $CRM_EX_OK 0
desc="XML output filtered by tag"
cmd="crm_mon --output-as=xml --include=all --node=even-nodes"
test_assert_validate $CRM_EX_OK 0
desc="Complete text output filtered by resource tag"
cmd="crm_mon -1 --include=all --resource=fencing-rscs"
test_assert $CRM_EX_OK 0
desc="XML output filtered by resource tag"
cmd="crm_mon --output-as=xml --include=all --resource=fencing-rscs"
test_assert_validate $CRM_EX_OK 0
desc="Basic text output filtered by node that doesn't exist"
cmd="crm_mon -1 --node=blah"
test_assert $CRM_EX_OK 0
desc="XML output filtered by node that doesn't exist"
cmd="crm_mon --output-as=xml --node=blah"
test_assert_validate $CRM_EX_OK 0
desc="Basic text output with inactive resources"
cmd="crm_mon -1 -r"
test_assert $CRM_EX_OK 0
# XML already includes inactive resources
desc="Basic text output with inactive resources, filtered by node"
cmd="crm_mon -1 -r --node=cluster02"
test_assert $CRM_EX_OK 0
# XML already includes inactive resources
desc="Complete text output filtered by primitive resource"
cmd="crm_mon -1 --include=all --resource=Fencing"
test_assert $CRM_EX_OK 0
desc="XML output filtered by primitive resource"
cmd="crm_mon --output-as=xml --resource=Fencing"
test_assert_validate $CRM_EX_OK 0
desc="Complete text output filtered by group resource"
cmd="crm_mon -1 --include=all --resource=exim-group"
test_assert $CRM_EX_OK 0
desc="XML output filtered by group resource"
cmd="crm_mon --output-as=xml --resource=exim-group"
test_assert_validate $CRM_EX_OK 0
desc="Complete text output filtered by group resource member"
cmd="crm_mon -1 --include=all --resource=Public-IP"
test_assert $CRM_EX_OK 0
desc="XML output filtered by group resource member"
cmd="crm_mon --output-as=xml --resource=Email"
test_assert_validate $CRM_EX_OK 0
desc="Complete text output filtered by clone resource"
cmd="crm_mon -1 --include=all --resource=ping-clone"
test_assert $CRM_EX_OK 0
desc="XML output filtered by clone resource"
cmd="crm_mon --output-as=xml --resource=ping-clone"
test_assert_validate $CRM_EX_OK 0
desc="Complete text output filtered by clone resource instance"
cmd="crm_mon -1 --include=all --resource=ping"
test_assert $CRM_EX_OK 0
desc="XML output filtered by clone resource instance"
cmd="crm_mon --output-as=xml --resource=ping"
test_assert_validate $CRM_EX_OK 0
desc="Complete text output filtered by exact clone resource instance"
cmd="crm_mon -1 --include=all --show-detail --resource=ping:0"
test_assert $CRM_EX_OK 0
desc="XML output filtered by exact clone resource instance"
cmd="crm_mon --output-as=xml --resource=ping:1"
test_assert_validate $CRM_EX_OK 0
desc="Basic text output filtered by resource that doesn't exist"
cmd="crm_mon -1 --resource=blah"
test_assert $CRM_EX_OK 0
desc="XML output filtered by resource that doesn't exist"
cmd="crm_mon --output-as=xml --resource=blah"
test_assert_validate $CRM_EX_OK 0
desc="Basic text output with inactive resources, filtered by tag"
cmd="crm_mon -1 -r --resource=inactive-rscs"
test_assert $CRM_EX_OK 0
desc="Basic text output with inactive resources, filtered by bundle resource"
cmd="crm_mon -1 -r --resource=httpd-bundle"
test_assert $CRM_EX_OK 0
desc="XML output filtered by inactive bundle resource"
cmd="crm_mon --output-as=xml --resource=httpd-bundle"
test_assert_validate $CRM_EX_OK 0
desc="Basic text output with inactive resources, filtered by bundled IP address resource"
cmd="crm_mon -1 -r --resource=httpd-bundle-ip-192.168.122.131"
test_assert $CRM_EX_OK 0
desc="XML output filtered by bundled IP address resource"
cmd="crm_mon --output-as=xml --resource=httpd-bundle-ip-192.168.122.132"
test_assert_validate $CRM_EX_OK 0
desc="Basic text output with inactive resources, filtered by bundled container"
cmd="crm_mon -1 -r --resource=httpd-bundle-docker-1"
test_assert $CRM_EX_OK 0
desc="XML output filtered by bundled container"
cmd="crm_mon --output-as=xml --resource=httpd-bundle-docker-2"
test_assert_validate $CRM_EX_OK 0
desc="Basic text output with inactive resources, filtered by bundle connection"
cmd="crm_mon -1 -r --resource=httpd-bundle-0"
test_assert $CRM_EX_OK 0
desc="XML output filtered by bundle connection"
cmd="crm_mon --output-as=xml --resource=httpd-bundle-0"
test_assert_validate $CRM_EX_OK 0
desc="Basic text output with inactive resources, filtered by bundled primitive resource"
cmd="crm_mon -1 -r --resource=httpd"
test_assert $CRM_EX_OK 0
desc="XML output filtered by bundled primitive resource"
cmd="crm_mon --output-as=xml --resource=httpd"
test_assert_validate $CRM_EX_OK 0
desc="Complete text output, filtered by clone name in cloned group"
cmd="crm_mon -1 --include=all --show-detail --resource=mysql-clone-group"
test_assert $CRM_EX_OK 0
desc="XML output, filtered by clone name in cloned group"
cmd="crm_mon --output-as=xml --resource=mysql-clone-group"
test_assert_validate $CRM_EX_OK 0
desc="Complete text output, filtered by group name in cloned group"
cmd="crm_mon -1 --include=all --show-detail --resource=mysql-group"
test_assert $CRM_EX_OK 0
desc="XML output, filtered by group name in cloned group"
cmd="crm_mon --output-as=xml --resource=mysql-group"
test_assert_validate $CRM_EX_OK 0
desc="Complete text output, filtered by exact group instance name in cloned group"
cmd="crm_mon -1 --include=all --show-detail --resource=mysql-group:1"
test_assert $CRM_EX_OK 0
desc="XML output, filtered by exact group instance name in cloned group"
cmd="crm_mon --output-as=xml --resource=mysql-group:1"
test_assert_validate $CRM_EX_OK 0
desc="Complete text output, filtered by primitive name in cloned group"
cmd="crm_mon -1 --include=all --show-detail --resource=mysql-proxy"
test_assert $CRM_EX_OK 0
desc="XML output, filtered by primitive name in cloned group"
cmd="crm_mon --output-as=xml --resource=mysql-proxy"
test_assert_validate $CRM_EX_OK 0
desc="Complete text output, filtered by exact primitive instance name in cloned group"
cmd="crm_mon -1 --include=all --show-detail --resource=mysql-proxy:1"
test_assert $CRM_EX_OK 0
desc="XML output, filtered by exact primitive instance name in cloned group"
cmd="crm_mon --output-as=xml --resource=mysql-proxy:1"
test_assert_validate $CRM_EX_OK 0
unset CIB_file
export CIB_file="$test_home/cli/crm_mon-partial.xml"
desc="Text output of partially active resources"
cmd="crm_mon -1 --show-detail"
test_assert $CRM_EX_OK 0
desc="XML output of partially active resources"
cmd="crm_mon -1 --output-as=xml"
test_assert_validate $CRM_EX_OK 0
desc="Text output of partially active resources, with inactive resources"
cmd="crm_mon -1 -r --show-detail"
test_assert $CRM_EX_OK 0
# XML already includes inactive resources
desc="Complete brief text output, with inactive resources"
cmd="crm_mon -1 -r --include=all --brief --show-detail"
test_assert $CRM_EX_OK 0
# XML does not have a brief output option
desc="Text output of partially active group"
cmd="crm_mon -1 --resource=partially-active-group"
test_assert $CRM_EX_OK 0
desc="Text output of partially active group, with inactive resources"
cmd="crm_mon -1 --resource=partially-active-group -r"
test_assert $CRM_EX_OK 0
desc="Text output of active member of partially active group"
cmd="crm_mon -1 --resource=dummy-1"
test_assert $CRM_EX_OK 0
desc="Text output of inactive member of partially active group"
cmd="crm_mon -1 --resource=dummy-2 --show-detail"
test_assert $CRM_EX_OK 0
desc="Complete brief text output grouped by node, with inactive resources"
cmd="crm_mon -1 -r --include=all --group-by-node --brief --show-detail"
test_assert $CRM_EX_OK 0
desc="Text output of partially active resources, with inactive resources, filtered by node"
cmd="crm_mon -1 -r --node=cluster01"
test_assert $CRM_EX_OK 0
desc="Text output of partially active resources, filtered by node"
cmd="crm_mon -1 --output-as=xml --node=cluster01"
test_assert_validate $CRM_EX_OK 0
unset CIB_file
export CIB_file="$test_home/cli/crm_mon-unmanaged.xml"
desc="Text output of active unmanaged resource on offline node"
cmd="crm_mon -1"
test_assert $CRM_EX_OK 0
desc="XML output of active unmanaged resource on offline node"
cmd="crm_mon -1 --output-as=xml"
test_assert $CRM_EX_OK 0
desc="Brief text output of active unmanaged resource on offline node"
cmd="crm_mon -1 --brief"
test_assert $CRM_EX_OK 0
desc="Brief text output of active unmanaged resource on offline node, grouped by node"
cmd="crm_mon -1 --brief --group-by-node"
test_assert $CRM_EX_OK 0
export CIB_file=$(mktemp ${TMPDIR:-/tmp}/cts-cli.crm_mon.xml.XXXXXXXXXX)
sed -e '/maintenance-mode/ s/false/true/' "$test_home/cli/crm_mon.xml" > $CIB_file
desc="Text output of all resources with maintenance-mode enabled"
cmd="crm_mon -1 -r"
test_assert $CRM_EX_OK 0
rm -r "$CIB_file"
unset CIB_file
}
function test_tools() {
local TMPXML
local TMPORIG
TMPXML=$(mktemp ${TMPDIR:-/tmp}/cts-cli.tools.xml.XXXXXXXXXX)
TMPORIG=$(mktemp ${TMPDIR:-/tmp}/cts-cli.tools.existing.xml.XXXXXXXXXX)
create_shadow_cib
desc="Validate CIB"
cmd="cibadmin -Q"
test_assert $CRM_EX_OK
desc="Configure something before erasing"
cmd="crm_attribute -n cluster-delay -v 60s"
test_assert $CRM_EX_OK
desc="Require --force for CIB erasure"
cmd="cibadmin -E"
test_assert $CRM_EX_UNSAFE
desc="Allow CIB erasure with --force"
cmd="cibadmin -E --force"
test_assert $CRM_EX_OK 0
# Skip outputting the resulting CIB in the previous command, and delete
# rsc_defaults now, so tests behave the same regardless of build options.
delete_shadow_resource_defaults
# Verify the output after erasure
desc="Query CIB"
cmd="cibadmin -Q"
test_assert $CRM_EX_OK
# Save a copy of the CIB for a later test
cibadmin -Q > "$TMPORIG"
desc="Set cluster option"
cmd="crm_attribute -n cluster-delay -v 60s"
test_assert $CRM_EX_OK
desc="Query new cluster option"
cmd="cibadmin -Q -o crm_config | grep cib-bootstrap-options-cluster-delay"
test_assert $CRM_EX_OK
desc="Query cluster options"
cmd="cibadmin -Q -o crm_config > $TMPXML"
test_assert $CRM_EX_OK
desc="Set no-quorum policy"
cmd="crm_attribute -n no-quorum-policy -v ignore"
test_assert $CRM_EX_OK
desc="Delete nvpair"
cmd="cibadmin -D -o crm_config --xml-text ''"
test_assert $CRM_EX_OK
desc="Create operation should fail"
cmd="cibadmin -C -o crm_config --xml-file $TMPXML"
test_assert $CRM_EX_EXISTS
desc="Modify cluster options section"
cmd="cibadmin -M -o crm_config --xml-file $TMPXML"
test_assert $CRM_EX_OK
desc="Query updated cluster option"
cmd="cibadmin -Q -o crm_config | grep cib-bootstrap-options-cluster-delay"
test_assert $CRM_EX_OK
desc="Set duplicate cluster option"
cmd="crm_attribute -n cluster-delay -v 40s -s duplicate"
test_assert $CRM_EX_OK
desc="Setting multiply defined cluster option should fail"
cmd="crm_attribute -n cluster-delay -v 30s"
test_assert $CRM_EX_MULTIPLE
desc="Set cluster option with -s"
cmd="crm_attribute -n cluster-delay -v 30s -s duplicate"
test_assert $CRM_EX_OK
desc="Delete cluster option with -i"
cmd="crm_attribute -n cluster-delay -D -i cib-bootstrap-options-cluster-delay"
test_assert $CRM_EX_OK
desc="Create node1 and bring it online"
cmd="crm_simulate --live-check --in-place --node-up=node1"
test_assert $CRM_EX_OK
desc="Create node attribute"
cmd="crm_attribute -n ram -v 1024M -N node1 -t nodes"
test_assert $CRM_EX_OK
desc="Query new node attribute"
cmd="cibadmin -Q -o nodes | grep node1-ram"
test_assert $CRM_EX_OK
desc="Set a transient (fail-count) node attribute"
cmd="crm_attribute -n fail-count-foo -v 3 -N node1 -t status"
test_assert $CRM_EX_OK
desc="Query a fail count"
cmd="crm_failcount --query -r foo -N node1"
test_assert $CRM_EX_OK
desc="Show node attributes with crm_simulate"
cmd="crm_simulate --live-check --show-attrs"
test_assert $CRM_EX_OK 0
desc="Delete a transient (fail-count) node attribute"
cmd="crm_attribute -n fail-count-foo -D -N node1 -t status"
test_assert $CRM_EX_OK
desc="Digest calculation"
cmd="cibadmin -Q | cibadmin -5 -p 2>&1 > /dev/null"
test_assert $CRM_EX_OK
# This update will fail because it has version numbers
desc="Replace operation should fail"
cmd="cibadmin -R --xml-file $TMPORIG"
test_assert $CRM_EX_OLD
desc="Default standby value"
cmd="crm_standby -N node1 -G"
test_assert $CRM_EX_OK
desc="Set standby status"
cmd="crm_standby -N node1 -v true"
test_assert $CRM_EX_OK
desc="Query standby value"
cmd="crm_standby -N node1 -G"
test_assert $CRM_EX_OK
desc="Delete standby value"
cmd="crm_standby -N node1 -D"
test_assert $CRM_EX_OK
desc="Create a resource"
cmd="cibadmin -C -o resources --xml-text ''"
test_assert $CRM_EX_OK
desc="Create a resource meta attribute"
cmd="crm_resource -r dummy --meta -p is-managed -v false"
test_assert $CRM_EX_OK
desc="Query a resource meta attribute"
cmd="crm_resource -r dummy --meta -g is-managed"
test_assert $CRM_EX_OK
desc="Remove a resource meta attribute"
cmd="crm_resource -r dummy --meta -d is-managed"
test_assert $CRM_EX_OK
desc="Create another resource meta attribute"
cmd="crm_resource -r dummy --meta -p target-role -v Stopped --output-as=xml"
test_assert_validate $CRM_EX_OK 0
desc="Show why a resource is not running"
cmd="crm_resource -Y -r dummy"
test_assert $CRM_EX_OK 0
desc="Remove another resource meta attribute"
cmd="crm_resource -r dummy --meta -d target-role --output-as=xml"
test_assert_validate $CRM_EX_OK 0
desc="Create a resource attribute"
cmd="crm_resource -r dummy -p delay -v 10s"
test_assert $CRM_EX_OK
desc="List the configured resources"
cmd="crm_resource -L"
test_assert $CRM_EX_OK
desc="List the configured resources in XML"
cmd="crm_resource -L --output-as=xml"
test_assert_validate $CRM_EX_OK 0
desc="List IDs of instantiated resources"
cmd="crm_resource -l"
test_assert $CRM_EX_OK 0
desc="Show XML configuration of resource"
cmd="crm_resource -q -r dummy"
test_assert $CRM_EX_OK 0
desc="Require a destination when migrating a resource that is stopped"
cmd="crm_resource -r dummy -M"
test_assert $CRM_EX_USAGE
desc="Don't support migration to non-existent locations"
cmd="crm_resource -r dummy -M -N i.do.not.exist"
test_assert $CRM_EX_NOSUCH
desc="Create a fencing resource"
cmd="cibadmin -C -o resources --xml-text ''"
test_assert $CRM_EX_OK
desc="Bring resources online"
cmd="crm_simulate --live-check --in-place -S"
test_assert $CRM_EX_OK
desc="Try to move a resource to its existing location"
cmd="crm_resource -r dummy --move --node node1"
test_assert $CRM_EX_EXISTS
desc="Move a resource from its existing location"
cmd="crm_resource -r dummy --move"
test_assert $CRM_EX_OK
desc="Clear out constraints generated by --move"
cmd="crm_resource -r dummy --clear"
test_assert $CRM_EX_OK
desc="Default ticket granted state"
cmd="crm_ticket -t ticketA -G granted -d false"
test_assert $CRM_EX_OK
desc="Set ticket granted state"
cmd="crm_ticket -t ticketA -r --force"
test_assert $CRM_EX_OK
desc="Query ticket granted state"
cmd="crm_ticket -t ticketA -G granted"
test_assert $CRM_EX_OK
desc="Delete ticket granted state"
cmd="crm_ticket -t ticketA -D granted --force"
test_assert $CRM_EX_OK
desc="Make a ticket standby"
cmd="crm_ticket -t ticketA -s"
test_assert $CRM_EX_OK
desc="Query ticket standby state"
cmd="crm_ticket -t ticketA -G standby"
test_assert $CRM_EX_OK
desc="Activate a ticket"
cmd="crm_ticket -t ticketA -a"
test_assert $CRM_EX_OK
desc="Delete ticket standby state"
cmd="crm_ticket -t ticketA -D standby"
test_assert $CRM_EX_OK
desc="Ban a resource on unknown node"
cmd="crm_resource -r dummy -B -N host1"
test_assert $CRM_EX_NOSUCH
desc="Create two more nodes and bring them online"
cmd="crm_simulate --live-check --in-place --node-up=node2 --node-up=node3"
test_assert $CRM_EX_OK
desc="Ban dummy from node1"
cmd="crm_resource -r dummy -B -N node1"
test_assert $CRM_EX_OK
desc="Show where a resource is running"
cmd="crm_resource -r dummy -W"
test_assert $CRM_EX_OK 0
desc="Show constraints on a resource"
cmd="crm_resource -a -r dummy"
test_assert $CRM_EX_OK 0
desc="Ban dummy from node2"
cmd="crm_resource -r dummy -B -N node2 --output-as=xml"
test_assert_validate $CRM_EX_OK
desc="Relocate resources due to ban"
cmd="crm_simulate --live-check --in-place -S"
test_assert $CRM_EX_OK
desc="Move dummy to node1"
cmd="crm_resource -r dummy -M -N node1 --output-as=xml"
test_assert_validate $CRM_EX_OK
desc="Clear implicit constraints for dummy on node2"
cmd="crm_resource -r dummy -U -N node2"
test_assert $CRM_EX_OK
desc="Drop the status section"
cmd="cibadmin -R -o status --xml-text ''"
test_assert $CRM_EX_OK 0
desc="Create a clone"
cmd="cibadmin -C -o resources --xml-text ''"
test_assert $CRM_EX_OK 0
desc="Create a resource meta attribute"
cmd="crm_resource -r test-primitive --meta -p is-managed -v false"
test_assert $CRM_EX_OK
desc="Create a resource meta attribute in the primitive"
cmd="crm_resource -r test-primitive --meta -p is-managed -v false --force"
test_assert $CRM_EX_OK
desc="Update resource meta attribute with duplicates"
cmd="crm_resource -r test-clone --meta -p is-managed -v true"
test_assert $CRM_EX_OK
desc="Update resource meta attribute with duplicates (force clone)"
cmd="crm_resource -r test-clone --meta -p is-managed -v true --force"
test_assert $CRM_EX_OK
desc="Update child resource meta attribute with duplicates"
cmd="crm_resource -r test-primitive --meta -p is-managed -v false"
test_assert $CRM_EX_OK
desc="Delete resource meta attribute with duplicates"
cmd="crm_resource -r test-clone --meta -d is-managed"
test_assert $CRM_EX_OK
desc="Delete resource meta attribute in parent"
cmd="crm_resource -r test-primitive --meta -d is-managed"
test_assert $CRM_EX_OK
desc="Create a resource meta attribute in the primitive"
cmd="crm_resource -r test-primitive --meta -p is-managed -v false --force"
test_assert $CRM_EX_OK
desc="Update existing resource meta attribute"
cmd="crm_resource -r test-clone --meta -p is-managed -v true"
test_assert $CRM_EX_OK
desc="Create a resource meta attribute in the parent"
cmd="crm_resource -r test-clone --meta -p is-managed -v true --force"
test_assert $CRM_EX_OK
desc="Copy resources"
cmd="cibadmin -Q -o resources > $TMPXML"
test_assert $CRM_EX_OK 0
desc="Delete resource parent meta attribute (force)"
cmd="crm_resource -r test-clone --meta -d is-managed --force"
test_assert $CRM_EX_OK
desc="Restore duplicates"
cmd="cibadmin -R -o resources --xml-file $TMPXML"
test_assert $CRM_EX_OK
desc="Delete resource child meta attribute"
cmd="crm_resource -r test-primitive --meta -d is-managed"
test_assert $CRM_EX_OK
cibadmin -C -o resources --xml-text ' \
\
\
'
desc="Create a resource meta attribute in dummy1"
cmd="crm_resource -r dummy1 --meta -p is-managed -v true"
test_assert $CRM_EX_OK
desc="Create a resource meta attribute in dummy-group"
cmd="crm_resource -r dummy-group --meta -p is-managed -v false"
test_assert $CRM_EX_OK
cibadmin -D -o resource --xml-text ''
desc="Specify a lifetime when moving a resource"
cmd="crm_resource -r dummy --move --node node2 --lifetime=PT1H"
test_assert $CRM_EX_OK
desc="Try to move a resource previously moved with a lifetime"
cmd="crm_resource -r dummy --move --node node1"
test_assert $CRM_EX_OK
desc="Ban dummy from node1 for a short time"
cmd="crm_resource -r dummy -B -N node1 --lifetime=PT1S"
test_assert $CRM_EX_OK
desc="Remove expired constraints"
sleep 2
cmd="crm_resource --clear --expired"
test_assert $CRM_EX_OK
# Clear has already been tested elsewhere, but we need to get rid of the
# constraints so testing delete works. It won't delete if there's still
# a reference to the resource somewhere.
desc="Clear all implicit constraints for dummy"
cmd="crm_resource -r dummy -U"
test_assert $CRM_EX_OK
desc="Delete a resource"
cmd="crm_resource -D -r dummy -t primitive"
test_assert $CRM_EX_OK
unset CIB_shadow
unset CIB_shadow_dir
rm -f "$TMPXML" "$TMPORIG"
desc="Create an XML patchset"
cmd="crm_diff -o $test_home/cli/crm_diff_old.xml -n $test_home/cli/crm_diff_new.xml"
test_assert $CRM_EX_ERROR 0
export CIB_file="$test_home/cli/constraints.xml"
for rsc in prim1 prim2 prim3 prim4 prim5 prim6 prim7 prim8 prim9 \
prim10 prim11 prim12 prim13 group clone; do
desc="Check locations and constraints for $rsc"
cmd="crm_resource -a -r $rsc"
test_assert $CRM_EX_OK 0
desc="Recursively check locations and constraints for $rsc"
cmd="crm_resource -A -r $rsc"
test_assert $CRM_EX_OK 0
desc="Check locations and constraints for $rsc in XML"
cmd="crm_resource -a -r $rsc --output-as=xml"
test_assert_validate $CRM_EX_OK 0
desc="Recursively check locations and constraints for $rsc in XML"
cmd="crm_resource -A -r $rsc --output-as=xml"
test_assert_validate $CRM_EX_OK 0
done
unset CIB_file
export CIB_file="$test_home/cli/crm_resource_digests.xml"
desc="Show resource digests"
cmd="crm_resource --digests -r rsc1 -N node1 --output-as=xml"
test_assert_validate $CRM_EX_OK 0
desc="Show resource digests with overrides"
cmd="$cmd CRM_meta_interval=10000 CRM_meta_timeout=20000"
test_assert $CRM_EX_OK 0
unset CIB_file
export CIB_file="$test_home/cli/crmadmin-cluster-remote-guest-nodes.xml"
desc="List all nodes"
cmd="crmadmin -N | wc -l | grep 11"
test_assert $CRM_EX_OK 0
desc="List cluster nodes"
cmd="crmadmin -N cluster | wc -l | grep 6"
test_assert $CRM_EX_OK 0
desc="List guest nodes"
cmd="crmadmin -N guest | wc -l | grep 2"
test_assert $CRM_EX_OK 0
desc="List remote nodes"
cmd="crmadmin -N remote | wc -l | grep 3"
test_assert $CRM_EX_OK 0
desc="List cluster,remote nodes"
cmd="crmadmin -N cluster,remote | wc -l | grep 9"
test_assert $CRM_EX_OK 0
desc="List guest,remote nodes"
cmd="crmadmin -N guest,remote | wc -l | grep 5"
test_assert $CRM_EX_OK 0
unset CIB_file
export CIB_file="$test_home/cli/crm_mon.xml"
export CIB_shadow_dir="${shadow_dir}"
desc="Show allocation scores with crm_simulate"
cmd="crm_simulate -x $CIB_file --show-scores --output-as=xml"
test_assert_validate $CRM_EX_OK 0
desc="Show utilization with crm_simulate"
cmd="crm_simulate -x $CIB_file --show-utilization"
test_assert $CRM_EX_OK 0
desc="Simulate injecting a failure"
cmd="crm_simulate -x $CIB_file -S -i ping_monitor_10000@cluster02=1"
test_assert $CRM_EX_OK 0
desc="Simulate bringing a node down"
cmd="crm_simulate -x $CIB_file -S --node-down=cluster01"
test_assert $CRM_EX_OK 0
desc="Simulate a node failing"
cmd="crm_simulate -x $CIB_file -S --node-fail=cluster02"
test_assert $CRM_EX_OK 0
unset CIB_shadow_dir
desc="List a promotable clone resource"
cmd="crm_resource --locate -r promotable-clone"
test_assert $CRM_EX_OK 0
desc="List the primitive of a promotable clone resource"
cmd="crm_resource --locate -r promotable-rsc"
test_assert $CRM_EX_OK 0
desc="List a single instance of a promotable clone resource"
cmd="crm_resource --locate -r promotable-rsc:0"
test_assert $CRM_EX_OK 0
desc="List another instance of a promotable clone resource"
cmd="crm_resource --locate -r promotable-rsc:1"
test_assert $CRM_EX_OK 0
desc="List a promotable clone resource in XML"
cmd="crm_resource --locate -r promotable-clone --output-as=xml"
test_assert_validate $CRM_EX_OK 0
desc="List the primitive of a promotable clone resource in XML"
cmd="crm_resource --locate -r promotable-rsc --output-as=xml"
test_assert_validate $CRM_EX_OK 0
desc="List a single instance of a promotable clone resource in XML"
cmd="crm_resource --locate -r promotable-rsc:0 --output-as=xml"
test_assert_validate $CRM_EX_OK 0
desc="List another instance of a promotable clone resource in XML"
cmd="crm_resource --locate -r promotable-rsc:1 --output-as=xml"
test_assert_validate $CRM_EX_OK 0
unset CIB_file
export CIB_file="-"
desc="Check that CIB_file=\"-\" works - crm_mon"
cmd="cat $test_home/cli/crm_mon.xml | crm_mon -1"
test_assert $CRM_EX_OK 0
desc="Check that CIB_file=\"-\" works - crm_resource"
cmd="cat $test_home/cli/crm_resource_digests.xml | crm_resource --digests -r rsc1 -N node1 --output-as=xml"
test_assert_validate $CRM_EX_OK 0
desc="Check that CIB_file=\"-\" works - crmadmin"
cmd="cat $test_home/cli/crmadmin-cluster-remote-guest-nodes.xml | crmadmin -N | wc -l | grep 11"
test_assert $CRM_EX_OK 0
unset CIB_file
}
INVALID_PERIODS=(
"2019-01-01 00:00:00Z" # Start with no end
"2019-01-01 00:00:00Z/" # Start with only a trailing slash
"PT2S/P1M" # Two durations
"2019-13-01 00:00:00Z/P1M" # Out-of-range month
"20191077T15/P1M" # Out-of-range day
"2019-10-01T25:00:00Z/P1M" # Out-of-range hour
"2019-10-01T24:00:01Z/P1M" # Hour 24 with anything but :00:00
"PT5H/20191001T007000Z" # Out-of-range minute
"2019-10-01 00:00:80Z/P1M" # Out-of-range second
"2019-10-01 00:00:10 +25:00/P1M" # Out-of-range offset hour
"20191001T000010 -00:61/P1M" # Out-of-range offset minute
"P1Y/2019-02-29 00:00:00Z" # Feb. 29 in non-leap-year
"2019-01-01 00:00:00Z/P" # Duration with no values
"P1Z/2019-02-20 00:00:00Z" # Invalid duration unit
"P1YM/2019-02-20 00:00:00Z" # No number for duration unit
)
function test_dates() {
# Ensure invalid period specifications are rejected
for spec in '' "${INVALID_PERIODS[@]}"; do
desc="Invalid period - [$spec]"
cmd="iso8601 -p \"$spec\""
test_assert $CRM_EX_INVALID_PARAM 0
done
desc="2014-01-01 00:30:00 - 1 Hour"
cmd="iso8601 -d '2014-01-01 00:30:00Z' -D P-1H -E '2013-12-31 23:30:00Z'"
test_assert $CRM_EX_OK 0
desc="Valid date - Feb 29 in leap year"
cmd="iso8601 -d '2020-02-29 00:00:00Z' -E '2020-02-29 00:00:00Z'"
test_assert $CRM_EX_OK 0
desc="Valid date - using 'T' and offset"
cmd="iso8601 -d '20191201T131211 -05:00' -E '2019-12-01 18:12:11Z'"
test_assert $CRM_EX_OK 0
desc="24:00:00 equivalent to 00:00:00 of next day"
cmd="iso8601 -d '2019-12-31 24:00:00Z' -E '2020-01-01 00:00:00Z'"
test_assert $CRM_EX_OK 0
for y in 06 07 08 09 10 11 12 13 14 15 16 17 18 40; do
desc="20$y-W01-7"
cmd="iso8601 -d '20$y-W01-7 00Z'"
test_assert $CRM_EX_OK 0
desc="20$y-W01-7 - round-trip"
cmd="iso8601 -d '20$y-W01-7 00Z' -W -E '20$y-W01-7 00:00:00Z'"
test_assert $CRM_EX_OK 0
desc="20$y-W01-1"
cmd="iso8601 -d '20$y-W01-1 00Z'"
test_assert $CRM_EX_OK 0
desc="20$y-W01-1 - round-trip"
cmd="iso8601 -d '20$y-W01-1 00Z' -W -E '20$y-W01-1 00:00:00Z'"
test_assert $CRM_EX_OK 0
done
desc="2009-W53-07"
cmd="iso8601 -d '2009-W53-7 00:00:00Z' -W -E '2009-W53-7 00:00:00Z'"
test_assert $CRM_EX_OK 0
desc="epoch + 2 Years 5 Months 6 Minutes"
cmd="iso8601 -d 'epoch' -D P2Y5MT6M -E '1972-06-01 00:06:00Z'"
test_assert $CRM_EX_OK 0
desc="2009-01-31 + 1 Month"
cmd="iso8601 -d '20090131T000000Z' -D P1M -E '2009-02-28 00:00:00Z'"
test_assert $CRM_EX_OK 0
desc="2009-01-31 + 2 Months"
cmd="iso8601 -d '2009-01-31 00:00:00Z' -D P2M -E '2009-03-31 00:00:00Z'"
test_assert $CRM_EX_OK 0
desc="2009-01-31 + 3 Months"
cmd="iso8601 -d '2009-01-31 00:00:00Z' -D P3M -E '2009-04-30 00:00:00Z'"
test_assert $CRM_EX_OK 0
desc="2009-03-31 - 1 Month"
cmd="iso8601 -d '2009-03-31 01:00:00 +01:00' -D P-1M -E '2009-02-28 00:00:00Z'"
test_assert $CRM_EX_OK 0
desc="2038-01-01 + 3 Months"
cmd="iso8601 -d '2038-01-01 00:00:00Z' -D P3M -E '2038-04-01 00:00:00Z'"
test_assert $CRM_EX_OK 0
}
function test_acl_loop() {
local TMPXML
TMPXML="$1"
# Make sure we're rejecting things for the right reasons
export PCMK_trace_functions=pcmk__check_acl,pcmk__apply_creation_acl
export PCMK_stderr=1
CIB_user=root cibadmin --replace --xml-text ''
### no ACL ###
export CIB_user=unknownguy
desc="$CIB_user: Query configuration"
cmd="cibadmin -Q"
test_assert $CRM_EX_INSUFFICIENT_PRIV 0
desc="$CIB_user: Set enable-acl"
cmd="crm_attribute -n enable-acl -v false"
test_assert $CRM_EX_INSUFFICIENT_PRIV 0
desc="$CIB_user: Set stonith-enabled"
cmd="crm_attribute -n stonith-enabled -v false"
test_assert $CRM_EX_INSUFFICIENT_PRIV 0
desc="$CIB_user: Create a resource"
cmd="cibadmin -C -o resources --xml-text ''"
test_assert $CRM_EX_INSUFFICIENT_PRIV 0
### deny /cib permission ###
export CIB_user=l33t-haxor
desc="$CIB_user: Query configuration"
cmd="cibadmin -Q"
test_assert $CRM_EX_INSUFFICIENT_PRIV 0
desc="$CIB_user: Set enable-acl"
cmd="crm_attribute -n enable-acl -v false"
test_assert $CRM_EX_INSUFFICIENT_PRIV 0
desc="$CIB_user: Set stonith-enabled"
cmd="crm_attribute -n stonith-enabled -v false"
test_assert $CRM_EX_INSUFFICIENT_PRIV 0
desc="$CIB_user: Create a resource"
cmd="cibadmin -C -o resources --xml-text ''"
test_assert $CRM_EX_INSUFFICIENT_PRIV 0
### observer role ###
export CIB_user=niceguy
desc="$CIB_user: Query configuration"
cmd="cibadmin -Q"
test_assert $CRM_EX_OK 0
desc="$CIB_user: Set enable-acl"
cmd="crm_attribute -n enable-acl -v false"
test_assert $CRM_EX_INSUFFICIENT_PRIV 0
desc="$CIB_user: Set stonith-enabled"
cmd="crm_attribute -n stonith-enabled -v false"
test_assert $CRM_EX_OK
desc="$CIB_user: Create a resource"
cmd="cibadmin -C -o resources --xml-text ''"
test_assert $CRM_EX_INSUFFICIENT_PRIV 0
export CIB_user=root
desc="$CIB_user: Query configuration"
cmd="cibadmin -Q"
test_assert $CRM_EX_OK 0
desc="$CIB_user: Set stonith-enabled"
cmd="crm_attribute -n stonith-enabled -v true"
test_assert $CRM_EX_OK
desc="$CIB_user: Create a resource"
cmd="cibadmin -C -o resources --xml-text ''"
test_assert $CRM_EX_OK
### deny /cib permission ###
export CIB_user=l33t-haxor
desc="$CIB_user: Create a resource meta attribute"
cmd="crm_resource -r dummy --meta -p target-role -v Stopped"
test_assert $CRM_EX_INSUFFICIENT_PRIV 0
desc="$CIB_user: Query a resource meta attribute"
cmd="crm_resource -r dummy --meta -g target-role"
test_assert $CRM_EX_INSUFFICIENT_PRIV 0
desc="$CIB_user: Remove a resource meta attribute"
cmd="crm_resource -r dummy --meta -d target-role"
test_assert $CRM_EX_INSUFFICIENT_PRIV 0
### observer role ###
export CIB_user=niceguy
desc="$CIB_user: Create a resource meta attribute"
cmd="crm_resource -r dummy --meta -p target-role -v Stopped"
test_assert $CRM_EX_OK
desc="$CIB_user: Query a resource meta attribute"
cmd="crm_resource -r dummy --meta -g target-role"
test_assert $CRM_EX_OK
desc="$CIB_user: Remove a resource meta attribute"
cmd="crm_resource -r dummy --meta -d target-role"
test_assert $CRM_EX_OK
desc="$CIB_user: Create a resource meta attribute"
cmd="crm_resource -r dummy --meta -p target-role -v Started"
test_assert $CRM_EX_OK
### read //meta_attributes ###
export CIB_user=badidea
desc="$CIB_user: Query configuration - implied deny"
cmd="cibadmin -Q"
test_assert $CRM_EX_OK 0
### deny /cib, read //meta_attributes ###
export CIB_user=betteridea
desc="$CIB_user: Query configuration - explicit deny"
cmd="cibadmin -Q"
test_assert $CRM_EX_OK 0
CIB_user=root cibadmin -Q > "$TMPXML"
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin --delete --xml-text ''
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
### observer role ###
export CIB_user=niceguy
desc="$CIB_user: Replace - remove acls"
cmd="cibadmin --replace --xml-file $TMPXML"
test_assert $CRM_EX_INSUFFICIENT_PRIV 0
CIB_user=root cibadmin -Q > "$TMPXML"
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -C -o resources --xml-text ''
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
desc="$CIB_user: Replace - create resource"
cmd="cibadmin --replace --xml-file $TMPXML"
test_assert $CRM_EX_INSUFFICIENT_PRIV 0
CIB_user=root cibadmin -Q > "$TMPXML"
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" crm_attribute -n enable-acl -v false
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
desc="$CIB_user: Replace - modify attribute (deny)"
cmd="cibadmin --replace --xml-file $TMPXML"
test_assert $CRM_EX_INSUFFICIENT_PRIV 0
CIB_user=root cibadmin -Q > "$TMPXML"
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin --replace --xml-text ''
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
desc="$CIB_user: Replace - delete attribute (deny)"
cmd="cibadmin --replace --xml-file $TMPXML"
test_assert $CRM_EX_INSUFFICIENT_PRIV 0
CIB_user=root cibadmin -Q > "$TMPXML"
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin --modify --xml-text ''
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
desc="$CIB_user: Replace - create attribute (deny)"
cmd="cibadmin --replace --xml-file $TMPXML"
test_assert $CRM_EX_INSUFFICIENT_PRIV 0
### admin role ###
CIB_user=bob
CIB_user=root cibadmin -Q > "$TMPXML"
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin --modify --xml-text ''
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
desc="$CIB_user: Replace - create attribute (direct allow)"
cmd="cibadmin --replace -o resources --xml-file $TMPXML"
test_assert $CRM_EX_OK 0
CIB_user=root cibadmin -Q > "$TMPXML"
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin --modify --xml-text ''
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
desc="$CIB_user: Replace - modify attribute (direct allow)"
cmd="cibadmin --replace -o resources --xml-file $TMPXML"
test_assert $CRM_EX_OK 0
CIB_user=root cibadmin -Q > "$TMPXML"
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin --replace -o resources --xml-text ''
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
desc="$CIB_user: Replace - delete attribute (direct allow)"
cmd="cibadmin --replace -o resources --xml-file $TMPXML"
test_assert $CRM_EX_OK 0
### super_user role ###
export CIB_user=joe
CIB_user=root cibadmin -Q > "$TMPXML"
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin --modify --xml-text ''
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
desc="$CIB_user: Replace - create attribute (inherited allow)"
cmd="cibadmin --replace -o resources --xml-file $TMPXML"
test_assert $CRM_EX_OK 0
CIB_user=root cibadmin -Q > "$TMPXML"
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin --modify --xml-text ''
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
desc="$CIB_user: Replace - modify attribute (inherited allow)"
cmd="cibadmin --replace -o resources --xml-file $TMPXML"
test_assert $CRM_EX_OK 0
CIB_user=root cibadmin -Q > "$TMPXML"
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin --replace -o resources --xml-text ''
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
desc="$CIB_user: Replace - delete attribute (inherited allow)"
cmd="cibadmin --replace -o resources --xml-file $TMPXML"
test_assert $CRM_EX_OK 0
### rsc_writer role ###
export CIB_user=mike
CIB_user=root cibadmin -Q > "$TMPXML"
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin --modify --xml-text ''
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
desc="$CIB_user: Replace - create attribute (allow overrides deny)"
cmd="cibadmin --replace -o resources --xml-file $TMPXML"
test_assert $CRM_EX_OK 0
CIB_user=root cibadmin -Q > "$TMPXML"
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin --modify --xml-text ''
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
desc="$CIB_user: Replace - modify attribute (allow overrides deny)"
cmd="cibadmin --replace -o resources --xml-file $TMPXML"
test_assert $CRM_EX_OK 0
CIB_user=root cibadmin -Q > "$TMPXML"
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin --replace -o resources --xml-text ''
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
desc="$CIB_user: Replace - delete attribute (allow overrides deny)"
cmd="cibadmin --replace -o resources --xml-file $TMPXML"
test_assert $CRM_EX_OK 0
### rsc_denied role ###
export CIB_user=chris
CIB_user=root cibadmin -Q > "$TMPXML"
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin --modify --xml-text ''
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
desc="$CIB_user: Replace - create attribute (deny overrides allow)"
cmd="cibadmin --replace -o resources --xml-file $TMPXML"
test_assert $CRM_EX_INSUFFICIENT_PRIV 0
# Set as root since setting as chris failed
CIB_user=root cibadmin --modify --xml-text ''
CIB_user=root cibadmin -Q > "$TMPXML"
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin --modify --xml-text ''
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
desc="$CIB_user: Replace - modify attribute (deny overrides allow)"
cmd="cibadmin --replace -o resources --xml-file $TMPXML"
test_assert $CRM_EX_INSUFFICIENT_PRIV 0
# Set as root since setting as chris failed
CIB_user=root cibadmin --modify --xml-text ''
CIB_user=root cibadmin -Q > "$TMPXML"
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin --replace -o resources --xml-text ''
CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
desc="$CIB_user: Replace - delete attribute (deny overrides allow)"
cmd="cibadmin --replace -o resources --xml-file $TMPXML"
test_assert $CRM_EX_INSUFFICIENT_PRIV 0
}
function test_acls() {
local SHADOWPATH
local TMPXML
TMPXML=$(mktemp ${TMPDIR:-/tmp}/cts-cli.acls.xml.XXXXXXXXXX)
create_shadow_cib pacemaker-1.3
cat < "$TMPXML"
EOF
desc="Configure some ACLs"
cmd="cibadmin -M -o acls --xml-file $TMPXML"
test_assert $CRM_EX_OK
desc="Enable ACLs"
cmd="crm_attribute -n enable-acl -v true"
test_assert $CRM_EX_OK
desc="Set cluster option"
cmd="crm_attribute -n no-quorum-policy -v ignore"
test_assert $CRM_EX_OK
desc="New ACL"
cmd="cibadmin --create -o acls --xml-text ''"
test_assert $CRM_EX_OK
desc="Another ACL"
cmd="cibadmin --create -o acls --xml-text ''"
test_assert $CRM_EX_OK
desc="Updated ACL"
cmd="cibadmin --replace -o acls --xml-text ''"
test_assert $CRM_EX_OK
test_acl_loop "$TMPXML"
printf "\n\n !#!#!#!#! Upgrading to latest CIB schema and re-testing !#!#!#!#!\n"
printf "\nUpgrading to latest CIB schema and re-testing\n" 1>&2
export CIB_user=root
desc="$CIB_user: Upgrade to latest CIB schema"
cmd="cibadmin --upgrade --force -V"
test_assert $CRM_EX_OK
reset_shadow_cib_version
test_acl_loop "$TMPXML"
unset CIB_shadow_dir
rm -f "$TMPXML"
}
function test_validity() {
local TMPGOOD
local TMPBAD
TMPGOOD=$(mktemp ${TMPDIR:-/tmp}/cts-cli.validity.good.xml.XXXXXXXXXX)
TMPBAD=$(mktemp ${TMPDIR:-/tmp}/cts-cli.validity.bad.xml.XXXXXXXXXX)
create_shadow_cib pacemaker-1.2
export PCMK_trace_functions=apply_upgrade,update_validation,cli_config_update
export PCMK_stderr=1
cibadmin -C -o resources --xml-text ''
cibadmin -C -o resources --xml-text ''
cibadmin -C -o constraints --xml-text ''
cibadmin -Q > "$TMPGOOD"
desc="Try to make resulting CIB invalid (enum violation)"
cmd="cibadmin -M -o constraints --xml-text ''"
test_assert $CRM_EX_CONFIG
sed 's|"start"|"break"|' "$TMPGOOD" > "$TMPBAD"
desc="Run crm_simulate with invalid CIB (enum violation)"
cmd="crm_simulate -x $TMPBAD -S"
test_assert $CRM_EX_CONFIG 0
desc="Try to make resulting CIB invalid (unrecognized validate-with)"
cmd="cibadmin -M --xml-text ''"
test_assert $CRM_EX_CONFIG
sed 's|"pacemaker-1.2"|"pacemaker-9999.0"|' "$TMPGOOD" > "$TMPBAD"
desc="Run crm_simulate with invalid CIB (unrecognized validate-with)"
cmd="crm_simulate -x $TMPBAD -S"
test_assert $CRM_EX_CONFIG 0
desc="Try to make resulting CIB invalid, but possibly recoverable (valid with X.Y+1)"
cmd="cibadmin -C -o configuration --xml-text ''"
test_assert $CRM_EX_CONFIG
sed 's|||' "$TMPGOOD" > "$TMPBAD"
desc="Run crm_simulate with invalid, but possibly recoverable CIB (valid with X.Y+1)"
cmd="crm_simulate -x $TMPBAD -S"
test_assert $CRM_EX_OK 0
sed 's|[ ][ ]*validate-with="[^"]*"||' "$TMPGOOD" > "$TMPBAD"
desc="Make resulting CIB valid, although without validate-with attribute"
cmd="cibadmin -R --xml-file $TMPBAD"
test_assert $CRM_EX_OK
desc="Run crm_simulate with valid CIB, but without validate-with attribute"
cmd="crm_simulate -x $TMPBAD -S"
test_assert $CRM_EX_OK 0
# this will just disable validation and accept the config, outputting
# validation errors
sed -e 's|[ ][ ]*validate-with="[^"]*"||' \
-e 's|\([ ][ ]*epoch="[^"]*\)"|\10"|' -e 's|"start"|"break"|' \
"$TMPGOOD" > "$TMPBAD"
desc="Make resulting CIB invalid, and without validate-with attribute"
cmd="cibadmin -R --xml-file $TMPBAD"
test_assert $CRM_EX_OK
desc="Run crm_simulate with invalid CIB, also without validate-with attribute"
cmd="crm_simulate -x $TMPBAD -S"
test_assert $CRM_EX_OK 0
unset CIB_shadow_dir
rm -f "$TMPGOOD" "$TMPBAD"
}
test_upgrade() {
local TMPXML
TMPXML=$(mktemp ${TMPDIR:-/tmp}/cts-cli.tools.xml.XXXXXXXXXX)
create_shadow_cib pacemaker-2.10
desc="Set stonith-enabled=false"
cmd="crm_attribute -n stonith-enabled -v false"
test_assert $CRM_EX_OK
cat < "$TMPXML"
EOF
desc="Configure the initial resource"
cmd="cibadmin -M -o resources --xml-file $TMPXML"
test_assert $CRM_EX_OK
desc="Upgrade to latest CIB schema (trigger 2.10.xsl + the wrapping)"
cmd="cibadmin --upgrade --force -V -V"
test_assert $CRM_EX_OK
desc="Query a resource instance attribute (shall survive)"
cmd="crm_resource -r mySmartFuse -g requires"
test_assert $CRM_EX_OK
unset CIB_shadow_dir
rm -f "$TMPXML"
}
test_rules() {
local TMPXML
create_shadow_cib
cibadmin -C -o crm_config --xml-text ''
cibadmin -C -o resources --xml-text ''
TMPXML=$(mktemp ${TMPDIR:-/tmp}/cts-cli.tools.xml.XXXXXXXXXX)
cat < "$TMPXML"
EOF
cibadmin -C -o constraints -x "$TMPXML"
rm -f "$TMPXML"
TMPXML=$(mktemp ${TMPDIR:-/tmp}/cts-cli.tools.xml.XXXXXXXXXX)
cat < "$TMPXML"
EOF
cibadmin -C -o constraints -x "$TMPXML"
rm -f "$TMPXML"
if [ "$(uname)" == "FreeBSD" ]; then
tomorrow=$(date -v+1d +"%F %T %z")
else
tomorrow=$(date --date=tomorrow +"%F %T %z")
fi
TMPXML=$(mktemp ${TMPDIR:-/tmp}/cts-cli.tools.xml.XXXXXXXXXX)
cat < "$TMPXML"
EOF
cibadmin -C -o constraints -x "$TMPXML"
rm -f "$TMPXML"
TMPXML=$(mktemp ${TMPDIR:-/tmp}/cts-cli.tools.xml.XXXXXXXXXX)
cat < "$TMPXML"
EOF
cibadmin -C -o constraints -x "$TMPXML"
rm -f "$TMPXML"
TMPXML=$(mktemp ${TMPDIR:-/tmp}/cts-cli.tools.xml.XXXXXXXXXX)
cat < "$TMPXML"
EOF
cibadmin -C -o constraints -x "$TMPXML"
rm -f "$TMPXML"
TMPXML=$(mktemp ${TMPDIR:-/tmp}/cts-cli.tools.xml.XXXXXXXXXX)
cat < "$TMPXML"
EOF
cibadmin -C -o constraints -x "$TMPXML"
rm -f "$TMPXML"
TMPXML=$(mktemp ${TMPDIR:-/tmp}/cts-cli.tools.xml.XXXXXXXXXX)
cat < "$TMPXML"
EOF
cibadmin -C -o constraints -x "$TMPXML"
rm -f "$TMPXML"
desc="Try to check a rule that doesn't exist"
cmd="crm_rule -c -r blahblah"
test_assert $CRM_EX_NOSUCH
desc="Try to check a rule that doesn't exist, with XML output"
cmd="crm_rule -c -r blahblah --output-as=xml"
test_assert $CRM_EX_NOSUCH 0
desc="Try to check a rule that has too many date_expressions"
cmd="crm_rule -c -r cli-rule-too-many-date-expressions"
test_assert $CRM_EX_UNIMPLEMENT_FEATURE 0
desc="Verify basic rule is expired"
cmd="crm_rule -c -r cli-prefer-rule-dummy-expired"
test_assert $CRM_EX_EXPIRED 0
desc="Verify basic rule is expired, with XML output"
cmd="crm_rule -c -r cli-prefer-rule-dummy-expired --output-as=xml"
test_assert $CRM_EX_EXPIRED 0
desc="Verify basic rule worked in the past"
cmd="crm_rule -c -r cli-prefer-rule-dummy-expired -d 20180101"
test_assert $CRM_EX_OK 0
desc="Verify basic rule is not yet in effect"
cmd="crm_rule -c -r cli-prefer-rule-dummy-not-yet"
test_assert $CRM_EX_NOT_YET_IN_EFFECT 0
desc="Verify date_spec rule with years has expired"
cmd="crm_rule -c -r cli-prefer-rule-dummy-date_spec-only-years"
test_assert $CRM_EX_EXPIRED 0
desc="Verify multiple rules at once"
cmd="crm_rule -c -r cli-prefer-rule-dummy-not-yet -r cli-prefer-rule-dummy-date_spec-only-years"
test_assert $CRM_EX_EXPIRED 0
desc="Verify multiple rules at once, with XML output"
cmd="crm_rule -c -r cli-prefer-rule-dummy-not-yet -r cli-prefer-rule-dummy-date_spec-only-years --output-as=xml"
test_assert $CRM_EX_EXPIRED 0
desc="Verify date_spec rule with years is in effect"
cmd="crm_rule -c -r cli-prefer-rule-dummy-date_spec-only-years -d 20190201"
test_assert $CRM_EX_OK 0
desc="Try to check a rule whose date_spec does not contain years="
cmd="crm_rule -c -r cli-prefer-rule-dummy-date_spec-without-years"
test_assert $CRM_EX_NOSUCH 0
desc="Try to check a rule whose date_spec contains years= and moon="
cmd="crm_rule -c -r cli-prefer-rule-dummy-date_spec-years-moon"
test_assert $CRM_EX_NOSUCH 0
desc="Try to check a rule with no date_expression"
cmd="crm_rule -c -r cli-no-date_expression-rule"
test_assert $CRM_EX_UNIMPLEMENT_FEATURE 0
unset CIB_shadow_dir
}
# Ensure all command output is in portable locale for comparison
export LC_ALL="C"
+test_access_render() {
+ local TMPXML
+
+ TMPXML=$(mktemp ${TMPDIR:-/tmp}/cts-cli.access_render.xml.XXXXXXXXXX)
+ export CIB_shadow_dir="${shadow_dir}"
+
+ $VALGRIND_CMD crm_shadow --batch --force --create-empty $shadow 2>&1
+ export CIB_shadow=$shadow
+
+ # Create a test CIB that has ACL roles
+ cat < "$TMPXML"
+
+
+
+
+
+
+
+
+
+EOF
+
+ desc="Configure some ACLs"
+ cmd="cibadmin -M -o acls --xml-file $TMPXML"
+ test_assert $CRM_EX_OK
+
+ desc="Enable ACLs"
+ cmd="crm_attribute -n enable-acl -v true"
+ test_assert $CRM_EX_OK
+
+ unset CIB_user
+
+ # Run cibadmin --show-access on the test CIB with different users (tony here)
+
+ desc="An instance of ACLs render (into color)"
+ cmd="cibadmin --force --show-access=color -Q --user tony"
+ test_assert $CRM_EX_OK 0
+
+ desc="An instance of ACLs render (into namespacing)"
+ cmd="cibadmin --force --show-access=namespace -Q --user tony"
+ test_assert $CRM_EX_OK 0
+
+ desc="An instance of ACLs render (into text)"
+ cmd="cibadmin --force --show-access=text -Q --user tony"
+ test_assert $CRM_EX_OK 0
+
+ unset CIB_shadow_dir
+ rm -f "$TMPXML"
+}
# Process command-line arguments
while [ $# -gt 0 ]; do
case "$1" in
-t)
tests="$2"
shift 2
;;
-V|--verbose)
verbose=1
shift
;;
-v|--valgrind)
export G_SLICE=always-malloc
VALGRIND_CMD="valgrind $VALGRIND_OPTS"
shift
;;
-s)
do_save=1
shift
;;
-p)
export PATH="$2:$PATH"
shift
;;
--help)
echo "$USAGE_TEXT"
exit $CRM_EX_OK
;;
*)
echo "error: unknown option $1"
echo
echo "$USAGE_TEXT"
exit $CRM_EX_USAGE
;;
esac
done
for t in $tests; do
case "$t" in
dates) ;;
tools) ;;
acls) ;;
validity) ;;
upgrade) ;;
rules) ;;
crm_mon) ;;
*)
echo "error: unknown test $t"
echo
echo "$USAGE_TEXT"
exit $CRM_EX_USAGE
;;
esac
done
XMLLINT_CMD=$(which xmllint 2>/dev/null)
if [ $? -ne 0 ]; then
XMLLINT_CMD=""
echo "xmllint is missing - install it to validate command output"
fi
# Check whether we're running from source directory
SRCDIR=$(dirname $test_home)
if [ -x "$SRCDIR/tools/crm_simulate" ]; then
export PATH="$SRCDIR/tools:$PATH"
echo "Using local binaries from: $SRCDIR/tools"
if [ -x "$SRCDIR/xml" ]; then
export PCMK_schema_directory="$SRCDIR/xml"
echo "Using local schemas from: $PCMK_schema_directory"
fi
else
export PCMK_schema_directory=@CRM_SCHEMA_DIRECTORY@
fi
for t in $tests; do
echo "Testing $t"
TMPFILE=$(mktemp ${TMPDIR:-/tmp}/cts-cli.$t.XXXXXXXXXX)
eval TMPFILE_$t="$TMPFILE"
test_$t > "$TMPFILE"
# last-rc-change= is always numeric in the CIB. However, for the crm_mon
# test we also need to compare against the XML output of the crm_mon
# program. There, these are shown as human readable strings (like the
# output of the `date` command).
sed -e 's/cib-last-written.*>/>/'\
-e 's/Last updated: .*/Last updated:/' \
-e 's/Last change: .*/Last change:/' \
-e 's/(version .*)/(version)/' \
-e 's/last_update time=\".*\"/last_update time=\"\"/' \
-e 's/last_change time=\".*\"/last_change time=\"\"/' \
-e 's/ api-version=\".*\" / api-version=\"X\" /' \
-e 's/ version=\".*\" / version=\"\" /' \
-e 's/request=\".*\(crm_[a-zA-Z0-9]*\)/request=\"\1/' \
-e 's/crm_feature_set="[^"]*" //'\
-e 's/validate-with="[^"]*" //'\
-e 's/Created new pacemaker-.* configuration/Created new pacemaker configuration/'\
-e 's/.*\(pcmk__.*\)@.*\.c:[0-9][0-9]*)/\1/g' \
-e 's/.*\(unpack_.*\)@.*\.c:[0-9][0-9]*)/\1/g' \
-e 's/.*\(update_validation\)@.*\.c:[0-9][0-9]*)/\1/g' \
-e 's/.*\(apply_upgrade\)@.*\.c:[0-9][0-9]*)/\1/g' \
-e "s/ last-rc-change=['\"][-+A-Za-z0-9: ]*['\"],\{0,1\}//" \
-e 's|^/tmp/cts-cli\.validity\.bad.xml\.[^:]*:|validity.bad.xml:|'\
-e 's/^Entity: line [0-9][0-9]*: //'\
-e 's/\(validation ([0-9][0-9]* of \)[0-9][0-9]*\().*\)/\1X\2/' \
-e 's/^Migration will take effect until: .*/Migration will take effect until:/' \
-e 's/ end=\"[0-9][-+: 0-9]*Z*\"/ end=\"\"/' \
-e 's/ start=\"[0-9][-+: 0-9]*Z*\"/ start=\"\"/' \
-e 's/^Error checking rule: Device not configured/Error checking rule: No such device or address/' \
-e 's/\(Injecting attribute last-failure-ping#monitor_10000=\)[0-9]*/\1/' \
-e 's/^lt-//' \
-e 's/ocf::/ocf:/' \
-e 's/Masters:/Promoted:/' \
-e 's/Slaves:/Unpromoted:/' \
-e 's/Master/Promoted/' \
-e 's/Slave/Unpromoted/' \
+ -e 's/\x1b/\\x1b/' \
"$TMPFILE" > "${TMPFILE}.$$"
mv -- "${TMPFILE}.$$" "$TMPFILE"
if [ $do_save -eq 1 ]; then
cp "$TMPFILE" $test_home/cli/regression.$t.exp
fi
done
rm -rf "${shadow_dir}"
failed=0
if [ $verbose -eq 1 ]; then
echo -e "\n\nResults"
fi
for t in $tests; do
eval TMPFILE="\$TMPFILE_$t"
if [ $verbose -eq 1 ]; then
diff -wu $test_home/cli/regression.$t.exp "$TMPFILE"
else
diff -w $test_home/cli/regression.$t.exp "$TMPFILE" >/dev/null 2>&1
fi
if [ $? -ne 0 ]; then
failed=1
fi
done
echo -e "\n\nSummary"
for t in $tests; do
eval TMPFILE="\$TMPFILE_$t"
grep -e '^\* \(Passed\|Failed\)' "$TMPFILE"
done
function print_or_remove_file() {
eval TMPFILE="\$TMPFILE_$1"
if [[ ! $(diff -wq $test_home/cli/regression.$1.exp "$TMPFILE") ]]; then
rm -f "$TMPFILE"
else
echo " $TMPFILE"
fi
}
if [ $num_errors -ne 0 ] && [ $failed -ne 0 ]; then
echo "$num_errors tests failed; see output in:"
for t in $tests; do
print_or_remove_file "$t"
done
exit $CRM_EX_ERROR
elif [ $num_errors -ne 0 ]; then
echo "$num_errors tests failed"
for t in $tests; do
print_or_remove_file "$t"
done
exit $CRM_EX_ERROR
elif [ $failed -eq 1 ]; then
echo "$num_passed tests passed but output was unexpected; see output in:"
for t in $tests; do
print_or_remove_file "$t"
done
exit $CRM_EX_DIGEST
else
echo $num_passed tests passed
for t in $tests; do
eval TMPFILE="\$TMPFILE_$t"
rm -f "$TMPFILE"
done
crm_shadow --force --delete $shadow >/dev/null 2>&1
exit $CRM_EX_OK
fi
diff --git a/include/pcmki/pcmki_acl.h b/include/pcmki/pcmki_acl.h
index 26e1a7abbc..500525fc15 100644
--- a/include/pcmki/pcmki_acl.h
+++ b/include/pcmki/pcmki_acl.h
@@ -1,74 +1,74 @@
/*
* Copyright 2004-2021 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU Lesser General Public License
* version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
*/
#ifndef PCMK__PCMKI_PCMKI_ACL__H
#define PCMK__PCMKI_PCMKI_ACL__H
#include
enum pcmk__acl_cred_type {
pcmk__acl_cred_unset = 0,
pcmk__acl_cred_user,
/* XXX no proper support for groups yet */
};
enum pcmk__acl_render_how {
- pcmk__acl_render_ns_simple = 1,
+ pcmk__acl_render_namespace = 1,
pcmk__acl_render_text,
pcmk__acl_render_color,
};
/*
* Version compatibility tracking incl. open-ended intervals for occasional
* bumps (to avoid hard to follow open-coding throughout). Grouped by context.
*/
/* Schema version vs. evaluate-as-namespace-annotations-per-credentials */
#define PCMK__COMPAT_ACL_2_MIN_INCL "pacemaker-2.0"
/*!
* \brief Mark CIB with namespace-encoded result of ACLs eval'd per credential
*
* \param[in] cred_type credential type that \p cred represents
* \param[in] cred credential whose ACL perspective to switch to
* \param[in] cib_doc XML document representing CIB
* \param[out] acl_evaled_doc XML document representing CIB, with said
* namespace-based annotations throughout
*
* \return A standard Pacemaker return code
* Namely:
* - pcmk_rc_ok upon success,
* - pcmk_rc_already if ACLs were not applicable,
* - pcmk_rc_schema_validation if the validation schema version
* is unsupported (see note), or
* - EINVAL or ENOMEM as appropriate;
*
* \note Only supported schemas are those following acls-2.0.rng, that is,
* those validated with pacemaker-2.0.rng and newer.
*/
int pcmk__acl_annotate_permissions(const char *cred, xmlDoc *cib_doc,
xmlDoc **acl_evaled_doc);
/*!
* \internal
* \brief Serialize-render already pcmk__acl_annotate_permissions annotated XML
*
* \param[in] annotated_doc pcmk__acl_annotate_permissions annotated XML
* \param[in] how render kind, see #pcmk__acl_render_how enumeration
* \param[out] doc_txt_ptr where to put the final outcome string
* \return A standard Pacemaker return code
*
* \note Currently, the function did not receive enough of testing regarding
* leak of resources, hence it is not recommended for anything other
* than short-lived processes at this time.
*/
int pcmk__acl_evaled_render(xmlDoc *annotated_doc, enum pcmk__acl_render_how,
xmlChar **doc_txt_ptr);
#endif
diff --git a/lib/pacemaker/pcmk_acl.c b/lib/pacemaker/pcmk_acl.c
index 1e6758801a..b79ed0480e 100644
--- a/lib/pacemaker/pcmk_acl.c
+++ b/lib/pacemaker/pcmk_acl.c
@@ -1,356 +1,356 @@
/*
* Copyright 2004-2022 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU Lesser General Public License
* version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ACL_NS_PREFIX "http://clusterlabs.org/ns/pacemaker/access/"
#define ACL_NS_Q_PREFIX "pcmk-access-"
#define ACL_NS_Q_WRITABLE (const xmlChar *) ACL_NS_Q_PREFIX "writable"
#define ACL_NS_Q_READABLE (const xmlChar *) ACL_NS_Q_PREFIX "readable"
#define ACL_NS_Q_DENIED (const xmlChar *) ACL_NS_Q_PREFIX "denied"
static const xmlChar *NS_WRITABLE = (const xmlChar *) ACL_NS_PREFIX "writable";
static const xmlChar *NS_READABLE = (const xmlChar *) ACL_NS_PREFIX "readable";
static const xmlChar *NS_DENIED = (const xmlChar *) ACL_NS_PREFIX "denied";
/*!
* \brief This function takes a node and marks it with the namespace
* given in the ns parameter.
*
* \param[in,out] i_node
* \param[in] ns
* \param[in,out] ret
* \param[in,out] ns_recycle_writable
* \param[in,out] ns_recycle_readable
* \param[in,out] ns_recycle_denied
*/
static void
pcmk__acl_mark_node_with_namespace(xmlNode *i_node, const xmlChar *ns, int *ret, xmlNs **ns_recycle_writable, xmlNs **ns_recycle_readable, xmlNs **ns_recycle_denied)
{
if (ns == NS_WRITABLE)
{
if (*ns_recycle_writable == NULL)
{
*ns_recycle_writable = xmlNewNs(xmlDocGetRootElement(i_node->doc),
NS_WRITABLE, ACL_NS_Q_WRITABLE);
}
xmlSetNs(i_node, *ns_recycle_writable);
*ret = pcmk_rc_ok;
}
else if (ns == NS_READABLE)
{
if (*ns_recycle_readable == NULL)
{
*ns_recycle_readable = xmlNewNs(xmlDocGetRootElement(i_node->doc),
NS_READABLE, ACL_NS_Q_READABLE);
}
xmlSetNs(i_node, *ns_recycle_readable);
*ret = pcmk_rc_ok;
}
else if (ns == NS_DENIED)
{
if (*ns_recycle_denied == NULL)
{
*ns_recycle_denied = xmlNewNs(xmlDocGetRootElement(i_node->doc),
NS_DENIED, ACL_NS_Q_DENIED);
};
xmlSetNs(i_node, *ns_recycle_denied);
*ret = pcmk_rc_ok;
}
}
/*!
* \brief This function takes some XML, and annotates it with XML
* namespaces to indicate the ACL permissions.
*
* \param[in,out] xml_modify
*
* \return A standard Pacemaker return code
* Namely:
* - pcmk_rc_ok upon success,
* - pcmk_rc_already if ACLs were not applicable,
* - pcmk_rc_schema_validation if the validation schema version
* is unsupported (see note), or
* - EINVAL or ENOMEM as appropriate;
*/
static int
pcmk__acl_annotate_permissions_recursive(xmlNode *xml_modify)
{
static xmlNs *ns_recycle_writable = NULL,
*ns_recycle_readable = NULL,
*ns_recycle_denied = NULL;
static const xmlDoc *prev_doc = NULL;
xmlNode *i_node = NULL;
const xmlChar *ns;
int ret = EINVAL; // nodes have not been processed yet
if (prev_doc == NULL || prev_doc != xml_modify->doc) {
prev_doc = xml_modify->doc;
ns_recycle_writable = ns_recycle_readable = ns_recycle_denied = NULL;
}
for (i_node = xml_modify; i_node != NULL; i_node = i_node->next) {
switch (i_node->type) {
case XML_ELEMENT_NODE:
pcmk__set_xml_doc_flag(i_node, pcmk__xf_tracking);
if (!pcmk__check_acl(i_node, NULL, pcmk__xf_acl_read)) {
ns = NS_DENIED;
} else if (!pcmk__check_acl(i_node, NULL, pcmk__xf_acl_write)) {
ns = NS_READABLE;
} else {
ns = NS_WRITABLE;
}
pcmk__acl_mark_node_with_namespace(i_node, ns, &ret, &ns_recycle_writable, &ns_recycle_readable, &ns_recycle_denied);
/* XXX recursion can be turned into plain iteration to save stack */
if (i_node->properties != NULL) {
/* this is not entirely clear, but relies on the very same
class-hierarchy emulation that libxml2 has firmly baked in
its API/ABI */
ret |= pcmk__acl_annotate_permissions_recursive((xmlNodePtr) i_node->properties);
}
if (i_node->children != NULL) {
ret |= pcmk__acl_annotate_permissions_recursive(i_node->children);
}
break;
case XML_ATTRIBUTE_NODE:
/* we can utilize that parent has already been assigned the ns */
if (!pcmk__check_acl(i_node->parent,
(const char *) i_node->name,
pcmk__xf_acl_read)) {
ns = NS_DENIED;
} else if (!pcmk__check_acl(i_node,
(const char *) i_node->name,
pcmk__xf_acl_write)) {
ns = NS_READABLE;
} else {
ns = NS_WRITABLE;
}
pcmk__acl_mark_node_with_namespace(i_node, ns, &ret, &ns_recycle_writable, &ns_recycle_readable, &ns_recycle_denied);
break;
case XML_COMMENT_NODE:
/* we can utilize that parent has already been assigned the ns */
if (!pcmk__check_acl(i_node->parent, (const char *) i_node->name, pcmk__xf_acl_read))
{
ns = NS_DENIED;
}
else if (!pcmk__check_acl(i_node->parent, (const char *) i_node->name, pcmk__xf_acl_write))
{
ns = NS_READABLE;
}
else
{
ns = NS_WRITABLE;
}
pcmk__acl_mark_node_with_namespace(i_node, ns, &ret, &ns_recycle_writable, &ns_recycle_readable, &ns_recycle_denied);
break;
default:
break;
}
}
return ret;
}
int
pcmk__acl_annotate_permissions(const char *cred, xmlDoc *cib_doc,
xmlDoc **acl_evaled_doc)
{
int ret, version;
xmlNode *target, *comment;
const char *validation;
CRM_CHECK(cred != NULL, return EINVAL);
CRM_CHECK(cib_doc != NULL, return EINVAL);
CRM_CHECK(acl_evaled_doc != NULL, return EINVAL);
/* avoid trivial accidental XML injection */
if (strpbrk(cred, "<>&") != NULL) {
return EINVAL;
}
if (!pcmk_acl_required(cred)) {
/* nothing to evaluate */
return pcmk_rc_already;
}
validation = crm_element_value(xmlDocGetRootElement(cib_doc),
XML_ATTR_VALIDATION);
version = get_schema_version(validation);
if (get_schema_version(PCMK__COMPAT_ACL_2_MIN_INCL) > version) {
return pcmk_rc_schema_validation;
}
target = copy_xml(xmlDocGetRootElement(cib_doc));
if (target == NULL) {
return EINVAL;
}
pcmk__enable_acl(target, target, cred);
ret = pcmk__acl_annotate_permissions_recursive(target);
if (ret == pcmk_rc_ok) {
- char* credentials = crm_strdup_printf("%s", cred);
+ char* credentials = crm_strdup_printf("ACLs as evaluated for user %s", cred);
comment = xmlNewDocComment(target->doc, (pcmkXmlStr) credentials);
free(credentials);
if (comment == NULL) {
xmlFreeNode(target);
return EINVAL;
}
xmlAddPrevSibling(xmlDocGetRootElement(target->doc), comment);
*acl_evaled_doc = target->doc;
return pcmk_rc_ok;
} else {
xmlFreeNode(target);
return ret; //for now, it should be some kind of error
}
}
int
pcmk__acl_evaled_render(xmlDoc *annotated_doc, enum pcmk__acl_render_how how,
xmlChar **doc_txt_ptr)
{
xmlDoc *xslt_doc;
xsltStylesheet *xslt;
xsltTransformContext *xslt_ctxt;
xmlDoc *res;
char *sfile;
- static const char *params_ns_simple[] = {
+ static const char *params_namespace[] = {
"accessrendercfg:c-writable", ACL_NS_Q_PREFIX "writable:",
"accessrendercfg:c-readable", ACL_NS_Q_PREFIX "readable:",
"accessrendercfg:c-denied", ACL_NS_Q_PREFIX "denied:",
"accessrendercfg:c-reset", "",
"accessrender:extra-spacing", "no",
"accessrender:self-reproducing-prefix", ACL_NS_Q_PREFIX,
NULL
}, *params_useansi[] = {
/* start with hard-coded defaults, then adapt per the template ones */
"accessrendercfg:c-writable", "\x1b[32m",
"accessrendercfg:c-readable", "\x1b[34m",
"accessrendercfg:c-denied", "\x1b[31m",
"accessrendercfg:c-reset", "\x1b[0m",
"accessrender:extra-spacing", "no",
"accessrender:self-reproducing-prefix", ACL_NS_Q_PREFIX,
NULL
}, *params_noansi[] = {
"accessrendercfg:c-writable", "vvv---[ WRITABLE ]---vvv",
"accessrendercfg:c-readable", "vvv---[ READABLE ]---vvv",
"accessrendercfg:c-denied", "vvv---[ ~DENIED~ ]---vvv",
"accessrendercfg:c-reset", "",
"accessrender:extra-spacing", "yes",
"accessrender:self-reproducing-prefix", "",
NULL
};
const char **params;
int ret;
xmlParserCtxtPtr parser_ctxt;
/* unfortunately, the input (coming from CIB originally) was parsed with
blanks ignored, and since the output is a conversion of XML to text
format (we would be covered otherwise thanks to implicit
pretty-printing), we need to dump the tree to string output first,
only to subsequently reparse it -- this time with blanks honoured */
xmlChar *annotated_dump;
int dump_size;
xmlDocDumpFormatMemory(annotated_doc, &annotated_dump, &dump_size, 1);
res = xmlReadDoc(annotated_dump, "on-the-fly-access-render", NULL,
XML_PARSE_NONET);
CRM_ASSERT(res != NULL);
xmlFree(annotated_dump);
xmlFreeDoc(annotated_doc);
annotated_doc = res;
sfile = pcmk__xml_artefact_path(pcmk__xml_artefact_ns_base_xslt,
"access-render-2");
parser_ctxt = xmlNewParserCtxt();
CRM_ASSERT(sfile != NULL);
CRM_ASSERT(parser_ctxt != NULL);
xslt_doc = xmlCtxtReadFile(parser_ctxt, sfile, NULL, XML_PARSE_NONET);
xslt = xsltParseStylesheetDoc(xslt_doc); /* acquires xslt_doc! */
if (xslt == NULL) {
crm_crit("Problem in parsing %s", sfile);
return EINVAL;
}
free(sfile);
sfile = NULL;
xmlFreeParserCtxt(parser_ctxt);
xslt_ctxt = xsltNewTransformContext(xslt, annotated_doc);
CRM_ASSERT(xslt_ctxt != NULL);
- if (how == pcmk__acl_render_ns_simple) {
- params = params_ns_simple;
- } else if (how == pcmk__acl_render_text) {
+ if (how == pcmk__acl_render_text) {
params = params_noansi;
+ } else if (how == pcmk__acl_render_namespace) {
+ params = params_namespace;
} else {
params = params_useansi;
}
xsltQuoteUserParams(xslt_ctxt, params);
res = xsltApplyStylesheetUser(xslt, annotated_doc, NULL,
NULL, NULL, xslt_ctxt);
xmlFreeDoc(annotated_doc);
annotated_doc = NULL;
xsltFreeTransformContext(xslt_ctxt);
xslt_ctxt = NULL;
if (how == pcmk__acl_render_color && params != params_useansi) {
char **param_i = (char **) params;
do {
free(*param_i);
} while (*param_i++ != NULL);
free(params);
}
if (res == NULL) {
ret = EINVAL;
} else {
int doc_txt_len;
int temp = xsltSaveResultToString(doc_txt_ptr, &doc_txt_len, res, xslt);
xmlFreeDoc(res);
if (temp == 0) {
ret = pcmk_rc_ok;
} else {
ret = EINVAL;
}
}
xsltFreeStylesheet(xslt);
return ret;
}
diff --git a/tools/cibadmin.c b/tools/cibadmin.c
index 1e28a412c7..407eb78986 100644
--- a/tools/cibadmin.c
+++ b/tools/cibadmin.c
@@ -1,921 +1,914 @@
/*
* Copyright 2004-2022 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.
*/
#include
#include
#include
#include
#include
#include
#include
#include
static int message_timeout_ms = 30;
static int command_options = 0;
static int request_id = 0;
static int bump_log_num = 0;
static char *host = NULL;
static const char *cib_user = NULL;
static const char *cib_action = NULL;
static const char *obj_type = NULL;
static cib_t *the_cib = NULL;
static GMainLoop *mainloop = NULL;
static gboolean force_flag = FALSE;
static crm_exit_t exit_code = CRM_EX_OK;
int do_init(void);
int do_work(xmlNode *input, int command_options, xmlNode **output);
void cibadmin_op_callback(xmlNode *msg, int call_id, int rc, xmlNode *output,
void *user_data);
static pcmk__cli_option_t long_options[] = {
// long option, argument type, storage, short option, description, flags
{
"help", no_argument, NULL, '?',
"\tThis text", pcmk__option_default
},
{
"version", no_argument, NULL, '$',
"\tVersion information", pcmk__option_default
},
{
"verbose", no_argument, NULL, 'V',
"\tIncrease debug output\n", pcmk__option_default
},
{
"-spacer-", no_argument, NULL, '-',
"Commands:", pcmk__option_default
},
{
"upgrade", no_argument, NULL, 'u',
"\tUpgrade the configuration to the latest syntax", pcmk__option_default
},
{
"query", no_argument, NULL, 'Q',
"\tQuery the contents of the CIB", pcmk__option_default
},
{
"erase", no_argument, NULL, 'E',
"\tErase the contents of the whole CIB", pcmk__option_default
},
{
"bump", no_argument, NULL, 'B',
"\tIncrease the CIB's epoch value by 1", pcmk__option_default
},
{
"create", no_argument, NULL, 'C',
"\tCreate an object in the CIB (will fail if object already exists)",
pcmk__option_default
},
{
"modify", no_argument, NULL, 'M',
"\tFind object somewhere in CIB's XML tree and update it "
"(fails if object does not exist unless -c is also specified)",
pcmk__option_default
},
{
"patch", no_argument, NULL, 'P',
"\tSupply an update in the form of an XML diff (see crm_diff(8))",
pcmk__option_default
},
{
"replace", no_argument, NULL, 'R',
"\tRecursively replace an object in the CIB", pcmk__option_default
},
{
"delete", no_argument, NULL, 'D',
"\tDelete first object matching supplied criteria "
"(for example, )",
pcmk__option_default
},
{
"-spacer-", no_argument, NULL, '-',
"\n\tThe XML element name and all attributes must match "
"in order for the element to be deleted.\n",
pcmk__option_default
},
{
"delete-all", no_argument, NULL, 'd',
"When used with --xpath, remove all matching objects in the "
"configuration instead of just the first one",
pcmk__option_default
},
{
"empty", no_argument, NULL, 'a',
"\tOutput an empty CIB", pcmk__option_default
},
{
"md5-sum", no_argument, NULL, '5',
"\tCalculate the on-disk CIB digest", pcmk__option_default
},
{
"md5-sum-versioned", no_argument, NULL, '6',
"Calculate an on-the-wire versioned CIB digest", pcmk__option_default
},
{
"show-access", optional_argument, NULL, 'S',
"Whether to use syntax highlighting for ACLs "
"(with -Q/--query and -U/--user)",
pcmk__option_default
},
{
"-spacer-", no_argument, NULL, '-',
"\n\tThat amounts to one of \"color\" (default for terminal),"
- " \"text\" (otherwise), \"ns-full\", \"ns-simple\", or \"auto\""
+ " \"text\" (otherwise), \"namespace\", or \"auto\""
" (per former defaults).",
pcmk__option_default
},
{
"blank", no_argument, NULL, '-',
NULL, pcmk__option_hidden
},
{
"-spacer-", required_argument, NULL, '-',
"\nAdditional options:", pcmk__option_default
},
{
"force", no_argument, NULL, 'f',
NULL, pcmk__option_default
},
{
"timeout", required_argument, NULL, 't',
"Time (in seconds) to wait before declaring the operation failed",
pcmk__option_default
},
{
"user", required_argument, NULL, 'U',
"Run the command with permissions of the named user (valid only for "
"the root and " CRM_DAEMON_USER " accounts)",
pcmk__option_default
},
{
"sync-call", no_argument, NULL, 's',
"Wait for call to complete before returning", pcmk__option_default
},
{
"local", no_argument, NULL, 'l',
"\tCommand takes effect locally (should be used only for queries)",
pcmk__option_default
},
{
"allow-create", no_argument, NULL, 'c',
"(Advanced) Allow target of --modify/-M to be created "
"if it does not exist",
pcmk__option_default
},
{
"no-children", no_argument, NULL, 'n',
"(Advanced) When querying an object, do not include its children "
"in the result",
pcmk__option_default
},
{
"no-bcast", no_argument, NULL, 'b',
NULL, pcmk__option_hidden
},
{
"-spacer-", no_argument, NULL, '-',
"\nData:", pcmk__option_default
},
{
"xml-text", required_argument, NULL, 'X',
"Retrieve XML from the supplied string", pcmk__option_default
},
{
"xml-file", required_argument, NULL, 'x',
"Retrieve XML from the named file", pcmk__option_default
},
{
"xml-pipe", no_argument, NULL, 'p',
"Retrieve XML from stdin\n", pcmk__option_default
},
{
"scope", required_argument, NULL, 'o',
"Limit scope of operation to specific section of CIB",
pcmk__option_default
},
{
"-spacer-", no_argument, NULL, '-',
"\tValid values: configuration, nodes, resources, constraints, "
"crm_config, rsc_defaults, op_defaults, acls, fencing-topology, "
"tags, alerts",
pcmk__option_default
},
{
"xpath", required_argument, NULL, 'A',
"A valid XPath to use instead of --scope/-o", pcmk__option_default
},
{
"node-path", no_argument, NULL, 'e',
"When performing XPath queries, return path of any matches found",
pcmk__option_default
},
{
"-spacer-", no_argument, NULL, '-',
"\t(for example, \"/cib/configuration/resources/clone[@id='ms_RH1_SCS']"
"/primitive[@id='prm_RH1_SCS']\")",
pcmk__option_paragraph
},
{
"node", required_argument, NULL, 'N',
"(Advanced) Send command to the specified host", pcmk__option_default
},
{
"-spacer-", no_argument, NULL, '!',
NULL, pcmk__option_hidden
},
{
"-spacer-", no_argument, NULL, '-',
"\n\nExamples:\n", pcmk__option_default
},
{
"-spacer-", no_argument, NULL, '-',
"Query the configuration from the local node:", pcmk__option_paragraph
},
{
"-spacer-", no_argument, NULL, '-',
" cibadmin --query --local", pcmk__option_example
},
{
"-spacer-", no_argument, NULL, '-',
"Query just the cluster options configuration:", pcmk__option_paragraph
},
{
"-spacer-", no_argument, NULL, '-',
" cibadmin --query --scope crm_config", pcmk__option_example
},
{
"-spacer-", no_argument, NULL, '-',
"Query all 'target-role' settings:", pcmk__option_paragraph
},
{
"-spacer-", no_argument, NULL, '-',
" cibadmin --query --xpath \"//nvpair[@name='target-role']\"",
pcmk__option_example
},
{
"-spacer-", no_argument, NULL, '-',
"Remove all 'is-managed' settings:", pcmk__option_paragraph
},
{
"-spacer-", no_argument, NULL, '-',
" cibadmin --delete-all --xpath \"//nvpair[@name='is-managed']\"",
pcmk__option_example
},
{
"-spacer-", no_argument, NULL, '-',
"Remove the resource named 'old':", pcmk__option_paragraph
},
{
"-spacer-", no_argument, NULL, '-',
" cibadmin --delete --xml-text ''",
pcmk__option_example
},
{
"-spacer-", no_argument, NULL, '-',
"Remove all resources from the configuration:", pcmk__option_paragraph
},
{
"-spacer-", no_argument, NULL, '-',
" cibadmin --replace --scope resources --xml-text ''",
pcmk__option_example
},
{
"-spacer-", no_argument, NULL, '-',
"Replace complete configuration with contents of $HOME/pacemaker.xml:",
pcmk__option_paragraph
},
{
"-spacer-", no_argument, NULL, '-',
" cibadmin --replace --xml-file $HOME/pacemaker.xml",
pcmk__option_example
},
{
"-spacer-", no_argument, NULL, '-',
"Replace constraints section of configuration with contents of "
"$HOME/constraints.xml:",
pcmk__option_paragraph
},
{
"-spacer-", no_argument, NULL, '-',
" cibadmin --replace --scope constraints --xml-file "
"$HOME/constraints.xml",
pcmk__option_example
},
{
"-spacer-", no_argument, NULL, '-',
"Increase configuration version to prevent old configurations from "
"being loaded accidentally:",
pcmk__option_paragraph
},
{
"-spacer-", no_argument, NULL, '-',
" cibadmin --modify --xml-text ''",
pcmk__option_example
},
{
"-spacer-", no_argument, NULL, '-',
"Edit the configuration with your favorite $EDITOR:",
pcmk__option_paragraph
},
{
"-spacer-", no_argument, NULL, '-',
" cibadmin --query > $HOME/local.xml", pcmk__option_example
},
{
"-spacer-", no_argument, NULL, '-',
" $EDITOR $HOME/local.xml", pcmk__option_example
},
{
"-spacer-", no_argument, NULL, '-',
" cibadmin --replace --xml-file $HOME/local.xml", pcmk__option_example
},
{
"-spacer-", no_argument, NULL, '-',
"Assuming terminal, render configuration in color (green for writable, blue for readable, red for denied) to visualize permissions for user tony:",
pcmk__option_paragraph
},
{
"-spacer-", no_argument, NULL, '-',
" cibadmin --show-access=color --query --user tony | less -r",
pcmk__option_example
},
{
"-spacer-", no_argument, NULL, '-',
"SEE ALSO:", pcmk__option_default
},
{
"-spacer-", no_argument, NULL, '-',
" crm(8), pcs(8), crm_shadow(8), crm_diff(8)", pcmk__option_default
},
{
"host", required_argument, NULL, 'h',
"deprecated", pcmk__option_hidden
},
{ 0, 0, 0, 0 }
};
static void
print_xml_output(xmlNode * xml)
{
char *buffer;
if (!xml) {
return;
} else if (xml->type != XML_ELEMENT_NODE) {
return;
}
if (command_options & cib_xpath_address) {
const char *id = crm_element_value(xml, XML_ATTR_ID);
if (pcmk__str_eq((const char *)xml->name, "xpath-query", pcmk__str_casei)) {
xmlNode *child = NULL;
for (child = xml->children; child; child = child->next) {
print_xml_output(child);
}
} else if (id) {
printf("%s\n", id);
}
} else {
buffer = dump_xml_formatted(xml);
fprintf(stdout, "%s", crm_str(buffer));
free(buffer);
}
}
// Upgrade requested but already at latest schema
static void
report_schema_unchanged(void)
{
const char *err = pcmk_rc_str(pcmk_rc_schema_unchanged);
crm_info("Upgrade unnecessary: %s\n", err);
printf("Upgrade unnecessary: %s\n", err);
exit_code = CRM_EX_OK;
}
int
main(int argc, char **argv)
{
int argerr = 0;
int rc = pcmk_ok;
int flag;
const char *source = NULL;
const char *admin_input_xml = NULL;
const char *admin_input_file = NULL;
gboolean dangerous_cmd = FALSE;
gboolean admin_input_stdin = FALSE;
xmlNode *output = NULL;
xmlNode *input = NULL;
char *username = NULL;
const char *acl_cred = NULL;
enum acl_eval_how {
acl_eval_unused,
acl_eval_auto,
- acl_eval_ns_full,
- acl_eval_ns_simple,
+ acl_eval_namespace,
acl_eval_text,
acl_eval_color,
} acl_eval_how = acl_eval_unused;
int option_index = 0;
pcmk__cli_init_logging("cibadmin", 0);
set_crm_log_level(LOG_CRIT);
pcmk__set_cli_options(NULL, " [options]", long_options,
"query and edit the Pacemaker configuration");
if (argc < 2) {
pcmk__cli_help('?', CRM_EX_USAGE);
}
while (1) {
flag = pcmk__next_cli_option(argc, argv, &option_index, NULL);
if (flag == -1)
break;
switch (flag) {
case 't':
message_timeout_ms = atoi(optarg);
if (message_timeout_ms < 1) {
message_timeout_ms = 30;
}
break;
case 'A':
obj_type = optarg;
cib__set_call_options(command_options, crm_system_name,
cib_xpath);
break;
case 'e':
cib__set_call_options(command_options, crm_system_name,
cib_xpath_address);
break;
case 'u':
cib_action = CIB_OP_UPGRADE;
dangerous_cmd = TRUE;
break;
case 'E':
cib_action = CIB_OP_ERASE;
dangerous_cmd = TRUE;
break;
case 'S':
if (optarg != NULL) {
if (!strcmp(optarg, "auto")) {
acl_eval_how = acl_eval_auto;
- } else if (!strcmp(optarg, "ns-full")) {
- acl_eval_how = acl_eval_ns_full;
- } else if (!strcmp(optarg, "ns-simple")) {
- acl_eval_how = acl_eval_ns_simple;
+ } else if (!strcmp(optarg, "namespace")) {
+ acl_eval_how = acl_eval_namespace;
} else if (!strcmp(optarg, "text")) {
acl_eval_how = acl_eval_text;
} else if (!strcmp(optarg, "color")) {
acl_eval_how = acl_eval_color;
} else {
fprintf(stderr, "Unrecognized value for --show-access: \"%s\"\n",
optarg);
++argerr;
}
} else {
acl_eval_how = acl_eval_auto;
}
/* XXX this is a workaround until we unify happy paths for
both a/sync handling; the respective extra code is
only in sync path now, but does it matter at all for
query-like request wrt. what blackbox users observe? */
command_options |= cib_sync_call;
break;
case 'Q':
cib_action = CIB_OP_QUERY;
break;
case 'P':
cib_action = CIB_OP_APPLY_DIFF;
break;
case 'U':
cib_user = optarg;
break;
case 'M':
cib_action = CIB_OP_MODIFY;
break;
case 'R':
cib_action = CIB_OP_REPLACE;
break;
case 'C':
cib_action = CIB_OP_CREATE;
break;
case 'D':
cib_action = CIB_OP_DELETE;
break;
case '5':
cib_action = "md5-sum";
break;
case '6':
cib_action = "md5-sum-versioned";
break;
case 'c':
cib__set_call_options(command_options, crm_system_name,
cib_can_create);
break;
case 'n':
cib__set_call_options(command_options, crm_system_name,
cib_no_children);
break;
case 'B':
cib_action = CIB_OP_BUMP;
crm_log_args(argc, argv);
break;
case 'V':
cib__set_call_options(command_options, crm_system_name,
cib_verbose);
bump_log_num++;
break;
case '?':
case '$':
case '!':
pcmk__cli_help(flag, CRM_EX_OK);
break;
case 'o':
crm_trace("Option %c => %s", flag, optarg);
obj_type = optarg;
break;
case 'X':
crm_trace("Option %c => %s", flag, optarg);
admin_input_xml = optarg;
crm_log_args(argc, argv);
break;
case 'x':
crm_trace("Option %c => %s", flag, optarg);
admin_input_file = optarg;
crm_log_args(argc, argv);
break;
case 'p':
admin_input_stdin = TRUE;
crm_log_args(argc, argv);
break;
case 'N':
case 'h':
pcmk__str_update(&host, optarg);
break;
case 'l':
cib__set_call_options(command_options, crm_system_name,
cib_scope_local);
break;
case 'd':
cib_action = CIB_OP_DELETE;
cib__set_call_options(command_options, crm_system_name,
cib_multiple);
dangerous_cmd = TRUE;
break;
case 'b':
dangerous_cmd = TRUE;
cib__set_call_options(command_options, crm_system_name,
cib_inhibit_bcast|cib_scope_local);
break;
case 's':
cib__set_call_options(command_options, crm_system_name,
cib_sync_call);
break;
case 'f':
force_flag = TRUE;
cib__set_call_options(command_options, crm_system_name,
cib_quorum_override);
crm_log_args(argc, argv);
break;
case 'a':
output = createEmptyCib(1);
if (optind < argc) {
crm_xml_add(output, XML_ATTR_VALIDATION, argv[optind]);
}
admin_input_xml = dump_xml_formatted(output);
fprintf(stdout, "%s\n", crm_str(admin_input_xml));
crm_exit(CRM_EX_OK);
break;
default:
printf("Argument code 0%o (%c)" " is not (?yet?) supported\n", flag, flag);
++argerr;
break;
}
}
while (bump_log_num > 0) {
crm_bump_log_level(argc, argv);
bump_log_num--;
}
if (optind < argc) {
printf("non-option ARGV-elements: ");
while (optind < argc)
printf("%s ", argv[optind++]);
printf("\n");
pcmk__cli_help('?', CRM_EX_USAGE);
}
if (optind > argc || cib_action == NULL) {
++argerr;
}
if (argerr) {
pcmk__cli_help('?', CRM_EX_USAGE);
}
if (dangerous_cmd && force_flag == FALSE) {
fprintf(stderr, "The supplied command is considered dangerous."
" To prevent accidental destruction of the cluster,"
" the --force flag is required in order to proceed.\n");
fflush(stderr);
crm_exit(CRM_EX_UNSAFE);
}
if (admin_input_file != NULL) {
input = filename2xml(admin_input_file);
source = admin_input_file;
} else if (admin_input_xml != NULL) {
source = "input string";
input = string2xml(admin_input_xml);
} else if (admin_input_stdin) {
source = "STDIN";
input = stdin2xml();
} else if (acl_eval_how != acl_eval_unused) {
username = pcmk__uid2username(geteuid());
if (pcmk_acl_required(username)) {
if (force_flag) {
fprintf(stderr, "The supplied command can provide skewed"
" result since it is run under user that also"
" gets guarded per ACLs on their own right."
" Continuing since --force flag was"
" provided.\n");
} else {
fprintf(stderr, "The supplied command can provide skewed"
" result since it is run under user that also"
" gets guarded per ACLs in their own right."
" To accept the risk of such a possible"
" distortion (without even knowing it at this"
" time), use the --force flag.\n");
crm_exit(CRM_EX_UNSAFE);
}
}
free(username);
username = NULL;
if (cib_user == NULL) {
fprintf(stderr, "The supplied command requires -U user specified.\n");
crm_exit(CRM_EX_USAGE);
}
/* we already stopped/warned ACL-controlled users about consequences */
acl_cred = cib_user;
cib_user = NULL;
}
if (input != NULL) {
crm_log_xml_debug(input, "[admin input]");
} else if (source) {
fprintf(stderr, "Couldn't parse input from %s.\n", source);
crm_exit(CRM_EX_CONFIG);
}
if (pcmk__str_eq(cib_action, "md5-sum", pcmk__str_casei)) {
char *digest = NULL;
if (input == NULL) {
fprintf(stderr, "Please supply XML to process with -X, -x or -p\n");
crm_exit(CRM_EX_USAGE);
}
digest = calculate_on_disk_digest(input);
fprintf(stderr, "Digest: ");
fprintf(stdout, "%s\n", crm_str(digest));
free(digest);
free_xml(input);
crm_exit(CRM_EX_OK);
} else if (pcmk__str_eq(cib_action, "md5-sum-versioned", pcmk__str_casei)) {
char *digest = NULL;
const char *version = NULL;
if (input == NULL) {
fprintf(stderr, "Please supply XML to process with -X, -x or -p\n");
crm_exit(CRM_EX_USAGE);
}
version = crm_element_value(input, XML_ATTR_CRM_VERSION);
digest = calculate_xml_versioned_digest(input, FALSE, TRUE, version);
fprintf(stderr, "Versioned (%s) digest: ", version);
fprintf(stdout, "%s\n", crm_str(digest));
free(digest);
free_xml(input);
crm_exit(CRM_EX_OK);
}
rc = do_init();
if (rc != pcmk_ok) {
crm_err("Init failed, could not perform requested operations");
fprintf(stderr, "Init failed, could not perform requested operations\n");
free_xml(input);
crm_exit(crm_errno2exit(rc));
}
rc = do_work(input, command_options, &output);
if (rc > 0) {
/* wait for the reply by creating a mainloop and running it until
* the callbacks are invoked...
*/
request_id = rc;
the_cib->cmds->register_callback(the_cib, request_id, message_timeout_ms, FALSE, NULL,
"cibadmin_op_callback", cibadmin_op_callback);
mainloop = g_main_loop_new(NULL, FALSE);
crm_trace("%s waiting for reply from the local CIB", crm_system_name);
crm_info("Starting mainloop");
g_main_loop_run(mainloop);
} else if ((rc == -pcmk_err_schema_unchanged)
&& pcmk__str_eq(cib_action, CIB_OP_UPGRADE, pcmk__str_none)) {
report_schema_unchanged();
} else if (rc < 0) {
crm_err("Call failed: %s", pcmk_strerror(rc));
fprintf(stderr, "Call failed: %s\n", pcmk_strerror(rc));
if (rc == -pcmk_err_schema_validation) {
if (pcmk__str_eq(cib_action, CIB_OP_UPGRADE, pcmk__str_none)) {
xmlNode *obj = NULL;
int version = 0, rc = 0;
rc = the_cib->cmds->query(the_cib, NULL, &obj, command_options);
if (rc == pcmk_ok) {
update_validation(&obj, &version, 0, TRUE, FALSE);
}
} else if (output) {
validate_xml_verbose(output);
}
}
exit_code = crm_errno2exit(rc);
}
if (output != NULL && acl_eval_how != acl_eval_unused) {
xmlDoc *acl_evaled_doc;
rc = pcmk__acl_annotate_permissions(acl_cred, output->doc, &acl_evaled_doc);
if (rc == pcmk_rc_ok) {
+ enum pcmk__acl_render_how how;
+ xmlChar *rendered = NULL;
free_xml(output);
- if (acl_eval_how != acl_eval_ns_full) {
- xmlChar *rendered = NULL;
- enum pcmk__acl_render_how how;
- switch(acl_eval_how) {
- case acl_eval_ns_simple:
- how = pcmk__acl_render_ns_simple;
- break;
- case acl_eval_text:
- how = pcmk__acl_render_text;
- break;
- case acl_eval_color:
+ switch(acl_eval_how) {
+ case acl_eval_text:
+ how = pcmk__acl_render_text;
+ break;
+ case acl_eval_color:
+ how = pcmk__acl_render_color;
+ break;
+ case acl_eval_namespace:
+ how = pcmk__acl_render_namespace;
+ break;
+ default:
+ if (/*acl_eval_auto*/ isatty(STDOUT_FILENO)) {
how = pcmk__acl_render_color;
- break;
- default:
- if (/*acl_eval_auto*/ isatty(STDOUT_FILENO)) {
- how = pcmk__acl_render_color;
- } else {
- how = pcmk__acl_render_text;
- }
- break;
- }
+ } else {
+ how = pcmk__acl_render_text;
+ }
+ break;
+ }
- if (!pcmk__acl_evaled_render(acl_evaled_doc, how,
- &rendered)) {
- printf("%s\n", (char *) rendered);
- free(rendered);
- } else {
- fprintf(stderr, "Could not render evaluated access\n");
- crm_exit(CRM_EX_CONFIG);
- }
- output = NULL;
+ if (!pcmk__acl_evaled_render(acl_evaled_doc, how,
+ &rendered)) {
+ printf("%s\n", (char *) rendered);
+ free(rendered);
} else {
- output = xmlDocGetRootElement(acl_evaled_doc);
+ fprintf(stderr, "Could not render evaluated access\n");
+ crm_exit(CRM_EX_CONFIG);
}
+ output = NULL;
} else {
fprintf(stderr, "Could not evaluate access per request (%s, error: %s)\n", acl_cred, pcmk_rc_str(rc));
crm_exit(CRM_EX_CONFIG);
}
}
if (output != NULL) {
print_xml_output(output);
free_xml(output);
}
crm_trace("%s exiting normally", crm_system_name);
free_xml(input);
rc = cib__clean_up_connection(&the_cib);
if (exit_code == CRM_EX_OK) {
exit_code = pcmk_rc2exitc(rc);
}
free(host);
crm_exit(exit_code);
}
int
do_work(xmlNode * input, int call_options, xmlNode ** output)
{
/* construct the request */
the_cib->call_timeout = message_timeout_ms;
if (strcasecmp(CIB_OP_REPLACE, cib_action) == 0
&& pcmk__str_eq(crm_element_name(input), XML_TAG_CIB, pcmk__str_casei)) {
xmlNode *status = pcmk_find_cib_element(input, XML_CIB_TAG_STATUS);
if (status == NULL) {
create_xml_node(input, XML_CIB_TAG_STATUS);
}
}
if (cib_action != NULL) {
crm_trace("Passing \"%s\" to variant_op...", cib_action);
return cib_internal_op(the_cib, cib_action, host, obj_type, input, output, call_options, cib_user);
} else {
crm_err("You must specify an operation");
}
return -EINVAL;
}
int
do_init(void)
{
int rc = pcmk_ok;
the_cib = cib_new();
rc = the_cib->cmds->signon(the_cib, crm_system_name, cib_command);
if (rc != pcmk_ok) {
crm_err("Could not connect to the CIB: %s", pcmk_strerror(rc));
fprintf(stderr, "Could not connect to the CIB: %s\n",
pcmk_strerror(rc));
}
return rc;
}
void
cibadmin_op_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
{
exit_code = crm_errno2exit(rc);
if (rc == -pcmk_err_schema_unchanged) {
report_schema_unchanged();
} else if (rc != pcmk_ok) {
crm_warn("Call %s failed (%d): %s", cib_action, rc, pcmk_strerror(rc));
fprintf(stderr, "Call %s failed (%d): %s\n", cib_action, rc, pcmk_strerror(rc));
print_xml_output(output);
} else if (pcmk__str_eq(cib_action, CIB_OP_QUERY, pcmk__str_casei) && output == NULL) {
crm_err("Query returned no output");
crm_log_xml_err(msg, "no output");
} else if (output == NULL) {
crm_info("Call passed");
} else {
crm_info("Call passed");
print_xml_output(output);
}
if (call_id == request_id) {
g_main_loop_quit(mainloop);
} else {
crm_info("Message was not the response we were looking for (%d vs. %d)",
call_id, request_id);
}
}
diff --git a/xml/base/access-render-2.xsl b/xml/base/access-render-2.xsl
index 6f93ad7ca2..a0c370af9f 100644
--- a/xml/base/access-render-2.xsl
+++ b/xml/base/access-render-2.xsl
@@ -1,260 +1,258 @@
\x1b[32m
\x1b[34m
\x1b[31m
\x1b[0m
-
-