* 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:
parent
03e618b1e5
commit
f872c7e295
45 changed files with 807 additions and 405 deletions
|
|
@ -468,12 +468,12 @@ from_client_edit_config(clicon_handle h,
|
|||
}
|
||||
}
|
||||
if ((xc = xpath_first(xn, "config")) == NULL){
|
||||
if (netconf_missing_element(cbret, "protocol", "<bad-element>config</bad-element>", NULL) < 0)
|
||||
if (netconf_missing_element(cbret, "protocol", "config", NULL) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
else{
|
||||
/* <config> yang spec may be set to anyxml by ingress yang check,...*/
|
||||
/* <config> yang spec may be set to anyxmly by ingress yang check,...*/
|
||||
if (xml_spec(xc) != NULL)
|
||||
xml_spec_set(xc, NULL);
|
||||
/* Populate XML with Yang spec (why not do this in parser?)
|
||||
|
|
@ -530,7 +530,7 @@ from_client_lock(clicon_handle h,
|
|||
cbuf *cbx = NULL; /* Assist cbuf */
|
||||
|
||||
if ((db = netconf_db_find(xe, "target")) == NULL){
|
||||
if (netconf_missing_element(cbret, "protocol", "<bad-element>target</bad-element>", NULL) < 0)
|
||||
if (netconf_missing_element(cbret, "protocol", "target", NULL) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -589,7 +589,7 @@ from_client_unlock(clicon_handle h,
|
|||
cbuf *cbx = NULL; /* Assist cbuf */
|
||||
|
||||
if ((db = netconf_db_find(xe, "target")) == NULL){
|
||||
if (netconf_missing_element(cbret, "protocol", "<bad-element>target</bad-element>", NULL) < 0)
|
||||
if (netconf_missing_element(cbret, "protocol", "target", NULL) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -651,7 +651,7 @@ from_client_kill_session(clicon_handle h,
|
|||
|
||||
if ((x = xml_find(xe, "session-id")) == NULL ||
|
||||
(str = xml_find_value(x, "body")) == NULL){
|
||||
if (netconf_missing_element(cbret, "protocol", "<bad-element>session-id</bad-element>", NULL) < 0)
|
||||
if (netconf_missing_element(cbret, "protocol", "session-id", NULL) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -709,7 +709,7 @@ from_client_copy_config(clicon_handle h,
|
|||
cbuf *cbx = NULL; /* Assist cbuf */
|
||||
|
||||
if ((source = netconf_db_find(xe, "source")) == NULL){
|
||||
if (netconf_missing_element(cbret, "protocol", "<bad-element>source</bad-element>", NULL) < 0)
|
||||
if (netconf_missing_element(cbret, "protocol", "source", NULL) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -724,7 +724,7 @@ from_client_copy_config(clicon_handle h,
|
|||
goto ok;
|
||||
}
|
||||
if ((target = netconf_db_find(xe, "target")) == NULL){
|
||||
if (netconf_missing_element(cbret, "protocol", "<bad-element>target</bad-element>", NULL) < 0)
|
||||
if (netconf_missing_element(cbret, "protocol", "target", NULL) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -777,7 +777,7 @@ from_client_delete_config(clicon_handle h,
|
|||
|
||||
if ((target = netconf_db_find(xe, "target")) == NULL||
|
||||
strcmp(target, "running")==0){
|
||||
if (netconf_missing_element(cbret, "protocol", "<bad-element>target</bad-element>", NULL) < 0)
|
||||
if (netconf_missing_element(cbret, "protocol", "target", NULL) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -856,7 +856,7 @@ from_client_create_subscription(clicon_handle h,
|
|||
if ((x = xpath_first(xe, "//stopTime")) != NULL){
|
||||
if ((stoptime = xml_find_value(x, "body")) != NULL &&
|
||||
str2time(stoptime, &stop) < 0){
|
||||
if (netconf_bad_element(cbret, "application", "<bad-element>stopTime</bad-element>", "Expected timestamp") < 0)
|
||||
if (netconf_bad_element(cbret, "application", "stopTime", "Expected timestamp") < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -864,7 +864,7 @@ from_client_create_subscription(clicon_handle h,
|
|||
if ((x = xpath_first(xe, "//startTime")) != NULL){
|
||||
if ((starttime = xml_find_value(x, "body")) != NULL &&
|
||||
str2time(starttime, &start) < 0){
|
||||
if (netconf_bad_element(cbret, "application", "<bad-element>startTime</bad-element>", "Expected timestamp") < 0)
|
||||
if (netconf_bad_element(cbret, "application", "startTime", "Expected timestamp") < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -925,7 +925,7 @@ from_client_debug(clicon_handle h,
|
|||
char *valstr;
|
||||
|
||||
if ((valstr = xml_find_body(xe, "level")) == NULL){
|
||||
if (netconf_missing_element(cbret, "application", "<bad-element>level</bad-element>", NULL) < 0)
|
||||
if (netconf_missing_element(cbret, "application", "level", NULL) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -993,13 +993,10 @@ from_client_msg(clicon_handle h,
|
|||
/* Populate incoming XML tree with yang */
|
||||
if (xml_spec_populate_rpc(h, x, yspec) < 0)
|
||||
goto done;
|
||||
if ((ret = xml_yang_validate_rpc(x)) < 0)
|
||||
if ((ret = xml_yang_validate_rpc(x, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
if (netconf_operation_failed(cbret, "application", "Validation failed")< 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto reply;
|
||||
}
|
||||
xe = NULL;
|
||||
username = xml_find_value(x, "username");
|
||||
while ((xe = xml_child_each(x, xe, CX_ELMNT)) != NULL) {
|
||||
|
|
@ -1059,7 +1056,7 @@ from_client_msg(clicon_handle h,
|
|||
}
|
||||
else if (strcmp(rpc, "validate") == 0){
|
||||
if ((db = netconf_db_find(xe, "source")) == NULL){
|
||||
if (netconf_missing_element(cbret, "protocol", "<bad-element>source</bad-element>", NULL) < 0)
|
||||
if (netconf_missing_element(cbret, "protocol", "source", NULL) < 0)
|
||||
goto done;
|
||||
goto reply;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,68 +81,86 @@
|
|||
* 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)
|
||||
* @retval -1 Error
|
||||
* @retval 0 Validation failed (with cbret set)
|
||||
* @retval 1 Validation OK
|
||||
*/
|
||||
static int
|
||||
generic_validate(yang_spec *yspec,
|
||||
transaction_data_t *td)
|
||||
transaction_data_t *td,
|
||||
cbuf *cbret)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *x1;
|
||||
cxobj *x2;
|
||||
yang_stmt *ys;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
/* All entries */
|
||||
if (xml_apply(td->td_target, CX_ELMNT,
|
||||
(xml_applyfn_t*)xml_yang_validate_all, NULL) < 0)
|
||||
if ((ret = xml_yang_validate_all_top(td->td_target, cbret)) < 0)
|
||||
goto done;
|
||||
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
/* changed entries */
|
||||
for (i=0; i<td->td_clen; i++){
|
||||
x1 = td->td_scvec[i]; /* source changed */
|
||||
x2 = td->td_tcvec[i]; /* target changed */
|
||||
if (xml_yang_validate_add(x2, NULL) < 0)
|
||||
/* Should this be recursive? */
|
||||
if ((ret = xml_yang_validate_add(x2, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
}
|
||||
/* deleted entries */
|
||||
for (i=0; i<td->td_dlen; i++){
|
||||
x1 = td->td_dvec[i];
|
||||
ys = xml_spec(x1);
|
||||
if (ys && yang_mandatory(ys)){
|
||||
clicon_err(OE_CFG, 0,"Removed mandatory variable: %s",
|
||||
xml_name(x1));
|
||||
goto done;
|
||||
if (netconf_missing_element(cbret, "protocol", xml_name(x1), "Removed mandatory variable") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
/* added entries */
|
||||
for (i=0; i<td->td_alen; i++){
|
||||
x2 = td->td_avec[i];
|
||||
if (xml_apply0(x2, CX_ELMNT,
|
||||
(xml_applyfn_t*)xml_yang_validate_add, NULL) < 0)
|
||||
if ((ret = xml_yang_validate_add(x2, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
}
|
||||
retval = 0;
|
||||
// ok:
|
||||
retval = 1;
|
||||
done:
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Common code of candidate_validate and candidate_commit
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] candidate The candidate database. The wanted backend state
|
||||
* @retval 0 OK
|
||||
* @retval -1 Fatal error or validation fail
|
||||
* @note Need to differentiate between error and validation fail
|
||||
* @retval -1 Error - or validation failed (but cbret not set)
|
||||
* @retval 0 Validation failed (with cbret set)
|
||||
* @retval 1 Validation OK
|
||||
* @note Need to differentiate between error and validation fail
|
||||
* (only done for generic_validate)
|
||||
*/
|
||||
static int
|
||||
validate_common(clicon_handle h,
|
||||
char *candidate,
|
||||
transaction_data_t *td)
|
||||
transaction_data_t *td,
|
||||
cbuf *cbret)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_spec *yspec;
|
||||
int i;
|
||||
cxobj *xn;
|
||||
|
||||
int ret;
|
||||
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||
goto done;
|
||||
|
|
@ -193,9 +211,12 @@ validate_common(clicon_handle h,
|
|||
if (plugin_transaction_begin(h, td) < 0)
|
||||
goto done;
|
||||
|
||||
/* 5. Make generic validation on all new or changed data. */
|
||||
if (generic_validate(yspec, td) < 0)
|
||||
/* 5. Make generic validation on all new or changed data.
|
||||
Note this is only call that uses 3-values */
|
||||
if ((ret = generic_validate(yspec, td, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
|
||||
/* 6. Call plugin transaction validate callbacks */
|
||||
if (plugin_transaction_validate(h, td) < 0)
|
||||
|
|
@ -204,9 +225,12 @@ validate_common(clicon_handle h,
|
|||
/* 7. Call plugin transaction complete callbacks */
|
||||
if (plugin_transaction_complete(h, td) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
retval = 1;
|
||||
done:
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Do a diff between candidate and running, then start a commit transaction
|
||||
|
|
@ -216,24 +240,30 @@ validate_common(clicon_handle h,
|
|||
* do something more drastic?
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] candidate A candidate database, not necessarily "candidate"
|
||||
* @retval 0 OK
|
||||
* @retval -1 Fatal error or validation fail
|
||||
* @retval -1 Error - or validation failed (but cbret not set)
|
||||
* @retval 0 Validation failed (with cbret set)
|
||||
* @retval 1 Validation OK
|
||||
* @note Need to differentiate between error and validation fail
|
||||
* (only done for validate_common)
|
||||
*/
|
||||
int
|
||||
candidate_commit(clicon_handle h,
|
||||
char *candidate)
|
||||
char *candidate,
|
||||
cbuf *cbret)
|
||||
{
|
||||
int retval = -1;
|
||||
int retval = -1;
|
||||
transaction_data_t *td = NULL;
|
||||
int ret;
|
||||
|
||||
/* 1. Start transaction */
|
||||
if ((td = transaction_new()) == NULL)
|
||||
goto done;
|
||||
|
||||
/* Common steps (with validate) */
|
||||
if (validate_common(h, candidate, td) < 0)
|
||||
/* Common steps (with validate). Note this is only call that uses 3-values */
|
||||
if ((ret = validate_common(h, candidate, td, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
|
||||
/* 7. Call plugin transaction commit callbacks */
|
||||
if (plugin_transaction_commit(h, td) < 0)
|
||||
|
|
@ -252,21 +282,23 @@ candidate_commit(clicon_handle h,
|
|||
/* 9. Call plugin transaction end callbacks */
|
||||
plugin_transaction_end(h, td);
|
||||
|
||||
|
||||
/* 8. Copy running back to candidate in case end functions updated running */
|
||||
if (xmldb_copy(h, "running", candidate) < 0){
|
||||
/* ignore errors or signal major setback ? */
|
||||
clicon_log(LOG_NOTICE, "Error in rollback, trying to continue");
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
retval = 1;
|
||||
done:
|
||||
/* In case of failure, call plugin transaction termination callbacks */
|
||||
if (retval < 0 && td)
|
||||
/* In case of failure (or error), call plugin transaction termination callbacks */
|
||||
if (retval < 1 && td)
|
||||
plugin_transaction_abort(h, td);
|
||||
if (td)
|
||||
transaction_free(td);
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Commit changes from candidate to running
|
||||
|
|
@ -283,6 +315,7 @@ from_client_commit(clicon_handle h,
|
|||
int retval = -1;
|
||||
int piddb;
|
||||
cbuf *cbx = NULL; /* Assist cbuf */
|
||||
int ret;
|
||||
|
||||
/* Check if target locked by other client */
|
||||
piddb = xmldb_islocked(h, "running");
|
||||
|
|
@ -296,9 +329,10 @@ from_client_commit(clicon_handle h,
|
|||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
if (candidate_commit(h, "candidate") < 0){ /* Assume validation fail, nofatal */
|
||||
if ((ret = candidate_commit(h, "candidate", cbret)) < 0){ /* Assume validation fail, nofatal */
|
||||
clicon_debug(1, "Commit candidate failed");
|
||||
if (netconf_invalid_value(cbret, "protocol", clicon_err_reason)< 0)
|
||||
if (ret < 0)
|
||||
if (netconf_operation_failed(cbret, "application", clicon_err_reason)< 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -367,6 +401,7 @@ from_client_validate(clicon_handle h,
|
|||
{
|
||||
int retval = -1;
|
||||
transaction_data_t *td = NULL;
|
||||
int ret;
|
||||
|
||||
if (strcmp(db, "candidate") != 0 && strcmp(db, "tmp") != 0){
|
||||
if (netconf_invalid_value(cbret, "protocol", "No such database")< 0)
|
||||
|
|
@ -379,11 +414,12 @@ from_client_validate(clicon_handle h,
|
|||
if ((td = transaction_new()) == NULL)
|
||||
goto done;
|
||||
/* Common steps (with commit) */
|
||||
if (validate_common(h, db, td) < 0){
|
||||
if ((ret = validate_common(h, db, td, cbret)) < 1){
|
||||
clicon_debug(1, "Validate %s failed", db);
|
||||
/* XXX: candidate_validate should have proper error handling */
|
||||
if (netconf_operation_failed(cbret, "application", clicon_err_reason)< 0)
|
||||
goto done;
|
||||
if (ret < 0){
|
||||
if (netconf_operation_failed(cbret, "application", clicon_err_reason)< 0)
|
||||
goto done;
|
||||
}
|
||||
goto ok;
|
||||
}
|
||||
/* Optionally write (potentially modified) tree back to candidate */
|
||||
|
|
|
|||
|
|
@ -43,6 +43,6 @@
|
|||
int from_client_validate(clicon_handle h, char *db, cbuf *cbret);
|
||||
int from_client_commit(clicon_handle h, int pid, cbuf *cbret);
|
||||
int from_client_discard_changes(clicon_handle h, int pid, cbuf *cbret);
|
||||
int candidate_commit(clicon_handle h, char *db);
|
||||
int candidate_commit(clicon_handle h, char *db, cbuf *cbret);
|
||||
|
||||
#endif /* _BACKEND_COMMIT_H_ */
|
||||
|
|
|
|||
|
|
@ -386,6 +386,7 @@ startup_mode_running(clicon_handle h,
|
|||
char *extraxml_file)
|
||||
{
|
||||
int retval = -1;
|
||||
cbuf *cbret = NULL;
|
||||
|
||||
/* Stash original running to candidate for later commit */
|
||||
if (xmldb_copy(h, "running", "candidate") < 0)
|
||||
|
|
@ -405,15 +406,20 @@ startup_mode_running(clicon_handle h,
|
|||
/* Clear running db */
|
||||
if (db_reset(h, "running") < 0)
|
||||
goto done;
|
||||
if ((cbret = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
/* Commit original running. Assume -1 is validate fail */
|
||||
if (candidate_commit(h, "candidate") < 0){
|
||||
if (candidate_commit(h, "candidate", cbret) < 1){
|
||||
/* (1) We cannot differentiate between fatal errors and validation
|
||||
* failures
|
||||
* (2) If fatal error, we should exit
|
||||
* (3) If validation fails we cannot continue. How could we?
|
||||
* (4) Need to restore the running db since we destroyed it above
|
||||
*/
|
||||
clicon_log(LOG_NOTICE, "%s: Commit of saved running failed, exiting.", __FUNCTION__);
|
||||
clicon_log(LOG_NOTICE, "%s: Commit of saved running failed, exiting: %s.",
|
||||
__FUNCTION__, cbuf_get(cbret));
|
||||
/* Reinstate original */
|
||||
if (xmldb_copy(h, "candidate", "running") < 0)
|
||||
goto done;
|
||||
|
|
@ -424,6 +430,8 @@ startup_mode_running(clicon_handle h,
|
|||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
if (cbret)
|
||||
cbuf_free(cbret);
|
||||
if (xmldb_delete(h, "tmp") < 0)
|
||||
goto done;
|
||||
return retval;
|
||||
|
|
@ -455,6 +463,7 @@ startup_mode_startup(clicon_handle h,
|
|||
char *extraxml_file)
|
||||
{
|
||||
int retval = -1;
|
||||
cbuf *cbret = NULL;
|
||||
|
||||
/* Stash original running to backup */
|
||||
if (xmldb_copy(h, "running", "backup") < 0)
|
||||
|
|
@ -478,13 +487,19 @@ startup_mode_startup(clicon_handle h,
|
|||
/* Clear running db */
|
||||
if (db_reset(h, "running") < 0)
|
||||
goto done;
|
||||
/* Create return buffer (not used) */
|
||||
if ((cbret = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
/* Commit startup */
|
||||
if (candidate_commit(h, "startup") < 0){ /* diff */
|
||||
if (candidate_commit(h, "startup", cbret) < 1){ /* diff */
|
||||
/* We cannot differentiate between fatal errors and validation
|
||||
* failures
|
||||
* In both cases we copy back the original running and quit
|
||||
*/
|
||||
clicon_log(LOG_NOTICE, "%s: Commit of startup failed, exiting.", __FUNCTION__);
|
||||
clicon_log(LOG_NOTICE, "%s: Commit of startup failed, exiting: %s.",
|
||||
__FUNCTION__, cbuf_get(cbret));
|
||||
if (xmldb_copy(h, "backup", "running") < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
|
|
@ -494,6 +509,8 @@ startup_mode_startup(clicon_handle h,
|
|||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
if (cbret)
|
||||
cbuf_free(cbret);
|
||||
if (xmldb_delete(h, "backup") < 0)
|
||||
goto done;
|
||||
if (xmldb_delete(h, "tmp") < 0)
|
||||
|
|
|
|||
|
|
@ -83,15 +83,17 @@ static int
|
|||
process_incoming_packet(clicon_handle h,
|
||||
cbuf *cb)
|
||||
{
|
||||
char *str;
|
||||
char *str0;
|
||||
cxobj *xreq = NULL; /* Request (in) */
|
||||
int isrpc = 0; /* either hello or rpc */
|
||||
cbuf *cbret = NULL;
|
||||
cxobj *xret = NULL; /* Return (out) */
|
||||
cxobj *xrpc;
|
||||
cxobj *xc;
|
||||
int retval = -1;
|
||||
char *str;
|
||||
char *str0;
|
||||
cxobj *xreq = NULL; /* Request (in) */
|
||||
int isrpc = 0; /* either hello or rpc */
|
||||
cbuf *cbret = NULL;
|
||||
cxobj *xret = NULL; /* Return (out) */
|
||||
cxobj *xrpc;
|
||||
cxobj *xc;
|
||||
yang_spec *yspec;
|
||||
int ret;
|
||||
|
||||
clicon_debug(1, "RECV");
|
||||
clicon_debug(2, "%s: RCV: \"%s\"", __FUNCTION__, cbuf_get(cb));
|
||||
|
|
@ -115,15 +117,12 @@ process_incoming_packet(clicon_handle h,
|
|||
}
|
||||
free(str0);
|
||||
if ((xrpc=xpath_first(xreq, "//rpc")) != NULL){
|
||||
int ret;
|
||||
isrpc++;
|
||||
if ((ret = xml_yang_validate_rpc(xrpc)) < 0)
|
||||
if ((ret = xml_yang_validate_rpc(xrpc, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
if (netconf_operation_failed(cbret, "application", "Validation failed")< 0)
|
||||
goto done;
|
||||
netconf_output(1, cbret, "rpc-error");
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -168,6 +167,8 @@ process_incoming_packet(clicon_handle h,
|
|||
}
|
||||
}
|
||||
}
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
if (xreq)
|
||||
xml_free(xreq);
|
||||
|
|
@ -175,7 +176,7 @@ process_incoming_packet(clicon_handle h,
|
|||
xml_free(xret);
|
||||
if (cbret)
|
||||
cbuf_free(cbret);
|
||||
return 0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Get netconf message: detect end-of-msg
|
||||
|
|
@ -229,7 +230,7 @@ netconf_input_cb(int s,
|
|||
/* Remove trailer */
|
||||
*(((char*)cbuf_get(cb)) + cbuf_len(cb) - strlen("]]>]]>")) = '\0';
|
||||
if (process_incoming_packet(h, cb) < 0)
|
||||
goto done;
|
||||
; //goto done; // ignore errors
|
||||
if (cc_closed)
|
||||
break;
|
||||
cbuf_reset(cb);
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@
|
|||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <syslog.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/param.h>
|
||||
|
|
@ -876,12 +877,16 @@ netconf_application_rpc(clicon_handle h,
|
|||
cbuf *cb = NULL;
|
||||
cbuf *cbret = NULL;
|
||||
int ret;
|
||||
|
||||
|
||||
/* First check system / netconf RPC:s */
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, 0, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if ((cbret = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, 0, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
/* Find yang rpc statement, return yang rpc statement if found
|
||||
Check application RPC */
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
|
|
@ -917,15 +922,18 @@ 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 (xml_apply(xn, CX_ELMNT,
|
||||
(xml_applyfn_t*)xml_yang_validate_all, NULL) < 0)
|
||||
if ((ret = xml_yang_validate_all_top(xn, cbret)) < 0)
|
||||
goto done;
|
||||
if (xml_yang_validate_add(xn, NULL) < 0)
|
||||
if (ret == 0){
|
||||
netconf_output(1, cbret, "rpc-error");
|
||||
goto ok;
|
||||
}
|
||||
if ((ret = xml_yang_validate_add(xn, cbret)) < 0)
|
||||
goto done;
|
||||
}
|
||||
if ((cbret = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, 0, "cbuf_new");
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
netconf_output(1, cbret, "rpc-error");
|
||||
goto ok;
|
||||
}
|
||||
}
|
||||
/* Look for local (client-side) netconf plugins. */
|
||||
if ((ret = rpc_callback_call(h, xn, cbret, NULL)) < 0)
|
||||
|
|
@ -943,11 +951,18 @@ netconf_application_rpc(clicon_handle h,
|
|||
xml_spec_set(xoutput, youtput); /* needed for xml_spec_populate */
|
||||
if (xml_apply(xoutput, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
||||
goto done;
|
||||
if (xml_apply(xoutput, CX_ELMNT,
|
||||
(xml_applyfn_t*)xml_yang_validate_all, NULL) < 0)
|
||||
if ((ret = xml_yang_validate_all_top(xoutput, cbret)) < 0)
|
||||
goto done;
|
||||
if (xml_yang_validate_add(xoutput, NULL) < 0)
|
||||
if (ret == 0){
|
||||
clicon_log(LOG_WARNING, "Errors in output netconf %s", cbuf_get(cbret));
|
||||
goto ok;
|
||||
}
|
||||
if ((ret = xml_yang_validate_add(xoutput, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
clicon_log(LOG_WARNING, "Errors in output netconf %s", cbuf_get(cbret));
|
||||
goto ok;
|
||||
}
|
||||
}
|
||||
retval = 1; /* handled by callback */
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -71,11 +71,12 @@ static const map_str2int netconf_restconf_map[] = {
|
|||
{"missing-attribute", 400},
|
||||
{"bad-attribute", 400},
|
||||
{"unknown-attribute", 400},
|
||||
{"missing-element", 400},
|
||||
{"bad-element", 400},
|
||||
{"unknown-element", 400},
|
||||
{"unknown-namespace", 400},
|
||||
{"access-denied", 401},
|
||||
{"access-denied", 403},
|
||||
{"access-denied", 401}, /* or 403 */
|
||||
{"access-denied", 403},
|
||||
{"lock-denied", 409},
|
||||
{"resource-denied", 409},
|
||||
{"rollback-failed", 500},
|
||||
|
|
@ -436,7 +437,8 @@ api_return_err(clicon_handle h,
|
|||
goto ok;
|
||||
}
|
||||
tagstr = xml_body(xtag);
|
||||
code = restconf_err2code(tagstr);
|
||||
if ((code = restconf_err2code(tagstr)) < 0)
|
||||
code = 500; /* internal server error */
|
||||
if ((reason_phrase = restconf_code2reason(code)) == NULL)
|
||||
reason_phrase="";
|
||||
if (xml_name_set(xerr, "error") < 0)
|
||||
|
|
@ -448,6 +450,7 @@ api_return_err(clicon_handle h,
|
|||
else
|
||||
if (xml2json_cbuf(cb, xerr, pretty) < 0)
|
||||
goto done;
|
||||
FCGX_SetExitStatus(code, r->out); /* Created */
|
||||
FCGX_FPrintF(r->out, "Status: %d %s\r\n", code, reason_phrase);
|
||||
FCGX_FPrintF(r->out, "Content-Type: application/yang-data+%s\r\n\r\n",
|
||||
use_xml?"xml":"json");
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ api_data_get2(clicon_handle h,
|
|||
yang_spec *yspec;
|
||||
cxobj *xret = NULL;
|
||||
cxobj *xerr = NULL; /* malloced */
|
||||
cxobj *xe;
|
||||
cxobj *xe = NULL;
|
||||
cxobj **xvec = NULL;
|
||||
size_t xlen;
|
||||
int i;
|
||||
|
|
@ -206,8 +206,9 @@ api_data_get2(clicon_handle h,
|
|||
if (api_path2xpath_cvv(yspec, pcvec, pi, cbpath) < 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;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
path = cbuf_get(cbpath);
|
||||
|
|
@ -215,8 +216,9 @@ api_data_get2(clicon_handle h,
|
|||
if (clicon_rpc_get(h, path, &xret) < 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;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
/* We get return via netconf which is complete tree from root
|
||||
|
|
@ -434,16 +436,18 @@ api_data_post(clicon_handle h,
|
|||
if (xml_parse_string(data, NULL, &xdata) < 0){
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
}
|
||||
else if (json_parse_str(data, &xdata) < 0){
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
/* 4.4.1: The message-body MUST contain exactly one instance of the
|
||||
|
|
@ -452,8 +456,9 @@ api_data_post(clicon_handle h,
|
|||
if (xml_child_nr(xdata) != 1){
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
x = xml_child_i(xdata,0);
|
||||
|
|
@ -662,16 +667,18 @@ api_data_put(clicon_handle h,
|
|||
if (xml_parse_string(data, NULL, &xdata) < 0){
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
}
|
||||
else if (json_parse_str(data, &xdata) < 0){
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
/* The message-body MUST contain exactly one instance of the
|
||||
|
|
@ -680,8 +687,9 @@ api_data_put(clicon_handle h,
|
|||
if (xml_child_nr(xdata) != 1){
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
x = xml_child_i(xdata,0);
|
||||
|
|
@ -705,8 +713,9 @@ api_data_put(clicon_handle h,
|
|||
if (strcmp(xml_name(x), xml_name(xbot))){
|
||||
if (netconf_operation_failed_xml(&xerr, "protocol", "Not same symbol in api-path as data") < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
/* If list or leaf-list, api-path keys must match data keys */
|
||||
|
|
@ -714,8 +723,9 @@ api_data_put(clicon_handle h,
|
|||
if (match_list_keys((yang_stmt*)y, x, xbot) < 0){
|
||||
if (netconf_operation_failed_xml(&xerr, "protocol", "api-path keys do not match data keys") < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
}
|
||||
|
|
@ -866,7 +876,7 @@ api_data_delete(clicon_handle h,
|
|||
if ((xa = xml_new("operation", xbot, NULL)) == NULL)
|
||||
goto done;
|
||||
xml_type_set(xa, CX_ATTR);
|
||||
if (xml_value_set(xa, xml_operation2str(op)) < 0)
|
||||
if (xml_value_set(xa, xml_operation2str(op)) < 0)
|
||||
goto done;
|
||||
if ((cbx = cbuf_new()) == NULL)
|
||||
goto done;
|
||||
|
|
@ -1054,7 +1064,6 @@ api_operations_post(clicon_handle h,
|
|||
cxobj *xdata = NULL;
|
||||
cxobj *xret = NULL;
|
||||
cxobj *xerr = NULL; /* malloced must be freed */
|
||||
cxobj *xer; /* non-malloced error */
|
||||
cbuf *cbx = NULL;
|
||||
cxobj *xtop = NULL; /* xpath root */
|
||||
cxobj *xbot = NULL;
|
||||
|
|
@ -1076,13 +1085,18 @@ api_operations_post(clicon_handle h,
|
|||
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||
goto done;
|
||||
}
|
||||
if ((cbret = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, 0, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
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;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
clicon_debug(1, "%s oppath: %s", __FUNCTION__, oppath);
|
||||
|
|
@ -1098,22 +1112,25 @@ api_operations_post(clicon_handle h,
|
|||
if ((ys = yang_find((yang_node*)yspec, Y_MODULE, prefix)) == NULL){
|
||||
if (netconf_operation_failed_xml(&xerr, "protocol", "yang module not found") < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
if ((yrpc = yang_find((yang_node*)ys, Y_RPC, id)) == NULL){
|
||||
if (netconf_operation_failed_xml(&xerr, "protocol", "yang node not found") < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
if (yrpc == NULL){
|
||||
if (netconf_operation_failed_xml(&xerr, "protocol", "yang node not found") < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
/* Create an xml message:
|
||||
|
|
@ -1142,16 +1159,18 @@ api_operations_post(clicon_handle h,
|
|||
if (xml_parse_string(data, NULL, &xdata) < 0){
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
}
|
||||
else if (json_parse_str(data, &xdata) < 0){
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
yinput = yang_find((yang_node*)yrpc, Y_INPUT, NULL);
|
||||
|
|
@ -1160,11 +1179,14 @@ api_operations_post(clicon_handle h,
|
|||
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)
|
||||
if ((ret = xml_yang_validate_add(xdata, cbret)) < 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)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
}
|
||||
|
|
@ -1182,23 +1204,31 @@ api_operations_post(clicon_handle h,
|
|||
/* XXX yinput <-> h ?*/
|
||||
if (xml_apply(xbot, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
||||
goto done;
|
||||
if (xml_apply(xbot, CX_ELMNT,
|
||||
(xml_applyfn_t*)xml_yang_validate_all, NULL) < 0)
|
||||
if ((ret = xml_yang_validate_all(xbot, cbret)) < 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)
|
||||
if (ret == 0){ /* validation failed */
|
||||
clicon_debug(1, "%s err: %s", __FUNCTION__, cbuf_get(cbret));
|
||||
if (xml_parse_string(cbuf_get(cbret), yspec, &xerr) < 0)
|
||||
goto done;
|
||||
if ((xe=xpath_first(xerr, "rpc-reply/rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
if ((ret = xml_yang_validate_add(xbot, cbret)) < 0){
|
||||
if (xml_parse_string(cbuf_get(cbret), yspec, &xerr) < 0)
|
||||
goto done;
|
||||
if ((xe=xpath_first(xerr, "rpc-reply/rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
if (xml_apply0(xbot, CX_ELMNT, xml_default, NULL) < 0)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((cbret = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, 0, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
ret = 0;
|
||||
xe = NULL;
|
||||
while ((xe = xml_child_each(xtop, xe, CX_ELMNT)) != NULL) {
|
||||
/* Look for local (client-side) restconf plugins. */
|
||||
|
|
@ -1208,8 +1238,8 @@ api_operations_post(clicon_handle h,
|
|||
if (xml_parse_string(cbuf_get(cbret), NULL, &xret) < 0)
|
||||
goto done;
|
||||
/* Local error: return it and quit */
|
||||
if ((xer = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
if (api_return_err(h, r, xer, pretty, use_xml) < 0)
|
||||
if ((xe = xpath_first(xret, "rpc-reply/rpc-error")) != NULL){
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -1219,8 +1249,8 @@ api_operations_post(clicon_handle h,
|
|||
if (ret == 0){ /* Send to backend */
|
||||
if (clicon_rpc_netconf_xml(h, xtop, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xer = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
if (api_return_err(h, r, xer, pretty, use_xml) < 0)
|
||||
if ((xe = xpath_first(xret, "rpc-reply/rpc-error")) != NULL){
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -1240,18 +1270,31 @@ api_operations_post(clicon_handle h,
|
|||
goto done;
|
||||
if ((xoutput=xpath_first(xret, "/")) != NULL){
|
||||
xml_name_set(xoutput, "output");
|
||||
#if 0
|
||||
clicon_debug(1, "%s xoutput:%s", __FUNCTION__, cbuf_get(cbx));
|
||||
#endif
|
||||
cbuf_reset(cbx);
|
||||
xml_spec_set(xoutput, youtput); /* needed for xml_spec_populate */
|
||||
if (xml_apply(xoutput, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
||||
goto done;
|
||||
if (xml_apply(xoutput, CX_ELMNT,
|
||||
(xml_applyfn_t*)xml_yang_validate_all, NULL) < 0)
|
||||
if ((ret = xml_yang_validate_all(xoutput, cbret)) < 0)
|
||||
goto done;
|
||||
if (xml_yang_validate_add(xoutput, NULL) < 0)
|
||||
if (ret == 0){ /* validation failed */
|
||||
clicon_debug(1, "%s output validation failed", __FUNCTION__);
|
||||
if (xml_parse_string(cbuf_get(cbret), yspec, &xerr) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xret, "rpc-reply/rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
if ((ret = xml_yang_validate_add(xoutput, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){ /* validation failed */
|
||||
if (xml_parse_string(cbuf_get(cbret), yspec, &xerr) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xret, "rpc-reply/rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
}
|
||||
/* Sanity check of outgoing XML */
|
||||
FCGX_SetExitStatus(200, r->out); /* OK */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue