* xml_merge() changed to use 3-value return: 1:OK, 0:Yang failed, -1: Error
* `clixon_netconf_error(category, xerr, msg, arg)` removed first argument -> `clixon_netconf_error(xerr, msg, arg)` * Renamed utility function `clixon_util_insert()` to `clixon_util_xml_mod()` and added merge functionality. * Fixed: Insertion of subtree leaf nodes were not made in the crrect place, always ended up last regardless of yang spec (if ordered-by system).
This commit is contained in:
parent
f401c07c4b
commit
0d4263e324
16 changed files with 376 additions and 274 deletions
|
|
@ -140,7 +140,7 @@ clicon_err_reset(void)
|
|||
*
|
||||
* @param[in] fn Inline function name (when called from clicon_err() macro)
|
||||
* @param[in] line Inline file line number (when called from clicon_err() macro)
|
||||
* @param[in] category See enum clicon_err
|
||||
* @param[in] category Clixon error category, See enum clicon_err
|
||||
* @param[in] errno Error number, typically errno
|
||||
* @param[in] reason Error string, format with argv
|
||||
* @see clicon_err_reser Resetting the global error variables.
|
||||
|
|
|
|||
|
|
@ -1503,13 +1503,12 @@ netconf_hello_req(clicon_handle h,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Generate clicon error from Netconf error message
|
||||
/*! Generate textual error log from Netconf error message
|
||||
*
|
||||
* Get a text error message from netconf error message and generate error on the form:
|
||||
* <msg>: "<arg>": <netconf-error> or <msg>: <netconf-error>
|
||||
* @param[in] fn Inline function name (when called from clicon_err() macro)
|
||||
* @param[in] line Inline file line number (when called from clicon_err() macro)
|
||||
* @param[in] err Error number, typically errno
|
||||
* @param[in] fn Inline function name (when called from clicon_err() macro)
|
||||
* @param[in] line Inline file line number (when called from clicon_err() macro)
|
||||
* @param[in] xerr Netconf error xml tree on the form: <rpc-error>
|
||||
* @param[in] format Format string
|
||||
* @param[in] arg String argument to format (optional)
|
||||
|
|
@ -1517,7 +1516,6 @@ netconf_hello_req(clicon_handle h,
|
|||
int
|
||||
clixon_netconf_error_fn(const char *fn,
|
||||
const int line,
|
||||
int category,
|
||||
cxobj *xerr,
|
||||
const char *msg,
|
||||
const char *arg)
|
||||
|
|
|
|||
|
|
@ -246,7 +246,7 @@ parse_configfile(clicon_handle h,
|
|||
if (netconf_err2cb(xerr, cbret) < 0)
|
||||
goto done;
|
||||
/* Here one could make it more relaxing to not quit on unrecognized option? */
|
||||
clixon_netconf_error(OE_CFG, xerr, NULL, NULL);
|
||||
clixon_netconf_error(xerr, NULL, NULL);
|
||||
goto done;
|
||||
}
|
||||
if (xml_child_nr(xt)==1 && xml_child_nr_type(xt, CX_BODY)==1){
|
||||
|
|
|
|||
|
|
@ -301,7 +301,7 @@ clicon_rpc_netconf_xml(clicon_handle h,
|
|||
* if (clicon_rpc_get_config(h, NULL, "running", "/hello/world", nsc, &xt) < 0)
|
||||
* err;
|
||||
* if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
|
||||
* clixon_netconf_error(OE_NETCONF, xerr, "msg", "/hello/world");
|
||||
* clixon_netconf_error(xerr, "msg", "/hello/world");
|
||||
* err;
|
||||
* }
|
||||
* if (xt)
|
||||
|
|
@ -445,7 +445,7 @@ clicon_rpc_edit_config(clicon_handle h,
|
|||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
clixon_netconf_error(OE_NETCONF, xerr, "Editing configuration", NULL);
|
||||
clixon_netconf_error(xerr, "Editing configuration", NULL);
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
|
|
@ -495,7 +495,7 @@ clicon_rpc_copy_config(clicon_handle h,
|
|||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
clixon_netconf_error(OE_NETCONF, xerr, "Copying configuration", NULL);
|
||||
clixon_netconf_error(xerr, "Copying configuration", NULL);
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
|
|
@ -538,7 +538,7 @@ clicon_rpc_delete_config(clicon_handle h,
|
|||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
clixon_netconf_error(OE_NETCONF, xerr, "Deleting configuration", NULL);
|
||||
clixon_netconf_error(xerr, "Deleting configuration", NULL);
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
|
|
@ -577,7 +577,7 @@ clicon_rpc_lock(clicon_handle h,
|
|||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
clixon_netconf_error(OE_NETCONF, xerr, "Locking configuration", NULL);
|
||||
clixon_netconf_error(xerr, "Locking configuration", NULL);
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
|
|
@ -615,7 +615,7 @@ clicon_rpc_unlock(clicon_handle h,
|
|||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
clixon_netconf_error(OE_NETCONF, xerr, "Configuration unlock", NULL);
|
||||
clixon_netconf_error(xerr, "Configuration unlock", NULL);
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
|
|
@ -649,7 +649,7 @@ clicon_rpc_unlock(clicon_handle h,
|
|||
* if (clicon_rpc_get(h, "/hello/world", nsc, CONTENT_ALL, -1, &xt) < 0)
|
||||
* err;
|
||||
* if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
|
||||
* clixon_netconf_error(OE_NETCONF, xerr, "clicon_rpc_get", NULL);
|
||||
* clixon_netconf_error(xerr, "clicon_rpc_get", NULL);
|
||||
* err;
|
||||
* }
|
||||
* if (xt)
|
||||
|
|
@ -779,7 +779,7 @@ clicon_rpc_close_session(clicon_handle h)
|
|||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
clixon_netconf_error(OE_NETCONF, xerr, "Close session", NULL);
|
||||
clixon_netconf_error(xerr, "Close session", NULL);
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
|
|
@ -818,7 +818,7 @@ clicon_rpc_kill_session(clicon_handle h,
|
|||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
clixon_netconf_error(OE_NETCONF, xerr, "Kill session", NULL);
|
||||
clixon_netconf_error(xerr, "Kill session", NULL);
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
|
|
@ -856,7 +856,7 @@ clicon_rpc_validate(clicon_handle h,
|
|||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
clixon_netconf_error(OE_NETCONF, xerr, CLIXON_ERRSTR_VALIDATE_FAILED, NULL);
|
||||
clixon_netconf_error(xerr, CLIXON_ERRSTR_VALIDATE_FAILED, NULL);
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
|
|
@ -892,7 +892,7 @@ clicon_rpc_commit(clicon_handle h)
|
|||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
clixon_netconf_error(OE_NETCONF, xerr, CLIXON_ERRSTR_COMMIT_FAILED, NULL);
|
||||
clixon_netconf_error(xerr, CLIXON_ERRSTR_COMMIT_FAILED, NULL);
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
|
|
@ -928,7 +928,7 @@ clicon_rpc_discard_changes(clicon_handle h)
|
|||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
clixon_netconf_error(OE_NETCONF, xerr, "Discard changes", NULL);
|
||||
clixon_netconf_error(xerr, "Discard changes", NULL);
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
|
|
@ -978,7 +978,7 @@ clicon_rpc_create_subscription(clicon_handle h,
|
|||
if (clicon_rpc_msg(h, msg, &xret, s0) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
clixon_netconf_error(OE_NETCONF, xerr, "Create subscription", NULL);
|
||||
clixon_netconf_error(xerr, "Create subscription", NULL);
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
|
|
@ -1016,7 +1016,7 @@ clicon_rpc_debug(clicon_handle h,
|
|||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
clixon_netconf_error(OE_NETCONF, xerr, "Debug", NULL);
|
||||
clixon_netconf_error(xerr, "Debug", NULL);
|
||||
goto done;
|
||||
}
|
||||
if (xpath_first(xret, NULL, "//rpc-reply/ok") == NULL){
|
||||
|
|
@ -1059,7 +1059,7 @@ clicon_hello_req(clicon_handle h,
|
|||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
clixon_netconf_error(OE_NETCONF, xerr, "Hello", NULL);
|
||||
clixon_netconf_error(xerr, "Hello", NULL);
|
||||
goto done;
|
||||
}
|
||||
if ((x = xpath_first(xret, NULL, "hello/session-id")) == NULL){
|
||||
|
|
|
|||
|
|
@ -1172,12 +1172,13 @@ xml_find(cxobj *xp,
|
|||
* @see xml_wrap
|
||||
* @see xml_insert
|
||||
* @note xc is not sorted correctly, need to call xml_sort on parent
|
||||
* @see xml_insert which is a higher layer function including yang and sorting
|
||||
*/
|
||||
int
|
||||
xml_addsub(cxobj *xp,
|
||||
cxobj *xc)
|
||||
{
|
||||
int retval = -1;
|
||||
int retval = -1;
|
||||
cxobj *oldp;
|
||||
int i;
|
||||
char *pns = NULL; /* parent namespace */
|
||||
|
|
|
|||
|
|
@ -1357,15 +1357,15 @@ assign_namespace_body(cxobj *x0, /* source */
|
|||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*! Merge a base tree x0 with x1 with yang spec y
|
||||
* @param[in] x0 Base xml tree (can be NULL in add scenarios)
|
||||
* @param[in] y0 Yang spec corresponding to xml-node x0. NULL if x0 is NULL
|
||||
* @param[in] x0p Parent of x0
|
||||
* @param[in] x1 xml tree which modifies base
|
||||
* @param[out] reason If retval=0 a malloced string
|
||||
* @retval 0 OK. If reason is set, Yang error
|
||||
* @retval -1 Error
|
||||
* @retval 1 OK
|
||||
* @retval 0 Yang error, reason is set
|
||||
* @retval -1 Error
|
||||
* Assume x0 and x1 are same on entry and that y is the spec
|
||||
*/
|
||||
static int
|
||||
|
|
@ -1384,7 +1384,8 @@ xml_merge1(cxobj *x0, /* the target */
|
|||
char *x1bstr; /* mod body string */
|
||||
yang_stmt *yc; /* yang child */
|
||||
cbuf *cbr = NULL; /* Reason buffer */
|
||||
int i;
|
||||
int ret;
|
||||
int i;
|
||||
struct {
|
||||
cxobj *w_x0c;
|
||||
cxobj *w_x1c;
|
||||
|
|
@ -1398,7 +1399,7 @@ xml_merge1(cxobj *x0, /* the target */
|
|||
if (yang_keyword_get(y0) == Y_LEAF_LIST || yang_keyword_get(y0) == Y_LEAF){
|
||||
x1bstr = xml_body(x1);
|
||||
if (x0==NULL){
|
||||
if ((x0 = xml_new(x1name, x0p, CX_ELMNT)) == NULL)
|
||||
if ((x0 = xml_new(x1name, NULL, CX_ELMNT)) == NULL)
|
||||
goto done;
|
||||
xml_spec_set(x0, y0);
|
||||
if (x1bstr){ /* empty type does not have body */
|
||||
|
|
@ -1414,6 +1415,9 @@ xml_merge1(cxobj *x0, /* the target */
|
|||
if (xml_value_set(x0b, x1bstr) < 0)
|
||||
goto done;
|
||||
}
|
||||
if (xml_parent(x0) == NULL &&
|
||||
xml_insert(x0p, x0, INS_LAST, NULL, NULL) < 0)
|
||||
goto done;
|
||||
if (assign_namespace_element(x1, x0, x0p) < 0)
|
||||
goto done;
|
||||
} /* if LEAF|LEAF_LIST */
|
||||
|
|
@ -1447,7 +1451,7 @@ xml_merge1(cxobj *x0, /* the target */
|
|||
goto done;
|
||||
}
|
||||
}
|
||||
break;
|
||||
goto fail;
|
||||
}
|
||||
/* See if there is a corresponding node in the base tree */
|
||||
x0c = NULL;
|
||||
|
|
@ -1466,40 +1470,41 @@ xml_merge1(cxobj *x0, /* the target */
|
|||
x1c = NULL;
|
||||
i = 0;
|
||||
while ((x1c = xml_child_each(x1, x1c, CX_ELMNT)) != NULL) {
|
||||
if (xml_merge1(second_wave[i].w_x0c,
|
||||
if ((ret = xml_merge1(second_wave[i].w_x0c,
|
||||
second_wave[i].w_yc,
|
||||
x0,
|
||||
second_wave[i].w_x1c,
|
||||
reason) < 0)
|
||||
reason)) < 0)
|
||||
goto done;
|
||||
if (*reason != NULL)
|
||||
goto ok;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
i++;
|
||||
}
|
||||
if (xml_parent(x0) == NULL &&
|
||||
xml_insert(x0p, x0, INS_LAST, NULL, NULL) < 0)
|
||||
goto done;
|
||||
} /* else Y_CONTAINER */
|
||||
ok:
|
||||
retval = 0;
|
||||
retval = 1;
|
||||
done:
|
||||
if (second_wave)
|
||||
free(second_wave);
|
||||
if (cbr)
|
||||
cbuf_free(cbr);
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Merge XML trees x1 into x0 according to yang spec yspec
|
||||
* @param[in] x0 Base xml tree (can be NULL in add scenarios)
|
||||
* @param[in] x1 xml tree which modifies base
|
||||
* @param[in] yspec Yang spec
|
||||
* @param[in] x0 Base xml tree (can be NULL in add scenarios)
|
||||
* @param[in] x1 xml tree which modifies base
|
||||
* @param[in] yspec Yang spec
|
||||
* @param[out] reason If retval=0, reason is set. Malloced. Needs to be freed by caller
|
||||
* @retval 0 OK. If reason is set, Yang error
|
||||
* @retval -1 Error
|
||||
* @retval 1 OK
|
||||
* @retval 0 Yang error, reason is set
|
||||
* @retval -1 Error
|
||||
* @note both x0 and x1 need to be top-level trees
|
||||
* @see text_modify_top as more generic variant (in datastore text)
|
||||
* @note returns -1 if YANG do not match, you may want to have a softer error
|
||||
*/
|
||||
int
|
||||
xml_merge(cxobj *x0,
|
||||
|
|
@ -1518,7 +1523,6 @@ xml_merge(cxobj *x0,
|
|||
if (x0 == NULL || x1 == NULL){
|
||||
clicon_err(OE_UNIX, EINVAL, "parameters x0 or x1 is NULL");
|
||||
goto done;
|
||||
goto done;
|
||||
}
|
||||
/* Loop through children of the modification tree */
|
||||
x1c = NULL;
|
||||
|
|
@ -1532,7 +1536,7 @@ xml_merge(cxobj *x0,
|
|||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
goto ok;
|
||||
goto fail;
|
||||
}
|
||||
/* Get yang spec of the child */
|
||||
if ((yc = yang_find_datanode(ymod, x1cname)) == NULL){
|
||||
|
|
@ -1547,7 +1551,7 @@ xml_merge(cxobj *x0,
|
|||
goto done;
|
||||
}
|
||||
}
|
||||
break;
|
||||
goto fail;
|
||||
}
|
||||
/* See if there is a corresponding node (x1c) in the base tree (x0) */
|
||||
if (match_base_child(x0, x1c, yc, &x0c) < 0)
|
||||
|
|
@ -1561,12 +1565,14 @@ xml_merge(cxobj *x0,
|
|||
if (*reason != NULL)
|
||||
break;
|
||||
}
|
||||
ok:
|
||||
retval = 0; /* OK */
|
||||
retval = 1; /* OK */
|
||||
done:
|
||||
if (cbr)
|
||||
cbuf_free(cbr);
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Get integer value from xml node from yang enumeration
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue