- New netconf-specific uint32 parse functions

- Added failure handling to xpath traverse_canonical
- Started pagination cli code
This commit is contained in:
Olof hagsand 2021-08-30 14:43:24 +02:00
parent 390b0886ed
commit a046306270
16 changed files with 410 additions and 241 deletions

View file

@ -1841,3 +1841,111 @@ clixon_netconf_internal_error(cxobj *xerr,
done:
return retval;
}
/*! Parse string into uint32 and return netconf bad-element msg on error
*
* @param[in] name Name of attribute (for error msg)
* @param[in] valstr Value string to be parsed
* @param[in] defaultstr If given, default string which is accepted and sets value to 0
* @param[in,out] cbret Output buffer for internal RPC message if invalid
* @param[out] value Value if valid
* @retval -1 Error
* @retval 0 Invalid, cbret set
* @retval 1 OK
* @code
* char *name = "a";
* char *valstr = "322";
* char *defaultstr = "unbounded";
* cbuf *cbret = cbuf_new();
* uint32_t value = 0;
*
* if ((ret = netconf_parse_uint32(name, valstr, defaultstr, cbret, &value) < 0)
* goto err;
* if (ret == 0)
* // cbret contains netconf errmsg
* else
* // value contains uin32
* @endcode
*/
int
netconf_parse_uint32(char *name,
char *valstr,
char *defaultstr,
uint32_t defaultvalue,
cbuf *cbret,
uint32_t *value)
{
int retval = -1;
int ret;
char *reason = NULL;
if (valstr == NULL){
clicon_err(OE_NETCONF, EINVAL, "valstr is NULL");
goto done;
}
if (defaultstr && strcmp(valstr, defaultstr) == 0)
*value = defaultvalue;
else {
if ((ret = parse_uint32(valstr, value, &reason)) < 0){
clicon_err(OE_XML, errno, "parse_uint32");
goto done;
}
if (ret == 0){
if (netconf_bad_element(cbret, "application",
name, "Unrecognized value") < 0)
goto done;
goto fail;
}
}
retval = 1;
done:
if (reason)
free(reason);
return retval;
fail:
retval = 0;
goto done;
}
/*! Parse string into uint32 and return netconf bad-element msg on error xml variant
* @see netconf_parse_uint32_xml
*/
int
netconf_parse_uint32_xml(char *name,
char *valstr,
char *defaultstr,
uint32_t defaultvalue,
cxobj **xerr,
uint32_t *value)
{
int retval = -1;
int ret;
char *reason = NULL;
if (valstr == NULL){
clicon_err(OE_NETCONF, EINVAL, "valstr is NULL");
goto done;
}
if (defaultstr && strcmp(valstr, defaultstr) == 0)
*value = defaultvalue;
else {
if ((ret = parse_uint32(valstr, value, &reason)) < 0){
clicon_err(OE_XML, errno, "parse_uint32");
goto done;
}
if (ret == 0){
if (netconf_bad_element_xml(xerr, "application",
name, "Unrecognized value") < 0)
goto done;
goto fail;
}
}
retval = 1;
done:
if (reason)
free(reason);
return retval;
fail:
retval = 0;
goto done;
}

View file

@ -435,7 +435,7 @@ clicon_rpc_get_config(clicon_handle h,
cbuf *cb = NULL;
cxobj *xret = NULL;
cxobj *xerr = NULL;
cxobj *xd;
cxobj *xd = NULL;
uint32_t session_id;
int ret;
yang_stmt *yspec;
@ -488,7 +488,7 @@ clicon_rpc_get_config(clicon_handle h,
}
}
}
if (xt){
if (xt && xd){
if (xml_rm(xd) < 0)
goto done;
*xt = xd;
@ -799,7 +799,7 @@ clicon_rpc_get(clicon_handle h,
cbuf *cb = NULL;
cxobj *xret = NULL;
cxobj *xerr = NULL;
cxobj *xd;
cxobj *xd = NULL;
char *username;
uint32_t session_id;
int ret;
@ -860,7 +860,7 @@ clicon_rpc_get(clicon_handle h,
}
}
}
if (xt){
if (xt && xd){
if (xml_rm(xd) < 0)
goto done;
*xt = xd;
@ -882,14 +882,12 @@ clicon_rpc_get(clicon_handle h,
/*! Get database configuration and state data collection
* @param[in] h Clicon handle
* @param[in] xpath To identify a list/leaf-list
* @param[in] yli Yang-stmt of list/leaf-list of collection, if given yang populate return
* xt and make sanity check
* @param[in] namespace Namespace associated w xpath
* @param[in] nsc Namespace context for filter
* @param[in] content Clixon extension: all, config, noconfig. -1 means all
* @param[in] depth Nr of XML levels to get, -1 is all, 0 is none
* @param[in] limit Collection/clixon extension
* @param[in] offset Collection/clixon extension
* @param[in] offset uint32, 0 means none
* @param[in] limit uint32, 0 means unbounded
* @param[in] direction Collection/clixon extension
* @param[in] sort Collection/clixon extension
* @param[in] where Collection/clixon extension
@ -905,12 +903,11 @@ int
clicon_rpc_get_pageable_list(clicon_handle h,
char *datastore,
char *xpath,
yang_stmt *yli,
cvec *nsc, /* namespace context for xpath */
netconf_content content,
int32_t depth,
char *limit,
char *offset,
uint32_t offset,
uint32_t limit,
char *direction,
char *sort,
char *where,
@ -921,8 +918,7 @@ clicon_rpc_get_pageable_list(clicon_handle h,
cbuf *cb = NULL;
cxobj *xret = NULL;
cxobj *xerr = NULL;
cxobj *xr; /* return msg */
cxobj *xd; /* return data */
cxobj *xd = NULL; /* return data */
char *username;
uint32_t session_id;
int ret;
@ -963,10 +959,10 @@ clicon_rpc_get_pageable_list(clicon_handle h,
}
/* Explicit use of list-pagination */
cprintf(cb, "<cp:list-pagination>true</cp:list-pagination>");
if (limit)
cprintf(cb, "<cp:limit>%s</cp:limit>", limit);
if (offset)
cprintf(cb, "<cp:offset>%s</cp:offset>", offset);
if (offset != 0)
cprintf(cb, "<cp:offset>%u</cp:offset>", offset);
if (limit != 0)
cprintf(cb, "<cp:limit>%u</cp:limit>", limit);
if (direction)
cprintf(cb, "<cp:direction>%s</cp:direction>", direction);
if (sort)
@ -980,8 +976,8 @@ clicon_rpc_get_pageable_list(clicon_handle h,
if (clicon_rpc_msg(h, msg, &xret) < 0)
goto done;
/* Send xml error back: first check error, then ok */
if ((xr = xpath_first(xret, NULL, "/rpc-reply/rpc-error")) != NULL)
xr = xml_parent(xr); /* point to rpc-reply */
if ((xd = xpath_first(xret, NULL, "/rpc-reply/rpc-error")) != NULL)
xd = xml_parent(xd); /* point to rpc-reply */
else if ((xd = xpath_first(xret, NULL, "/rpc-reply/data")) == NULL){
if ((xd = xml_new(NETCONF_OUTPUT_DATA, NULL, CX_ELMNT)) == NULL)
goto done;
@ -1001,7 +997,7 @@ clicon_rpc_get_pageable_list(clicon_handle h,
}
}
}
if (xt){
if (xt && xd){
if (xml_rm(xd) < 0)
goto done;
*xt = xd;

View file

@ -930,37 +930,64 @@ xpath_vec_bool(cxobj *xcur,
return retval;
}
/*!
/*! Translate an xpath/nsc pair to a "canonical" form using yang prefixes
*
* @param[in] xs Parsed xpath - xpath_tree
* @param[in] yspec Yang spec containing all modules, associated with namespaces
* @param[in] nsc0 Input namespace context
* @param[out] nsc1 Output namespace context. Free after use with xml_nsctx_free
* @param[out] reason Error reason if result is 0 - failed
* @retval 1 OK with nsc1 containing the transformed nsc
* @retval 0 XPath failure with reason set to why
* @retval -1 Fatal Error
*/
static int
traverse_canonical(xpath_tree *xs,
yang_stmt *yspec,
cvec *nsc0,
cvec *nsc1)
cvec *nsc1,
cbuf **reason)
{
int retval = -1;
char *prefix0;
char *prefix1;
char *namespace;
yang_stmt *ymod;
cbuf *cb = NULL;
int ret;
switch (xs->xs_type){
case XP_NODE: /* s0 is namespace prefix, s1 is name */
prefix0 = xs->xs_s0;
if ((namespace = xml_nsctx_get(nsc0, prefix0)) == NULL){
clicon_err(OE_XML, ENOENT, "No namespace found for prefix: %s",
prefix0);
goto done;
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
cprintf(cb, "No namespace found for prefix: %s", prefix0);
if (reason)
*reason = cb;
goto failed;
}
if ((ymod = yang_find_module_by_namespace(yspec, namespace)) == NULL){
clicon_err(OE_XML, ENOENT, "No modules found for namespace: %s",
namespace);
goto done;
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
cprintf(cb, "No modules found for namespace: %s", namespace);
if (reason)
*reason = cb;
goto failed;
}
if ((prefix1 = yang_find_myprefix(ymod)) == NULL){
clicon_err(OE_XML, ENOENT, "No prefix found in module: %s",
yang_argument_get(ymod));
goto done;
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
cprintf(cb, "No prefix found in module: %s", yang_argument_get(ymod));
if (reason)
*reason = cb;
goto failed;
}
if (xml_nsctx_get(nsc1, prefix1) == NULL)
if (xml_nsctx_add(nsc1, prefix1, namespace) < 0)
@ -977,25 +1004,36 @@ traverse_canonical(xpath_tree *xs,
default:
break;
}
if (xs->xs_c0)
if (traverse_canonical(xs->xs_c0, yspec, nsc0, nsc1) < 0)
if (xs->xs_c0){
if ((ret = traverse_canonical(xs->xs_c0, yspec, nsc0, nsc1, reason)) < 0)
goto done;
if (xs->xs_c1)
if (traverse_canonical(xs->xs_c1, yspec, nsc0, nsc1) < 0)
if (ret == 0)
goto failed;
}
if (xs->xs_c1){
if ((ret = traverse_canonical(xs->xs_c1, yspec, nsc0, nsc1, reason)) < 0)
goto done;
retval = 0;
if (ret == 0)
goto failed;
}
retval = 1;
done:
return retval;
failed:
retval = 0;
goto done;
}
/*! Translate an xpath/nsc pair to a "canonical" form using yang prefixes
*
* @param[in] xpath0 Input xpath
* @param[in] nsc0 Input namespace context
* @param[in] yspec Yang spec containing all modules, associated with namespaces
* @param[out] xpath1 Output xpath. Free after use with free
* @param[out] nsc1 Output namespace context. Free after use with xml_nsctx_free
* @retval 0 OK, xpath1 and nsc1 allocated
* @retval -1 Error
* @retval 1 OK, xpath1 and nsc1 allocated
* @retval 0 XPath failure with reason set to why
* @retval -1 Fatal Error
* Example:
* Module A has prefix a and namespace urn:example:a and symbols x
* Module B with prefix b and namespace urn:example:b and symbols y
@ -1008,7 +1046,8 @@ traverse_canonical(xpath_tree *xs,
* @code
* char *xpath1 = NULL;
* cvec *nsc1 = NULL;
* if (xpath2canonical(xpath0, nsc0, yspec, &xpath1, &nsc1) < 0)
* cbuf *reason = NULL;
* if ((ret = xpath2canonical(xpath0, nsc0, yspec, &xpath1, &nsc1, &reason)) < 0)
* err;
* ...
* if (xpath1) free(xpath1);
@ -1017,15 +1056,17 @@ traverse_canonical(xpath_tree *xs,
*/
int
xpath2canonical(const char *xpath0,
cvec *nsc0,
yang_stmt *yspec,
char **xpath1,
cvec **nsc1p)
cvec *nsc0,
yang_stmt *yspec,
char **xpath1,
cvec **nsc1p,
cbuf **cbreason)
{
int retval = -1;
xpath_tree *xpt = NULL;
cvec *nsc1 = NULL;
cbuf *xcb = NULL;
int ret;
/* Parse input xpath into an xpath-tree */
if (xpath_parse(xpath0, &xpt) < 0)
@ -1036,8 +1077,10 @@ xpath2canonical(const char *xpath0,
/* Traverse tree to find prefixes, transform them to canonical form and
* create a canonical network namespace
*/
if (traverse_canonical(xpt, yspec, nsc0, nsc1) < 0)
if ((ret = traverse_canonical(xpt, yspec, nsc0, nsc1, cbreason)) < 0)
goto done;
if (ret == 0)
goto failed;
/* Print tree with new prefixes */
if ((xcb = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
@ -1055,7 +1098,7 @@ xpath2canonical(const char *xpath0,
*nsc1p = nsc1;
nsc1 = NULL;
}
retval = 0;
retval = 1;
done:
if (xcb)
cbuf_free(xcb);
@ -1064,6 +1107,9 @@ xpath2canonical(const char *xpath0,
if (xpt)
xpath_tree_free(xpt);
return retval;
failed:
retval = 0;
goto done;
}
/*! Return a count(xpath)