Merge branch 'master' of https://github.com/clicon/clixon
This commit is contained in:
commit
af720e8f28
58 changed files with 1527 additions and 770 deletions
|
|
@ -411,6 +411,7 @@ from_client_edit_config(clicon_handle h,
|
|||
cbuf *cbx = NULL; /* Assist cbuf */
|
||||
int ret;
|
||||
char *username;
|
||||
cxobj *xret = NULL;
|
||||
|
||||
username = clicon_username_get(h);
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
|
|
@ -470,10 +471,13 @@ from_client_edit_config(clicon_handle h,
|
|||
goto ok;
|
||||
}
|
||||
/* xmldb_put (difflist handling) requires list keys */
|
||||
if ((ret = xml_yang_validate_list_key_only(h, xc, cbret)) < 0)
|
||||
if ((ret = xml_yang_validate_list_key_only(h, xc, &xret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
if (ret == 0){
|
||||
if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
/* Cant do this earlier since we dont have a yang spec to
|
||||
* the upper part of the tree, until we get the "config" tree.
|
||||
*/
|
||||
|
|
@ -493,6 +497,8 @@ from_client_edit_config(clicon_handle h,
|
|||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
if (xret)
|
||||
xml_free(xret);
|
||||
if (cbx)
|
||||
cbuf_free(cbx);
|
||||
clicon_debug(1, "%s done cbret:%s", __FUNCTION__, cbuf_get(cbret));
|
||||
|
|
@ -1121,6 +1127,7 @@ from_client_msg(clicon_handle h,
|
|||
yang_stmt *ye;
|
||||
yang_stmt *ymod;
|
||||
cxobj *xnacm = NULL;
|
||||
cxobj *xret = NULL;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
yspec = clicon_dbspec_yang(h);
|
||||
|
|
@ -1147,10 +1154,13 @@ from_client_msg(clicon_handle h,
|
|||
* maybe not necessary since it should be */
|
||||
if (xml_spec_populate_rpc(h, x, yspec) < 0)
|
||||
goto done;
|
||||
if ((ret = xml_yang_validate_rpc(h, x, cbret)) < 0)
|
||||
if ((ret = xml_yang_validate_rpc(h, x, &xret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
if (ret == 0){
|
||||
if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
|
||||
goto done;
|
||||
goto reply;
|
||||
}
|
||||
xe = NULL;
|
||||
username = xml_find_value(x, "username");
|
||||
/* May be used by callbacks, etc */
|
||||
|
|
@ -1222,6 +1232,8 @@ from_client_msg(clicon_handle h,
|
|||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
if (xret)
|
||||
xml_free(xret);
|
||||
if (xt)
|
||||
xml_free(xt);
|
||||
if (cbret)
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@
|
|||
* are if code comes via XML/NETCONF.
|
||||
* @param[in] yspec Yang spec
|
||||
* @param[in] td Transaction data
|
||||
* @param[out] cbret Cligen buffer containing netconf error (if retval == 0)
|
||||
* @param[out] xret Error XML tree. Free with xml_free after use
|
||||
* @retval -1 Error
|
||||
* @retval 0 Validation failed (with cbret set)
|
||||
* @retval 1 Validation OK
|
||||
|
|
@ -90,7 +90,7 @@ static int
|
|||
generic_validate(clicon_handle h,
|
||||
yang_stmt *yspec,
|
||||
transaction_data_t *td,
|
||||
cbuf *cbret)
|
||||
cxobj **xret)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *x1;
|
||||
|
|
@ -100,7 +100,7 @@ generic_validate(clicon_handle h,
|
|||
int ret;
|
||||
|
||||
/* All entries */
|
||||
if ((ret = xml_yang_validate_all_top(h, td->td_target, cbret)) < 0)
|
||||
if ((ret = xml_yang_validate_all_top(h, td->td_target, xret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
|
|
@ -109,7 +109,7 @@ generic_validate(clicon_handle h,
|
|||
x1 = td->td_scvec[i]; /* source changed */
|
||||
x2 = td->td_tcvec[i]; /* target changed */
|
||||
/* Should this be recursive? */
|
||||
if ((ret = xml_yang_validate_add(h, x2, cbret)) < 0)
|
||||
if ((ret = xml_yang_validate_add(h, x2, xret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
|
|
@ -119,7 +119,7 @@ generic_validate(clicon_handle h,
|
|||
x1 = td->td_dvec[i];
|
||||
ys = xml_spec(x1);
|
||||
if (ys && yang_mandatory(ys) && yang_config(ys)==0){
|
||||
if (netconf_missing_element(cbret, "protocol", xml_name(x1), "Missing mandatory variable") < 0)
|
||||
if (netconf_missing_element_xml(xret, "protocol", xml_name(x1), "Missing mandatory variable") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
|
|
@ -127,7 +127,7 @@ generic_validate(clicon_handle h,
|
|||
/* added entries */
|
||||
for (i=0; i<td->td_alen; i++){
|
||||
x2 = td->td_avec[i];
|
||||
if ((ret = xml_yang_validate_add(h, x2, cbret)) < 0)
|
||||
if ((ret = xml_yang_validate_add(h, x2, xret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
|
|
@ -175,6 +175,7 @@ startup_common(clicon_handle h,
|
|||
modstate_diff_t *msd = NULL;
|
||||
cxobj *xt = NULL;
|
||||
cxobj *x;
|
||||
cxobj *xret = NULL;
|
||||
|
||||
/* If CLICON_XMLDB_MODSTATE is enabled, then get the db XML with
|
||||
* potentially non-matching module-state in msd
|
||||
|
|
@ -225,11 +226,13 @@ startup_common(clicon_handle h,
|
|||
/* 5. Make generic validation on all new or changed data.
|
||||
Note this is only call that uses 3-values */
|
||||
clicon_debug(1, "Validating startup %s", db);
|
||||
if ((ret = generic_validate(h, yspec, td, cbret)) < 0)
|
||||
if ((ret = generic_validate(h, yspec, td, &xret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
if (ret == 0){
|
||||
if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
|
||||
goto done;
|
||||
goto fail; /* STARTUP_INVALID */
|
||||
|
||||
}
|
||||
/* 6. Call plugin transaction validate callbacks */
|
||||
if (plugin_transaction_validate(h, td) < 0)
|
||||
goto done;
|
||||
|
|
@ -240,6 +243,8 @@ startup_common(clicon_handle h,
|
|||
ok:
|
||||
retval = 1;
|
||||
done:
|
||||
if (xret)
|
||||
xml_free(xret);
|
||||
if (xt)
|
||||
xml_free(xt);
|
||||
if (msd)
|
||||
|
|
@ -374,6 +379,7 @@ startup_commit(clicon_handle h,
|
|||
* and call application callback validations.
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] candidate The candidate database. The wanted backend state
|
||||
* @param[out] xret Error XML tree. Free with xml_free after use
|
||||
* @retval -1 Error - or validation failed (but cbret not set)
|
||||
* @retval 0 Validation failed (with cbret set)
|
||||
* @retval 1 Validation OK
|
||||
|
|
@ -385,7 +391,7 @@ static int
|
|||
from_validate_common(clicon_handle h,
|
||||
char *candidate,
|
||||
transaction_data_t *td,
|
||||
cbuf *cbret)
|
||||
cxobj **xret)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt *yspec;
|
||||
|
|
@ -409,7 +415,7 @@ from_validate_common(clicon_handle h,
|
|||
* But xml_diff requires some basic validation, at least check that yang-specs
|
||||
* have been assigned
|
||||
*/
|
||||
if ((ret = xml_yang_validate_all_top(h, td->td_target, cbret)) < 0)
|
||||
if ((ret = xml_yang_validate_all_top(h, td->td_target, xret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
|
|
@ -462,7 +468,7 @@ from_validate_common(clicon_handle h,
|
|||
|
||||
/* 5. Make generic validation on all new or changed data.
|
||||
Note this is only call that uses 3-values */
|
||||
if ((ret = generic_validate(h, yspec, td, cbret)) < 0)
|
||||
if ((ret = generic_validate(h, yspec, td, xret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
|
|
@ -503,6 +509,7 @@ candidate_commit(clicon_handle h,
|
|||
int retval = -1;
|
||||
transaction_data_t *td = NULL;
|
||||
int ret;
|
||||
cxobj *xret = NULL;
|
||||
|
||||
/* 1. Start transaction */
|
||||
if ((td = transaction_new()) == NULL)
|
||||
|
|
@ -511,10 +518,13 @@ candidate_commit(clicon_handle h,
|
|||
/* Common steps (with validate). Load candidate and running and compute diffs
|
||||
* Note this is only call that uses 3-values
|
||||
*/
|
||||
if ((ret = from_validate_common(h, candidate, td, cbret)) < 0)
|
||||
if ((ret = from_validate_common(h, candidate, td, &xret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
if (ret == 0){
|
||||
if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* 7. Call plugin transaction commit callbacks */
|
||||
if (plugin_transaction_commit(h, td) < 0)
|
||||
|
|
@ -563,7 +573,9 @@ candidate_commit(clicon_handle h,
|
|||
xmldb_get0_free(h, &td->td_src);
|
||||
transaction_free(td);
|
||||
}
|
||||
return retval;
|
||||
if (xret)
|
||||
xml_free(xret);
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
|
|
@ -725,6 +737,7 @@ from_client_validate(clicon_handle h,
|
|||
transaction_data_t *td = NULL;
|
||||
int ret;
|
||||
char *db;
|
||||
cxobj *xret = NULL;
|
||||
|
||||
if ((db = netconf_db_find(xe, "source")) == NULL){
|
||||
if (netconf_missing_element(cbret, "protocol", "source", NULL) < 0)
|
||||
|
|
@ -737,9 +750,15 @@ from_client_validate(clicon_handle h,
|
|||
if ((td = transaction_new()) == NULL)
|
||||
goto done;
|
||||
/* Common steps (with commit) */
|
||||
if ((ret = from_validate_common(h, db, td, cbret)) < 1){
|
||||
if ((ret = from_validate_common(h, db, td, &xret)) < 1){
|
||||
/* A little complex due to several sources of validation fails or errors.
|
||||
* (1) xerr is set -> translate to cbret; (2) cbret set use that; otherwise
|
||||
* use clicon_err. */
|
||||
if (xret && clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
|
||||
goto done;
|
||||
plugin_transaction_abort(h, td);
|
||||
if (netconf_operation_failed(cbret, "application", clicon_err_reason)< 0)
|
||||
if (!cbuf_len(cbret) &&
|
||||
netconf_operation_failed(cbret, "application", clicon_err_reason)< 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -773,6 +792,8 @@ from_client_validate(clicon_handle h,
|
|||
xmldb_get0_free(h, &td->td_src);
|
||||
transaction_free(td);
|
||||
}
|
||||
if (xret)
|
||||
xml_free(xret);
|
||||
return retval;
|
||||
} /* from_client_validate */
|
||||
|
||||
|
|
|
|||
|
|
@ -642,7 +642,7 @@ main(int argc,
|
|||
switch (startup_mode){
|
||||
case SM_INIT: /* Scratch running and start from empty */
|
||||
/* [Delete and] create running db */
|
||||
if (startup_db_reset(h, "running") < 0)
|
||||
if (xmldb_db_reset(h, "running") < 0)
|
||||
goto done;
|
||||
case SM_NONE: /* Fall through *
|
||||
* Load plugins and call plugin_init() */
|
||||
|
|
|
|||
|
|
@ -70,22 +70,6 @@
|
|||
#include "backend_commit.h"
|
||||
#include "backend_startup.h"
|
||||
|
||||
/*! Create an XML database. If it exists already, delete it before creating
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] db Symbolic database name, eg "candidate", "running"
|
||||
*/
|
||||
int
|
||||
startup_db_reset(clicon_handle h,
|
||||
char *db)
|
||||
{
|
||||
if (xmldb_exists(h, db) == 1){
|
||||
if (xmldb_delete(h, db) != 0 && errno != ENOENT)
|
||||
return -1;
|
||||
}
|
||||
if (xmldb_create(h, db) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Merge db1 into db2 without commit
|
||||
* @retval -1 Error
|
||||
|
|
@ -235,34 +219,45 @@ startup_extraxml(clicon_handle h,
|
|||
cbuf *cbret)
|
||||
{
|
||||
int retval = -1;
|
||||
char *db = "tmp";
|
||||
char *tmp_db = "tmp";
|
||||
int ret;
|
||||
cxobj *xt = NULL; /* Potentially upgraded XML */
|
||||
|
||||
/* Clear tmp db */
|
||||
if (startup_db_reset(h, db) < 0)
|
||||
if (xmldb_db_reset(h, tmp_db) < 0)
|
||||
goto done;
|
||||
/* Application may define extra xml in its reset function*/
|
||||
if (clixon_plugin_reset(h, db) < 0)
|
||||
if (clixon_plugin_reset(h, tmp_db) < 0)
|
||||
goto done;
|
||||
/* Extra XML can also be added via file */
|
||||
if (file){
|
||||
/* Parse and load file into tmp db */
|
||||
if ((ret = load_extraxml(h, file, db, cbret)) < 0)
|
||||
if ((ret = load_extraxml(h, file, tmp_db, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
}
|
||||
/*
|
||||
* Check if tmp db is empty.
|
||||
* It should be empty if extra-xml is null and reset plugins did nothing
|
||||
* then skip validation.
|
||||
*/
|
||||
if (xmldb_get(h, tmp_db, NULL, &xt) < 0)
|
||||
goto done;
|
||||
if (xt==NULL || xml_child_nr(xt)==0)
|
||||
goto ok;
|
||||
xml_free(xt);
|
||||
xt = NULL;
|
||||
/* Validate the tmp db and return possibly upgraded xml in xt
|
||||
*/
|
||||
if ((ret = startup_validate(h, db, &xt, cbret)) < 0)
|
||||
if ((ret = startup_validate(h, tmp_db, &xt, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
if (xt==NULL || xml_child_nr(xt)==0)
|
||||
goto ok;
|
||||
/* Merge tmp into running (no commit) */
|
||||
if ((ret = db_merge(h, db, "running", cbret)) < 0)
|
||||
if ((ret = db_merge(h, tmp_db, "running", cbret)) < 0)
|
||||
goto fail;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
|
|
@ -270,7 +265,7 @@ startup_extraxml(clicon_handle h,
|
|||
retval = 1;
|
||||
done:
|
||||
xmldb_get0_free(h, &xt);
|
||||
if (xmldb_delete(h, db) != 0 && errno != ENOENT)
|
||||
if (xmldb_delete(h, tmp_db) != 0 && errno != ENOENT)
|
||||
return -1;
|
||||
return retval;
|
||||
fail:
|
||||
|
|
@ -306,7 +301,7 @@ startup_failsafe(clicon_handle h)
|
|||
/* Copy original running to tmp as backup (restore if error) */
|
||||
if (xmldb_copy(h, "running", "tmp") < 0)
|
||||
goto done;
|
||||
if (startup_db_reset(h, "running") < 0)
|
||||
if (xmldb_db_reset(h, "running") < 0)
|
||||
goto done;
|
||||
ret = candidate_commit(h, db, cbret);
|
||||
if (ret != 1)
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@
|
|||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
int startup_db_reset(clicon_handle h, char *db);
|
||||
int startup_mode_startup(clicon_handle h, char *db, cbuf *cbret);
|
||||
int startup_extraxml(clicon_handle h, char *file, cbuf *cbret);
|
||||
int startup_failsafe(clicon_handle h);
|
||||
|
|
|
|||
|
|
@ -283,6 +283,7 @@ main(int argc, char **argv)
|
|||
yang_stmt *yspecfg = NULL; /* For config XXX clixon bug */
|
||||
struct passwd *pw;
|
||||
char *str;
|
||||
int tabmode;
|
||||
|
||||
/* Defaults */
|
||||
once = 0;
|
||||
|
|
@ -542,7 +543,11 @@ main(int argc, char **argv)
|
|||
clicon_log(LOG_WARNING, "No such cli mode: %s (Specify cli mode with CLICON_CLI_MODE in config file or -m <mode> on command line", cli_syntax_mode(h));
|
||||
|
||||
/* CLIgen tab mode, ie how <tab>s behave */
|
||||
cligen_tabmode_set(cli_cligen(h), clicon_cli_tab_mode(h));
|
||||
if ((tabmode = clicon_cli_tab_mode(h)) < 0){
|
||||
fprintf(stderr, "FATAL: CLICON_CLI_TAB_MODE not set\n");
|
||||
goto done;
|
||||
}
|
||||
cligen_tabmode_set(cli_cligen(h), tabmode);
|
||||
|
||||
if (logclisyntax)
|
||||
cli_logsyntax_set(h, logclisyntax);
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ static int ignore_packet_errors = 1;
|
|||
*/
|
||||
static int
|
||||
netconf_input_packet(clicon_handle h,
|
||||
cbuf *cb)
|
||||
cbuf *cb)
|
||||
{
|
||||
int retval = -1;
|
||||
char *str;
|
||||
|
|
@ -125,9 +125,10 @@ netconf_input_packet(clicon_handle h,
|
|||
isrpc++;
|
||||
if (xml_spec_populate_rpc(h, xrpc, yspec) < 0)
|
||||
goto done;
|
||||
if ((ret = xml_yang_validate_rpc(h, xrpc, cbret)) < 0)
|
||||
if ((ret = xml_yang_validate_rpc(h, xrpc, &xret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
clicon_xml2cbuf(cbret, xret, 0, 0);
|
||||
netconf_output_encap(1, cbret, "rpc-error");
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -155,7 +156,7 @@ netconf_input_packet(clicon_handle h,
|
|||
netconf_output_encap(1, cbret, "rpc-error");
|
||||
goto done;
|
||||
}
|
||||
if ((xc = xml_child_i(xret,0))!=NULL){
|
||||
if ((xc = xml_child_i(xret, 0))!=NULL){
|
||||
xa=NULL;
|
||||
/* Copy message-id attribute from incoming to reply.
|
||||
* RFC 6241:
|
||||
|
|
|
|||
|
|
@ -547,6 +547,7 @@ netconf_application_rpc(clicon_handle h,
|
|||
yang_stmt *yinput;
|
||||
yang_stmt *youtput;
|
||||
cxobj *xoutput;
|
||||
cxobj *xerr = NULL;
|
||||
cbuf *cb = NULL;
|
||||
cbuf *cbret = NULL;
|
||||
int ret;
|
||||
|
|
@ -587,15 +588,13 @@ netconf_application_rpc(clicon_handle h,
|
|||
xml_spec_set(xn, yinput); /* needed for xml_spec_populate */
|
||||
if (xml_apply(xn, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
||||
goto done;
|
||||
if ((ret = xml_yang_validate_all_top(h, xn, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
netconf_output_encap(1, cbret, "rpc-error");
|
||||
goto ok;
|
||||
}
|
||||
if ((ret = xml_yang_validate_add(h, xn, cbret)) < 0)
|
||||
if ((ret = xml_yang_validate_all_top(h, xn, &xerr)) < 0)
|
||||
goto done;
|
||||
if (ret > 0 && (ret = xml_yang_validate_add(h, xn, &xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
if (clicon_xml2cbuf(cbret, xerr, 0, 0) < 0)
|
||||
goto done;
|
||||
netconf_output_encap(1, cbret, "rpc-error");
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -622,15 +621,13 @@ netconf_application_rpc(clicon_handle h,
|
|||
if (xml_apply(xoutput, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
||||
goto done;
|
||||
|
||||
if ((ret = xml_yang_validate_all_top(h, xoutput, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
clicon_log(LOG_WARNING, "Errors in output netconf %s", cbuf_get(cbret));
|
||||
goto ok;
|
||||
}
|
||||
if ((ret = xml_yang_validate_add(h, xoutput, cbret)) < 0)
|
||||
if ((ret = xml_yang_validate_all_top(h, xoutput, &xerr)) < 0)
|
||||
goto done;
|
||||
if (ret > 0 && (ret = xml_yang_validate_add(h, xoutput, &xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
if (clicon_xml2cbuf(cbret, xerr, 0, 0) < 0)
|
||||
goto done;
|
||||
clicon_log(LOG_WARNING, "Errors in output netconf %s", cbuf_get(cbret));
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -641,6 +638,8 @@ netconf_application_rpc(clicon_handle h,
|
|||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
if (xerr)
|
||||
xml_free(xerr);
|
||||
if (cb)
|
||||
cbuf_free(cb);
|
||||
if (cbret)
|
||||
|
|
|
|||
|
|
@ -437,13 +437,17 @@ api_data_post(clicon_handle h,
|
|||
{
|
||||
int retval = -1;
|
||||
enum operation_type op = OP_CREATE;
|
||||
cxobj *xdata0 = NULL; /* Original -d data struct (including top symbol) */
|
||||
cxobj *xdata; /* -d data (without top symbol)*/
|
||||
int i;
|
||||
cxobj *xdata = NULL;
|
||||
cbuf *cbx = NULL;
|
||||
cxobj *xtop = NULL; /* xpath root */
|
||||
cxobj *xbot = NULL;
|
||||
cxobj *x;
|
||||
yang_stmt *y = NULL;
|
||||
cxobj *xtop = NULL; /* top of api-path */
|
||||
cxobj *xbot = NULL; /* bottom of api-path */
|
||||
yang_stmt *ybot = NULL; /* yang of xbot */
|
||||
#ifdef RESTCONF_NS_DATA_CHECK
|
||||
yang_stmt *ymodapi = NULL; /* yang module of api-path (if any) */
|
||||
yang_stmt *ymoddata = NULL; /* yang module of data (-d) */
|
||||
#endif
|
||||
yang_stmt *yspec;
|
||||
cxobj *xa;
|
||||
cxobj *xret = NULL;
|
||||
|
|
@ -469,8 +473,12 @@ api_data_post(clicon_handle h,
|
|||
/* Translate api_path to xtop/xbot */
|
||||
xbot = xtop;
|
||||
if (api_path){
|
||||
if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, &y)) < 0)
|
||||
if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, &ybot)) < 0)
|
||||
goto done;
|
||||
#ifdef RESTCONF_NS_DATA_CHECK
|
||||
if (ybot)
|
||||
ymodapi=ys_module(ybot);
|
||||
#endif
|
||||
if (ret == 0){ /* validation failed */
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
|
|
@ -486,7 +494,7 @@ api_data_post(clicon_handle h,
|
|||
}
|
||||
/* Parse input data as json or xml into xml */
|
||||
if (parse_xml){
|
||||
if (xml_parse_string(data, NULL, &xdata) < 0){
|
||||
if (xml_parse_string(data, NULL, &xdata0) < 0){
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
|
|
@ -499,7 +507,7 @@ api_data_post(clicon_handle h,
|
|||
}
|
||||
}
|
||||
else {
|
||||
if ((ret = json_parse_str(data, yspec, &xdata, &xerr)) < 0){
|
||||
if ((ret = json_parse_str(data, yspec, &xdata0, &xerr)) < 0){
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
|
|
@ -523,7 +531,7 @@ api_data_post(clicon_handle h,
|
|||
/* 4.4.1: The message-body MUST contain exactly one instance of the
|
||||
* expected data resource.
|
||||
*/
|
||||
if (xml_child_nr(xdata) != 1){
|
||||
if (xml_child_nr(xdata0) != 1){
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
|
|
@ -534,15 +542,46 @@ api_data_post(clicon_handle h,
|
|||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
x = xml_child_i(xdata,0);
|
||||
xdata = xml_child_i(xdata0,0);
|
||||
#ifdef RESTCONF_NS_DATA_CHECK
|
||||
/* If the api-path (above) defines a module, then xdata must have a prefix
|
||||
* and it match the module defined in api-path.
|
||||
* In a POST, maybe there are cornercases where xdata (which is a child) and
|
||||
* xbot (which is the parent) may have non-matching namespaces?
|
||||
* This does not apply if api-path is / (no module)
|
||||
*/
|
||||
if (ys_module_by_xml(yspec, xdata, &ymoddata) < 0)
|
||||
goto done;
|
||||
if (ymoddata && ymodapi){
|
||||
if (ymoddata != ymodapi){
|
||||
if (netconf_malformed_message_xml(&xerr, "Data is not prefixed with matching namespace") < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
if (debug){
|
||||
cbuf *ccc=cbuf_new();
|
||||
if (clicon_xml2cbuf(ccc, xe, 0, 0) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s XE:%s", __FUNCTION__, cbuf_get(ccc));
|
||||
}
|
||||
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
}
|
||||
#endif /* RESTCONF_NS_DATA_CHECK */
|
||||
|
||||
/* Add operation (create/replace) as attribute */
|
||||
if ((xa = xml_new("operation", x, NULL)) == NULL)
|
||||
if ((xa = xml_new("operation", xdata, NULL)) == NULL)
|
||||
goto done;
|
||||
xml_type_set(xa, CX_ATTR);
|
||||
if (xml_value_set(xa, xml_operation2str(op)) < 0)
|
||||
goto done;
|
||||
/* Replace xbot with x, ie bottom of api-path with data */
|
||||
if (xml_addsub(xbot, x) < 0)
|
||||
if (xml_addsub(xbot, xdata) < 0)
|
||||
goto done;
|
||||
/* Create text buffer for transfer to backend */
|
||||
if ((cbx = cbuf_new()) == NULL)
|
||||
|
|
@ -626,8 +665,8 @@ api_data_post(clicon_handle h,
|
|||
xml_free(xretdis);
|
||||
if (xtop)
|
||||
xml_free(xtop);
|
||||
if (xdata)
|
||||
xml_free(xdata);
|
||||
if (xdata0)
|
||||
xml_free(xdata0);
|
||||
if (cbx)
|
||||
cbuf_free(cbx);
|
||||
return retval;
|
||||
|
|
@ -636,11 +675,14 @@ api_data_post(clicon_handle h,
|
|||
|
||||
/*! Check matching keys
|
||||
*
|
||||
* Check that x1 and x2 are of type list/leaf-list and share the same key statements
|
||||
* I.e that if x1=<list><key>b</key></list> then x2 = <list><key>b</key></list> as
|
||||
* well. Otherwise return -1.
|
||||
* @param[in] y Yang statement, should be list or leaf-list
|
||||
* @param[in] xdata XML data tree
|
||||
* @param[in] xapipath XML api-path tree
|
||||
* @param[in] x1 First XML tree (eg data)
|
||||
* @param[in] x2 Second XML tree (eg api-path)
|
||||
* @retval 0 Yes, keys match
|
||||
* @retval -1 No keys do not match
|
||||
* @retval -1 No, keys do not match
|
||||
* If the target resource represents a YANG leaf-list, then the PUT
|
||||
* method MUST NOT change the value of the leaf-list instance.
|
||||
*
|
||||
|
|
@ -651,17 +693,17 @@ api_data_post(clicon_handle h,
|
|||
*/
|
||||
static int
|
||||
match_list_keys(yang_stmt *y,
|
||||
cxobj *xdata,
|
||||
cxobj *xapipath)
|
||||
cxobj *x1,
|
||||
cxobj *x2)
|
||||
{
|
||||
int retval = -1;
|
||||
cvec *cvk = NULL; /* vector of index keys */
|
||||
cg_var *cvi;
|
||||
char *keyname;
|
||||
cxobj *xkeya; /* xml key object in api-path */
|
||||
cxobj *xkeyd; /* xml key object in data */
|
||||
char *keya;
|
||||
char *keyd;
|
||||
cxobj *xkey1; /* xml key object of x1 */
|
||||
cxobj *xkey2; /* xml key object of x2 */
|
||||
char *key1;
|
||||
char *key2;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
switch (yang_keyword_get(y)){
|
||||
|
|
@ -670,29 +712,30 @@ match_list_keys(yang_stmt *y,
|
|||
cvi = NULL;
|
||||
while ((cvi = cvec_each(cvk, cvi)) != NULL) {
|
||||
keyname = cv_string_get(cvi);
|
||||
if ((xkeya = xml_find(xapipath, keyname)) == NULL)
|
||||
if ((xkey2 = xml_find(x2, keyname)) == NULL)
|
||||
goto done; /* No key in api-path */
|
||||
if ((keya = xml_body(xkeya)) == NULL)
|
||||
if ((key2 = xml_body(xkey2)) == NULL)
|
||||
goto done;
|
||||
if ((xkeyd = xml_find(xdata, keyname)) == NULL)
|
||||
if ((xkey1 = xml_find(x1, keyname)) == NULL)
|
||||
goto done; /* No key in data */
|
||||
if ((keyd = xml_body(xkeyd)) == NULL)
|
||||
if ((key1 = xml_body(xkey1)) == NULL)
|
||||
goto done;
|
||||
if (strcmp(keya, keyd) != 0)
|
||||
if (strcmp(key2, key1) != 0)
|
||||
goto done; /* keys dont match */
|
||||
}
|
||||
break;
|
||||
case Y_LEAF_LIST:
|
||||
if ((keya = xml_body(xapipath)) == NULL)
|
||||
if ((key2 = xml_body(x2)) == NULL)
|
||||
goto done; /* No key in api-path */
|
||||
if ((keyd = xml_body(xdata)) == NULL)
|
||||
if ((key1 = xml_body(x1)) == NULL)
|
||||
goto done; /* No key in data */
|
||||
if (strcmp(keya, keyd) != 0)
|
||||
if (strcmp(key2, key1) != 0)
|
||||
goto done; /* keys dont match */
|
||||
break;
|
||||
default:
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
|
|
@ -738,13 +781,17 @@ api_data_put(clicon_handle h,
|
|||
int retval = -1;
|
||||
enum operation_type op = OP_REPLACE;
|
||||
int i;
|
||||
cxobj *xdata = NULL;
|
||||
cxobj *xdata0 = NULL; /* Original -d data struct (including top symbol) */
|
||||
cxobj *xdata; /* -d data (without top symbol)*/
|
||||
cbuf *cbx = NULL;
|
||||
cxobj *xtop = NULL; /* xpath root */
|
||||
cxobj *xbot = NULL;
|
||||
cxobj *xtop = NULL; /* top of api-path */
|
||||
cxobj *xbot = NULL; /* bottom of api-path */
|
||||
yang_stmt *ybot = NULL; /* yang of xbot */
|
||||
#ifdef RESTCONF_NS_DATA_CHECK
|
||||
yang_stmt *ymodapi = NULL; /* yang module of api-path (if any) */
|
||||
yang_stmt *ymoddata = NULL; /* yang module of data (-d) */
|
||||
#endif
|
||||
cxobj *xparent;
|
||||
cxobj *x;
|
||||
yang_stmt *y = NULL;
|
||||
yang_stmt *yp; /* yang parent */
|
||||
yang_stmt *yspec;
|
||||
cxobj *xa;
|
||||
|
|
@ -757,6 +804,7 @@ api_data_put(clicon_handle h,
|
|||
char *username;
|
||||
int ret;
|
||||
char *namespace0;
|
||||
char *dname;
|
||||
|
||||
clicon_debug(1, "%s api_path:\"%s\" json:\"%s\"",
|
||||
__FUNCTION__, api_path0, data);
|
||||
|
|
@ -773,8 +821,12 @@ api_data_put(clicon_handle h,
|
|||
/* Translate api_path to xtop/xbot */
|
||||
xbot = xtop;
|
||||
if (api_path){
|
||||
if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, &y)) < 0)
|
||||
if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, &ybot)) < 0)
|
||||
goto done;
|
||||
#ifdef RESTCONF_NS_DATA_CHECK
|
||||
if (ybot)
|
||||
ymodapi=ys_module(ybot);
|
||||
#endif
|
||||
if (ret == 0){ /* validation failed */
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
|
|
@ -788,9 +840,10 @@ api_data_put(clicon_handle h,
|
|||
goto ok;
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse input data as json or xml into xml */
|
||||
if (parse_xml){
|
||||
if (xml_parse_string(data, NULL, &xdata) < 0){
|
||||
if (xml_parse_string(data, yspec, &xdata0) < 0){
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
|
|
@ -803,7 +856,7 @@ api_data_put(clicon_handle h,
|
|||
}
|
||||
}
|
||||
else{
|
||||
if ((ret = json_parse_str(data, yspec, &xdata, &xerr)) < 0){
|
||||
if ((ret = json_parse_str(data, yspec, &xdata0, &xerr)) < 0){
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
|
|
@ -827,7 +880,7 @@ api_data_put(clicon_handle h,
|
|||
/* The message-body MUST contain exactly one instance of the
|
||||
* expected data resource.
|
||||
*/
|
||||
if (xml_child_nr(xdata) != 1){
|
||||
if (xml_child_nr(xdata0) != 1){
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
|
|
@ -838,34 +891,56 @@ api_data_put(clicon_handle h,
|
|||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
x = xml_child_i(xdata,0);
|
||||
xdata = xml_child_i(xdata0,0);
|
||||
#ifdef RESTCONF_NS_DATA_CHECK
|
||||
/* If the api-path (above) defines a module, then xdata must have a prefix
|
||||
* and it match the module defined in api-path
|
||||
* This does not apply if api-path is / (no module)
|
||||
*/
|
||||
if (ys_module_by_xml(yspec, xdata, &ymoddata) < 0)
|
||||
goto done;
|
||||
if (ymoddata && ymodapi){
|
||||
if (ymoddata != ymodapi){
|
||||
if (netconf_malformed_message_xml(&xerr, "Data is not prefixed with matching namespace") < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
}
|
||||
#endif /* RESTCONF_NS_DATA_CHECK */
|
||||
|
||||
/* Add operation (create/replace) as attribute */
|
||||
if ((xa = xml_new("operation", x, NULL)) == NULL)
|
||||
if ((xa = xml_new("operation", xdata, NULL)) == NULL)
|
||||
goto done;
|
||||
xml_type_set(xa, CX_ATTR);
|
||||
if (xml_value_set(xa, xml_operation2str(op)) < 0)
|
||||
goto done;
|
||||
#if 0
|
||||
if (debug){
|
||||
cbuf *ccc=cbuf_new();
|
||||
if (clicon_xml2cbuf(ccc, xdata, 0, 0) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s DATA:%s", __FUNCTION__, cbuf_get(ccc));
|
||||
}
|
||||
#endif
|
||||
/* Replace xparent with x, ie bottom of api-path with data */
|
||||
if (api_path==NULL && strcmp(xml_name(x),"data")==0){
|
||||
if (xml_addsub(NULL, x) < 0)
|
||||
|
||||
/* Top-of tree, no api-path
|
||||
* Replace xparent with x, ie bottom of api-path with data
|
||||
*/
|
||||
dname = xml_name(xdata);
|
||||
if (api_path==NULL && strcmp(dname,"data")==0){
|
||||
if (xml_addsub(NULL, xdata) < 0)
|
||||
goto done;
|
||||
if (xtop)
|
||||
xml_free(xtop);
|
||||
xtop = x;
|
||||
xtop = xdata;
|
||||
xml_name_set(xtop, "config");
|
||||
}
|
||||
else {
|
||||
clicon_debug(1, "%s x:%s xbot:%s",__FUNCTION__, xml_name(x), xml_name(xbot));
|
||||
/* There is an api-path that defines an element in the datastore tree.
|
||||
* Not top-of-tree.
|
||||
*/
|
||||
clicon_debug(1, "%s x:%s xbot:%s",__FUNCTION__, dname, xml_name(xbot));
|
||||
|
||||
/* Check same symbol in api-path as data */
|
||||
if (strcmp(xml_name(x), xml_name(xbot))){
|
||||
if (strcmp(dname, xml_name(xbot))){
|
||||
if (netconf_operation_failed_xml(&xerr, "protocol", "Not same symbol in api-path as data") < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
|
|
@ -884,27 +959,13 @@ api_data_put(clicon_handle h,
|
|||
* That is why the conditional is somewhat hairy
|
||||
*/
|
||||
xparent = xml_parent(xbot);
|
||||
#if 1
|
||||
if (debug){
|
||||
cbuf *ccc=cbuf_new();
|
||||
if (clicon_xml2cbuf(ccc, xtop, 0, 0) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s AAA XPATH:%s", __FUNCTION__, cbuf_get(ccc));
|
||||
}
|
||||
if (debug){
|
||||
cbuf *ccc=cbuf_new();
|
||||
if (clicon_xml2cbuf(ccc, xdata, 0, 0) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s DATA:%s", __FUNCTION__, cbuf_get(ccc));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (y){
|
||||
yp = yang_parent_get(y);
|
||||
if (((yang_keyword_get(y) == Y_LIST || yang_keyword_get(y) == Y_LEAF_LIST) &&
|
||||
match_list_keys(y, x, xbot) < 0) ||
|
||||
(yp && yang_keyword_get(yp) == Y_LIST &&
|
||||
match_list_keys(yp, xml_parent(x), xparent) < 0)){
|
||||
if (ybot){
|
||||
/* Ensure list keys match between uri and data. That is:
|
||||
* If data is on the form: -d {"a":{"k":1}} where a is list or leaf-list
|
||||
* then uri-path must be ../a=1
|
||||
* match_list_key() checks if this is true
|
||||
*/
|
||||
if (match_list_keys(ybot, xdata, xbot) < 0){
|
||||
if (netconf_operation_failed_xml(&xerr, "protocol", "api-path keys do not match data keys") < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
|
|
@ -914,15 +975,40 @@ api_data_put(clicon_handle h,
|
|||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
|
||||
}
|
||||
/* Ensure keys in lists are not changed. That is:
|
||||
* If data is on the form: -d {"k":1} and its parent is a list "a"
|
||||
* then the uri-path must be "../a=1 (you cannot change a's key)"
|
||||
*/
|
||||
if ((yp = yang_parent_get(ybot)) != NULL &&
|
||||
yang_keyword_get(yp) == Y_LIST){
|
||||
if ((ret = yang_key_match(yp, dname)) < 0)
|
||||
goto done;
|
||||
if (ret == 1){ /* Match: xdata is a key */
|
||||
char *parbod = xml_find_body(xparent, dname);
|
||||
/* Check if the key is different from the one in uri-path,
|
||||
* or does not exist
|
||||
*/
|
||||
if (parbod == NULL || strcmp(parbod, xml_body(xdata))){
|
||||
if (netconf_operation_failed_xml(&xerr, "protocol", "api-path keys do not match data keys") < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xml_purge(xbot);
|
||||
if (xml_addsub(xparent, x) < 0)
|
||||
if (xml_addsub(xparent, xdata) < 0)
|
||||
goto done;
|
||||
/* If we already have that default namespace, remove it in child */
|
||||
if ((xa = xml_find_type(x, NULL, "xmlns", CX_ATTR)) != NULL){
|
||||
if ((xa = xml_find_type(xdata, NULL, "xmlns", CX_ATTR)) != NULL){
|
||||
if (xml2ns(xparent, NULL, &namespace0) < 0)
|
||||
goto done;
|
||||
/* Set xmlns="" default namespace attribute (if diff from default) */
|
||||
|
|
@ -945,6 +1031,7 @@ api_data_put(clicon_handle h,
|
|||
clicon_debug(1, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path);
|
||||
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0)
|
||||
goto done;
|
||||
|
||||
if ((xe = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
|
|
@ -1010,8 +1097,8 @@ api_data_put(clicon_handle h,
|
|||
xml_free(xretdis);
|
||||
if (xtop)
|
||||
xml_free(xtop);
|
||||
if (xdata)
|
||||
xml_free(xdata);
|
||||
if (xdata0)
|
||||
xml_free(xdata0);
|
||||
if (cbx)
|
||||
cbuf_free(cbx);
|
||||
return retval;
|
||||
|
|
@ -1454,14 +1541,9 @@ api_operations_post_output(clicon_handle h,
|
|||
cxobj *xa; /* xml attribute (xmlns) */
|
||||
cxobj *x;
|
||||
cxobj *xok;
|
||||
cbuf *cbret = NULL;
|
||||
int isempty;
|
||||
|
||||
// clicon_debug(1, "%s", __FUNCTION__);
|
||||
if ((cbret = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, 0, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
/* Validate that exactly only <rpc-reply> tag */
|
||||
if ((xoutput = xml_child_i_type(xret, 0, CX_ELMNT)) == NULL ||
|
||||
strcmp(xml_name(xoutput),"rpc-reply") != 0 ||
|
||||
|
|
@ -1499,14 +1581,12 @@ api_operations_post_output(clicon_handle h,
|
|||
#if 0
|
||||
if (xml_apply(xoutput, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
||||
goto done;
|
||||
if ((ret = xml_yang_validate_all(xoutput, cbret)) < 0)
|
||||
if ((ret = xml_yang_validate_all(xoutput, &xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 1 &&
|
||||
(ret = xml_yang_validate_add(h, xoutput, cbret)) < 0)
|
||||
(ret = xml_yang_validate_add(h, xoutput, &xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){ /* validation failed */
|
||||
if (xml_parse_string(cbuf_get(cbret), yspec, &xerr) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-reply/rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
|
|
@ -1551,8 +1631,6 @@ api_operations_post_output(clicon_handle h,
|
|||
retval = 1;
|
||||
done:
|
||||
clicon_debug(1, "%s retval: %d", __FUNCTION__, retval);
|
||||
if (cbret)
|
||||
cbuf_free(cbret);
|
||||
if (xerr)
|
||||
xml_free(xerr);
|
||||
return retval;
|
||||
|
|
@ -1738,14 +1816,12 @@ api_operations_post(clicon_handle h,
|
|||
/* 6. Validate incoming RPC and fill in defaults */
|
||||
if (xml_spec_populate_rpc(h, xtop, yspec) < 0) /* */
|
||||
goto done;
|
||||
if ((ret = xml_yang_validate_rpc(h, xtop, cbret)) < 0)
|
||||
if ((ret = xml_yang_validate_rpc(h, xtop, &xret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
if (xml_parse_string(cbuf_get(cbret), NULL, &xret) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xret, "rpc-reply/rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xret, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue