* Fixed issue https://github.com/clicon/clixon/issues/18 RPC response issues reported by Stephen Jones at Netgate

This commit is contained in:
Olof hagsand 2018-04-22 16:53:12 +02:00
parent 67c0abead7
commit 3ed1c98556
11 changed files with 215 additions and 113 deletions

View file

@ -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, "<rpc-reply>");

View file

@ -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)

View file

@ -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 *);

View file

@ -1003,6 +1003,13 @@ api_operations_post(clicon_handle h,
}
for (i=0; i<pi; i++)
oppath = index(oppath+1, '/');
if (oppath == NULL || strcmp(oppath,"/")==0){
if (netconf_operation_failed_xml(&xerr, "protocol", "Operation name expected") < 0)
goto done;
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
goto done;
goto ok;
}
clicon_debug(1, "%s oppath: %s", __FUNCTION__, oppath);
/* Find yang rpc statement, return yang rpc statement if found */
@ -1040,7 +1047,7 @@ api_operations_post(clicon_handle h,
{
cbuf *c = cbuf_new();
clicon_xml2cbuf(c, xtop, 0, 0);
clicon_debug(1, "%s xinput:%s", __FUNCTION__, cbuf_get(c));
clicon_debug(1, "%s xtop:%s", __FUNCTION__, cbuf_get(c));
cbuf_free(c);
}
#endif
@ -1056,8 +1063,22 @@ api_operations_post(clicon_handle h,
badrequest(r);
goto ok;
}
yinput = yang_find((yang_node*)yrpc, Y_INPUT, NULL);
/* xdata should have format <top><input> */
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 <rpc>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");