#!/usr/bin/env bash # Choice type and mandatory # Example from RFC7950 Sec 7.9.6 # Also test mandatory behaviour as in 7.6.5 # (XXX Would need default test in 7.6.4) # Use-case: The ietf-netconf edit-config has a shorthand version of choice w mandatory: # container { choice target { mandatory; leaf candidate; leaf running; }} # 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/choice.xml clidir=$dir/cli fyang=$dir/type.yang test -d ${clidir} || rm -rf ${clidir} mkdir $clidir # Define default restconfig config: RESTCONFIG RESTCONFIG=$(restconf_config none false) cat < $cfg $cfg clixon-restconf:allow-auth-none $dir ${YANG_INSTALLDIR} $fyang /usr/local/lib/$APPNAME/clispec /usr/local/lib/$APPNAME/cli $APPNAME $clidir /usr/local/var/$APPNAME/$APPNAME.sock /usr/local/var/$APPNAME/$APPNAME.pidfile /usr/local/var/$APPNAME $RESTCONFIG EOF cat < $fyang module system{ yang-version 1.1; namespace "urn:example:config"; prefix ex; container system{ /* From RFC 7950 7.9.6 */ container protocol { presence true; choice name { case a { leaf udp { type empty; } } case b { leaf tcp { type empty; } } } } /* Same but shorthand */ container shorthand { presence true; choice name { leaf udp { type empty; } leaf tcp { type empty; } } } /* Same with mandatory true */ container mandatory { presence true; choice name { mandatory true; case a { leaf udp { type empty; } } case b { leaf tcp { type empty; } } } } /* Choice with multiple items */ choice mch { case first{ leaf-list ma { type int32; } leaf mb { type int32; } } case second{ leaf-list mc { type int32; } } } /* Choice shorthand with sub-container */ container choice-subcontainer { presence true; choice name { container udp { leaf udp1{ type string; } leaf udp2{ type string; } } container tcp { leaf tcp1{ type string; } } } } } /* Case with mandatory leaf */ container manleaf { choice name { case a { leaf a1 { type string; } leaf a2 { mandatory true; type string; } } case b { leaf b1 { type string; } } case c { leaf c1 { mandatory true; type string; } choice c2 { case cc1 { leaf ccc1 { type string; } } } } } } list mylist { key k; leaf k{ type string; } choice c { case c1 { leaf c1 { mandatory true; type string; } choice c1c { case c1c1 { leaf c1c1l { type string; } } } } } } } EOF cat < $clidir/ex.cli # Clixon example specification CLICON_MODE="example"; CLICON_PROMPT="%U@%H %W> "; CLICON_PLUGIN="example_cli"; # Autocli syntax tree operations set @datamodel, cli_auto_set(); delete("Delete a configuration item") { @datamodel, cli_auto_del(); all("Delete whole candidate configuration"), delete_all("candidate"); } validate("Validate changes"), cli_validate(); commit("Commit the changes"), cli_commit(); quit("Quit"), cli_quit(); discard("Discard edits (rollback 0)"), discard_changes(); show("Show a particular state of the system"){ configuration("Show configuration"), cli_auto_show("datamodel", "candidate", "text", true, false);{ cli("Show configuration as CLI commands"), cli_auto_show("datamodel", "candidate", "cli", true, false, "set "); xml("Show configuration as XML"), cli_auto_show("datamodel", "candidate", "xml", true, false, NULL); } } EOF new "test params: -f $cfg" if [ $BE -ne 0 ]; then new "kill old backend" sudo clixon_backend -zf $cfg if [ $? -ne 0 ]; then err fi sudo pkill -f clixon_backend # to be sure new "start backend -s init -f $cfg" start_backend -s init -f $cfg fi new "wait backend" wait_backend 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 # First vanilla (protocol) case new "netconf validate empty" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "netconf set protocol both udp and tcp" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "netconf validate both udp and tcp fail" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "applicationbad-elementudperrorElement in choice statement already exists" new "netconf discard-changes" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "netconf set empty protocol" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "netconf validate protocol" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "netconf set protocol tcp" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "netconf get protocol tcp" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "netconf commit protocol tcp" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "netconf changing from TCP to UDP (RFC7950 7.9.6)" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "$" "" new "netconf get protocol udp" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "netconf commit protocol udp" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" #-- restconf new "restconf DELETE whole datastore" expectpart "$(curl $CURLOPTS -X DELETE $RCPROTO://localhost/restconf/data)" 0 "HTTP/$HVER 204" new "restconf set protocol tcp+udp fail" expectpart "$(curl $CURLOPTS -X PUT -H "Content-Type: application/yang-data+json" $RCPROTO://localhost/restconf/data/system:system/protocol -d '{"system:protocol":{"tcp": [null], "udp": [null]}}')" 0 "HTTP/$HVER 400" '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"bad-element","error-info":{"bad-element":"udp"},"error-severity":"error","error-message":"Element in choice statement already exists"}}}' new "restconf set protocol tcp" expectpart "$(curl $CURLOPTS -X PUT -H "Content-Type: application/yang-data+json" $RCPROTO://localhost/restconf/data/system:system/protocol -d {\"system:protocol\":{\"tcp\":[null]}})" 0 "HTTP/$HVER 201" new "restconf get protocol tcp" expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/system:system)" 0 "HTTP/$HVER 200" '{"system:system":{"protocol":{"tcp":\[null\]}}}' new "restconf set protocol tcp+udp fail again" expectpart "$(curl $CURLOPTS -X PUT -H "Content-Type: application/yang-data+json" $RCPROTO://localhost/restconf/data/system:system/protocol -d '{"system:protocol":{"tcp": [null], "udp": [null]}}')" 0 "HTTP/$HVER 400" '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"bad-element","error-info":{"bad-element":"tcp"},"error-severity":"error","error-message":"Element in choice statement already exists"}}}' new "cli set protocol udp" expectpart "$($clixon_cli -1 -f $cfg -l o set system protocol udp)" 0 "^$" new "cli get protocol udp" expectpart "$($clixon_cli -1 -f $cfg -l o show configuration cli)" 0 "set system protocol" "set system protocol udp" new "cli change protocol to tcp" expectpart "$($clixon_cli -1 -f $cfg -l o set system protocol tcp)" 0 "^$" new "cli get protocol tcp" expectpart "$($clixon_cli -1 -f $cfg -l o show configuration cli)" 0 "set system protocol" "set system protocol tcp" new "cli delete all" expectpart "$($clixon_cli -1 -f $cfg -l o delete all)" 0 "^$" new "commit" expectpart "$($clixon_cli -1 -f $cfg -l o commit)" 0 "^$" # Second shorthand (no case) new "netconf set protocol both udp and tcp" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "netconf validate both udp and tcp fail" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "applicationbad-elementudperrorElement in choice statement already exists" new "netconf discard-changes" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "netconf set shorthand tcp" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "netconf changing from TCP to UDP (RFC7950 7.9.6)" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "netconf get shorthand udp" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "netconf validate shorthand" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "netconf discard-changes" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" # Third check mandatory new "netconf set empty mandatory" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "netconf get mandatory empty" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "netconf validate mandatory" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "applicationdata-missingmissing-choicenameerror" new "netconf set mandatory udp" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "netconf get mandatory udp" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "netconf validate mandatory" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "netconf discard-changes" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" # Choice with multiple items new "netconf choice multiple items first" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" " 0 1 2 " "" "" new "netconf get multiple items" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "012" "" new "netconf validate multiple ok" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "netconf choice multiple items second" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" " 0 1 " "" "protocoloperation-failedtoo-many-elementserror/rpc/edit-config/config/system/mb" new "netconf choice multiple items mix" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" " 0 2 2 " "" "" new "netconf validate multiple error" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "applicationbad-elementmcerrorElement in choice statement already exists" # Double merge new "netconf choice single item" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" " 12 " "" "" new "netconf choice merge second item" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" " 99 " "" "" new "netconf get both items" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "1299" "" new "netconf validate ok" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "netconf discard-changes" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" # Merge in choice-subcontainer new "netconf choice sub-container 1st leaf" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" " 42 " "" "" new "netconf choice sub-container 2nd leaf (dont remove 1st)" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" " 99 " "" "" new "netconf get both items" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "4299" "" new "netconf validate ok" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "netconf discard-changes" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "netconf set non-mandatory leaf" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "xxx" "" "" new "netconf validate missing" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "applicationmissing-elementa2errorMandatory variable a2 in module system" new "netconf set mandatory leaf" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "yyy" "" "" new "netconf commit ok" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "netconf set other case" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "zzz" "" "" # This tests https://github.com/clicon/clixon/issues/349 part 1 new "netconf validate ok" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" # This tests https://github.com/clicon/clixon/issues/349 part 2 new "set case with choice" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "kkk" "" "" new "validate expect error" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "applicationmissing-elementc1errorMandatory variable c1 in module system" new "netconf discard-changes" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "set case mandatory + non" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "ab" "" "" new "netconf validate ok" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "netconf discard-changes" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "set list+mandatory case" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "0xy" "" "" new "netconf validate ok" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" 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 root -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 rm -rf $dir new "endtest" endtest