#!/usr/bin/env bash # Yang features. if-feature. # The test has a example module with FEATURES A and B, where A is enabled and # B is disabled. # It also uses an ietf-router module where (only) router-id is enabled # Also check modules-state (RFC7895) announces the enabled features. # # From RFC7950: # 7.20.1 Schema nodes tagged with an "if-feature" statement are _ignored_ by # the server unless the server supports the given feature expression. # 8.1: There MUST be no nodes tagged with "if-feature" present if the # "if-feature" expression evaluates to "false" in the server. # - Should the server just "ignore" these nodes or actively reject them? # # Clixon has a strict implementation of the features so that setting # data with disabled features is same as if they are not present in the Yang. # Which means no cli syntax or edit operations were syntactically allowed # (and therefore invalid). # 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 fyang=$dir/test.yang # Note ietf-routing@2018-03-13 assumed cat < $cfg $APPNAME:A $APPNAME:A1 ietf-routing:router-id $cfg ${YANG_INSTALLDIR} $IETFRFC $fyang /usr/local/lib/$APPNAME/clispec /usr/local/lib/$APPNAME/cli $APPNAME /usr/local/var/$APPNAME/$APPNAME.sock /usr/local/var/$APPNAME/$APPNAME.pidfile /usr/local/var/$APPNAME true EOF cat < $fyang module example{ yang-version 1.1; namespace "urn:example:clixon"; prefix ex; import ietf-routing { prefix rt; } feature A{ description "This test feature is enabled"; } feature A1{ description "This test feature is enabled (extra for multiple)"; } feature B{ description "This test feature is disabled"; } feature B1{ description "This test feature is disabled (extra for multiple)"; } leaf x{ if-feature A; type "string"; } leaf y{ if-feature B; type "string"; } leaf u { if-feature rt:router-id; type "string"; } leaf z{ type "string"; } leaf m1{ if-feature "A and A1"; description "Enabled"; type "string"; } leaf m2{ if-feature "A or A1"; description "Enabled"; type "string"; } leaf m3{ if-feature "A and B"; description "Not enabled"; type "string"; } leaf m4{ if-feature "A or B"; description "Enabled"; type "string"; } leaf m5{ if-feature "B and B1"; description "Not enabled"; type "string"; } leaf m6{ if-feature "B or B1"; description "Not enabled"; type "string"; } leaf m7{ if-feature "A or A1 or B or B1"; description "Enabled"; type "string"; } leaf m8{ if-feature "A and A1 and B and B1"; description "Not enabled"; type "string"; } leaf m9{ if-feature "(A or B " + "or B1) and A1"; description "Enabled"; type "string"; } leaf m10{ if-feature "(A and A1 " + "and B1) or not A"; description "Disabled"; type "string"; } leaf m11{ if-feature "not (A or B)"; description "Disabled"; type "string"; } } EOF # Run netconf feature test # 1: syntax node # 2: disabled or enabled # NOTE, this was before failures when disabled, but after https://github.com/clicon/clixon/issues/322 that # disabled nodes should be "ignored". Instead now if disabled a random node is inserted under the disabled node # which should not work function testrun() { node=$1 enabled=$2 new "netconf set $node" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<$node xmlns=\"urn:example:clixon\">foo" "" "" new "netconf validate $node" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" if $enabled; then new "netconf set extra element under $node (expect fail)" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<$node xmlns=\"urn:example:clixon\">" "" "applicationunknown-elementkallekakaerrorFailed to find YANG spec of XML node: kallekaka with parent: $node in namespace: urn:example:clixon" else new "netconf set extra element under $node" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<$node xmlns=\"urn:example:clixon\">" "" "" new "netconf validate $node" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" fi new "netconf discard-changes" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" } 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 new "start backend -s init -f $cfg" start_backend -s init -f $cfg fi new "wait backend" wait_backend new "cli enabled feature" expectpart "$($clixon_cli -1f $cfg set x foo)" 0 "" new "cli disabled feature" expectpart "$($clixon_cli -1f $cfg -l o set y foo)" 255 "CLI syntax error: \"set y foo\": Unknown command" new "cli enabled feature in other module" expectpart "$($clixon_cli -1f $cfg set routing router-id 1.2.3.4)" 0 "" new "cli disabled feature in other module" expectpart "$($clixon_cli -1f $cfg -l o set routing ribs rib default-rib false)" 255 "CLI syntax error: \"set routing ribs rib default-rib false\": Unknown command" new "netconf discard-changes" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" # Single if-feature testrun x true testrun y false testrun u true # Multiple if-feature testrun m1 true testrun m2 true testrun m3 false testrun m4 true testrun m5 false testrun m6 false testrun m7 true testrun m8 false testrun m9 true testrun m10 false testrun m11 false # This test has been broken up into all different modules instead of one large # reply since the modules change so often new "netconf schema resource, RFC 7895" rpc=$(chunked_framing "") ret=$($clixon_netconf -qf $cfg<default" match=`echo "$ret" | grep --null -Go "$expect"` if [ -z "$match" ]; then err "$expect" "$ret" fi new "netconf module A" expect="exampleurn:example:clixonAA1" match=`echo "$ret" | grep --null -Go "$expect"` if [ -z "$match" ]; then err "$expect" "$ret" fi if false ; then # clixon "config" is a meta-config and not visisble in regular features new "netconf module clixon-config" expect="clixon-config2018-09-30" match=`echo "$ret" | grep --null -Go "$expect"` if [ -z "$match" ]; then err "$expect" "$ret" fi fi # false new "netconf module ietf-inet-types" expect="ietf-inet-types2021-02-22urn:ietf:params:xml:ns:yang:ietf-inet-types" match=`echo "$ret" | grep --null -Go "$expect"` if [ -z "$match" ]; then err "$expect" "$ret" fi new "netconf module ietf-interfaces" expect="ietf-interfaces2018-02-20urn:ietf:params:xml:ns:yang:ietf-interfaces" match=`echo "$ret" | grep --null -Go "$expect"` if [ -z "$match" ]; then err "$expect" "$ret" fi # Note order of features in ietf-netconf yang is alphabetically: candidate, startup, validate, xpath new "netconf module ietf-netconf" expect="ietf-netconf2011-06-01urn:ietf:params:xml:ns:netconf:base:1.0candidatevalidatexpath" match=`echo "$ret" | grep --null -Go "$expect"` if [ -z "$match" ]; then err "$expect" "$ret" fi new "netconf module ietf-routing" expect="ietf-routing2018-03-13urn:ietf:params:xml:ns:yang:ietf-routingrouter-id" match=`echo "$ret" | grep --null -Go "$expect"` if [ -z "$match" ]; then err "$expect" "$ret" fi expect="ietf-yang-library2019-01-04urn:ietf:params:xml:ns:yang:ietf-yang-library" match=`echo "$ret" | grep --null -Go "$expect"` if [ -z "$match" ]; then err "$expect" "$ret" fi new "netconf module ietf-yang_types" expect="ietf-yang-types2013-07-15urn:ietf:params:xml:ns:yang:ietf-yang-types" match=`echo "$ret" | grep --null -Go "$expect"` if [ -z "$match" ]; then err "$expect" "$ret" 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 #------------------------ # Negative test, if if-feature but no feature, signal error cat < $fyang module example{ yang-version 1.1; namespace "urn:example:clixon"; prefix ex; feature A{ description "This feature exists"; } leaf x{ if-feature "A or B"; type "string"; } } 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 new "start backend -s init -f $cfg: feature missing expected fail" expectpart "$(sudo $clixon_backend -F1s init -f $cfg -l o)" 255 " Yang module example has IF_FEATURE B, but no such FEATURE statement exists" stop_backend -f $cfg fi rm -rf $dir new "endtest" endtest