* Stricter handling of multi-namespace handling

* This occurs in cases where there are more than one XML namespaces in a config tree, such as `augment`:ed trees.
  * Affects all parts of the system, including datastore, backend, restconf and cli.
* Invalid api-path syntax (eg non-matching yang) error changed from 412 operation-failed to 400 Bad request invalid-value, or unknown-element.
This commit is contained in:
Olof hagsand 2019-09-29 14:45:08 +02:00
parent a547b3f31d
commit d9136c8972
22 changed files with 777 additions and 236 deletions

View file

@ -6,7 +6,12 @@
# both defined in the basic ietf-interfaces module (type) as well as the main
# module through the augmented module ()
# The ietf-interfaces is very restricted (not original).
# From a namespace perspective, there are two modules, with symbols as follows:
# 1. ietf-interface - urn:ietf:params:xml:ns:yang:ietf-interfaces
# interfaces, interface, name, type
# 2. example-augment - urn:example:augment - mymod
# (augmented): mandatory-leaf, me, other,
# (uses/grouping): ip, port, lid, lport
# Magic line must be first in script (see README.md)
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
@ -175,7 +180,7 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></
</interface></interfaces></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf verify get with refined ports"
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface xmlns:mymod="urn:example:augment"><name>e1</name><type>mymod:some-new-iftype</type><mandatory-leaf>true</mandatory-leaf><port>80</port><lport>8080</lport></interface></interfaces></data></rpc-reply>]]>]]>$'
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface xmlns:mymod="urn:example:augment"><name>e1</name><type>mymod:some-new-iftype</type><mymod:mandatory-leaf>true</mymod:mandatory-leaf><mymod:port>80</mymod:port><mymod:lport>8080</mymod:lport></interface></interfaces></data></rpc-reply>]]>]]>$'
new "netconf set identity defined in other"
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
@ -183,7 +188,7 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></
<name>e2</name>
<type>fddi</type>
<mymod:mandatory-leaf>true</mymod:mandatory-leaf>
<other>if:fddi</other>
<mymod:other>if:fddi</mymod:other>
</interface></interfaces></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf validate ok"
@ -195,7 +200,7 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></
<name>e3</name>
<type>fddi</type>
<mymod:mandatory-leaf>true</mymod:mandatory-leaf>
<me>mymod:you</me>
<mymod:me>mymod:you</mymod:me>
</interface></interfaces></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf commit ok"
@ -203,11 +208,11 @@ expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" '^<rpc-reply
# restconf and augment
new "restconf get augment"
new "restconf get augment json"
expectpart "$(curl -s -i -X GET http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 'HTTP/1.1 200 OK ' '{"ietf-interfaces:interfaces":{"interface":\[{"name":"e1","type":"example-augment:some-new-iftype","example-augment:mandatory-leaf":"true","example-augment:port":80,"example-augment:lport":8080},{"name":"e2","type":"fddi","example-augment:mandatory-leaf":"true","example-augment:other":"ietf-interfaces:fddi","example-augment:port":80,"example-augment:lport":8080},{"name":"e3","type":"fddi","example-augment:mandatory-leaf":"true","example-augment:me":"you","example-augment:port":80,"example-augment:lport":8080}\]}} '
new "restconf get augment xml"
expectpart "$(curl -s -i -X GET -H 'Accept: application/yang-data+xml' http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 'HTTP/1.1 200 OK ' '<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface xmlns:mymod="urn:example:augment"><name>e1</name><type>mymod:some-new-iftype</type><mandatory-leaf>true</mandatory-leaf><port>80</port><lport>8080</lport></interface><interface xmlns:mymod="urn:example:augment"><name>e2</name><type>fddi</type><mandatory-leaf>true</mandatory-leaf><other>if:fddi</other><port>80</port><lport>8080</lport></interface><interface xmlns:mymod="urn:example:augment"><name>e3</name><type>fddi</type><mandatory-leaf>true</mandatory-leaf><me>mymod:you</me><port>80</port><lport>8080</lport></interface></interfaces>'
expectpart "$(curl -s -i -X GET -H 'Accept: application/yang-data+xml' http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 'HTTP/1.1 200 OK ' '<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface xmlns:mymod="urn:example:augment"><name>e1</name><type>mymod:some-new-iftype</type><mymod:mandatory-leaf>true</mymod:mandatory-leaf><mymod:port>80</mymod:port><mymod:lport>8080</mymod:lport></interface><interface xmlns:mymod="urn:example:augment"><name>e2</name><type>fddi</type><mymod:mandatory-leaf>true</mymod:mandatory-leaf><mymod:other>if:fddi</mymod:other><mymod:port>80</mymod:port><mymod:lport>8080</mymod:lport></interface><interface xmlns:mymod="urn:example:augment"><name>e3</name><type>fddi</type><mymod:mandatory-leaf>true</mymod:mandatory-leaf><mymod:me>mymod:you</mymod:me><mymod:port>80</mymod:port><mymod:lport>8080</mymod:lport></interface></interfaces>'
new "Kill restconf daemon"
stop_restconf

View file

@ -77,6 +77,7 @@ expectfn "$clixon_cli -1 -f $cfg -l o validate" 255 "Validate failed. Edit and t
new "cli configure ip addr"
expectfn "$clixon_cli -1 -f $cfg set interfaces interface eth/0/0 ipv4 address 1.2.3.4 prefix-length 24" 0 "^$"
new "cli configure ip descr"
expectfn "$clixon_cli -1 -f $cfg set interfaces interface eth/0/0 description mydesc" 0 "^$"
new "cli configure ip type"

View file

@ -56,10 +56,10 @@ module example{
}
}
leaf address {
description "From RFC7950 9.9.5";
description "From RFC7950 9.9.6";
type leafref {
path "../../if:interfaces/if:interface[if:name = current()/../relname]"
+ "/if:ipv4/if:address/if:ip";
+ "/ip:ipv4/ip:address/ip:ip";
}
}
leaf wrong {
@ -85,29 +85,29 @@ EOF
BASEXML=$(cat <<EOF
<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
<interface>
<interface xmlns:ip="urn:ietf:params:xml:ns:yang:ietf-ip">
<name>eth0</name>
<type>ex:eth</type>
<ipv4>
<address>
<ip>192.0.2.1</ip>
<prefix-length>24</prefix-length>
</address>
<address>
<ip>192.0.2.2</ip>
<prefix-length>24</prefix-length>
</address>
</ipv4>
<ip:ipv4>
<ip:address>
<ip:ip>192.0.2.1</ip:ip>
<ip:prefix-length>24</ip:prefix-length>
</ip:address>
<ip:address>
<ip:ip>192.0.2.2</ip:ip>
<ip:prefix-length>24</ip:prefix-length>
</ip:address>
</ip:ipv4>
</interface>
<interface>
<interface xmlns:ip="urn:ietf:params:xml:ns:yang:ietf-ip">
<name>lo</name>
<type>ex:lo</type>
<ipv4>
<address>
<ip>127.0.0.1</ip>
<prefix-length>32</prefix-length>
</address>
</ipv4>
<ip:ipv4>
<ip:address>
<ip:ip>127.0.0.1</ip:ip>
<ip:prefix-length>32</ip:prefix-length>
</ip:address>
</ip:ipv4>
</interface>
</interfaces>
EOF

View file

@ -94,7 +94,7 @@ new "netconf discard-changes"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf edit config"
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth/0/0</name></interface><interface><name>eth1</name><enabled>true</enabled><ipv4><address><ip>9.2.3.4</ip><prefix-length>24</prefix-length></address></ipv4></interface></interfaces></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth/0/0</name></interface><interface xmlns:ip="urn:ietf:params:xml:ns:yang:ietf-ip"><name>eth1</name><enabled>true</enabled><ip:ipv4><ip:address><ip:ip>9.2.3.4</ip:ip><ip:prefix-length>24</ip:prefix-length></ip:address></ip:ipv4></interface></interfaces></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
# Too many quotes
cat <<EOF > $tmp # new
@ -102,7 +102,7 @@ cat <<EOF > $tmp # new
EOF
new "netconf get config xpath"
expecteof "$clixon_netconf -qf $cfg" 0 "$(cat $tmp)" '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth1</name><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$'
expecteof "$clixon_netconf -qf $cfg" 0 "$(cat $tmp)" '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface xmlns:ip="urn:ietf:params:xml:ns:yang:ietf-ip"><name>eth1</name><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$'
# Too many quotes
cat <<EOF > $tmp # new
@ -110,7 +110,7 @@ cat <<EOF > $tmp # new
EOF
new "netconf get config xpath parent"
expecteof "$clixon_netconf -qf $cfg" 0 "$(cat $tmp)" '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth/0/0</name><enabled>true</enabled></interface><interface><name>eth1</name><enabled>true</enabled><ipv4><enabled>true</enabled><forwarding>false</forwarding><address><ip>9.2.3.4</ip><prefix-length>24</prefix-length></address></ipv4></interface></interfaces></data></rpc-reply>]]>]]>$'
expecteof "$clixon_netconf -qf $cfg" 0 "$(cat $tmp)" '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth/0/0</name><enabled>true</enabled></interface><interface xmlns:ip="urn:ietf:params:xml:ns:yang:ietf-ip"><name>eth1</name><enabled>true</enabled><ip:ipv4><ip:enabled>true</ip:enabled><ip:forwarding>false</ip:forwarding><ip:address><ip:ip>9.2.3.4</ip:ip><ip:prefix-length>24</ip:prefix-length></ip:address></ip:ipv4></interface></interfaces></data></rpc-reply>]]>]]>$'
new "netconf validate missing type"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error>"

View file

@ -11,7 +11,10 @@
# usually contain a payload that represents the error condition, such
# that it describes the error state and what next steps are suggested
# for resolving it.
#
# Note this is different from an api-path that is invalid from a yang point
# of view, this is interpreted as 400 Bad Request invalid-value/unknown-element
# XXX: complete non-existent yang with unknown-element for all PUT/POST/GET api-paths
# Magic line must be first in script (see README.md)
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
@ -20,7 +23,7 @@ APPNAME=example
cfg=$dir/conf.xml
fyang=$dir/example.yang
fyang2=$dir/aug.yang
fyang2=$dir/augment.yang
fxml=$dir/initial.xml
# <CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN>
@ -34,15 +37,24 @@ cat <<EOF > $cfg
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
<CLICON_BACKEND_PIDFILE>$dir/restconf.pidfile</CLICON_BACKEND_PIDFILE>
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
</clixon-config>
EOF
cat <<EOF > $fyang2
module augm{
module augment{
yang-version 1.1;
namespace "urn:example:aug";
prefix aug;
description "Used as a base for augment";
container route-config {
description
"Root container for routing models";
container dynamic {
}
}
container route-state {
description
"Root container for routing models";
@ -58,7 +70,7 @@ module example{
yang-version 1.1;
namespace "urn:example:clixon";
prefix ex;
import aug {
import augment {
description "Just for augment";
prefix "aug";
}
@ -86,12 +98,15 @@ module example{
}
augment "/aug:route-config/aug:dynamic" {
container ospf {
container routers {
container auto-cost {
leaf reference-bandwidth {
type uint32;
}
}
leaf reference-bandwidth {
type uint32;
}
}
}
augment "/aug:route-config/aug:dynamic" {
container ospf {
leaf reference-bandwidth {
type uint32;
}
}
}
@ -147,13 +162,28 @@ if false; then
new "restconf POST non-existent (no yang) element"
# should be invalid element
expectpart "$(curl -is -X POST -H 'Content-Type: application/yang-data+xml' -d "$XML" http://localhost/restconf/data/example:a=23/xxx)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"invalid-value","error-severity":"error","error-message":"Unknown element: '
new "restconf GET multi-namespace path"
# simplify yang
# works for config?
expectpart "$(curl -si -X GET http://localhost/restconf/data/augm:route-state/dynamic/ospf/routers/auto-cost/reference-bandwidth)" 0 'HTTP/1.1 404 Not Found' '{"ietf-restconf:errors":{"error":{"rpc-error":{"error-type":"application","error-tag":"invalid-value","error-severity":"error","error-message":"Unknown element: 'xxx'"}}}}'
fi
# Test for multi-module path where an augment stretches across modules
new "restconf POST augment multi-namespace path"
expecteq "$(curl -s -X POST -H 'Content-Type: application/yang-data+xml' -d '<route-config xmlns="urn:example:aug"><dynamic><ospf xmlns="urn:example:clixon"><reference-bandwidth>23</reference-bandwidth></ospf></dynamic></route-config>' http://localhost/restconf/data)" 0 ''
new "restconf GET augment multi-namespace top"
expectpart "$(curl -si -X GET http://localhost/restconf/data/augment:route-config)" 0 'HTTP/1.1 200 OK' '{"augment:route-config":{"dynamic":{"example:ospf":{"reference-bandwidth":23}}}}'
new "restconf GET augment multi-namespace level 1"
expectpart "$(curl -si -X GET http://localhost/restconf/data/augment:route-config/dynamic)" 0 'HTTP/1.1 200 OK' '{"augment:dynamic":{"example:ospf":{"reference-bandwidth":23}}}'
new "restconf GET augment multi-namespace cross"
expectpart "$(curl -si -X GET http://localhost/restconf/data/augment:route-config/dynamic/example:ospf)" 0 'HTTP/1.1 200 OK' '{"example:ospf":{"reference-bandwidth":23}}'
new "restconf GET augment multi-namespace cross level 2"
expectpart "$(curl -si -X GET http://localhost/restconf/data/augment:route-config/dynamic/example:ospf/reference-bandwidth)" 0 'HTTP/1.1 200 OK' '{"example:reference-bandwidth":23}'
# XXX actually no such element
#new "restconf GET augment multi-namespace, no 2nd module in api-path, fail"
#expectpart "$(curl -si -X GET http://localhost/restconf/data/augment:route-config/dynamic/ospf)" 0 'HTTP/1.1 404 Not Found' '{"ietf-restconf:errors":{"error":{"rpc-error":{"error-type":"application","error-tag":"invalid-value","error-severity":"error","error-message":"Instance does not exist"}}}}'
new "Kill restconf daemon"
stop_restconf