diff --git a/CHANGELOG.md b/CHANGELOG.md index c361c0fe..28838c9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,10 @@ Expected: September, 2021 * Restconf YANG PATCH according to RFC 8072 (Work in progress) * Experimental: enable by setting YANG_PATCH in include/clixon_custom.h * Thanks to Alan Yaniger for providing this patch +* List pagination + * This is prototype work for ietf netconf work + * See draft-wwlh-netconf-list-pagination-00.txt + * New http media: application/yang.collection+xml/json ### API changes on existing protocol/config features @@ -476,7 +480,7 @@ Developers may need to change their code * This only applies to the evhtp restconf daemon, not fcgi/nginx, where the nginx config is used. * The RESTCONF clixon-config options are obsolete * Thanks to Dave Cornejo for the idea - + ### API changes on existing protocol/config features Users may have to change how they access the system diff --git a/apps/restconf/restconf_methods_get.c b/apps/restconf/restconf_methods_get.c index 5ff22dd6..f1071cec 100644 --- a/apps/restconf/restconf_methods_get.c +++ b/apps/restconf/restconf_methods_get.c @@ -534,6 +534,227 @@ api_data_collection(clicon_handle h, return retval; } +/*! GET Collection + * According to restconf collection draft. Lists, work in progress + * @param[in] h Clixon handle + * @param[in] req Generic Www handle + * @param[in] api_path According to restconf (Sec 3.5.3.1 in rfc8040) + * @param[in] pcvec Vector of path ie DOCUMENT_URI element + * @param[in] pi Offset, where path starts + * @param[in] qvec Vector of query string (QUERY_STRING) + * @param[in] pretty Set to 1 for pretty-printed xml/json output + * @param[in] media_out Output media + * @param[in] head If 1 is HEAD, otherwise GET + * @code + * curl -X GET http://localhost/restconf/data/interfaces + * @endcode + * A collection resource contains a set of data resources. It is used + * to represent a all instances or a subset of all instances in a YANG + * list or leaf-list. + * @see draft-ietf-netconf-restconf-collection-00.txt + */ +static int +api_data_collection(clicon_handle h, + void *req, + char *api_path, + cvec *pcvec, /* XXX remove? */ + int pi, + cvec *qvec, + int pretty, + restconf_media media_out) +{ + int retval = -1; + char *xpath = NULL; + cbuf *cbx = NULL; + yang_stmt *yspec; + cxobj *xret = NULL; + cxobj *xerr = NULL; /* malloced */ + cxobj *xe = NULL; /* not malloced */ + cxobj **xvec = NULL; + int i; + int ret; + cvec *nsc = NULL; + char *attr; /* attribute value string */ + netconf_content content = CONTENT_ALL; + cxobj *xtop = NULL; + cxobj *xbot = NULL; + yang_stmt *y = NULL; + cbuf *cbrpc = NULL; + char *depth; + char *count; + char *skip; + char *direction; + char *sort; + char *where; + + clicon_debug(1, "%s", __FUNCTION__); + if ((yspec = clicon_dbspec_yang(h)) == NULL){ + clicon_err(OE_FATAL, 0, "No DB_SPEC"); + goto done; + } + /* strip /... from start */ + for (i=0; i + * operations, content, and the element. + */ #define NETCONF_COLLECTION_NAMESPACE "urn:ietf:params:xml:ns:yang:ietf-netconf-list-pagination" /* Output symbol for netconf get/get-config diff --git a/lib/src/clixon_netconf_lib.c b/lib/src/clixon_netconf_lib.c index 291d106c..1f678d80 100644 --- a/lib/src/clixon_netconf_lib.c +++ b/lib/src/clixon_netconf_lib.c @@ -1516,7 +1516,6 @@ netconf_module_load(clicon_handle h) /* Load restconf yang. Note this is also a part of clixon-config */ if (yang_spec_parse_module(h, "clixon-restconf", NULL, yspec)< 0) goto done; -#if 1 /* XXX: Both the following settings are because clicon-handle is not part of all API * functions * Treat unknown XML as anydata */ @@ -1529,7 +1528,9 @@ netconf_module_load(clicon_handle h) /* Load restconf collection */ if (yang_spec_parse_module(h, "ietf-netconf-list-pagination", NULL, yspec)< 0) goto done; - + /* Load restconf collection */ + if (yang_spec_parse_module(h, "ietf-netconf-list-pagination", NULL, yspec)< 0) + goto done; retval = 0; done: return retval; diff --git a/test/test_collection.sh b/test/test_collection.sh new file mode 100755 index 00000000..5debe9a3 --- /dev/null +++ b/test/test_collection.sh @@ -0,0 +1,114 @@ +#!/usr/bin/env bash +# Restconf RFC8040 Appendix A and B "jukebox" example +# For collection / scaling activity +# 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.xml +fjukebox=$dir/example-jukebox.yang + +cat < $cfg + + $cfg + ietf-netconf:startup + /usr/local/share/clixon + $IETFRFC + $dir + false + /usr/local/var/$APPNAME/$APPNAME.sock + /usr/local/lib/$APPNAME/backend + $dir/restconf.pidfile + $dir + true + +EOF + +cat < $dir/startup_db + + + + + Foo Fighters + + Crime and Punishment + 1995 + + + One by One + 2002 + + + The Color and the Shape + 1997 + + + There is Nothing Left to Loose + 1999 + + + White and Black + 1998 + + + + + +EOF + +# Common Jukebox spec (fjukebox must be set) +. ./jukebox.sh + +new "test params: -f $cfg -- -s" # XXX: -sS state file + +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 startup -f $cfg" + start_backend -s startup -f "$cfg" +fi + +new "waiting" +wait_backend + +if [ $RC -ne 0 ]; then + new "kill old restconf daemon" + stop_restconf_pre + + new "start restconf daemon" + start_restconf -f $cfg + + new "waiting" + wait_restconf +fi + +new "C.1. 'count' Parameter RESTCONF" +expectpart "$(curl $CURLOPTS -X GET -H "Accept: application/yang.collection+xml" $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/library/artist=Foo%20Fighters/album/?count=2)" 0 "HTTP/1.1 200 OK" "application/yang.collection+xml" 'Crime and Punishment1995One by One2002' + +new "C.1. 'count' Parameter NETCONF" +expecteof "$clixon_netconf -qf $cfg" 0 "runningexample-jukebox/example-jukebox:jukebox/library/artist=Foo Fighters/album2]]>]]>" '^Crime and Punishment1995One by One2002]]>]]>$' + +if [ $RC -ne 0 ]; then + new "Kill restconf daemon" + stop_restconf +fi + +if [ $BE -eq 0 ]; then + exit # BE +fi + +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 + +rm -rf $dir diff --git a/test/test_restconf.sh b/test/test_restconf.sh index 6d32d836..135d2ba6 100755 --- a/test/test_restconf.sh +++ b/test/test_restconf.sh @@ -300,6 +300,10 @@ function testrun() new "restconf empty rpc JSON" expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d {\"clixon-example:input\":null} $proto://$addr/restconf/operations/clixon-example:empty)" 0 "HTTP/$HVER 204" + # -I / --head get headers only HEAD + new "restconf HEAD. RFC 8040 4.2" + expectpart "$(curl $CURLOPTS -I --head "Accept: application/yang-data+json" $RCPROTO://localhost/restconf/data)" 0 "HTTP/1.1 200 OK" "Content-Type: application/yang-data+json" + new "restconf empty rpc XML" expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+xml" -d '' $proto://$addr/restconf/operations/clixon-example:empty)" 0 "HTTP/$HVER 204" diff --git a/test/test_upgrade_quit.sh b/test/test_upgrade_quit.sh index 80edcfc1..50b94d51 100755 --- a/test/test_upgrade_quit.sh +++ b/test/test_upgrade_quit.sh @@ -342,6 +342,6 @@ if [ -z "$match" ]; then fi rm -rf $dir - new "endtest" endtest +