* Changed clicon_rpc_get and clicon_rpc_get_config functions: added username and replaced namespace with namespace context
* Fixed several issues with multiple namespaces.
This commit is contained in:
parent
3efd5703d6
commit
6e41592aec
16 changed files with 224 additions and 370 deletions
10
CHANGELOG.md
10
CHANGELOG.md
|
|
@ -17,6 +17,16 @@
|
|||
* RESTCONF: `GET http://localhost/restconf/data/mod1:a/mod2:b`
|
||||
* NETCONF: `<a xmlns="urn:example:a" xmlns:b="urn:example:b"><b:b>42</b:b></a>`
|
||||
* XPATH (in edit-config filter): `<filter type="xpath" select="a:a/b:b" xmlns:a="urn:example:a" xmlns:b="urn:example:b"/>`
|
||||
* Changed `clicon_rpc_get` and `clicon_rpc_get_config` as follows:
|
||||
* Added `username` as second parameter, default NULL
|
||||
* Changed `namespace` to namespace context, which needs to be created
|
||||
* Example new usage:
|
||||
```
|
||||
cvec *nsc = xml_nsctx_init(NULL, "urn:example:clixon")
|
||||
if (clicon_rpc_get_config(h, NULL, "running", "/interfaces", nsc, &xret) < 0)
|
||||
err;
|
||||
```
|
||||
See function reference how to make a call.
|
||||
* RESTCONF error reporting
|
||||
* Invalid api-path syntax (eg non-matching yang) error changed from 412 operation-failed to 400 Bad request invalid-value, or unknown-element.
|
||||
* Typical installation should now add a `clicon` user (as well as group)
|
||||
|
|
|
|||
|
|
@ -695,13 +695,13 @@ compare_dbs(clicon_handle h,
|
|||
astext = cv_int32_get(cvec_i(argv, 0));
|
||||
else
|
||||
astext = 0;
|
||||
if (clicon_rpc_get_config(h, "running", "/", NULL, &xc1) < 0)
|
||||
if (clicon_rpc_get_config(h, NULL, "running", "/", NULL, &xc1) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xc1, "/rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Get configuration", xerr);
|
||||
goto done;
|
||||
}
|
||||
if (clicon_rpc_get_config(h, "candidate", "/", NULL, &xc2) < 0)
|
||||
if (clicon_rpc_get_config(h, NULL, "candidate", "/", NULL, &xc2) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xc2, "/rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Get configuration", xerr);
|
||||
|
|
@ -862,7 +862,7 @@ save_config_file(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
filename = cv_string_get(cv);
|
||||
if (clicon_rpc_get_config(h, dbstr,"/", NULL, &xt) < 0)
|
||||
if (clicon_rpc_get_config(h, NULL, dbstr,"/", NULL, &xt) < 0)
|
||||
goto done;
|
||||
if (xt == NULL){
|
||||
clicon_err(OE_CFG, 0, "get config: empty tree"); /* Shouldnt happen */
|
||||
|
|
@ -1203,8 +1203,10 @@ cli_copy_config(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
cprintf(cb, xpath, keyname, fromname);
|
||||
if ((nsc = xml_nsctx_init(NULL, namespace)) == NULL)
|
||||
goto done;
|
||||
/* Get from object configuration and store in x1 */
|
||||
if (clicon_rpc_get_config(h, db, cbuf_get(cb), namespace, &x1) < 0)
|
||||
if (clicon_rpc_get_config(h, NULL, db, cbuf_get(cb), nsc, &x1) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(x1, "/rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Get configuration", xerr);
|
||||
|
|
@ -1224,8 +1226,7 @@ cli_copy_config(clicon_handle h,
|
|||
goto done;
|
||||
xml_name_set(x2, "config");
|
||||
cprintf(cb, "/%s", keyname);
|
||||
if ((nsc = xml_nsctx_init(NULL, namespace)) == NULL)
|
||||
goto done;
|
||||
|
||||
if ((x = xpath_first_nsc(x2, nsc, "%s", cbuf_get(cb))) == NULL){
|
||||
clicon_err(OE_PLUGIN, 0, "Field %s not found in copy tree", keyname);
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -117,7 +117,6 @@ expand_dbvar(void *h,
|
|||
cxobj *xcur;
|
||||
char *xpathcur;
|
||||
char *reason = NULL;
|
||||
char *namespace = NULL;
|
||||
cvec *nsc = NULL;
|
||||
|
||||
if (argv == NULL || cvec_len(argv) != 2){
|
||||
|
|
@ -150,11 +149,11 @@ expand_dbvar(void *h,
|
|||
*/
|
||||
if (api_path_fmt2api_path(api_path_fmt, cvv, &api_path) < 0)
|
||||
goto done;
|
||||
if (api_path2xpath(api_path, yspec, &xpath, &namespace) < 0)
|
||||
if (api_path2xpath(api_path, yspec, &xpath, &nsc) < 0)
|
||||
goto done;
|
||||
|
||||
/* Get configuration */
|
||||
if (clicon_rpc_get_config(h, dbstr, xpath, namespace, &xt) < 0) /* XXX */
|
||||
if (clicon_rpc_get_config(h, NULL, dbstr, xpath, nsc, &xt) < 0) /* XXX */
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Get configuration", xerr);
|
||||
|
|
@ -175,8 +174,6 @@ expand_dbvar(void *h,
|
|||
if (y==NULL)
|
||||
goto ok;
|
||||
|
||||
if ((nsc = xml_nsctx_init(NULL, namespace)) == NULL)
|
||||
goto done;
|
||||
|
||||
/* Special case for leafref. Detect leafref via Yang-type,
|
||||
* Get Yang path element, tentatively add the new syntax to the whole
|
||||
|
|
@ -437,6 +434,7 @@ cli_show_config1(clicon_handle h,
|
|||
enum genmodel_type gt;
|
||||
yang_stmt *yspec;
|
||||
char *namespace = NULL;
|
||||
cvec *nsc = NULL;
|
||||
|
||||
if (cvec_len(argv) != 3 && cvec_len(argv) != 4){
|
||||
clicon_err(OE_PLUGIN, 0, "Got %d arguments. Expected: <dbname>,<format>,<xpath>[,<attr>]", cvec_len(argv));
|
||||
|
|
@ -461,10 +459,13 @@ cli_show_config1(clicon_handle h,
|
|||
}
|
||||
cprintf(cbxpath, "%s", xpath);
|
||||
/* Fourth argument is namespace */
|
||||
if (cvec_len(argv) == 4)
|
||||
if (cvec_len(argv) == 4){
|
||||
namespace = cv_string_get(cvec_i(argv, 3));
|
||||
if ((nsc = xml_nsctx_init(NULL, namespace)) == NULL)
|
||||
goto done;
|
||||
}
|
||||
if (state == 0){ /* Get configuration-only from database */
|
||||
if (clicon_rpc_get_config(h, db, cbuf_get(cbxpath), namespace, &xt) < 0)
|
||||
if (clicon_rpc_get_config(h, NULL, db, cbuf_get(cbxpath), nsc, &xt) < 0)
|
||||
goto done;
|
||||
}
|
||||
else { /* Get configuration and state from database */
|
||||
|
|
@ -472,7 +473,7 @@ cli_show_config1(clicon_handle h,
|
|||
clicon_err(OE_FATAL, 0, "Show state only for running database, not %s", db);
|
||||
goto done;
|
||||
}
|
||||
if (clicon_rpc_get(h, cbuf_get(cbxpath), namespace, CONTENT_ALL, -1, &xt) < 0)
|
||||
if (clicon_rpc_get(h, cbuf_get(cbxpath), nsc, CONTENT_ALL, -1, &xt) < 0)
|
||||
goto done;
|
||||
}
|
||||
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
|
||||
|
|
@ -519,6 +520,8 @@ cli_show_config1(clicon_handle h,
|
|||
}
|
||||
retval = 0;
|
||||
done:
|
||||
if (nsc)
|
||||
xml_nsctx_free(nsc);
|
||||
if (xt)
|
||||
xml_free(xt);
|
||||
if (val)
|
||||
|
|
@ -617,15 +620,15 @@ show_conf_xpath(clicon_handle h,
|
|||
/* Look for namespace in command (kludge: cv must be called "ns") */
|
||||
cv = cvec_find(cvv, "ns");
|
||||
namespace = cv_string_get(cv);
|
||||
|
||||
if (clicon_rpc_get_config(h, str, xpath, namespace, &xt) < 0)
|
||||
if ((nsc = xml_nsctx_init(NULL, namespace)) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_get_config(h, NULL, str, xpath, nsc, &xt) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Get configuration", xerr);
|
||||
goto done;
|
||||
}
|
||||
if ((nsc = xml_nsctx_init(NULL, namespace)) == NULL)
|
||||
goto done;
|
||||
|
||||
if (xpath_vec_nsc(xt, nsc, "%s", &xv, &xlen, xpath) < 0)
|
||||
goto done;
|
||||
for (i=0; i<xlen; i++)
|
||||
|
|
@ -681,7 +684,6 @@ cli_show_auto1(clicon_handle h,
|
|||
cxobj *xp;
|
||||
cxobj *xerr;
|
||||
enum genmodel_type gt;
|
||||
char *namespace = NULL;
|
||||
char *api_path = NULL;
|
||||
|
||||
if (cvec_len(argv) != 3){
|
||||
|
|
@ -704,18 +706,16 @@ cli_show_auto1(clicon_handle h,
|
|||
}
|
||||
if (api_path_fmt2api_path(api_path_fmt, cvv, &api_path) < 0)
|
||||
goto done;
|
||||
if (api_path2xpath(api_path, yspec, &xpath, &namespace) < 0)
|
||||
if (api_path2xpath(api_path, yspec, &xpath, &nsc) < 0)
|
||||
goto done;
|
||||
/* XXX Kludge to overcome a trailing / in show, that I cannot add to
|
||||
* yang2api_path_fmt_1 where it should belong.
|
||||
*/
|
||||
if (xpath[strlen(xpath)-1] == '/')
|
||||
xpath[strlen(xpath)-1] = '\0';
|
||||
if ((nsc = xml_nsctx_init(NULL, namespace)) == NULL)
|
||||
goto done;
|
||||
|
||||
if (state == 0){ /* Get configuration-only from database */
|
||||
if (clicon_rpc_get_config(h, db, xpath, namespace, &xt) < 0)
|
||||
if (clicon_rpc_get_config(h, NULL, db, xpath, nsc, &xt) < 0)
|
||||
goto done;
|
||||
}
|
||||
else{ /* Get configuration and state from database */
|
||||
|
|
@ -723,7 +723,7 @@ cli_show_auto1(clicon_handle h,
|
|||
clicon_err(OE_FATAL, 0, "Show state only for running database, not %s", db);
|
||||
goto done;
|
||||
}
|
||||
if (clicon_rpc_get(h, xpath, namespace, CONTENT_ALL, -1, &xt) < 0)
|
||||
if (clicon_rpc_get(h, xpath, nsc, CONTENT_ALL, -1, &xt) < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -647,19 +647,15 @@ restconf_insert_attributes(cxobj *xdata,
|
|||
char *attrname;
|
||||
int ret;
|
||||
char *xpath = NULL;
|
||||
char *namespace = NULL;
|
||||
cvec *nsc = NULL;
|
||||
cbuf *cb = NULL;
|
||||
char *p;
|
||||
cg_var *cv = NULL;
|
||||
|
||||
y = xml_spec(xdata);
|
||||
if ((instr = cvec_find_str(qvec, "insert")) != NULL){
|
||||
/* First add xmlns:yang attribute */
|
||||
if ((xa = xml_new("yang", xdata, NULL)) == NULL)
|
||||
goto done;
|
||||
if (xml_prefix_set(xa, "xmlns") < 0)
|
||||
goto done;
|
||||
xml_type_set(xa, CX_ATTR);
|
||||
if (xml_value_set(xa, YANG_XML_NAMESPACE) < 0)
|
||||
if (xmlns_set(xdata, "yang", YANG_XML_NAMESPACE) < 0)
|
||||
goto done;
|
||||
/* Then add insert attribute */
|
||||
if ((xa = xml_new("insert", xdata, NULL)) == NULL)
|
||||
|
|
@ -685,7 +681,7 @@ restconf_insert_attributes(cxobj *xdata,
|
|||
if (xml_prefix_set(xa, "yang") < 0)
|
||||
goto done;
|
||||
xml_type_set(xa, CX_ATTR);
|
||||
if ((ret = api_path2xpath(pstr, ys_spec(y), &xpath, &namespace)) < 0)
|
||||
if ((ret = api_path2xpath(pstr, ys_spec(y), &xpath, &nsc)) < 0)
|
||||
goto done;
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
|
|
@ -715,10 +711,20 @@ restconf_insert_attributes(cxobj *xdata,
|
|||
if (xml_value_set(xa, cbuf_get(cb)) < 0)
|
||||
goto done;
|
||||
}
|
||||
/* Add prefix/namespaces used in attributes */
|
||||
cv = NULL;
|
||||
while ((cv = cvec_each(nsc, cv)) != NULL)
|
||||
if (xmlns_set(xdata, cv_name_get(cv), cv_string_get(cv)) < 0)
|
||||
goto done;
|
||||
if (nsc)
|
||||
xml_sort(xdata, NULL); /* Ensure attr is first */
|
||||
cprintf(cb, "/>");
|
||||
retval = 0;
|
||||
done:
|
||||
if (xpath)
|
||||
free(xpath);
|
||||
if (nsc)
|
||||
xml_nsctx_free(nsc);
|
||||
if (cb)
|
||||
cbuf_free(cb);
|
||||
return retval;
|
||||
|
|
|
|||
|
|
@ -262,8 +262,8 @@ api_data_write(clicon_handle h,
|
|||
char *namespace = NULL;
|
||||
char *dname;
|
||||
int nullspec = 0;
|
||||
char *xpath = NULL;
|
||||
cbuf *cbpath = NULL;
|
||||
cvec *nsc = NULL;
|
||||
|
||||
clicon_debug(1, "%s api_path:\"%s\"", __FUNCTION__, api_path0);
|
||||
clicon_debug(1, "%s data:\"%s\"", __FUNCTION__, data);
|
||||
|
|
@ -276,11 +276,11 @@ api_data_write(clicon_handle h,
|
|||
api_path = index(api_path+1, '/');
|
||||
/* Check if object exists in backend.
|
||||
* Translate api-path to xpath */
|
||||
namespace = NULL;
|
||||
if ((cbpath = cbuf_new()) == NULL)
|
||||
goto done;
|
||||
cprintf(cbpath, "/");
|
||||
if ((ret = api_path2xpath_cvv(pcvec, pi, yspec, cbpath, &namespace, &xerr)) < 0)
|
||||
|
||||
if ((ret = api_path2xpath_cvv(pcvec, pi, yspec, cbpath, &nsc, &xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
|
|
@ -291,25 +291,9 @@ api_data_write(clicon_handle h,
|
|||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
xpath = cbuf_get(cbpath);
|
||||
|
||||
/* Create text buffer for transfer to backend */
|
||||
if ((cbx = cbuf_new()) == NULL)
|
||||
goto done;
|
||||
/* show done automaticaly by the system, therefore recovery user is used
|
||||
* here */
|
||||
cprintf(cbx, "<rpc username=\"%s\"", NACM_RECOVERY_USER);
|
||||
if (namespace)
|
||||
cprintf(cbx, " xmlns:nc=\"%s\">", NETCONF_BASE_NAMESPACE);
|
||||
cprintf(cbx, "><get-config><source><candidate/></source>");
|
||||
if (namespace)
|
||||
cprintf(cbx, "<nc:filter nc:type=\"xpath\" nc:select=\"%s\" xmlns=\"%s\"/>",
|
||||
xpath, namespace);
|
||||
else /* If xpath != /, this will probably yield an error later */
|
||||
cprintf(cbx, "<filter type=\"xpath\" select=\"%s\"/>", xpath);
|
||||
cprintf(cbx, "</get-config></rpc>");
|
||||
xret = NULL;
|
||||
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0){
|
||||
if (clicon_rpc_get_config(h, NACM_RECOVERY_USER,
|
||||
"candidate", cbuf_get(cbpath), nsc, &xret) < 0){
|
||||
if (netconf_operation_failed_xml(&xerr, "protocol", clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
|
|
@ -319,6 +303,7 @@ api_data_write(clicon_handle h,
|
|||
if (api_return_err(h, r, xe, pretty, media_out, 0) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
|
||||
}
|
||||
#if 0
|
||||
if (debug){
|
||||
|
|
@ -329,8 +314,7 @@ api_data_write(clicon_handle h,
|
|||
cbuf_free(ccc);
|
||||
}
|
||||
#endif
|
||||
if ((xe = xpath_first(xret, "/rpc-reply/data")) == NULL ||
|
||||
xml_child_nr(xe) == 0){ /* Object does not exist */
|
||||
if (xml_child_nr(xret) == 0){ /* Object does not exist */
|
||||
if (plain_patch){ /* If the target resource instance does not exist, the server MUST NOT create it. */
|
||||
restconf_badrequest(r);
|
||||
goto ok;
|
||||
|
|
@ -348,7 +332,6 @@ api_data_write(clicon_handle h,
|
|||
xml_free(xret);
|
||||
xret = NULL;
|
||||
}
|
||||
|
||||
/* Create config top-of-tree */
|
||||
if ((xtop = xml_new("config", NULL, NULL)) == NULL)
|
||||
goto done;
|
||||
|
|
@ -573,7 +556,6 @@ api_data_write(clicon_handle h,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
xml_purge(xbot);
|
||||
if (xml_addsub(xparent, xdata) < 0)
|
||||
goto done;
|
||||
|
|
@ -597,7 +579,6 @@ api_data_write(clicon_handle h,
|
|||
/* If restconf insert/point attributes are present, translate to netconf */
|
||||
if (restconf_insert_attributes(xdata, qvec) < 0)
|
||||
goto done;
|
||||
|
||||
/* If we already have that default namespace, remove it in child */
|
||||
if ((xa = xml_find_type(xdata, NULL, "xmlns", CX_ATTR)) != NULL){
|
||||
if (xml2ns(xparent, NULL, &namespace) < 0)
|
||||
|
|
@ -610,7 +591,9 @@ api_data_write(clicon_handle h,
|
|||
/* For internal XML protocol: add username attribute for access control
|
||||
*/
|
||||
username = clicon_username_get(h);
|
||||
cbuf_reset(cbx);
|
||||
/* Create text buffer for transfer to backend */
|
||||
if ((cbx = cbuf_new()) == NULL)
|
||||
goto done;
|
||||
cprintf(cbx, "<rpc username=\"%s\" xmlns:%s=\"%s\">",
|
||||
username?username:"",
|
||||
NETCONF_BASE_PREFIX,
|
||||
|
|
@ -685,6 +668,8 @@ api_data_write(clicon_handle h,
|
|||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
if (nsc)
|
||||
xml_nsctx_free(nsc);
|
||||
if (cbpath)
|
||||
cbuf_free(cbpath);
|
||||
if (xret)
|
||||
|
|
|
|||
|
|
@ -165,16 +165,11 @@ api_data_get2(clicon_handle h,
|
|||
if ((cbpath = cbuf_new()) == NULL)
|
||||
goto done;
|
||||
cprintf(cbpath, "/");
|
||||
/* Create a namespace context for ymod as the default namespace to use with
|
||||
* xpath expressions */
|
||||
if ((nsc = cvec_new(0)) == NULL){
|
||||
clicon_err(OE_XML, errno, "cvec_new");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* We know "data" is element pi-1.
|
||||
* Translate api-path to xpath: xpath (cbpath) and namespace context (nsc)
|
||||
*/
|
||||
if ((ret = api_path2xpath_cvv2(pcvec, pi, yspec, cbpath, nsc, &xerr)) < 0)
|
||||
if ((ret = api_path2xpath_cvv(pcvec, pi, yspec, cbpath, &nsc, &xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
clicon_err_reset();
|
||||
|
|
@ -192,7 +187,7 @@ api_data_get2(clicon_handle h,
|
|||
case CONTENT_CONFIG:
|
||||
case CONTENT_NONCONFIG:
|
||||
case CONTENT_ALL:
|
||||
ret = clicon_rpc_get_nsc(h, xpath, nsc, content, depth, &xret);
|
||||
ret = clicon_rpc_get(h, xpath, nsc, content, depth, &xret);
|
||||
break;
|
||||
default:
|
||||
clicon_err(OE_XML, EINVAL, "Invalid content attribute %d", content);
|
||||
|
|
|
|||
|
|
@ -56,24 +56,29 @@
|
|||
int
|
||||
mycallback(clicon_handle h, cvec *cvv, cvec *argv)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *xret = NULL;
|
||||
cg_var *myvar;
|
||||
int retval = -1;
|
||||
cxobj *xret = NULL;
|
||||
cg_var *myvar;
|
||||
cvec *nsc = NULL;
|
||||
|
||||
/* Access cligen callback variables */
|
||||
myvar = cvec_find(cvv, "var"); /* get a cligen variable from vector */
|
||||
fprintf(stderr, "%s: %d\n", __FUNCTION__, cv_int32_get(myvar)); /* get int value */
|
||||
fprintf(stderr, "arg = %s\n", cv_string_get(cvec_i(argv,0))); /* get string value */
|
||||
|
||||
if ((nsc = xml_nsctx_init(NULL, "urn:example:clixon")) == NULL)
|
||||
goto done;
|
||||
/* Show eth0 interfaces config using XPATH */
|
||||
if (clicon_rpc_get_config(h, "running",
|
||||
if (clicon_rpc_get_config(h, NULL, "running",
|
||||
"/interfaces/interface[name='eth0']",
|
||||
"urn:example:clixon",
|
||||
nsc,
|
||||
&xret) < 0)
|
||||
goto done;
|
||||
xml_print(stdout, xret);
|
||||
retval = 0;
|
||||
done:
|
||||
if (nsc)
|
||||
xml_nsctx_free(nsc);
|
||||
if (xret)
|
||||
xml_free(xret);
|
||||
return retval;
|
||||
|
|
|
|||
|
|
@ -45,15 +45,14 @@ int clicon_rpc_msg(clicon_handle h, struct clicon_msg *msg, cxobj **xret0,
|
|||
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_generate_error(char *format, cxobj *xerr);
|
||||
int clicon_rpc_get_config(clicon_handle h, char *db, char *xpath, char *namespace, cxobj **xret);
|
||||
int clicon_rpc_get_config(clicon_handle h, char *username, char *db, char *xpath, cvec *nsc, 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);
|
||||
int clicon_rpc_delete_config(clicon_handle h, char *db);
|
||||
int clicon_rpc_lock(clicon_handle h, char *db);
|
||||
int clicon_rpc_unlock(clicon_handle h, char *db);
|
||||
int clicon_rpc_get(clicon_handle h, char *xpath, char *namespace, netconf_content content, int32_t depth, cxobj **xret);
|
||||
int clicon_rpc_get_nsc(clicon_handle h, char *xpath, cvec *nsc, netconf_content content, int32_t depth, cxobj **xret);
|
||||
int clicon_rpc_get(clicon_handle h, char *xpath, cvec *nsc, netconf_content content, int32_t depth, cxobj **xret);
|
||||
int clicon_rpc_close_session(clicon_handle h);
|
||||
int clicon_rpc_kill_session(clicon_handle h, int session_id);
|
||||
int clicon_rpc_validate(clicon_handle h, char *db);
|
||||
|
|
|
|||
|
|
@ -70,9 +70,8 @@ int xml_sanity(cxobj *x, void *arg);
|
|||
int xml_non_config_data(cxobj *xt, void *arg);
|
||||
int xml_spec_populate_rpc(clicon_handle h, cxobj *x, yang_stmt *yspec);
|
||||
int xml_spec_populate(cxobj *x, void *arg);
|
||||
int api_path2xpath_cvv(cvec *api_path, int offset, yang_stmt *yspec, cbuf *xpath, char **namespace, cxobj **xerr);
|
||||
int api_path2xpath_cvv2(cvec *api_path, int offset, yang_stmt *yspec, cbuf *xpath, cvec *nsc, cxobj **xerr);
|
||||
int api_path2xpath(char *api_path, yang_stmt *yspec, char **xpath, char **namespace);
|
||||
int api_path2xpath_cvv(cvec *api_path, int offset, yang_stmt *yspec, cbuf *xpath, cvec **nsc, cxobj **xerr);
|
||||
int api_path2xpath(char *api_path, yang_stmt *yspec, char **xpath, cvec **nsc);
|
||||
int api_path2xml(char *api_path, yang_stmt *yspec, cxobj *xtop,
|
||||
yang_class nodeclass, int strict, cxobj **xpathp, yang_stmt **ypathp);
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@
|
|||
int xml_child_spec(cxobj *x, cxobj *xp, yang_stmt *yspec, yang_stmt **yp);
|
||||
int xml_cmp(cxobj *x1, cxobj *x2, int enm);
|
||||
int xml_sort(cxobj *x0, void *arg);
|
||||
int xml_insert(cxobj *xp, cxobj *xc, enum insert_type ins, char *key_val);
|
||||
int xml_insert(cxobj *xp, cxobj *xc, enum insert_type ins, char *key_val, cvec *nsckey);
|
||||
int xml_sort_verify(cxobj *x, void *arg);
|
||||
int match_base_child(cxobj *x0, cxobj *x1c, yang_stmt *yc, cxobj **x0cp);
|
||||
cxobj *xml_binsearch(cxobj *xp, char *name, char *keyname, char *keyval);
|
||||
|
|
|
|||
|
|
@ -146,18 +146,18 @@ attr_ns_value(cxobj *x,
|
|||
* @see xml2ns
|
||||
* XXX: fail handling: if (netconf_data_missing(cbret, NULL, "Data does not exist; cannot delete resource") < 0)
|
||||
goto done;
|
||||
|
||||
*/
|
||||
static int
|
||||
check_namespaces(cxobj *x0,
|
||||
cxobj *x1,
|
||||
cxobj *x1p)
|
||||
check_namespaces(cxobj *x0,
|
||||
cxobj *x1,
|
||||
cxobj *x1p)
|
||||
{
|
||||
int retval = -1;
|
||||
char *namespace = NULL;
|
||||
char *prefix0 = NULL;;
|
||||
char *prefix10 = NULL; /* extra just for malloc problem */
|
||||
char *prefix1 = NULL;;
|
||||
char *prefixb = NULL; /* identityref body prefix */
|
||||
cvec *nsc0 = NULL;
|
||||
cvec *nsc = NULL;
|
||||
cxobj *xa = NULL;
|
||||
|
|
@ -258,6 +258,8 @@ check_namespaces(cxobj *x0,
|
|||
/* 6. Ensure x1 cache is updated (I think it is done w xmlns_set above) */
|
||||
retval = 0;
|
||||
done:
|
||||
if (prefixb)
|
||||
free(prefixb);
|
||||
if (prefix1)
|
||||
free(prefix1);
|
||||
return retval;
|
||||
|
|
@ -372,12 +374,9 @@ text_modify(clicon_handle h,
|
|||
char *opstr = NULL;
|
||||
char *x1name;
|
||||
char *x1cname; /* child name */
|
||||
// cxobj *x0a; /* attribute */
|
||||
// cxobj *x1a; /* attribute */
|
||||
cxobj *x0c; /* base child */
|
||||
cxobj *x0b; /* base body */
|
||||
cxobj *x1c; /* mod child */
|
||||
// char *xns; /* namespace */
|
||||
char *x0bstr; /* mod body string */
|
||||
char *x1bstr; /* mod body string */
|
||||
yang_stmt *yc; /* yang child */
|
||||
|
|
@ -388,7 +387,8 @@ text_modify(clicon_handle h,
|
|||
char *keystr = NULL;
|
||||
char *valstr = NULL;
|
||||
enum insert_type insert = INS_LAST;
|
||||
int changed = 0; /* Only if x0p's children have changed-> sort is necessary */
|
||||
int changed = 0; /* Only if x0p's children have changed-> sort necessary */
|
||||
cvec *nscx1 = NULL;
|
||||
|
||||
/* Check for operations embedded in tree according to netconf */
|
||||
if ((ret = attr_ns_value(x1,
|
||||
|
|
@ -514,7 +514,7 @@ text_modify(clicon_handle h,
|
|||
}
|
||||
}
|
||||
if (changed){
|
||||
if (xml_insert(x0p, x0, insert, valstr) < 0)
|
||||
if (xml_insert(x0p, x0, insert, valstr, NULL) < 0)
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
|
|
@ -563,6 +563,7 @@ text_modify(clicon_handle h,
|
|||
"key", YANG_XML_NAMESPACE,
|
||||
cbret, &keystr)) < 0)
|
||||
goto done;
|
||||
|
||||
/* if insert/before, key attribute must be there */
|
||||
if ((insert == INS_AFTER || insert == INS_BEFORE) &&
|
||||
keystr == NULL){
|
||||
|
|
@ -570,7 +571,9 @@ text_modify(clicon_handle h,
|
|||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* If keystr is set, need a full namespace context */
|
||||
if (keystr && xml_nsctx_node(x1, &nscx1) < 0)
|
||||
goto done;
|
||||
}
|
||||
switch(op){
|
||||
case OP_CREATE:
|
||||
|
|
@ -623,8 +626,6 @@ text_modify(clicon_handle h,
|
|||
}
|
||||
if ((x0 = xml_new(x1name, x0p, (yang_stmt*)y0)) == NULL)
|
||||
goto done;
|
||||
// XXX if (check_namespaces(x1, x0) < 0)
|
||||
// goto done;
|
||||
if (xml_copy(x1, x0) < 0)
|
||||
goto done;
|
||||
break;
|
||||
|
|
@ -708,7 +709,7 @@ text_modify(clicon_handle h,
|
|||
goto fail;
|
||||
}
|
||||
if (changed){
|
||||
if (xml_insert(x0p, x0, insert, keystr) < 0)
|
||||
if (xml_insert(x0p, x0, insert, keystr, nscx1) < 0)
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@
|
|||
#include "clixon_proto.h"
|
||||
#include "clixon_err.h"
|
||||
#include "clixon_err_string.h"
|
||||
#include "clixon_xml_nsctx.h"
|
||||
#include "clixon_netconf_lib.h"
|
||||
#include "clixon_proto_client.h"
|
||||
|
||||
|
|
@ -251,54 +252,70 @@ clicon_rpc_generate_error(char *prefix,
|
|||
/*! Get database configuration
|
||||
* Same as clicon_proto_change just with a cvec instead of lvec
|
||||
* @param[in] h CLICON handle
|
||||
* @param[in] username If NULL, use default
|
||||
* @param[in] db Name of database
|
||||
* @param[in] xpath XPath (or "")
|
||||
* @param[in] namespace Namespace associated w xpath
|
||||
* @param[in] nsc Namespace context for filter
|
||||
* @param[out] xt XML tree. Free with xml_free.
|
||||
* Either <config> or <rpc-error>.
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error, fatal or xml
|
||||
* @code
|
||||
* cxobj *xt = NULL;
|
||||
* if (clicon_rpc_get_config(h, "running", "/hello/world", "urn:example:hello", &xt) < 0)
|
||||
* cxobj *xt = NULL;
|
||||
* cvec *nsc = NULL;
|
||||
*
|
||||
* if ((nsc = xml_nsctx_init(NULL, "urn:example:hello")) == NULL)
|
||||
* err;
|
||||
* if (clicon_rpc_get_config(h, NULL, "running", "/hello/world", nsc, &xt) < 0)
|
||||
* err;
|
||||
* if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
|
||||
* clicon_rpc_generate_error("", xerr);
|
||||
* err;
|
||||
* }
|
||||
* if (xt)
|
||||
* xml_free(xt);
|
||||
* }
|
||||
* if (xt)
|
||||
* xml_free(xt);
|
||||
* if (nsc)
|
||||
* xml_nsctx_free(nsc);
|
||||
* @endcode
|
||||
* @see clicon_rpc_generate_error
|
||||
*/
|
||||
int
|
||||
clicon_rpc_get_config(clicon_handle h,
|
||||
char *db,
|
||||
char *xpath,
|
||||
char *namespace,
|
||||
cxobj **xt)
|
||||
clicon_rpc_get_config(clicon_handle h,
|
||||
char *username,
|
||||
char *db,
|
||||
char *xpath,
|
||||
cvec *nsc,
|
||||
cxobj **xt)
|
||||
{
|
||||
int retval = -1;
|
||||
struct clicon_msg *msg = NULL;
|
||||
cbuf *cb = NULL;
|
||||
cxobj *xret = NULL;
|
||||
cxobj *xd;
|
||||
char *username;
|
||||
cg_var *cv = NULL;
|
||||
char *prefix;
|
||||
|
||||
if ((cb = cbuf_new()) == NULL)
|
||||
goto done;
|
||||
cprintf(cb, "<rpc");
|
||||
if ((username = clicon_username_get(h)) != NULL)
|
||||
if (username == NULL)
|
||||
username = clicon_username_get(h);
|
||||
if (username != NULL)
|
||||
cprintf(cb, " username=\"%s\"", username);
|
||||
if (namespace)
|
||||
cprintf(cb, " xmlns:nc=\"%s\"", NETCONF_BASE_NAMESPACE);
|
||||
cprintf(cb, " xmlns:%s=\"%s\"",
|
||||
NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
|
||||
cprintf(cb, "><get-config><source><%s/></source>", db);
|
||||
if (xpath && strlen(xpath)){
|
||||
if (namespace)
|
||||
cprintf(cb, "<nc:filter nc:type=\"xpath\" nc:select=\"%s\" xmlns=\"%s\"/>",
|
||||
xpath, namespace);
|
||||
else /* If xpath != /, this will probably yield an error later */
|
||||
cprintf(cb, "<filter type=\"xpath\" select=\"%s\"/>", xpath);
|
||||
cprintf(cb, "<%s:filter %s:type=\"xpath\" %s:select=\"%s\"",
|
||||
NETCONF_BASE_PREFIX, NETCONF_BASE_PREFIX, NETCONF_BASE_PREFIX,
|
||||
xpath);
|
||||
while ((cv = cvec_each(nsc, cv)) != NULL){
|
||||
cprintf(cb, " xmlns");
|
||||
if ((prefix = cv_name_get(cv)))
|
||||
cprintf(cb, ":%s", prefix);
|
||||
cprintf(cb, "=\"%s\"", cv_string_get(cv));
|
||||
}
|
||||
cprintf(cb, "/>");
|
||||
}
|
||||
cprintf(cb, "</get-config></rpc>");
|
||||
if ((msg = clicon_msg_encode("%s", cbuf_get(cb))) == NULL)
|
||||
|
|
@ -327,6 +344,7 @@ clicon_rpc_get_config(clicon_handle h,
|
|||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*! Send database entries as XML to backend daemon
|
||||
* @param[in] h CLICON handle
|
||||
* @param[in] db Name of database
|
||||
|
|
@ -541,6 +559,7 @@ clicon_rpc_unlock(clicon_handle h,
|
|||
* @param[in] h Clicon handle
|
||||
* @param[in] xpath XPath in a filter stmt (or NULL/"" for no filter)
|
||||
* @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[out] xt XML tree. Free with xml_free.
|
||||
|
|
@ -550,15 +569,21 @@ clicon_rpc_unlock(clicon_handle h,
|
|||
* @note if xpath is set but namespace is NULL, the default, netconf base
|
||||
* namespace will be used which is most probably wrong.
|
||||
* @code
|
||||
* cxobj *xt = NULL;
|
||||
* if (clicon_rpc_get(h, "/hello/world", "urn:example:hello", CONTENT_ALL, -1, &xt) < 0)
|
||||
* err;
|
||||
* if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
|
||||
* clicon_rpc_generate_error(xerr);
|
||||
* err;
|
||||
* cxobj *xt = NULL;
|
||||
* cvec *nsc = NULL;
|
||||
*
|
||||
* if ((nsc = xml_nsctx_init(NULL, "urn:example:hello")) == NULL)
|
||||
* err;
|
||||
* if (clicon_rpc_get(h, "/hello/world", nsc, CONTENT_ALL, -1, &xt) < 0)
|
||||
* err;
|
||||
* if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
|
||||
* clicon_rpc_generate_error(xerr);
|
||||
* err;
|
||||
* }
|
||||
* if (xt)
|
||||
* xml_free(xt);
|
||||
* if (xt)
|
||||
* xml_free(xt);
|
||||
* if (nsc)
|
||||
* xml_nsctx_free(nsc);
|
||||
* @endcode
|
||||
* @see clicon_rpc_get_config which is almost the same as with content=config, but you can also select dbname
|
||||
* @see clicon_rpc_generate_error
|
||||
|
|
@ -566,7 +591,7 @@ clicon_rpc_unlock(clicon_handle h,
|
|||
int
|
||||
clicon_rpc_get(clicon_handle h,
|
||||
char *xpath,
|
||||
char *namespace,
|
||||
cvec *nsc, /* namespace context for filter */
|
||||
netconf_content content,
|
||||
int32_t depth,
|
||||
cxobj **xt)
|
||||
|
|
@ -577,71 +602,6 @@ clicon_rpc_get(clicon_handle h,
|
|||
cxobj *xret = NULL;
|
||||
cxobj *xd;
|
||||
char *username;
|
||||
|
||||
if ((cb = cbuf_new()) == NULL)
|
||||
goto done;
|
||||
cprintf(cb, "<rpc");
|
||||
if ((username = clicon_username_get(h)) != NULL)
|
||||
cprintf(cb, " username=\"%s\"", username);
|
||||
if (namespace)
|
||||
cprintf(cb, " xmlns:%s=\"%s\"",
|
||||
NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
|
||||
cprintf(cb, "><get");
|
||||
/* Clixon extension, content=all,config, or nonconfig */
|
||||
if (content != -1)
|
||||
cprintf(cb, " content=\"%s\"", netconf_content_int2str(content));
|
||||
/* Clixon extension, depth=<level> */
|
||||
if (depth != -1)
|
||||
cprintf(cb, " depth=\"%d\"", depth);
|
||||
cprintf(cb, ">");
|
||||
if (xpath && strlen(xpath)) {
|
||||
if (namespace)
|
||||
cprintf(cb, "<nc:filter nc:type=\"xpath\" nc:select=\"%s\" xmlns=\"%s\"/>",
|
||||
xpath, namespace);
|
||||
else /* If xpath != /, this will probably yield an error later */
|
||||
cprintf(cb, "<filter type=\"xpath\" select=\"%s\"/>", xpath);
|
||||
}
|
||||
cprintf(cb, "</get></rpc>");
|
||||
if ((msg = clicon_msg_encode("%s", cbuf_get(cb))) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
/* Send xml error back: first check error, then ok */
|
||||
if ((xd = xpath_first(xret, "/rpc-reply/rpc-error")) != NULL)
|
||||
xd = xml_parent(xd); /* point to rpc-reply */
|
||||
else if ((xd = xpath_first(xret, "/rpc-reply/data")) == NULL)
|
||||
if ((xd = xml_new("data", NULL, NULL)) == NULL)
|
||||
goto done;
|
||||
if (xt){
|
||||
if (xml_rm(xd) < 0)
|
||||
goto done;
|
||||
*xt = xd;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
if (cb)
|
||||
cbuf_free(cb);
|
||||
if (xret)
|
||||
xml_free(xret);
|
||||
if (msg)
|
||||
free(msg);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
clicon_rpc_get_nsc(clicon_handle h,
|
||||
char *xpath,
|
||||
cvec *nsc, /* namespace context for filter */
|
||||
netconf_content content,
|
||||
int32_t depth,
|
||||
cxobj **xt)
|
||||
{
|
||||
int retval = -1;
|
||||
struct clicon_msg *msg = NULL;
|
||||
cbuf *cb = NULL;
|
||||
cxobj *xret = NULL;
|
||||
cxobj *xd;
|
||||
char *username;
|
||||
cg_var *cv = NULL;
|
||||
char *prefix;
|
||||
|
||||
|
|
|
|||
|
|
@ -422,8 +422,8 @@ xmlns_set(cxobj *x,
|
|||
else{ /* xmlns="<uri>" */
|
||||
if ((xa = xml_new("xmlns", x, NULL)) == NULL)
|
||||
goto done;
|
||||
xml_type_set(xa, CX_ATTR);
|
||||
}
|
||||
xml_type_set(xa, CX_ATTR);
|
||||
if (xml_value_set(xa, ns) < 0)
|
||||
goto done;
|
||||
/* (re)set namespace cache (as used in xml2ns) */
|
||||
|
|
@ -449,38 +449,41 @@ xml2prefix(cxobj *xn,
|
|||
{
|
||||
int retval = -1;
|
||||
cxobj *xa = NULL;
|
||||
cxobj *xp;
|
||||
char *prefix = NULL;
|
||||
int ret;
|
||||
|
||||
while (xn != NULL){
|
||||
if (nscache_get_prefix(xn, namespace, &prefix) == 1) /* found */
|
||||
goto found;
|
||||
// if (xn->x_ns_cache == NULL){ /* Look in node */
|
||||
xa = NULL;
|
||||
while ((xa = xml_child_each(xn, xa, CX_ATTR)) != NULL) {
|
||||
/* xmlns=namespace */
|
||||
if (strcmp("xmlns", xml_name(xa)) == 0){
|
||||
if (strcmp(xml_value(xa), namespace) == 0){
|
||||
clicon_debug(1, "%sA NULL %s", __FUNCTION__, namespace);
|
||||
if (nscache_set(xn, NULL, namespace) < 0)
|
||||
goto done;
|
||||
prefix = NULL;
|
||||
goto found;
|
||||
}
|
||||
|
||||
}
|
||||
/* xmlns:prefix=namespace */
|
||||
else if (strcmp("xmlns", xml_prefix(xa)) == 0){
|
||||
if (strcmp(xml_value(xa), namespace) == 0){
|
||||
prefix = xml_name(xa);
|
||||
assert(strcmp(prefix, "xmlns"));
|
||||
if (nscache_set(xn, prefix, namespace) < 0)
|
||||
goto done;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
if (nscache_get_prefix(xn, namespace, &prefix) == 1) /* found */
|
||||
goto found;
|
||||
xa = NULL;
|
||||
while ((xa = xml_child_each(xn, xa, CX_ATTR)) != NULL) {
|
||||
/* xmlns=namespace */
|
||||
if (strcmp("xmlns", xml_name(xa)) == 0){
|
||||
if (strcmp(xml_value(xa), namespace) == 0){
|
||||
if (nscache_set(xn, NULL, namespace) < 0)
|
||||
goto done;
|
||||
prefix = NULL; /* Maybe should set all caches in ns:s children? */
|
||||
goto found;
|
||||
}
|
||||
// }
|
||||
xn = xml_parent(xn);
|
||||
}
|
||||
/* xmlns:prefix=namespace */
|
||||
else if (strcmp("xmlns", xml_prefix(xa)) == 0){
|
||||
if (strcmp(xml_value(xa), namespace) == 0){
|
||||
prefix = xml_name(xa);
|
||||
if (nscache_set(xn, prefix, namespace) < 0)
|
||||
goto done;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((xp = xml_parent(xn)) != NULL){
|
||||
if ((ret = xml2prefix(xp, namespace, &prefix)) < 0)
|
||||
goto done;
|
||||
if (ret == 1){
|
||||
if (nscache_set(xn, prefix, namespace) < 0)
|
||||
goto done;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
|
|||
|
|
@ -2212,7 +2212,7 @@ xml_default(cxobj *xt,
|
|||
goto done;
|
||||
free(str);
|
||||
added++;
|
||||
if (xml_insert(xt, xc, INS_LAST, NULL) < 0)
|
||||
if (xml_insert(xt, xc, INS_LAST, NULL, NULL) < 0)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
|
@ -2401,29 +2401,30 @@ xml_spec_populate(cxobj *x,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Translate from restconf api-path(cvv) to xml xpath(cbuf) and namespace
|
||||
/*! Translate from restconf api-path(cvv) to xml xpath(cbuf) and namespace context
|
||||
*
|
||||
* @param[in] api_path URI-encoded path expression" (RFC8040 3.5.3) as cvec
|
||||
* @param[in] offset Offset of cvec, where api-path starts
|
||||
* @param[in] yspec Yang spec
|
||||
* @param[in,out] xpath The xpath as cbuf (must be created and may have content)
|
||||
* @param[out] namespace Namespace of xpath (direct pointer don't free)
|
||||
* @param[out] nsc Namespace context of xpath (free w xml_nsctx_free)
|
||||
* @param[out] xerr Netconf error message
|
||||
* @retval 1 OK
|
||||
* @retval 0 Invalid api_path or associated XML, netconf error xml set
|
||||
* @retval -1 Fatal error, clicon_err called
|
||||
*
|
||||
|
||||
* @code
|
||||
* cbuf *xpath = cbuf_new();
|
||||
* cvec *cvv = NULL;
|
||||
* cvec *nsc = NULL;
|
||||
* if (str2cvec("www.foo.com/restconf/a/b=c", '/', '=', &cvv) < 0)
|
||||
* err;
|
||||
* if ((ret = api_path2xpath_cvv(yspec, cvv, 0, cxpath, NULL)) < 0)
|
||||
* if ((ret = api_path2xpath_cvv(yspec, cvv, 0, cxpath, &nsc, NULL)) < 0)
|
||||
* err;
|
||||
* if (ret == 1)
|
||||
* ... access xpath as cbuf_get(xpath)
|
||||
* cbuf_free(xpath)
|
||||
* cbuf_free(xpath);
|
||||
* cvec_free(nsc);
|
||||
* @endcode
|
||||
* It works like this:
|
||||
* Assume origin incoming path is
|
||||
|
|
@ -2441,137 +2442,8 @@ api_path2xpath_cvv(cvec *api_path,
|
|||
int offset,
|
||||
yang_stmt *yspec,
|
||||
cbuf *xpath,
|
||||
char **namespace,
|
||||
cvec **nscp,
|
||||
cxobj **xerr)
|
||||
{
|
||||
int retval = -1;
|
||||
int i;
|
||||
cg_var *cv;
|
||||
char *nodeid;
|
||||
char *prefix = NULL;
|
||||
char *name = NULL;
|
||||
cvec *cvk = NULL; /* vector of index keys */
|
||||
yang_stmt *y = NULL;
|
||||
yang_stmt *ymod = NULL;
|
||||
char *val;
|
||||
cg_var *cvi;
|
||||
char **valvec = NULL;
|
||||
int vi;
|
||||
int nvalvec;
|
||||
cbuf *cberr = NULL;
|
||||
|
||||
for (i=offset; i<cvec_len(api_path); i++){
|
||||
cv = cvec_i(api_path, i);
|
||||
nodeid = cv_name_get(cv);
|
||||
if (nodeid_split(nodeid, &prefix, &name) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s [%d] cvname: %s:%s",
|
||||
__FUNCTION__, i, prefix?prefix:"", name);
|
||||
if (i == offset){ /* top-node */
|
||||
if (prefix == NULL){
|
||||
if ((cberr = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
cprintf(cberr, "'%s': Expected prefix:name", nodeid);
|
||||
if (netconf_invalid_value_xml(xerr, "application", cbuf_get(cberr)) < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
if ((ymod = yang_find_module_by_name(yspec, prefix)) == NULL){
|
||||
if ((cberr = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
cprintf(cberr, "No such yang module: %s", prefix);
|
||||
if (netconf_invalid_value_xml(xerr, "application", cbuf_get(cberr)) < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
y = yang_find_datanode(ymod, name);
|
||||
}
|
||||
else
|
||||
y = yang_find_datanode(y, name);
|
||||
if (y == NULL){
|
||||
if (netconf_unknown_element_xml(xerr, "application", name, "Unknown element") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
/* Check if has value, means '=' */
|
||||
if (cv2str(cv, NULL, 0) > 0){
|
||||
if ((val = cv2str_dup(cv)) == NULL)
|
||||
goto done;
|
||||
switch (yang_keyword_get(y)){
|
||||
case Y_LIST:
|
||||
/* Transform value "a,b,c" to "a" "b" "c" (nvalvec=3)
|
||||
* Note that vnr can be < length of cvk, due to empty or unset values
|
||||
*/
|
||||
if (valvec){ /* loop, valvec may have been used before */
|
||||
free(valvec);
|
||||
valvec = NULL;
|
||||
}
|
||||
if ((valvec = clicon_strsep(val, ",", &nvalvec)) == NULL)
|
||||
goto done;
|
||||
cvk = y->ys_cvec; /* Use Y_LIST cache, see ys_populate_list() */
|
||||
cvi = NULL;
|
||||
/* Iterate over individual yang keys */
|
||||
cprintf(xpath, "/%s", name);
|
||||
vi = 0;
|
||||
while ((cvi = cvec_each(cvk, cvi)) != NULL && vi<nvalvec)
|
||||
cprintf(xpath, "[%s='%s']", cv_string_get(cvi), valvec[vi++]);
|
||||
break;
|
||||
case Y_LEAF_LIST: /* XXX: LOOP? */
|
||||
cprintf(xpath, "/%s", name);
|
||||
if (val)
|
||||
cprintf(xpath, "[.='%s']", val);
|
||||
else
|
||||
cprintf(xpath, "[.='']");
|
||||
break;
|
||||
default:
|
||||
cprintf(xpath, "%s%s", (i==offset?"":"/"), name);
|
||||
break;
|
||||
}
|
||||
if (val)
|
||||
free(val);
|
||||
}
|
||||
else
|
||||
cprintf(xpath, "%s%s", (i==offset?"":"/"), name);
|
||||
if (prefix){
|
||||
free(prefix);
|
||||
prefix = NULL;
|
||||
}
|
||||
if (name){
|
||||
free(name);
|
||||
name = NULL;
|
||||
}
|
||||
} /* for */
|
||||
/* return values: yang module */
|
||||
if (namespace)
|
||||
*namespace = yang_find_mynamespace(ymod);
|
||||
retval = 1; /* OK */
|
||||
done:
|
||||
if (cberr != NULL)
|
||||
cbuf_free(cberr);
|
||||
if (valvec)
|
||||
free(valvec);
|
||||
if (prefix)
|
||||
free(prefix);
|
||||
if (name)
|
||||
free(name);
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0; /* Validation failed */
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Temp alternative to api_path2xpath_cvv */
|
||||
int
|
||||
api_path2xpath_cvv2(cvec *api_path,
|
||||
int offset,
|
||||
yang_stmt *yspec,
|
||||
cbuf *xpath,
|
||||
cvec *nsc,
|
||||
cxobj **xerr)
|
||||
{
|
||||
int retval = -1;
|
||||
int i;
|
||||
|
|
@ -2590,7 +2462,11 @@ api_path2xpath_cvv2(cvec *api_path,
|
|||
int nvalvec;
|
||||
cbuf *cberr = NULL;
|
||||
char *namespace = NULL;
|
||||
cvec *nsc = NULL;
|
||||
|
||||
/* Initialize namespace context */
|
||||
if ((nsc = xml_nsctx_init(NULL, NULL)) == NULL)
|
||||
goto done;
|
||||
for (i=offset; i<cvec_len(api_path); i++){
|
||||
cv = cvec_i(api_path, i);
|
||||
nodeid = cv_name_get(cv);
|
||||
|
|
@ -2633,6 +2509,7 @@ api_path2xpath_cvv2(cvec *api_path,
|
|||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Get XML/xpath prefix given namespace.
|
||||
* note different from api-path prefix
|
||||
*/
|
||||
|
|
@ -2712,6 +2589,10 @@ api_path2xpath_cvv2(cvec *api_path,
|
|||
}
|
||||
} /* for */
|
||||
retval = 1; /* OK */
|
||||
if (nscp){
|
||||
*nscp = nsc;
|
||||
nsc = NULL;
|
||||
}
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
if (cberr != NULL)
|
||||
|
|
@ -2720,6 +2601,8 @@ api_path2xpath_cvv2(cvec *api_path,
|
|||
free(valvec);
|
||||
if (prefix)
|
||||
free(prefix);
|
||||
if (nsc)
|
||||
cvec_free(nsc);
|
||||
if (name)
|
||||
free(name);
|
||||
return retval;
|
||||
|
|
@ -2732,17 +2615,19 @@ api_path2xpath_cvv2(cvec *api_path,
|
|||
* @param[in] api_path URI-encoded path expression" (RFC8040 3.5.3)
|
||||
* @param[in] yspec Yang spec
|
||||
* @param[out] xpath xpath (use free() to deallocate)
|
||||
* @param[out] namespace Namespace of xpath (direct pointer don't free)
|
||||
* @param[out] nsc Namespace context of xpath (free w xml_nsctx_free)
|
||||
* @retval 1 OK
|
||||
* @retval 0 Invalid api_path or associated XML, netconf called
|
||||
* @retval -1 Fatal error, clicon_err called
|
||||
* @code
|
||||
* char *xpath = NULL;
|
||||
* if ((ret = api_path2xpath("/module:a/b", yspec, &xpath, &namespace)) < 0)
|
||||
* cvec *nsc = NULL;
|
||||
* if ((ret = api_path2xpath("/module:a/b", yspec, &xpath, &nsc)) < 0)
|
||||
* err;
|
||||
* if (ret == 1)
|
||||
* ... access xpath as cbuf_get(xpath)
|
||||
* free(xpath)
|
||||
* cvec_free(nsc);
|
||||
* @endcode
|
||||
*
|
||||
* @see api_path2xml_cvv which uses other parameter formats
|
||||
|
|
@ -2751,7 +2636,7 @@ int
|
|||
api_path2xpath(char *api_path,
|
||||
yang_stmt *yspec,
|
||||
char **xpathp,
|
||||
char **namespace)
|
||||
cvec **nsc)
|
||||
{
|
||||
int retval = -1;
|
||||
cvec *cvv = NULL; /* api-path vector */
|
||||
|
|
@ -2763,7 +2648,7 @@ api_path2xpath(char *api_path,
|
|||
goto done;
|
||||
if ((xpath = cbuf_new()) == NULL)
|
||||
goto done;
|
||||
if ((retval = api_path2xpath_cvv(cvv, 0, yspec, xpath, namespace, &xerr)) < 0){
|
||||
if ((retval = api_path2xpath_cvv(cvv, 0, yspec, xpath, nsc, &xerr)) < 0){
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ xml_nsctx_set(cvec *cvv,
|
|||
|
||||
/*! Create and initialize XML namespace context
|
||||
* @param[in] prefix Namespace prefix, or NULL for default
|
||||
* @param[in] namespace Cached namespace to set (assume non-null?)
|
||||
* @param[in] namespace Set this namespace. If NULL create empty nsctx
|
||||
* @retval nsc Return namespace context in form of a cvec
|
||||
* @retval NULL Error
|
||||
* @code
|
||||
|
|
@ -161,7 +161,7 @@ xml_nsctx_init(char *prefix,
|
|||
clicon_err(OE_XML, errno, "cvec_new");
|
||||
goto done;
|
||||
}
|
||||
if (xml_nsctx_set(cvv, prefix, namespace) < 0)
|
||||
if (namespace && xml_nsctx_set(cvv, prefix, namespace) < 0)
|
||||
goto done;
|
||||
done:
|
||||
return cvv;
|
||||
|
|
|
|||
|
|
@ -481,6 +481,7 @@ xml_search(cxobj *xp,
|
|||
* @param[in] yn Yang stmt of xml child node
|
||||
* @param[in] ins Insert operation (if ordered-by user)
|
||||
* @param[in] key_val Key if LIST and ins is before/after, val if LEAF_LIST
|
||||
* @param[in] nsc_key Network namespace for key
|
||||
* @retval i Order where xn should be inserted into xp:s children
|
||||
* @retval -1 Error
|
||||
* LIST: RFC 7950 7.8.6:
|
||||
|
|
@ -493,14 +494,14 @@ xml_search(cxobj *xp,
|
|||
* yang:insert="after"
|
||||
* yang:value="3des-cbc">blowfish-cbc</cipher>)
|
||||
*/
|
||||
|
||||
static int
|
||||
xml_insert_userorder(cxobj *xp,
|
||||
cxobj *xn,
|
||||
yang_stmt *yn,
|
||||
int mid,
|
||||
enum insert_type ins,
|
||||
char *key_val)
|
||||
char *key_val,
|
||||
cvec *nsc_key)
|
||||
{
|
||||
int retval = -1;
|
||||
int i;
|
||||
|
|
@ -538,7 +539,7 @@ xml_insert_userorder(cxobj *xp,
|
|||
else{
|
||||
switch (yang_keyword_get(yn)){
|
||||
case Y_LEAF_LIST:
|
||||
if ((xc = xpath_first(xp, "%s[.='%s']", xml_name(xn),key_val)) == NULL)
|
||||
if ((xc = xpath_first_nsc(xp, nsc_key, "%s[.='%s']", xml_name(xn), key_val)) == NULL)
|
||||
clicon_err(OE_YANG, 0, "bad-attribute: value, missing-instance: %s", key_val);
|
||||
else {
|
||||
if ((i = xml_child_order(xp, xc)) < 0)
|
||||
|
|
@ -548,7 +549,7 @@ xml_insert_userorder(cxobj *xp,
|
|||
}
|
||||
break;
|
||||
case Y_LIST:
|
||||
if ((xc = xpath_first(xp, "%s%s", xml_name(xn), key_val)) == NULL)
|
||||
if ((xc = xpath_first_nsc(xp, nsc_key, "%s%s", xml_name(xn), key_val)) == NULL)
|
||||
clicon_err(OE_YANG, 0, "bad-attribute: key, missing-instance: %s", key_val);
|
||||
else {
|
||||
if ((i = xml_child_order(xp, xc)) < 0)
|
||||
|
|
@ -577,6 +578,7 @@ xml_insert_userorder(cxobj *xp,
|
|||
* @param[in] userorder Set if ordered-by user, otherwise 0
|
||||
* @param[in] ins Insert operation (if ordered-by user)
|
||||
* @param[in] key_val Key if LIST and ins is before/after, val if LEAF_LIST
|
||||
* @param[in] nsc_key Network namespace for key
|
||||
* @param[in] low Lower range limit
|
||||
* @param[in] upper Upper range limit
|
||||
* @retval i Order where xn should be inserted into xp:s children
|
||||
|
|
@ -590,6 +592,7 @@ xml_insert2(cxobj *xp,
|
|||
int userorder,
|
||||
enum insert_type ins,
|
||||
char *key_val,
|
||||
cvec *nsc_key,
|
||||
int low,
|
||||
int upper)
|
||||
{
|
||||
|
|
@ -623,7 +626,7 @@ xml_insert2(cxobj *xp,
|
|||
}
|
||||
if (yc == yn){ /* Same yang */
|
||||
if (userorder){ /* append: increment linearly until no longer equal */
|
||||
retval = xml_insert_userorder(xp, xn, yn, mid, ins, key_val);
|
||||
retval = xml_insert_userorder(xp, xn, yn, mid, ins, key_val, nsc_key);
|
||||
goto done;
|
||||
}
|
||||
else /* Ordered by system */
|
||||
|
|
@ -649,9 +652,9 @@ xml_insert2(cxobj *xp,
|
|||
goto done;
|
||||
}
|
||||
else if (cmp < 0)
|
||||
return xml_insert2(xp, xn, yn, yni, userorder, ins, key_val, low, mid);
|
||||
return xml_insert2(xp, xn, yn, yni, userorder, ins, key_val, nsc_key, low, mid);
|
||||
else
|
||||
return xml_insert2(xp, xn, yn, yni, userorder, ins, key_val, mid+1, upper);
|
||||
return xml_insert2(xp, xn, yn, yni, userorder, ins, key_val, nsc_key, mid+1, upper);
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -660,7 +663,8 @@ xml_insert2(cxobj *xp,
|
|||
* @param[in] xp Parent xml node. If NULL just remove from old parent.
|
||||
* @param[in] x Child xml node to insert under xp
|
||||
* @param[in] ins Insert operation (if ordered-by user)
|
||||
* @param[in] key_val Key if LIST and ins is before/after, val if LEAF_LIST
|
||||
* @param[in] key_val Key if x is LIST and ins is before/after, val if LEAF_LIST
|
||||
* @param[in] nsc_key Network namespace for key
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see xml_addsub where xc is appended. xml_insert is xml_addsub();xml_sort()
|
||||
|
|
@ -669,7 +673,8 @@ int
|
|||
xml_insert(cxobj *xp,
|
||||
cxobj *xi,
|
||||
enum insert_type ins,
|
||||
char *key_val)
|
||||
char *key_val,
|
||||
cvec *nsc_key)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *xa;
|
||||
|
|
@ -704,7 +709,7 @@ xml_insert(cxobj *xp,
|
|||
userorder = (yang_find(y, Y_ORDERED_BY, "user") != NULL);
|
||||
yi = yang_order(y);
|
||||
if ((i = xml_insert2(xp, xi, y, yi,
|
||||
userorder, ins, key_val,
|
||||
userorder, ins, key_val, nsc_key,
|
||||
low, upper)) < 0)
|
||||
goto done;
|
||||
if (xml_child_insert_pos(xp, xi, i) < 0)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue