#!/usr/bin/env bash # Netconf confirm commit capability # See RFC 6241 Section 8.4 # Test uses privileges drop # TODO: # - privileges drop # - restconf # - lock check # Magic line must be first in script (see README.md) s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi APPNAME=example cfg=$dir/conf_yang.xml tmp=$dir/tmp.x fyang=$dir/clixon-example.yang # Backend user for priv drop, otherwise root USER=root #${BUSER} # Define default restconfig config: RESTCONFIG RESTCONFIG=$(restconf_config none false) cat < $cfg $cfg ietf-netconf:confirmed-commit clixon-restconf:allow-auth-none 42 ${YANG_INSTALLDIR} $IETFRFC $fyang /usr/local/lib/$APPNAME/clispec /usr/local/lib/$APPNAME/backend example_backend.so$ /usr/local/lib/$APPNAME/netconf false /usr/local/lib/$APPNAME/restconf /usr/local/lib/$APPNAME/cli $APPNAME $dir/$APPNAME.sock /usr/local/var/$APPNAME/$APPNAME.pidfile /usr/local/var/$APPNAME $USER drop_perm $RESTCONFIG EOF cat < $fyang module clixon-example{ yang-version 1.1; namespace "urn:example:clixon"; prefix ex; /* Generic config data */ container table{ list parameter{ key name; leaf name{ type string; } } } } EOF function data() { if [[ "$1" == "" ]] then echo "" else echo "$1" fi } # Pipe stdin to command and also do chunked framing (netconf 1.1) # Arguments: # - Command # - expected command return value (0 if OK) # - stdin input1 This is NOT encoded, eg preamble/hello # - stdin input2 This gets chunked encoding # - expect1 stdout outcome, can be partial and contain regexps # - expect2 stdout outcome This gets chunked encoding, must be complete netconf message # Use this if you want regex eg ^foo$ function rpc() { expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "$1" "" "$2" } function commit() { if [[ "$1" == "" ]] then rpc "" "" else rpc "$1" "" fi } function edit_config() { TARGET="$1" CONFIG="$2" rpc "<$TARGET/>$CONFIG" "" } function assert_config_equals() { TARGET="$1" EXPECTED="$2" # new "get-config: $TARGET" rpc "<$TARGET/>" "$(data "$EXPECTED")" } function reset() { rpc "none" "" commit assert_config_equals "candidate" "" assert_config_equals "running" "" } CANDIDATE_PATH="/usr/local/var/$APPNAME/candidate_db" RUNNING_PATH="/usr/local/var/$APPNAME/running_db" ROLLBACK_PATH="/usr/local/var/$APPNAME/rollback_db" FAILSAFE_PATH="/usr/local/var/$APPNAME/failsafe_db" CONFIGB="eth0
" CONFIGC="eth1
" CONFIGBPLUSC="eth0eth1
" FAILSAFE_CFG="eth99
" new "test params: -f $cfg" # Bring your own backend if [ $BE -ne 0 ]; then # kill old backend (if any) new "kill old backend" sudo clixon_backend -zf $cfg if [ $? -ne 0 ]; then err fi new "start backend -s init -f $cfg" start_backend -s init -f $cfg fi new "wait backend" wait_backend new "Hello check confirm-commit capability" expecteof "$clixon_netconf -f $cfg" 0 "urn:ietf:params:netconf:base:1.1]]>]]>" "urn:ietf:params:netconf:capability:confirmed-commit:1.1" '^$' ################################################################################ new "netconf ephemeral confirmed-commit rolls back after disconnect" reset edit_config "candidate" "$CONFIGB" assert_config_equals "candidate" "$CONFIGB" commit "30" assert_config_equals "running" "" ################################################################################ new "netconf persistent confirmed-commit" reset edit_config "candidate" "$CONFIGB" commit "a" assert_config_equals "running" "$CONFIGB" edit_config "candidate" "$CONFIGC" commit "aba" assert_config_equals "running" "$CONFIGBPLUSC" ################################################################################ new "netconf cancel-commit with invalid persist-id" rpc "abc" "applicationinvalid-valueerrora confirmed-commit with the given persist-id was not found" ################################################################################ new "netconf cancel-commit with valid persist-id" rpc "ab" "" ################################################################################ new "netconf persistent confirmed-commit with timeout" reset edit_config "candidate" "$CONFIGB" commit "2abcd" assert_config_equals "running" "$CONFIGB" sleep 2 assert_config_equals "running" "" ################################################################################ new "netconf persistent confirmed-commit with reset timeout" reset edit_config "candidate" "$CONFIGB" commit "abcde5" assert_config_equals "running" "$CONFIGB" edit_config "candidate" "$CONFIGC" commit "abcdeabcdef10" # prove the new timeout is active by sleeping longer than first timeout. get config, assert == B+C sleep 6 assert_config_equals "running" "$CONFIGBPLUSC" # now sleep long enough for rollback to happen; get config, assert == A sleep 5 assert_config_equals "running" "" ################################################################################ new "netconf persistent confirming-commit to epehemeral confirmed-commit should rollback" reset edit_config "candidate" "$CONFIGB" commit "10" assert_config_equals "running" "$CONFIGB" commit "" assert_config_equals "running" "" ################################################################################ new "netconf confirming-commit for persistent confirmed-commit with empty persist value" reset edit_config "candidate" "$CONFIGB" commit "10" assert_config_equals "running" "$CONFIGB" commit "" assert_config_equals "running" "$CONFIGB" ################################################################################ # TODO reconsider logic around presence/absence of rollback_db as a signal as dropping permissions may impact ability # to unlink and/or create that file. see clixon_datastore.c#xmldb_delete() and backend_startup.c#startup_mode_startup() new "backend loads rollback if present at startup" reset edit_config "candidate" "$CONFIGB" commit "" edit_config "candidate" "$CONFIGC" commit "abcdefg" assert_config_equals "running" "$CONFIGBPLUSC" stop_backend -f $cfg # kill backend and restart [ -f "$ROLLBACK_PATH" ] || err "rollback_db doesn't exist!" # assert rollback_db exists start_backend -s running -f $cfg wait_backend assert_config_equals "running" "$CONFIGB" [ -f "ROLLBACK_PATH" ] && err "rollback_db still exists!" # assert rollback_db doesn't exist stop_backend -f $cfg start_backend -s init -f $cfg ################################################################################ new "backend loads failsafe at startup if rollback present but cannot be loaded" reset sudo tee "$FAILSAFE_PATH" > /dev/null << EOF # create a failsafe database $FAILSAFE_CFG EOF edit_config "candidate" "$CONFIGC" commit "foobar" assert_config_equals "running" "$CONFIGC" stop_backend -f $cfg # kill the backend sudo rm $ROLLBACK_PATH # modify rollback_db so it won't commit successfully sudo tee "$ROLLBACK_PATH" > /dev/null << EOF EOF start_backend -s running -f $cfg wait_backend assert_config_equals "running" "$FAILSAFE_CFG" stop_backend -f $cfg start_backend -s init -f $cfg -lf/tmp/clixon.log -D1 wait_backend ################################################################################ new "ephemeral confirmed-commit survives unrelated ephemeral session disconnect" reset edit_config "candidate" "$CONFIGB" assert_config_equals "candidate" "$CONFIGB" # start a new ephemeral confirmed commit, but keep the confirmed-commit session alive (need to put it in the background) # use HELLONO11 which uses older EOM framing sleep 60 | cat <(echo "$HELLONO1160]]>]]>") -| $clixon_netconf -qf $cfg >> /dev/null & PIDS=($(jobs -l % | cut -c 6- | awk '{print $1}')) assert_config_equals "running" "$CONFIGB" # assert config twice to prove it surives disconnect assert_config_equals "running" "$CONFIGB" # of ephemeral sessions kill -9 ${PIDS[0]} # kill the while loop above to close STDIN on 1st ################################################################################ new "cli ephemeral confirmed-commit rolls back after disconnect" reset tmppipe=$(mktemp -u) mkfifo -m 600 "$tmppipe" cat << EOF | clixon_cli -f $cfg >> /dev/null & set table parameter eth0 commit confirmed 60 shell echo >> $tmppipe shell cat $tmppipe quit EOF cat $tmppipe >> /dev/null assert_config_equals "running" "$CONFIGB" echo >> $tmppipe sleep 1 assert_config_equals "running" "" rm $tmppipe ################################################################################ new "cli persistent confirmed-commit" reset cat << EOF | clixon_cli -f $cfg >> /dev/null set table parameter eth0 commit confirmed persist a quit EOF assert_config_equals "running" "$CONFIGB" cat << EOF | clixon_cli -f $cfg >> /dev/null set table parameter eth1 commit persist-id a confirmed persist ab quit EOF assert_config_equals "running" "$CONFIGBPLUSC" ################################################################################ new "cli cancel-commit with invalid persist-id" expectpart "$($clixon_cli -lo -1 -f $cfg commit persist-id abc cancel)" 255 "a confirmed-commit with the given persist-id was not found" ################################################################################ new "cli cancel-commit with valid persist-id" expectpart "$($clixon_cli -lo -1 -f $cfg commit persist-id ab cancel)" 0 "^$" assert_config_equals "running" "" ################################################################################ new "cli cancel-commit with no confirmed-commit in progress" expectpart "$($clixon_cli -lo -1 -f $cfg commit persist-id ab cancel)" 255 "no confirmed-commit is in progress" ################################################################################ new "cli persistent confirmed-commit with timeout" reset cat << EOF | clixon_cli -f $cfg >> /dev/null set table parameter eth0 commit confirmed persist abcd 2 EOF assert_config_equals "running" "$CONFIGB" sleep 2 assert_config_equals "running" "" ################################################################################ new "cli persistent confirmed-commit with reset timeout" reset cat << EOF | clixon_cli -f $cfg >> /dev/null set table parameter eth0 commit confirmed persist abcd 5 EOF assert_config_equals "running" "$CONFIGB" cat << EOF | clixon_cli -f $cfg >> /dev/null set table parameter eth1 commit persist-id abcd confirmed persist abcdef 10 EOF sleep 6 assert_config_equals "running" "$CONFIGBPLUSC" # now sleep long enough for rollback to happen; get config, assert == A sleep 5 assert_config_equals "running" "" # TODO test restconf receives "409 conflict" when there is a persistent confirmed-commit active # TODO test restconf causes confirming-commit for ephemeral confirmed-commit if [ $RC -ne 0 ]; then new "kill old restconf daemon" stop_restconf_pre new "start restconf daemon" start_restconf -f $cfg fi new "wait restconf" wait_restconf if [ $RC -ne 0 ]; then new "Kill restconf daemon" stop_restconf fi if [ $BE -ne 0 ]; then new "Kill backend" # Check if premature kill pid=$(pgrep -u ${USER} -f clixon_backend) if [ -z "$pid" ]; then err "backend already dead" fi # kill backend stop_backend -f $cfg fi # Set by restconf_config unset RESTCONFIG new "endtest" endtest