With-defaults CLI support

Extended cli_auto_show() with with-defaults argument, also changing its signature
Example: Added with-defaults argument to clispec
C-API: Added with-defaults argument to clicon_rpc_get_config
Replaced with-defaults prefix/namespace with constants
This commit is contained in:
Olof hagsand 2022-09-09 12:30:57 +02:00
parent 42d5b6fba2
commit 743076b171
23 changed files with 256 additions and 56 deletions

View file

@ -47,7 +47,7 @@ int clicon_rpc_msg(clicon_handle h, struct clicon_msg *msg, cxobj **xret0);
int clicon_rpc_msg_persistent(clicon_handle h, struct clicon_msg *msg, cxobj **xret0, int *sock0);
int clicon_rpc_netconf(clicon_handle h, char *xmlst, cxobj **xret, int *sp);
int clicon_rpc_netconf_xml(clicon_handle h, cxobj *xml, cxobj **xret, int *sp);
int clicon_rpc_get_config(clicon_handle h, char *username, char *db, char *xpath, cvec *nsc, cxobj **xret);
int clicon_rpc_get_config(clicon_handle h, char *username, char *db, char *xpath, cvec *nsc, char *defaults, cxobj **xret);
int clicon_rpc_edit_config(clicon_handle h, char *db, enum operation_type op,
char *xml);
int clicon_rpc_copy_config(clicon_handle h, char *db1, char *db2);

View file

@ -65,6 +65,16 @@
*/
#define IETF_PAGINATON_NC_NAMESPACE "urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc"
/* RFC 6243 With-defaults Capability for NETCONF
* ietf-netconf-with-defaults
* First in use in get requests
*/
#define IETF_NETCONF_WITH_DEFAULTS_YANG_NAMESPACE "urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults"
/* Second in use in by replies for tagged attributes */
#define IETF_NETCONF_WITH_DEFAULTS_ATTR_NAMESPACE "urn:ietf:params:xml:ns:netconf:default:1.0"
#define IETF_NETCONF_WITH_DEFAULTS_ATTR_PREFIX "wd"
/* Output symbol for netconf get/get-config
* ietf-netconf.yang defines it as output:
* output { anyxml data;

View file

@ -77,5 +77,6 @@ int xml_copy_marked(cxobj *x0, cxobj *x1);
int yang_check_when_xpath(cxobj *xn, cxobj *xp, yang_stmt *yn, int *hit, int *nrp, char **xpathp);
int xml_rpc_isaction(cxobj *xn);
int xml_find_action(cxobj *xn, int top, cxobj **xap);
int purge_tagged_nodes(cxobj *xn, char *ns, char *name, char *value, int keepnode);
#endif /* _CLIXON_XML_MAP_H_ */

View file

@ -921,7 +921,7 @@ nacm_datanode_read_recurse(clicon_handle h,
if (xml_flag(x, XML_FLAG_DEL)){
if (xml_purge(x) < 0)
goto done;
x = xprev;
x = xprev;
}
}
}

View file

@ -457,7 +457,8 @@ clicon_rpc_netconf_xml(clicon_handle h,
* @param[in] username If NULL, use default
* @param[in] db Name of database
* @param[in] xpath XPath (or "")
* @param[in] nsc Namespace context for filter
* @param[in] nsc Namespace context for filter
* @param[in] defaults Value of the with-defaults mode, rfc6243, or NULL
* @param[out] xt XML tree. Free with xml_free.
* Either <config> or <rpc-error>.
* @retval 0 OK
@ -468,7 +469,7 @@ clicon_rpc_netconf_xml(clicon_handle h,
*
* if ((nsc = xml_nsctx_init(NULL, "urn:example:hello")) == NULL)
* err;
* if (clicon_rpc_get_config(h, NULL, "running", "/hello/world", nsc, &xt) < 0)
* if (clicon_rpc_get_config(h, NULL, "running", "/hello/world", nsc, "explicit", &xt) < 0)
* err;
* if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
* clixon_netconf_error(xerr, "msg", "/hello/world");
@ -489,6 +490,7 @@ clicon_rpc_get_config(clicon_handle h,
char *db,
char *xpath,
cvec *nsc,
char *defaults,
cxobj **xt)
{
int retval = -1;
@ -523,6 +525,10 @@ clicon_rpc_get_config(clicon_handle h,
goto done;
cprintf(cb, "/>");
}
if (defaults != NULL)
cprintf(cb, "<with-defaults xmlns=\"%s\">%s</with-defaults>",
IETF_NETCONF_WITH_DEFAULTS_YANG_NAMESPACE,
defaults);
cprintf(cb, "</get-config></rpc>");
if ((msg = clicon_msg_encode(session_id, "%s", cbuf_get(cb))) == NULL)
goto done;
@ -910,7 +916,9 @@ clicon_rpc_get(clicon_handle h,
cprintf(cb, "/>");
}
if (defaults != NULL)
cprintf(cb, "<with-defaults xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\">%s</with-defaults>", defaults);
cprintf(cb, "<with-defaults xmlns=\"%s\">%s</with-defaults>",
IETF_NETCONF_WITH_DEFAULTS_YANG_NAMESPACE,
defaults);
cprintf(cb, "</get></rpc>");
if ((msg = clicon_msg_encode(session_id,
"%s", cbuf_get(cb))) == NULL)

View file

@ -1367,7 +1367,7 @@ xml_wrap(cxobj *xc,
* @param[in] xc xml child node (to be removed and freed)
* @retval 0 OK
* @retval -1
* @note you cannot remove xchild in the loop (unless yoy keep track of xprev)
* @note you cannot remove xchild in the loop (unless you keep track of xprev)
* @note Linear complexity - use xml_child_rm if possible
* @see xml_free Free, dont remove from parent
* @see xml_child_rm Remove if child order is known (does not free)
@ -1500,6 +1500,7 @@ xml_rm_children(cxobj *xp,
return retval;
}
/*! Remove top XML object and all children except a single child
* Given a root xml node, and the i:th child, remove the child from its parent
* and return it, remove the parent and all other children. (unwrap)

View file

@ -2218,3 +2218,52 @@ xml_find_action(cxobj *xn,
done:
return retval;
}
/*! Utility function: recursive traverse an XML tree and remove nodes based on attribute value
* Conditionally remove attribute and node
* @param[in] xn XML node
* @param[in] ns Namespace of attribute
* @param[in] name Attribute name
* @param[in] value Attribute value
* @param[in] keepnode 0: remove node associated with attribute; 1: keep node but remove attr
*/
int
purge_tagged_nodes(cxobj *xn,
char *ns,
char *name,
char *value,
int keepnode)
{
int retval = -1;
cxobj *x;
cxobj *xa;
cxobj *xprev;
char *prefix;
char *v;
int ret;
x = NULL;
xprev = NULL;
while ((x = xml_child_each(xn, x, CX_ELMNT)) != NULL) {
if ((ret = xml2prefix(x, ns, &prefix)) < 0)
goto done;
if (ret == 0)
continue;
if ((xa = xml_find_type(x, prefix, "default", CX_ATTR)) != NULL){
if (!keepnode &&
(v = xml_value(xa)) != NULL &&
strcmp(v, value) == 0){
xml_purge(x);
x = xprev;
continue;
}
xml_purge(xa); /* remove attribute regardless */
}
if (purge_tagged_nodes(x, ns, name, value, keepnode) < 0)
goto done;
xprev = x;
}
retval = 0;
done:
return retval;
}