Added nsctx argument to cli_dbxml() and exposed it as a public function
Added function clixon_instance_id_bind()
This commit is contained in:
parent
3ecc259ec7
commit
d2ccee4eab
4 changed files with 129 additions and 19 deletions
|
|
@ -180,14 +180,12 @@ cli_signal_flush(clicon_handle h)
|
||||||
cli_signal_block (h);
|
cli_signal_block (h);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Transform data
|
/*! Create body and add last CLI variable vector as value
|
||||||
* Add next-last cvv (resolved variable) as body to xml bottom for leaf and
|
* Create and add an XML body as child of XML node xbot. Set its value to the last
|
||||||
* leaf-list.
|
* CLI variable vector element.
|
||||||
* There may be some translation necessary.
|
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
dbxml_body(cxobj *xbot,
|
dbxml_body(cxobj *xbot,
|
||||||
yang_stmt *ybot,
|
|
||||||
cvec *cvv)
|
cvec *cvv)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
@ -214,12 +212,14 @@ dbxml_body(cxobj *xbot,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Modify xml datastore from a callback using xml key format strings
|
/*! Modify xml datastore from a callback using xml key format strings
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] cvv Vector of cli string and instantiated variables
|
* @param[in] cvv Vector of cli string and instantiated variables
|
||||||
* @param[in] argv Vector. First element xml key format string, eg "/aaa/%s"
|
* @param[in] argv Vector. First element xml key format string, eg "/aaa/%s"
|
||||||
* @param[in] op Operation to perform on database
|
* @param[in] op Operation to perform on database
|
||||||
|
* @param[in] nsctx Namespace context for last value added
|
||||||
* Cvv will contain first the complete cli string, and then a set of optional
|
* Cvv will contain first the complete cli string, and then a set of optional
|
||||||
* instantiated variables.
|
* instantiated variables.
|
||||||
|
* If the last node is a leaf, the last cvv element is added as a value. This value
|
||||||
* Example:
|
* Example:
|
||||||
* cvv[0] = "set interfaces interface eth0 type bgp"
|
* cvv[0] = "set interfaces interface eth0 type bgp"
|
||||||
* cvv[1] = "eth0"
|
* cvv[1] = "eth0"
|
||||||
|
|
@ -227,12 +227,16 @@ dbxml_body(cxobj *xbot,
|
||||||
* argv[0] = "/interfaces/interface/%s/type"
|
* argv[0] = "/interfaces/interface/%s/type"
|
||||||
* op: OP_MERGE
|
* op: OP_MERGE
|
||||||
* @see cli_callback_generate where arg is generated
|
* @see cli_callback_generate where arg is generated
|
||||||
|
* @note The last value may require namespace binding present in nsctx. Note that the nsctx
|
||||||
|
* cannot normally be supplied by the clispec functions, such as cli_set, but need to be
|
||||||
|
* generated by afunction such as clixon_instance_id_bind() or other programmatically.
|
||||||
*/
|
*/
|
||||||
static int
|
int
|
||||||
cli_dbxml(clicon_handle h,
|
cli_dbxml(clicon_handle h,
|
||||||
cvec *cvv,
|
cvec *cvv,
|
||||||
cvec *argv,
|
cvec *argv,
|
||||||
enum operation_type op)
|
enum operation_type op,
|
||||||
|
cvec *nsctx)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *api_path_fmt; /* xml key format */
|
char *api_path_fmt; /* xml key format */
|
||||||
|
|
@ -246,6 +250,7 @@ cli_dbxml(clicon_handle h,
|
||||||
cxobj *xa; /* attribute */
|
cxobj *xa; /* attribute */
|
||||||
cxobj *xerr = NULL;
|
cxobj *xerr = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
cg_var *cv;
|
||||||
|
|
||||||
if (cvec_len(argv) != 1){
|
if (cvec_len(argv) != 1){
|
||||||
clicon_err(OE_PLUGIN, 0, "Requires one element to be xml key format string");
|
clicon_err(OE_PLUGIN, 0, "Requires one element to be xml key format string");
|
||||||
|
|
@ -284,10 +289,20 @@ cli_dbxml(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
if (xml_value_set(xa, xml_operation2str(op)) < 0)
|
if (xml_value_set(xa, xml_operation2str(op)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (yang_keyword_get(y) != Y_LIST && yang_keyword_get(y) != Y_LEAF_LIST){
|
/* should it not be list & container?? */
|
||||||
if (cvec_len(cvv) > 1 &&
|
if (yang_keyword_get(y) != Y_LIST &&
|
||||||
dbxml_body(xbot, y, cvv) < 0)
|
yang_keyword_get(y) != Y_LEAF_LIST &&
|
||||||
|
cvec_len(cvv) > 1){
|
||||||
|
if (dbxml_body(xbot, cvv) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
/* Loop over namespace context and add them for the value */
|
||||||
|
cv = NULL;
|
||||||
|
while ((cv = cvec_each(nsctx, cv)) != NULL){
|
||||||
|
char *ns = cv_string_get(cv);
|
||||||
|
char *pf = cv_name_get(cv);
|
||||||
|
if (ns && pf && xmlns_set(xbot, pf, ns) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ((cb = cbuf_new()) == NULL){
|
if ((cb = cbuf_new()) == NULL){
|
||||||
clicon_err(OE_XML, errno, "cbuf_new");
|
clicon_err(OE_XML, errno, "cbuf_new");
|
||||||
|
|
@ -326,7 +341,7 @@ cli_set(clicon_handle h,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
||||||
if (cli_dbxml(h, cvv, argv, OP_REPLACE) < 0)
|
if (cli_dbxml(h, cvv, argv, OP_REPLACE, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
|
@ -345,7 +360,7 @@ cli_merge(clicon_handle h,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
||||||
if (cli_dbxml(h, cvv, argv, OP_MERGE) < 0)
|
if (cli_dbxml(h, cvv, argv, OP_MERGE, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
|
@ -364,7 +379,7 @@ cli_create(clicon_handle h,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
||||||
if (cli_dbxml(h, cvv, argv, OP_CREATE) < 0)
|
if (cli_dbxml(h, cvv, argv, OP_CREATE, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
|
@ -383,7 +398,7 @@ cli_remove(clicon_handle h,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
||||||
if (cli_dbxml(h, cvv, argv, OP_REMOVE) < 0)
|
if (cli_dbxml(h, cvv, argv, OP_REMOVE, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
|
@ -402,7 +417,7 @@ cli_del(clicon_handle h,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
||||||
if (cli_dbxml(h, cvv, argv, OP_REMOVE) < 0)
|
if (cli_dbxml(h, cvv, argv, OP_REMOVE, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,8 @@ int cli_notification_register(clicon_handle h, char *stream, enum format_enum fo
|
||||||
|
|
||||||
/* cli_common.c: CLIgen new vector callbacks */
|
/* cli_common.c: CLIgen new vector callbacks */
|
||||||
|
|
||||||
|
int cli_dbxml(clicon_handle h, cvec *vars, cvec *argv, cvec *nsctx);
|
||||||
|
|
||||||
int cli_set(clicon_handle h, cvec *vars, cvec *argv);
|
int cli_set(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
|
|
||||||
int cli_merge(clicon_handle h, cvec *vars, cvec *argv);
|
int cli_merge(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
|
|
|
||||||
|
|
@ -89,9 +89,11 @@ int clixon_xml_find_api_path(cxobj *xt, yang_stmt *yt, cxobj ***xvec, int *xlen,
|
||||||
...) __attribute__ ((format (printf, 5, 6)));;
|
...) __attribute__ ((format (printf, 5, 6)));;
|
||||||
int clixon_xml_find_instance_id(cxobj *xt, yang_stmt *yt, cxobj ***xvec, int *xlen, const char *format,
|
int clixon_xml_find_instance_id(cxobj *xt, yang_stmt *yt, cxobj ***xvec, int *xlen, const char *format,
|
||||||
...) __attribute__ ((format (printf, 5, 6)));;
|
...) __attribute__ ((format (printf, 5, 6)));;
|
||||||
|
int clixon_instance_id_bind(yang_stmt *yt, cvec *nsctx, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
|
||||||
#else
|
#else
|
||||||
int clixon_xml_find_api_path(cxobj *xt, yang_stmt *yt, cxobj ***xvec, int *xlen, const char *format, ...);
|
int clixon_xml_find_api_path(cxobj *xt, yang_stmt *yt, cxobj ***xvec, int *xlen, const char *format, ...);
|
||||||
int clixon_xml_find_instance_id(cxobj *xt, yang_stmt *yt, cxobj ***xvec, int *xlen, const char *format, ...);
|
int clixon_xml_find_instance_id(cxobj *xt, yang_stmt *yt, cxobj ***xvec, int *xlen, const char *format, ...);
|
||||||
|
int clixon_instance_id_bind(yang_stmt *yt, cvec *nsctx, const char *format, ...);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* _CLIXON_PATH_H_ */
|
#endif /* _CLIXON_PATH_H_ */
|
||||||
|
|
|
||||||
|
|
@ -1683,3 +1683,94 @@ clixon_xml_find_instance_id(cxobj *xt,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Given (instance-id) path and YANG, parse path, resolve YANG and return namespace binding
|
||||||
|
*
|
||||||
|
* Instance-identifier is a subset of XML XPaths and defined in Yang, used in NACM for
|
||||||
|
* example.
|
||||||
|
* @param[in] yt Yang statement of top symbol (can be yang-spec if top-level)
|
||||||
|
* @param[out] nsctx Namespace context (should be created on entry)
|
||||||
|
* @param[in] format Format string for api-path syntax
|
||||||
|
* @retval -1 Error
|
||||||
|
* @retval 0 Non-fatal failure, yang bind failures, etc,
|
||||||
|
* @retval 1 OK with found xml nodes in xvec (if any)
|
||||||
|
* Reasons for nomatch (retval = 0) are:
|
||||||
|
* - Modulename in api-path does not correspond to existing module
|
||||||
|
* - Modulename not defined for top-level id.
|
||||||
|
* - Number of keys in key-value list does not match Yang list
|
||||||
|
* @code
|
||||||
|
* cvec *nsctx = NULL;
|
||||||
|
*
|
||||||
|
* nsctx = cvec_new(0);
|
||||||
|
* if (clixon_instance_id_bind(yspec, nsctx, "/symbol/%s", "foo") < 0)
|
||||||
|
* goto err;
|
||||||
|
* ...
|
||||||
|
* cvec_free(nsctx);
|
||||||
|
* @endcode
|
||||||
|
* @note canonical namespace contexts are used, see xpath2canonical
|
||||||
|
* @see clixon_xml_find_instance_id for finding XML nodes using instance-id:s
|
||||||
|
* @see RFC7950 Sec 9.13
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
clixon_instance_id_bind(yang_stmt *yt,
|
||||||
|
cvec *nsctx,
|
||||||
|
const char *format,
|
||||||
|
...)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
va_list ap;
|
||||||
|
size_t len;
|
||||||
|
char *path = NULL;
|
||||||
|
clixon_path *cplist = NULL;
|
||||||
|
clixon_path *cp;
|
||||||
|
int ret;
|
||||||
|
char *namespace;
|
||||||
|
|
||||||
|
va_start(ap, format);
|
||||||
|
len = vsnprintf(NULL, 0, format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
/* allocate a path string exactly fitting the length */
|
||||||
|
if ((path = malloc(len+1)) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "malloc");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
/* second round: actually compute api-path string content */
|
||||||
|
va_start(ap, format);
|
||||||
|
if (vsnprintf(path, len+1, format, ap) < 0){
|
||||||
|
clicon_err(OE_UNIX, errno, "vsnprintf");
|
||||||
|
va_end(ap);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
va_end(ap);
|
||||||
|
if (instance_id_parse(path, &cplist) < 0)
|
||||||
|
goto done;
|
||||||
|
if (clicon_debug_get())
|
||||||
|
clixon_path_print(stderr, cplist);
|
||||||
|
/* Resolve module:name to pointer to yang-stmt, fail if not successful */
|
||||||
|
if ((ret = instance_id_resolve(cplist, yt)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (ret == 0)
|
||||||
|
goto fail;
|
||||||
|
/* Loop through prefixes used */
|
||||||
|
if ((cp = cplist) != NULL){
|
||||||
|
do {
|
||||||
|
if (cp->cp_prefix &&
|
||||||
|
cp->cp_yang &&
|
||||||
|
(namespace = yang_find_mynamespace(cp->cp_yang)) != NULL){
|
||||||
|
if (xml_nsctx_get(nsctx, cp->cp_prefix) == NULL)
|
||||||
|
if (xml_nsctx_add(nsctx, cp->cp_prefix, namespace) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
cp = NEXTQ(clixon_path *, cp);
|
||||||
|
} while (cp && cp != cplist);
|
||||||
|
}
|
||||||
|
retval = 1;
|
||||||
|
done:
|
||||||
|
if (cplist)
|
||||||
|
clixon_path_free(cplist);
|
||||||
|
if (path)
|
||||||
|
free(path);
|
||||||
|
return retval;
|
||||||
|
fail:
|
||||||
|
retval = 0;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue