#!/usr/bin/env bash # test xpath functions within YANG conditionals # XPATH base https://www.w3.org/TR/xpath-10/ # YANG XPATH functions: https://tools.ietf.org/html/rfc7950 # Test of xpath functions: # - contains # - derived-from # - derived-from-or-self # - bit-is-set # 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/$APPNAME.yang cat < $cfg $cfg ${YANG_INSTALLDIR} $dir $fyang /usr/local/lib/$APPNAME/clispec /usr/local/lib/$APPNAME/cli /usr/local/lib/$APPNAME/netconf /usr/local/lib/$APPNAME/backend $APPNAME /usr/local/var/run/$APPNAME.sock /usr/local/var/run/$APPNAME.pidfile /usr/local/var/$APPNAME false EOF cat < $fyang module $APPNAME{ yang-version 1.1; prefix ex; namespace "urn:example:clixon"; identity interface-type; identity atm { base interface-type; } identity ethernet { base interface-type; } identity fast-ethernet { base ethernet; } identity gigabit-ethernet { base ethernet; } container top{ leaf class { /* contains */ type string; } list mylist{ /* contains */ key id; leaf id { type string; } leaf site { /* If the XPath expression is defined in a substatement to a data * node that represents configuration, the accessible tree is the * data in the datastore where the context node exists. * The "when" statement makes its parent data definition statement conditional. */ when "contains(../../class,'foo') or contains(../../class,'bar')"; type int32; } } } list interface { /* derived-from */ key name; leaf name{ type string; } leaf type { type identityref { base interface-type; } } leaf flags { description "See RFC 7950 Sec 10.6.1"; type bits{ bit UP; bit PROMISCUOUS; bit DISABLED; } } } augment "/ex:interface" { when 'derived-from(type, "ex:ethernet")'; leaf mtu { type uint32; } } augment "/ex:interface" { when 'derived-from-or-self(type, "ex:ethernet")'; leaf crc { type uint32; } } /* Example derved from yangmodels ietf-mpls-ldp.yang */ container mustnot{ list mustlist{ key name; leaf name{ type string; } container mycont{ must "not (../../ex:mustlist[ex:name!=current()/../ex:name])" { description "Only one list instance is allowed."; } leaf foo{ type string; } } } } /* This is from ietf-ntp@2022-07-05.yang for testing boolean() * But note I reversed true/false */ container system { container ntp { presence "Enables the NTP client unless the 'enabled' leaf (which defaults to 'true') is set to 'false'"; } } container ntp { when 'true() = boolean(/sys:system/sys:ntp)' { description "Applicable when the system /sys/ntp/ is not used."; } presence "NTP is enabled and system should attempt to synchronize the system clock with an NTP server from the 'ntp/associations' list."; leaf port { type int16; } } } 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" start_backend -s init -f $cfg fi new "wait backend" wait_backend new "contains: Set site to foo that validates site OK" expecteof_netconf "$clixon_netconf -qf $cfg -D $DBG" 0 "$DEFAULTHELLO" "foo1242" "" "" new "netconf validate OK" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "Set site to fie which invalidates the when contains" expecteof_netconf "$clixon_netconf -qf $cfg -D $DBG" 0 "$DEFAULTHELLO" "fie" "" "" new "netconf validate not OK" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "applicationoperation-failederrorFailed WHEN condition of site in module example (WHEN xpath is contains(../../class,'foo') or contains(../../class,'bar'))" new "netconf discard-changes" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" # derived-from new "derived-from: Set mtu to interface OK on GE" expecteof_netconf "$clixon_netconf -qf $cfg -D $DBG" 0 "$DEFAULTHELLO" "e0fast-ethernet1500" "" "" new "netconf validate OK" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "Change type to atm" expecteof_netconf "$clixon_netconf -qf $cfg -D $DBG" 0 "$DEFAULTHELLO" "e0atm" "" "" new "netconf validate not OK (mtu not allowed)" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "applicationoperation-failederrorFailed WHEN condition of mtu in module example (WHEN xpath is derived-from(type, \"ex:ethernet\"))" new "Change type to ethernet (self)" expecteof_netconf "$clixon_netconf -qf $cfg -D $DBG" 0 "$DEFAULTHELLO" "e0ethernet" "" "" new "netconf validate not OK (mtu not allowed on self)" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "applicationoperation-failederrorFailed WHEN condition of mtu in module example (WHEN xpath is derived-from(type, \"ex:ethernet\"))" new "netconf discard-changes" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" # derived-from-or-self new "derived-from-or-self: Set crc to interface OK on GE" expecteof_netconf "$clixon_netconf -qf $cfg -D $DBG" 0 "$DEFAULTHELLO" "e0fast-ethernet42" "" "" new "netconf validate OK" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "Change type to atm" expecteof_netconf "$clixon_netconf -qf $cfg -D $DBG" 0 "$DEFAULTHELLO" "e0atm" "" "" new "netconf validate not OK (crc not allowed)" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "applicationoperation-failederrorFailed WHEN condition of crc in module example (WHEN xpath is derived-from-or-self(type, \"ex:ethernet\"))" new "Change type to ethernet (self)" expecteof_netconf "$clixon_netconf -qf $cfg -D $DBG" 0 "$DEFAULTHELLO" "e0ethernet" "" "" new "netconf validate OK (self)" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "netconf discard-changes" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" # bit-is-set new "Add interfaces with different flags" expecteof_netconf "$clixon_netconf -qf $cfg -D $DBG" 0 "$DEFAULTHELLO" "e0UPe1UP PROMISCUOUSe2PROMISCUOUS" "" "" new "netconf bit-is-set" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "e1UP PROMISCUOUSe2PROMISCUOUS" new "netconf set ntp port" expecteof_netconf "$clixon_netconf -qf $cfg -D $DBG" 0 "$DEFAULTHELLO" "99" "" "" new "netconf validate fail" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "applicationoperation-failederrorFailed WHEN condition of ntp in module example (WHEN xpath is true() = boolean(/sys:system/sys:ntp))" new "netconf set system boolean" expecteof_netconf "$clixon_netconf -qf $cfg -D $DBG" 0 "$DEFAULTHELLO" "" "" "" new "netconf validate ok" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" 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 sudo pkill -u root -f clixon_backend fi rm -rf $dir new "endtest" endtest