* More precise Yang validation and better error messages

* For Example, adding bad-, missing-, or unknown-element error messages, etc instead of operation-failed
* Removed delete-config support for candidate db since it is not supported in RFC6241.
* Switched the order of `error-type` and `error-tag` in all netconf and restconf error messages to comply to RFC order.
* Added example_rpc RPC to example backend
* Renamed xml_namespace[_set]() to xml_prefix[_set]()
* Some restconf error messages contained "rpc-reply" or "rpc-error" which have now been removed.
* Netconf/Restconf RPC extra input arguments are ignored (https://github.com/clicon/clixon/issues/47)
This commit is contained in:
Olof hagsand 2018-12-21 01:33:41 +01:00
parent 03e618b1e5
commit f872c7e295
45 changed files with 807 additions and 405 deletions

View file

@ -52,14 +52,6 @@ module example{
}
rpc empty {
}
rpc input {
input {
}
}
rpc output {
output {
}
}
rpc client-rpc {
description "Example local client-side rpc";
input {
@ -104,12 +96,15 @@ new "kill old restconf daemon"
sudo pkill -u www-data clixon_restconf
new "start restconf daemon"
sudo su -c "$clixon_restconf -f $cfg -y $fyang -D 1" -s /bin/sh www-data &
sudo su -c "$clixon_restconf -f $cfg -y $fyang -D $DBG" -s /bin/sh www-data &
sleep $RCWAIT
new "restconf tests"
new2 "restconf rpc using POST json without mandatory element"
expecteq "$(curl -s -X POST -d '{"input":{"wrongelement":"ipv4"}}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "unknown-element","error-info": {"bad-element": "wrongelement"},"error-severity": "error"}}} '
new2 "restconf root discovery. RFC 8040 3.1 (xml+xrd)"
expecteq "$(curl -s -X GET http://localhost/.well-known/host-meta)" "<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>
<Link rel='restconf' href='/restconf'/>
@ -125,12 +120,12 @@ expecteq "$(curl -s -H 'Accept: application/yang-data+xml' -G http://localhost/r
'
new2 "restconf get restconf/operations. RFC8040 3.3.2 (json)"
expecteq "$(curl -sG http://localhost/restconf/operations)" '{"operations": {"example:empty": null,"example:input": null,"example:output": null,"example:client-rpc": null,"ietf-routing:fib-route": null,"ietf-routing:route-count": null}}
expecteq "$(curl -sG http://localhost/restconf/operations)" '{"operations": {"example:client-rpc": null,"ietf-routing:fib-route": null,"ietf-routing:route-count": null,"example:empty": null}}
'
new "restconf get restconf/operations. RFC8040 3.3.2 (xml)"
ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/operations)
expect='<operations><empty xmlns="urn:example:clixon"/><input xmlns="urn:example:clixon"/><output xmlns="urn:example:clixon"/><client-rpc xmlns="urn:example:clixon"/><fib-route xmlns="urn:ietf:params:xml:ns:yang:ietf-routing"/><route-count xmlns="urn:ietf:params:xml:ns:yang:ietf-routing"/></operations>'
expect='<operations><client-rpc xmlns="urn:example:clixon"/><fib-route xmlns="urn:ietf:params:xml:ns:yang:ietf-routing"/><route-count xmlns="urn:ietf:params:xml:ns:yang:ietf-routing"/><empty xmlns="urn:example:clixon"/></operations>'
match=`echo $ret | grep -EZo "$expect"`
if [ -z "$match" ]; then
err "$expect" "$ret"
@ -161,6 +156,9 @@ expectfn "curl -s -I http://localhost/restconf/data" 0 "HTTP/1.1 200 OK"
new "restconf empty rpc"
expecteq "$(curl -s -X POST -d {\"input\":null} http://localhost/restconf/operations/example:empty)" ""
new2 "restconf empty rpc with extra args (should fail)"
expecteq "$(curl -s -X POST -d {\"input\":{\"extra\":null}} http://localhost/restconf/operations/example:empty)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "unknown-element","error-info": {"bad-element": "extra"},"error-severity": "error"}}} '
new2 "restconf get empty config + state json"
expecteq "$(curl -sSG http://localhost/restconf/data/state)" '{"state": {"op": "42"}}
'
@ -170,7 +168,7 @@ expecteq "$(curl -sSG http://localhost/restconf/data/example:state)" '{"state":
'
new2 "restconf get empty config + state json with wrong module name"
expecteq "$(curl -sSG http://localhost/restconf/data/badmodule:state)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "No yang node found: badmodule:state"}}}} '
expecteq "$(curl -sSG http://localhost/restconf/data/badmodule:state)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "No yang node found: badmodule:state"}}} '
new "restconf get empty config + state xml"
ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/data/state)
@ -215,10 +213,10 @@ new "restconf Add subtree to datastore using POST"
expectfn 'curl -s -i -X POST -H "Accept: application/yang-data+json" -d {"interfaces":{"interface":{"name":"eth/0/0","type":"ex:eth","enabled":true}}} http://localhost/restconf/data' 0 'HTTP/1.1 200 OK'
new "restconf Re-add subtree which should give error"
expectfn 'curl -s -X POST -d {"interfaces":{"interface":{"name":"eth/0/0","type":"ex:eth","enabled":true}}} http://localhost/restconf/data' 0 '{"ietf-restconf:errors" : {"error": {"error-tag": "data-exists","error-type": "application","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}}'
expectfn 'curl -s -X POST -d {"interfaces":{"interface":{"name":"eth/0/0","type":"ex:eth","enabled":true}}} http://localhost/restconf/data' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "data-exists","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}}'
# XXX Cant get this to work
#expecteq "$(curl -s -X POST -d {\"interfaces\":{\"interface\":{\"name\":\"eth/0/0\",\"type\":\"ex:eth\",\"enabled\":true}}} http://localhost/restconf/data)" '{"ietf-restconf:errors" : {"error": {"error-tag": "data-exists","error-type": "application","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}}'
#expecteq "$(curl -s -X POST -d {\"interfaces\":{\"interface\":{\"name\":\"eth/0/0\",\"type\":\"ex:eth\",\"enabled\":true}}} http://localhost/restconf/data)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "data-exists","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}}'
new "restconf Check interfaces eth/0/0 added"
expectfn "curl -s -G http://localhost/restconf/data" 0 '{"interfaces": {"interface": \[{"name": "eth/0/0","type": "ex:eth","enabled": true}\]},"state": {"op": "42"}}
@ -244,13 +242,13 @@ expecteq "$(curl -s -G http://localhost/restconf/data/state)" '{"state": {"op":
'
new2 "restconf Re-post eth/0/0 which should generate error"
expecteq "$(curl -s -X POST -d '{"interface":{"name":"eth/0/0","type":"ex:eth","enabled":true}}' http://localhost/restconf/data/interfaces)" '{"ietf-restconf:errors" : {"error": {"error-tag": "data-exists","error-type": "application","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}} '
expecteq "$(curl -s -X POST -d '{"interface":{"name":"eth/0/0","type":"ex:eth","enabled":true}}' http://localhost/restconf/data/interfaces)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "data-exists","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}} '
new "Add leaf description using POST"
expecteq "$(curl -s -X POST -d '{"description":"The-first-interface"}' http://localhost/restconf/data/interfaces/interface=eth%2f0%2f0)" ""
new "Add nothing using POST"
expectfn 'curl -s -X POST http://localhost/restconf/data/interfaces/interface=eth%2f0%2f0' 0 '"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "malformed-message","error-type": "rpc","error-severity": "error","error-message": " on line 1: syntax error at or before:'
expectfn 'curl -s -X POST http://localhost/restconf/data/interfaces/interface=eth%2f0%2f0' 0 '"ietf-restconf:errors" : {"error": {"error-type": "rpc","error-tag": "malformed-message","error-severity": "error","error-message": " on line 1: syntax error at or before:'
new2 "restconf Check description added"
expecteq "$(curl -s -G http://localhost/restconf/data/interfaces)" '{"interfaces": {"interface": [{"name": "eth/0/0","description": "The-first-interface","type": "ex:eth","enabled": true}]}}
@ -263,7 +261,7 @@ new "Check deleted eth/0/0"
expectfn 'curl -s -G http://localhost/restconf/data' 0 $state
new2 "restconf Re-Delete eth/0/0 using none should generate error"
expecteq "$(curl -s -X DELETE http://localhost/restconf/data/interfaces/interface=eth%2f0%2f0)" '{"ietf-restconf:errors" : {"error": {"error-tag": "data-missing","error-type": "application","error-severity": "error","error-message": "Data does not exist; cannot delete resource"}}} '
expecteq "$(curl -s -X DELETE http://localhost/restconf/data/interfaces/interface=eth%2f0%2f0)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "data-missing","error-severity": "error","error-message": "Data does not exist; cannot delete resource"}}} '
new "restconf Add subtree eth/0/0 using PUT"
expecteq "$(curl -s -X PUT -d '{"interface":{"name":"eth/0/0","type":"ex:eth","enabled":true}}' http://localhost/restconf/data/interfaces/interface=eth%2f0%2f0)" ""
@ -273,37 +271,38 @@ expecteq "$(curl -s -G http://localhost/restconf/data/interfaces)" '{"interfaces
'
new2 "restconf rpc using POST json"
expecteq "$(curl -s -X POST -d '{"input":{"routing-instance-name":"ipv4"}}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"output": {"route": {"address-family": "ipv4","next-hop": {"next-hop-list": "2.3.4.5"}}}}
expecteq "$(curl -s -X POST -d '{"input":{"routing-instance-name":"ipv4","destination-address":{"address-family":"ipv6"}}}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"output": {"route": {"address-family": "ipv4","next-hop": {"next-hop-list": "2.3.4.5"},"source-protocol": "static"}}}
'
# Cant get this to work due to quoting
#new2 "restconf rpc using POST wrong JSON"
#expecteq "$(curl -s -X POST -d '{"input":{"routing-instance-name":ipv4}}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": " on line 1: syntax error at or before: i"}}}} '
#expecteq "$(curl -s -X POST -d '{"input":{"routing-instance-name":ipv4}}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": " on line 1: syntax error at or before: i"}}} '
new2 "restconf rpc using POST json w/o mandatory element"
expecteq "$(curl -s -X POST -d '{"input":{"wrongelement":"ipv4"}}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "Missing mandatory variable: routing-instance-name"}}}} '
new2 "restconf rpc non-existing rpc w/o namespace"
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/kalle)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "yang node not found"}}}} '
new2 "restconf rpc using POST json without mandatory element"
expecteq "$(curl -s -X POST -d '{"input":{"wrongelement":"ipv4"}}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "unknown-element","error-info": {"bad-element": "wrongelement"},"error-severity": "error"}}} '
new2 "restconf rpc non-existing rpc without namespace"
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/kalle)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "yang node not found"}}} '
new2 "restconf rpc non-existing rpc"
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/example:kalle)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "yang node not found"}}}} '
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/example:kalle)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "yang node not found"}}} '
new2 "restconf rpc missing name"
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "Operation name expected"}}}} '
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "Operation name expected"}}} '
new2 "restconf rpc missing input"
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "Missing mandatory variable: routing-instance-name"}}}} '
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "missing-element","error-info": {"bad-element": "routing-instance-name"},"error-severity": "error","error-message": "Mandatory variable"}}} '
new "restconf rpc using POST xml"
ret=$(curl -s -X POST -H "Accept: application/yang-data+xml" -d '{"input":{"routing-instance-name":"ipv4"}}' http://localhost/restconf/operations/ietf-routing:fib-route)
expect="<output><route><address-family>ipv4</address-family><next-hop><next-hop-list>2.3.4.5</next-hop-list></next-hop></route></output>"
expect="<output><route><address-family>ipv4</address-family><next-hop><next-hop-list>2.3.4.5</next-hop-list></next-hop><source-protocol>static</source-protocol></route></output>"
match=`echo $ret | grep -EZo "$expect"`
if [ -z "$match" ]; then
err "$expect" "$ret"
fi
new2 "restconf rpc using wrong prefix"
expecteq "$(curl -s -X POST -d '{"input":{"routing-instance-name":"ipv4"}}' http://localhost/restconf/operations/wrong:fib-route)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "yang module not found"}}}} '
expecteq "$(curl -s -X POST -d '{"input":{"routing-instance-name":"ipv4"}}' http://localhost/restconf/operations/wrong:fib-route)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "yang module not found"}}} '
new "restconf local client rpc using POST xml"
ret=$(curl -s -X POST -H "Accept: application/yang-data+xml" -d '{"input":{"request":"example"}}' http://localhost/restconf/operations/example:client-rpc)
@ -321,7 +320,7 @@ fi
new "Kill restconf daemon"
sudo pkill -u www-data -f "/www-data/clixon_restconf"
if [ $BE -ne 0 ]; then
if [ $BE -eq 0 ]; then
exit # BE
fi