From 3ed1c985569f3e21b42b36eaaa6946e59ca912d0 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Sun, 22 Apr 2018 16:53:12 +0200 Subject: [PATCH] * Fixed issue https://github.com/clicon/clixon/issues/18 RPC response issues reported by Stephen Jones at Netgate --- CHANGELOG.md | 4 +- apps/backend/backend_client.c | 2 +- apps/backend/backend_plugin.c | 45 +++++------ apps/backend/backend_plugin.h | 2 +- apps/restconf/restconf_methods.c | 69 +++++++++++++---- example/example_backend.c | 39 ++++++---- example/example_backend_nacm.c | 7 +- lib/src/clixon_xml_map.c | 1 + lib/src/clixon_yang.c | 14 ++-- test/test_netconf.sh | 125 ++++++++++++++++++++----------- test/test_restconf.sh | 20 ++++- 11 files changed, 215 insertions(+), 113 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bbf2c9a9..01675118 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -103,7 +103,9 @@ enables saved files to be used as datastore without any editing. Thanks Matt. * Added cli_show_version() ### Corrected Bugs -* Fixed issue https://github.com/clicon/clixon/issues/17 special character in strings can break RPCs +* Fixed issue https://github.com/clicon/clixon/issues/18 RPC response issues reported by Stephen Jones at Netgate +* Fixed issue https://github.com/clicon/clixon/issues/17 special character in strings can break RPCs reported by David Cornejo at Netgate. + * This was a large rewright of XML parsing and output due to CharData not correctly encoded according to https://www.w3.org/TR/2008/REC-xml-20081126. * Fixed three-key list entry problem (reported by jdl@netgate) * Translate xml->json \n correctly * Fix issue: https://github.com/clicon/clixon/issues/15 Replace whole config diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c index 2debcfc2..1f8ac9c2 100644 --- a/apps/backend/backend_client.c +++ b/apps/backend/backend_client.c @@ -289,7 +289,7 @@ from_client_get(clicon_handle h, /* Get state data from plugins as defined by plugin_statedata(), if any */ assert(xret); clicon_err_reset(); - if ((ret = clixon_plugin_statedata(h, selector, xret)) < 0) + if ((ret = clixon_plugin_statedata(h, selector, &xret)) < 0) goto done; if (ret == 0){ /* OK */ cprintf(cbret, ""); diff --git a/apps/backend/backend_plugin.c b/apps/backend/backend_plugin.c index 80d0f128..e69c21fa 100644 --- a/apps/backend/backend_plugin.c +++ b/apps/backend/backend_plugin.c @@ -111,18 +111,18 @@ clixon_plugin_reset(clicon_handle h, /*! Go through all backend statedata callbacks and collect state data * This is internal system call, plugin is invoked (does not call) this function * Backend plugins can register - * @param[in] h clicon handle - * @param[in] xpath String with XPATH syntax. or NULL for all - * @param[in,out] xml XML tree. - * @param[out] cbret Return xml value cligen buffer - * @retval -1 Error - * @retval 0 OK - * @retval 1 Statedata callback failed + * @param[in] h clicon handle + * @param[in] xpath String with XPATH syntax. or NULL for all + * @param[in,out] xtop State XML tree is merged with existing tree. + * @retval -1 Error + * @retval 0 OK + * @retval 1 Statedata callback failed + * @note xtop can be replaced */ int clixon_plugin_statedata(clicon_handle h, char *xpath, - cxobj *xtop) + cxobj **xtop) { int retval = -1; int i; @@ -139,7 +139,7 @@ clixon_plugin_statedata(clicon_handle h, clicon_err(OE_YANG, ENOENT, "No yang spec"); goto done; } - if (xtop==NULL){ + if (*xtop==NULL){ clicon_err(OE_CFG, ENOENT, "XML tree expected"); goto done; } @@ -152,22 +152,14 @@ clixon_plugin_statedata(clicon_handle h, retval = 1; goto done; /* Dont quit here on user callbacks */ } - if (xml_merge(xtop, x, yspec, &reason) < 0) + if (xml_merge(*xtop, x, yspec, &reason) < 0) goto done; if (reason){ - cbuf *cb; - if ((cb = cbuf_new()) == NULL){ - clicon_err(OE_XML, errno, "cbuf_new"); + while ((xc = xml_child_i(*xtop, 0)) != NULL) + xml_purge(xc); + if (netconf_operation_failed_xml(xtop, "rpc", reason)< 0) goto done; - } - if (netconf_operation_failed(cb, "rpc", reason)< 0) - goto done; - while ((xc = xml_child_i(xtop, 0)) != NULL) - xml_purge(xc); - if (xml_parse_string(cbuf_get(cb), NULL, &xtop) < 0) - goto done; - cbuf_free(cb); - break; + goto ok; } if (x){ xml_free(x); @@ -175,7 +167,7 @@ clixon_plugin_statedata(clicon_handle h, } } /* Code complex to filter out anything that is outside of xpath */ - if (xpath_vec(xtop, xpath?xpath:"/", &xvec, &xlen) < 0) + if (xpath_vec(*xtop, xpath?xpath:"/", &xvec, &xlen) < 0) goto done; /* If vectors are specified then mark the nodes found and @@ -187,12 +179,13 @@ clixon_plugin_statedata(clicon_handle h, xml_flag_set(xvec[i], XML_FLAG_MARK); } /* Remove everything that is not marked */ - if (!xml_flag(xtop, XML_FLAG_MARK)) - if (xml_tree_prune_flagged_sub(xtop, XML_FLAG_MARK, 1, NULL) < 0) + if (!xml_flag(*xtop, XML_FLAG_MARK)) + if (xml_tree_prune_flagged_sub(*xtop, XML_FLAG_MARK, 1, NULL) < 0) goto done; /* reset flag */ - if (xml_apply(xtop, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, (void*)XML_FLAG_MARK) < 0) + if (xml_apply(*xtop, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, (void*)XML_FLAG_MARK) < 0) goto done; + ok: retval = 0; done: if (reason) diff --git a/apps/backend/backend_plugin.h b/apps/backend/backend_plugin.h index 3e9f4d1d..3dff37b2 100644 --- a/apps/backend/backend_plugin.h +++ b/apps/backend/backend_plugin.h @@ -71,7 +71,7 @@ int backend_plugin_initiate(clicon_handle h); int clixon_plugin_reset(clicon_handle h, char *db); -int clixon_plugin_statedata(clicon_handle h, char *xpath, cxobj *xml); +int clixon_plugin_statedata(clicon_handle h, char *xpath, cxobj **xtop); transaction_data_t * transaction_new(void); int transaction_free(transaction_data_t *); diff --git a/apps/restconf/restconf_methods.c b/apps/restconf/restconf_methods.c index ae233df3..b055f831 100644 --- a/apps/restconf/restconf_methods.c +++ b/apps/restconf/restconf_methods.c @@ -1003,6 +1003,13 @@ api_operations_post(clicon_handle h, } for (i=0; i */ - if ((xinput = xpath_first(xdata, "/input")) != NULL){ + if ((xinput = xpath_first(xdata, "/input")) == NULL){ + xml_name_set(xdata, "input"); + xml_spec_set(xdata, yinput); /* needed for xml_spec_populate */ + if (yinput){ + if (xml_yang_validate_add(xdata, NULL) < 0){ + if (netconf_operation_failed_xml(&xerr, "protocol", clicon_err_reason) < 0) + goto done; + if (api_return_err(h, r, xerr, pretty, use_xml) < 0) + goto done; + goto ok; + } + } + } + else{ /* Add all input under path */ x = NULL; while (xml_child_nr(xinput)){ @@ -1065,15 +1086,20 @@ api_operations_post(clicon_handle h, if (xml_addsub(xbot, x) < 0) goto done; } - if ((yinput = yang_find((yang_node*)yrpc, Y_INPUT, NULL)) != NULL){ - xml_spec_set(xinput, yinput); /* needed for xml_spec_populate */ - if (xml_apply(xinput, CX_ELMNT, xml_spec_populate, yinput) < 0) + if (yinput){ + xml_spec_set(xbot, yinput); /* needed for xml_spec_populate */ + if (xml_apply(xbot, CX_ELMNT, xml_spec_populate, yinput) < 0) goto done; - if (xml_apply(xinput, CX_ELMNT, + if (xml_apply(xbot, CX_ELMNT, (xml_applyfn_t*)xml_yang_validate_all, NULL) < 0) goto done; - if (xml_yang_validate_add(xinput, NULL) < 0) - goto done; + if (xml_yang_validate_add(xbot, NULL) < 0){ + if (netconf_operation_failed_xml(&xerr, "protocol", clicon_err_reason) < 0) + goto done; + if (api_return_err(h, r, xerr, pretty, use_xml) < 0) + goto done; + goto ok; + } } } } @@ -1099,15 +1125,30 @@ api_operations_post(clicon_handle h, } break; /* Just one if local */ } - if (ret == 0) /* Send to backend */ + if (ret == 0){ /* Send to backend */ if (clicon_rpc_netconf_xml(h, xtop, &xret, NULL) < 0) goto done; + if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){ + if (api_return_err(h, r, xerr, pretty, use_xml) < 0) + goto done; + goto ok; + } + } + /* Check if RPC output section */ + if ((youtput = yang_find((yang_node*)yrpc, Y_OUTPUT, NULL)) == NULL){ + /* If the RPC operation is invoked without errors and if the "rpc" or + * "action" statement has no "output" section, the response message + * MUST NOT include a message-body and MUST send a "204 No Content" + * status-line instead. + */ + FCGX_SetExitStatus(204, r->out); /* OK */ + FCGX_FPrintF(r->out, "\r\n"); + goto ok; + } if ((cbx = cbuf_new()) == NULL) goto done; - if ((xoutput=xpath_first(xret, "/")) != NULL) - xml_name_set(xoutput, "output"); - if ((youtput = yang_find((yang_node*)yrpc, Y_OUTPUT, NULL)) != NULL && - xoutput){ + if ((xoutput=xpath_first(xret, "/")) != NULL){ + xml_name_set(xoutput, "output"); #if 0 clicon_debug(1, "%s xoutput:%s", __FUNCTION__, cbuf_get(cbx)); #endif @@ -1134,7 +1175,7 @@ api_operations_post(clicon_handle h, if (xml2json_cbuf(cbx, xoutput, pretty) < 0) goto done; #if 1 - clicon_debug(1, "%s xoutput:%s", __FUNCTION__, cbuf_get(cbx)); + clicon_debug(1, "%s cbx:%s", __FUNCTION__, cbuf_get(cbx)); #endif FCGX_FPrintF(r->out, "%s", cbx?cbuf_get(cbx):""); FCGX_FPrintF(r->out, "\r\n\r\n"); diff --git a/example/example_backend.c b/example/example_backend.c index 28f5611e..696f8660 100644 --- a/example/example_backend.c +++ b/example/example_backend.c @@ -121,7 +121,9 @@ notification_timer_setup(clicon_handle h) return event_reg_timeout(t, notification_timer, h, "notification timer"); } -/*! IETF Routing fib-route rpc */ +/*! IETF Routing fib-route rpc + * @see ietf-routing@2014-10-26.yang (fib-route) + */ static int fib_route(clicon_handle h, /* Clicon handle */ cxobj *xe, /* Request: */ @@ -136,19 +138,9 @@ fib_route(clicon_handle h, /* Clicon handle */ return 0; } -/*! Smallest possible RPC declaration for test */ -static int -empty(clicon_handle h, /* Clicon handle */ - cxobj *xe, /* Request: */ - cbuf *cbret, /* Reply eg ... */ - void *arg, /* client_entry */ - void *regarg) /* Argument given at register */ -{ - cprintf(cbret, ""); - return 0; -} - -/*! IETF Routing route-count rpc */ +/*! IETF Routing route-count rpc + * @see ietf-routing@2014-10-26.yang (route-count) + */ static int route_count(clicon_handle h, cxobj *xe, /* Request: */ @@ -156,7 +148,24 @@ route_count(clicon_handle h, void *arg, void *regarg) /* Argument given at register */ { - cprintf(cbret, ""); + cprintf(cbret, "42"); + return 0; +} + +/*! Smallest possible RPC declaration for test + * Yang/XML: + * If the RPC operation invocation succeeded and no output parameters + * are returned, the contains a single element defined + * in [RFC6241]. + */ +static int +empty(clicon_handle h, /* Clicon handle */ + cxobj *xe, /* Request: */ + cbuf *cbret, /* Reply eg ... */ + void *arg, /* client_entry */ + void *regarg) /* Argument given at register */ +{ + cprintf(cbret, ""); return 0; } diff --git a/example/example_backend_nacm.c b/example/example_backend_nacm.c index cdc7346a..d6ed4600 100644 --- a/example/example_backend_nacm.c +++ b/example/example_backend_nacm.c @@ -87,7 +87,6 @@ nacm_statedata(clicon_handle h, return retval; } - int plugin_start(clicon_handle h, int argc, @@ -103,8 +102,8 @@ static clixon_plugin_api api = { clixon_plugin_init, /* init */ plugin_start, /* start */ NULL, /* exit */ - .ca_reset=NULL, /* reset */ /*--- Backend plugin only ---*/ - .ca_statedata=nacm_statedata, /* statedata */ + .ca_reset=NULL, /* reset */ + .ca_statedata=nacm_statedata, /* statedata */ }; /*! Backend plugin initialization @@ -115,6 +114,6 @@ static clixon_plugin_api api = { clixon_plugin_api * clixon_plugin_init(clicon_handle h) { - clicon_debug(1, "%s backend secondary", __FUNCTION__); + clicon_debug(1, "%s backend nacm", __FUNCTION__); return &api; } diff --git a/lib/src/clixon_xml_map.c b/lib/src/clixon_xml_map.c index 7741a14e..917131f7 100644 --- a/lib/src/clixon_xml_map.c +++ b/lib/src/clixon_xml_map.c @@ -322,6 +322,7 @@ xml_yang_validate_add(cxobj *xt, and !Node has a config sub-statement and it is false */ if ((ys = xml_spec(xt)) != NULL && yang_config(ys) != 0){ switch (ys->ys_keyword){ + case Y_INPUT: case Y_LIST: /* fall thru */ case Y_CONTAINER: diff --git a/lib/src/clixon_yang.c b/lib/src/clixon_yang.c index c704134f..fe119a6f 100644 --- a/lib/src/clixon_yang.c +++ b/lib/src/clixon_yang.c @@ -32,7 +32,9 @@ ***** END LICENSE BLOCK ***** * Yang functions - */ + * @see https://tools.ietf.org/html/rfc6020 YANG 1.0 + * @see https://tools.ietf.org/html/rfc7950 YANG 1.1 + */ #ifdef HAVE_CONFIG_H #include "clixon_config.h" /* generated by config & autoconf */ @@ -1975,8 +1977,9 @@ schema_nodeid_vec(yang_node *yn, /*! Given an absolute schema-nodeid (eg /a/b/c) find matching yang spec * @param[in] yspec Yang specification. * @param[in] schema_nodeid Absolute schema-node-id, ie /a/b - * @retval NULL Error, with clicon_err called - * @retval yres First yang node matching schema nodeid + * @param[out] yres Result yang statement node, or NULL if not found + * @retval -1 Error, with clicon_err called + * @retval 0 OK (if yres set then found, if yres=0 then not found) * Assume schema nodeid:s have prefixes, (actually the first). * @see yang_desc_schema_nodeid * Used in yang: deviation, top-level augment @@ -2011,8 +2014,8 @@ yang_abs_schema_nodeid(yang_spec *yspec, } /* split : */ if ((id = strchr(vec[1], ':')) == NULL){ /* no prefix */ - clicon_err(OE_YANG, 0, "Absolute schema nodeid must have prefix"); - goto done; + clicon_log(LOG_WARNING, "%s: Absolute schema nodeid must have prefix", __FUNCTION__); + goto ok; } if ((prefix = strdup(vec[1])) == NULL){ clicon_err(OE_UNIX, errno, "%s: strdup", __FUNCTION__); @@ -2040,6 +2043,7 @@ yang_abs_schema_nodeid(yang_spec *yspec, } if (schema_nodeid_vec((yang_node*)ymod, vec+1, nvec-1, yres) < 0) goto done; + ok: /* yres may not be set */ retval = 0; done: if (vec) diff --git a/test/test_netconf.sh b/test/test_netconf.sh index 5b872e67..7b66e88e 100755 --- a/test/test_netconf.sh +++ b/test/test_netconf.sh @@ -5,14 +5,16 @@ APPNAME=example . ./lib.sh cfg=$dir/conf_yang.xml +fyang=$dir/netconf.yang cat < $cfg $cfg /usr/local/share/$APPNAME/yang - example + $fyang /usr/local/lib/$APPNAME/clispec /usr/local/lib/$APPNAME/backend + example_backend.so$ /usr/local/lib/$APPNAME/netconf /usr/local/lib/$APPNAME/restconf /usr/local/lib/$APPNAME/cli @@ -25,138 +27,175 @@ cat < $cfg EOF +cat < $fyang +module example{ + prefix ex; + import ietf-ip { + prefix ip; + } + import ietf-routing { + prefix rt; + } + import ietf-inet-types { + prefix "inet"; + revision-date "2013-07-15"; + } + rpc empty { + } + rpc client-rpc { + description "Example local client-side RPC that is processed by the + the netconf/restconf and not sent to the backend. + This is a clixon implementation detail: some rpc:s + are better processed by the client for API or perf reasons"; + input { + leaf request { + type string; + } + } + output { + leaf result{ + type string; + } + } + } +} +EOF + # kill old backend (if any) new "kill old backend" sudo clixon_backend -zf $cfg if [ $? -ne 0 ]; then err fi -new "start backend -s init -f $cfg" +new "start backend -s init -f $cfg -y $fyang" # start new backend -sudo clixon_backend -s init -f $cfg # -D 1 +sudo clixon_backend -s init -f $cfg -y $fyang # -D 1 if [ $? -ne 0 ]; then err fi new "netconf get-config" -expecteof "$clixon_netconf -qf $cfg" ']]>]]>' '^]]>]]>$' +expecteof "$clixon_netconf -qf $cfg -y $fyang" ']]>]]>' '^]]>]]>$' new "Add subtree eth/0/0 using none which should not change anything" -expecteof "$clixon_netconf -qf $cfg" "noneeth/0/0]]>]]>" "^]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "noneeth/0/0]]>]]>" "^]]>]]>$" new "Check nothing added" -expecteof "$clixon_netconf -qf $cfg" ']]>]]>' '^]]>]]>$' +expecteof "$clixon_netconf -qf $cfg -y $fyang" ']]>]]>' '^]]>]]>$' new "Add subtree eth/0/0 using none and create which should add eth/0/0" -expecteof "$clixon_netconf -qf $cfg" 'eth/0/0ethnone ]]>]]>' "^]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" 'eth/0/0ethnone ]]>]]>' "^]]>]]>$" new "Check eth/0/0 added using xpath" -expecteof "$clixon_netconf -qf $cfg" ']]>]]>' "^eth/0/0ethtrue]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" ']]>]]>' "^eth/0/0ethtrue]]>]]>$" new "Re-create same eth/0/0 which should generate error" -expecteof "$clixon_netconf -qf $cfg" 'eth/0/0ethnone ]]>]]>' "^" +expecteof "$clixon_netconf -qf $cfg -y $fyang" 'eth/0/0ethnone ]]>]]>' "^" new "Delete eth/0/0 using none config" -expecteof "$clixon_netconf -qf $cfg" 'eth/0/0ethnone ]]>]]>' "^]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" 'eth/0/0ethnone ]]>]]>' "^]]>]]>$" new "Check deleted eth/0/0 (non-presence container)" -expecteof "$clixon_netconf -qf $cfg" ']]>]]>' '^]]>]]>$' +expecteof "$clixon_netconf -qf $cfg -y $fyang" ']]>]]>' '^]]>]]>$' new "Re-Delete eth/0/0 using none should generate error" -expecteof "$clixon_netconf -qf $cfg" 'eth/0/0ethnone ]]>]]>' "^" +expecteof "$clixon_netconf -qf $cfg -y $fyang" 'eth/0/0ethnone ]]>]]>' "^" new "netconf edit config" -expecteof "$clixon_netconf -qf $cfg" "eth/0/0eth1true
9.2.3.424
]]>]]>" "^]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "eth/0/0eth1true
9.2.3.424
]]>]]>" "^]]>]]>$" new "netconf get config xpath" -expecteof "$clixon_netconf -qf $cfg" ']]>]]>' "^eth1true]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" ']]>]]>' "^eth1true]]>]]>$" new "netconf get config xpath parent" -expecteof "$clixon_netconf -qf $cfg" ']]>]]>' "^eth/0/0trueeth1truetruefalse
9.2.3.424
]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" ']]>]]>' "^eth/0/0trueeth1truetruefalse
9.2.3.424
]]>]]>$" new "netconf validate missing type" -expecteof "$clixon_netconf -qf $cfg" "]]>]]>" "^" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^" new "netconf discard-changes" -expecteof "$clixon_netconf -qf $cfg" "]]>]]>" "^]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^]]>]]>$" new "netconf get empty config2" -expecteof "$clixon_netconf -qf $cfg" "]]>]]>" "^]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^]]>]]>$" new "netconf edit extra xml" -expecteof "$clixon_netconf -qf $cfg" "]]>]]>" "^" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^" new "netconf discard-changes" -expecteof "$clixon_netconf -qf $cfg" "]]>]]>" "^]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^]]>]]>$" new "netconf edit config eth1" -expecteof "$clixon_netconf -qf $cfg" "eth1eth]]>]]>" "^]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "eth1eth]]>]]>" "^]]>]]>$" new "netconf validate" -expecteof "$clixon_netconf -qf $cfg" "]]>]]>" "^]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^]]>]]>$" new "netconf commit" -expecteof "$clixon_netconf -qf $cfg" "]]>]]>" "^]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^]]>]]>$" new "netconf edit config merge" -expecteof "$clixon_netconf -qf $cfg" "eth2ethmerge]]>]]>" "^]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "eth2ethmerge]]>]]>" "^]]>]]>$" new "netconf edit ampersand encoding(<&): name:'eth&' type:'t<>'" -expecteof "$clixon_netconf -qf $cfg" "eth& t< > ]]>]]>" "^]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "eth& t< > ]]>]]>" "^]]>]]>$" new "netconf get replaced config" -expecteof "$clixon_netconf -qf $cfg" "]]>]]>" "^eth& t< > trueeth1ethtrueeth2ethtrue]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^eth& t< > trueeth1ethtrueeth2ethtrue]]>]]>$" new "cli show configuration eth& - encoding tests" -expectfn "$clixon_cli -1 -f $cfg show conf cli" "interfaces interface name eth&" +expectfn "$clixon_cli -1 -f $cfg -y $fyang show conf cli" "interfaces interface name eth&" new "netconf discard-changes" -expecteof "$clixon_netconf -qf $cfg" "]]>]]>" "^]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^]]>]]>$" new "netconf edit state operation should fail" -expecteof "$clixon_netconf -qf $cfg" "eth1eth]]>]]>" "^invalid-value" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "eth1eth]]>]]>" "^invalid-value" new "netconf get state operation" -expecteof "$clixon_netconf -qf $cfg" "]]>]]>" "^eth0eth42]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^eth0eth42]]>]]>$" new "netconf lock/unlock" -expecteof "$clixon_netconf -qf $cfg" "]]>]]>]]>]]>" "^]]>]]>]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>]]>]]>" "^]]>]]>]]>]]>$" new "netconf lock/lock" -expecteof "$clixon_netconf -qf $cfg" "]]>]]>" "^]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^]]>]]>$" new "netconf lock" -expecteof "$clixon_netconf -qf $cfg" "]]>]]>" "^]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^]]>]]>$" new "close-session" -expecteof "$clixon_netconf -qf $cfg" "]]>]]>" "^]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^]]>]]>$" new "kill-session" -expecteof "$clixon_netconf -qf $cfg" "44]]>]]>" "^]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "44]]>]]>" "^]]>]]>$" new "copy startup" -expecteof "$clixon_netconf -qf $cfg" "]]>]]>" "^]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^]]>]]>$" new "netconf get startup" -expecteof "$clixon_netconf -qf $cfg" "]]>]]>" "^eth1ethtrue]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^eth1ethtrue]]>]]>$" new "netconf delete startup" -expecteof "$clixon_netconf -qf $cfg" "]]>]]>" "^]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^]]>]]>$" new "netconf check empty startup" -expecteof "$clixon_netconf -qf $cfg" "]]>]]>" "^]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^]]>]]>$" new "netconf rpc" -expecteof "$clixon_netconf -qf $cfg" "ipv4ipv4]]>]]>" "^ipv4" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "ipv4ipv4]]>]]>" "^ipv4" new "netconf rpc w/o namespace" -expecteof "$clixon_netconf -qf $cfg" "ipv4ipv4]]>]]>" "^ipv4" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "ipv4ipv4]]>]]>" "^ipv4" + +new "netconf empty rpc" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^]]>]]>$" new "netconf client-side rpc" -expecteof "$clixon_netconf -qf $cfg" "example]]>]]>" "^ok]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "example]]>]]>" "^ok]]>]]>$" new "netconf subscription" -expectwait "$clixon_netconf -qf $cfg" "ROUTING]]>]]>" "^]]>]]>Routing notification]]>]]>$" 30 +expectwait "$clixon_netconf -qf $cfg -y $fyang" "ROUTING]]>]]>" "^]]>]]>Routing notification]]>]]>$" 30 new "Kill backend" # Check if still alive diff --git a/test/test_restconf.sh b/test/test_restconf.sh index 7901ea9c..bee9866f 100755 --- a/test/test_restconf.sh +++ b/test/test_restconf.sh @@ -86,7 +86,7 @@ new "kill old restconf daemon" sudo pkill -u www-data clixon_restconf new "start restconf daemon" -sudo start-stop-daemon -S -q -o -b -x /www-data/clixon_restconf -d /www-data -c www-data -- -f $cfg -D +sudo start-stop-daemon -S -q -o -b -x /www-data/clixon_restconf -d /www-data -c www-data -- -f $cfg -y $fyang # -D sleep 1 @@ -137,8 +137,7 @@ expectfn "curl -s -I http://localhost/restconf/data" "HTTP/1.1 200 OK" #Content-Type: application/yang-data+json" new2 "restconf empty rpc" -expecteq "$(curl -s -X POST -d {\"input\":{\"name\":\"\"}} http://localhost/restconf/operations/ex:empty)" '{"output": null} - ' +expecteq "$(curl -s -X POST -d {\"input\":{\"name\":\"\"}} http://localhost/restconf/operations/ex:empty)" '' new2 "restconf get empty config + state json" expecteq "$(curl -sSG http://localhost/restconf/data)" '{"data": {"interfaces-state": {"interface": [{"name": "eth0","type": "eth","if-index": 42}]}}} @@ -244,6 +243,21 @@ new2 "restconf rpc using POST json" expecteq "$(curl -s -X POST -d '{"input":{"routing-instance-name":"ipv4"}}' http://localhost/restconf/operations/rt:fib-route)" '{"output": {"route": {"address-family": "ipv4","next-hop": {"next-hop-list": "2.3.4.5"}}}} ' +new2 "restconf rpc using POST json w/o mandatory element" +expecteq "$(curl -s -X POST -d '{"input":{"wrongelement":"ipv4"}}' http://localhost/restconf/operations/rt: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 non-existing rpc" +expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/ex: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 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"}}}} ' + +new2 "restconf rpc missing input" +expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/rt: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"}}}} ' + 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/rt:fib-route) expect="ipv42.3.4.5"