* RESTCONF "depth" query parameter supported
* C API change: Added `depth` parameter to function `clicon_xml2cbuf`, default is -1.
This commit is contained in:
parent
10a2dbe8ec
commit
ee329ee382
31 changed files with 289 additions and 117 deletions
10
CHANGELOG.md
10
CHANGELOG.md
|
|
@ -7,6 +7,9 @@
|
|||
* RESTCONF PATCH (plain patch) is being implemented according to RFC 8040 Section 4.6.1
|
||||
* Note RESTCONF plain patch is different from RFC 8072 "YANG Patch Media Type" which is not implemented
|
||||
* RESTCONF "content" query parameter supported
|
||||
* Extended Netconf with content attribute for internal use
|
||||
* RESTCONF "depth" query parameter supported
|
||||
* Extended Netconf with depth attribute for internal use
|
||||
* RESTCONF "insert" and "point" query parameters supported
|
||||
* Applies to ordered-by-user leaf and leaf-lists
|
||||
* RESTCONF PUT/POST erroneously returned 200 OK. Instead restconf now returns:
|
||||
|
|
@ -45,10 +48,15 @@
|
|||
* Empty yang container encoded as `{}`
|
||||
* Empty leaf/leaf-list of type empty encoded as `[null]`
|
||||
* Other empty values remain as `null`
|
||||
* C API changes:
|
||||
* Added `depth` parameter to function `clicon_xml2cbuf`, default is -1.
|
||||
* Added two parameters to function `clicon_rpc_get`
|
||||
* `content`: to select state or config. Allowed values: CONTENT_CONFIG,CONTENT_NOCONFIG, CONTENT_ALL (default)
|
||||
* `depth`: Get levels of XML in get function: -1 is unbounded, 0 is nothing, 1 is top-level node only.
|
||||
|
||||
|
||||
### Minor changes
|
||||
* Added experimental binary search API function: `xml_binsearch`
|
||||
* Added content parameter to `clicon_rpc_get` (-1 or CONTENT_ALL is default)
|
||||
* Removed unnecessary configure dependencies
|
||||
* libnsl, libcrypt, if_vlan,...
|
||||
* pseudo-plugin added, to enable callbacks also for main programs. Useful for extensions
|
||||
|
|
|
|||
|
|
@ -236,15 +236,14 @@ run with NGINX.
|
|||
The implementatation is based on [RFC 8040: RESTCONF Protocol](https://tools.ietf.org/html/rfc8040).
|
||||
|
||||
The following features of RFC8040 are supported:
|
||||
- OPTIONS, HEAD, GET, POST, PUT, DELETE
|
||||
- OPTIONS, HEAD, GET, POST, PUT, DELETE, PATCH
|
||||
- stream notifications (Sec 6)
|
||||
- query parameters: "insert", "point", "start-time" and "stop-time".
|
||||
- query parameters: "insert", "point", "content", "depth", "start-time" and "stop-time".
|
||||
- Monitoring (Sec 9)
|
||||
|
||||
The following features are not implemented:
|
||||
- ETag/Last-Modified
|
||||
- PATCH
|
||||
- Query parameters: "content", "depth", "fields", "filter", "with-defaults"
|
||||
- Query parameters: "fields", "filter", "with-defaults"
|
||||
|
||||
See [more detailed instructions](apps/restconf/README.md).
|
||||
|
||||
|
|
|
|||
|
|
@ -176,6 +176,8 @@ client_get_capabilities(clicon_handle h,
|
|||
goto done;
|
||||
if (xml_parse_va(&xcap, yspec, "<capability>urn:ietf:params:restconf:capability:defaults:1.0?basic-mode=explicit</capability>") < 0)
|
||||
goto done;
|
||||
if (xml_parse_va(&xcap, yspec, "<capability>urn:ietf:params:restconf:capability:depth:1.0</capability>") < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
|
|
@ -428,7 +430,7 @@ from_client_get_config(clicon_handle h,
|
|||
else{
|
||||
if (xml_name_set(xret, "data") < 0)
|
||||
goto done;
|
||||
if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
}
|
||||
cprintf(cbret, "</rpc-reply>");
|
||||
|
|
@ -541,7 +543,7 @@ from_client_edit_config(clicon_handle h,
|
|||
if ((ret = xml_yang_validate_list_key_only(h, xc, &xret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -877,6 +879,7 @@ from_client_get(clicon_handle h,
|
|||
cvec *nsc = NULL; /* Create a netconf namespace context from filter */
|
||||
char *attr;
|
||||
netconf_content content = CONTENT_ALL;
|
||||
int32_t depth = -1; /* Nr of levels to print, -1 is all, 0 is none */
|
||||
|
||||
username = clicon_username_get(h);
|
||||
if ((xfilter = xml_find(xe, "filter")) != NULL){
|
||||
|
|
@ -890,9 +893,24 @@ from_client_get(clicon_handle h,
|
|||
if (xml_nsctx_node(xfilter, &nsc) < 0)
|
||||
goto done;
|
||||
}
|
||||
/* Clixon extensions: depth and content */
|
||||
if ((attr = xml_find_value(xe, "content")) != NULL)
|
||||
content = netconf_content_str2int(attr);
|
||||
|
||||
if ((attr = xml_find_value(xe, "depth")) != NULL){
|
||||
char *reason = NULL;
|
||||
if ((ret = parse_int32(attr, &depth, &reason)) < 0){
|
||||
clicon_err(OE_XML, errno, "parse_int32");
|
||||
goto done;
|
||||
}
|
||||
if (ret == 0){
|
||||
if (netconf_bad_attribute(cbret, "application",
|
||||
"<bad-attribute>depth</bad-attribute>", "Unrecognized value of depth attribute") < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
}
|
||||
|
||||
if (content != CONTENT_NONCONFIG){
|
||||
/* Get config
|
||||
* Note xret can be pruned by nacm below and change name and
|
||||
|
|
@ -911,7 +929,7 @@ from_client_get(clicon_handle h,
|
|||
if ((ret = client_statedata(h, xpath, nsc, &xret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){ /* Error from callback (error in xret) */
|
||||
if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -932,7 +950,8 @@ from_client_get(clicon_handle h,
|
|||
else{
|
||||
if (xml_name_set(xret, "data") < 0)
|
||||
goto done;
|
||||
if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
|
||||
/* Top level is data, so add 1 to depth if significant */
|
||||
if (clicon_xml2cbuf(cbret, xret, 0, 0, depth>0?depth+1:depth) < 0)
|
||||
goto done;
|
||||
}
|
||||
cprintf(cbret, "</rpc-reply>");
|
||||
|
|
@ -1250,7 +1269,7 @@ from_client_msg(clicon_handle h,
|
|||
if ((ret = xml_yang_validate_rpc(h, x, &xret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
goto reply;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -230,7 +230,7 @@ startup_common(clicon_handle h,
|
|||
if ((ret = generic_validate(h, yspec, td, &xret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
goto fail; /* STARTUP_INVALID */
|
||||
}
|
||||
|
|
@ -522,7 +522,7 @@ candidate_commit(clicon_handle h,
|
|||
if ((ret = from_validate_common(h, candidate, td, &xret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
|
|
@ -755,7 +755,7 @@ from_client_validate(clicon_handle h,
|
|||
/* A little complex due to several sources of validation fails or errors.
|
||||
* (1) xerr is set -> translate to cbret; (2) cbret set use that; otherwise
|
||||
* use clicon_err. */
|
||||
if (xret && clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
|
||||
if (xret && clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
plugin_transaction_abort(h, td);
|
||||
if (!cbuf_len(cbret) &&
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ transaction_log(clicon_handle h,
|
|||
}
|
||||
for (i=0; i<td->td_dlen; i++){
|
||||
xn = td->td_dvec[i];
|
||||
clicon_xml2cbuf(cb, xn, 0, 0);
|
||||
clicon_xml2cbuf(cb, xn, 0, 0, -1);
|
||||
}
|
||||
if (i)
|
||||
clicon_log(level, "%s %" PRIu64 " %s del: %s",
|
||||
|
|
@ -248,7 +248,7 @@ transaction_log(clicon_handle h,
|
|||
cbuf_reset(cb);
|
||||
for (i=0; i<td->td_alen; i++){
|
||||
xn = td->td_avec[i];
|
||||
clicon_xml2cbuf(cb, xn, 0, 0);
|
||||
clicon_xml2cbuf(cb, xn, 0, 0, -1);
|
||||
}
|
||||
if (i)
|
||||
clicon_log(level, "%s %" PRIu64 " %s add: %s", __FUNCTION__, td->td_id, op, cbuf_get(cb));
|
||||
|
|
@ -256,10 +256,10 @@ transaction_log(clicon_handle h,
|
|||
for (i=0; i<td->td_clen; i++){
|
||||
if (td->td_scvec){
|
||||
xn = td->td_scvec[i];
|
||||
clicon_xml2cbuf(cb, xn, 0, 0);
|
||||
clicon_xml2cbuf(cb, xn, 0, 0, -1);
|
||||
}
|
||||
xn = td->td_tcvec[i];
|
||||
clicon_xml2cbuf(cb, xn, 0, 0);
|
||||
clicon_xml2cbuf(cb, xn, 0, 0, -1);
|
||||
}
|
||||
if (i)
|
||||
clicon_log(level, "%s %" PRIu64 " %s change: %s", __FUNCTION__, td->td_id, op, cbuf_get(cb));
|
||||
|
|
|
|||
|
|
@ -279,7 +279,7 @@ cli_dbxml(clicon_handle h,
|
|||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if (clicon_xml2cbuf(cb, xtop, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(cb, xtop, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
if (clicon_rpc_edit_config(h, "candidate", OP_NONE, cbuf_get(cb)) < 0)
|
||||
goto done;
|
||||
|
|
@ -792,7 +792,7 @@ load_config_file(clicon_handle h,
|
|||
while ((x = xml_child_each(xt, x, -1)) != NULL) {
|
||||
/* Ensure top-level is "config", maybe this is too rough? */
|
||||
xml_name_set(x, "config");
|
||||
if (clicon_xml2cbuf(cbxml, x, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(cbxml, x, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
}
|
||||
if (clicon_rpc_edit_config(h, "candidate",
|
||||
|
|
@ -1235,7 +1235,7 @@ cli_copy_config(clicon_handle h,
|
|||
/* resuse cb */
|
||||
cbuf_reset(cb);
|
||||
/* create xml copy tree and merge it with database configuration */
|
||||
clicon_xml2cbuf(cb, x2, 0, 0);
|
||||
clicon_xml2cbuf(cb, x2, 0, 0, -1);
|
||||
if (clicon_rpc_edit_config(h, db, OP_MERGE, cbuf_get(cb)) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
|
|
|
|||
|
|
@ -472,7 +472,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, &xt) < 0)
|
||||
if (clicon_rpc_get(h, cbuf_get(cbxpath), namespace, CONTENT_ALL, -1, &xt) < 0)
|
||||
goto done;
|
||||
}
|
||||
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
|
||||
|
|
@ -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, &xt) < 0)
|
||||
if (clicon_rpc_get(h, xpath, namespace, CONTENT_ALL, -1, &xt) < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ netconf_input_packet(clicon_handle h,
|
|||
if ((ret = xml_yang_validate_rpc(h, xrpc, &xret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
clicon_xml2cbuf(cbret, xret, 0, 0);
|
||||
clicon_xml2cbuf(cbret, xret, 0, 0, -1);
|
||||
netconf_output_encap(1, cbret, "rpc-error");
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -170,7 +170,7 @@ netconf_input_packet(clicon_handle h,
|
|||
if (xml_addsub(xc, xa2) < 0)
|
||||
goto done;
|
||||
}
|
||||
clicon_xml2cbuf(cbret, xml_child_i(xret,0), 0, 0);
|
||||
clicon_xml2cbuf(cbret, xml_child_i(xret,0), 0, 0, -1);
|
||||
if (netconf_output_encap(1, cbret, "rpc-reply") < 0){
|
||||
cbuf_free(cbret);
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -455,7 +455,7 @@ netconf_notification_cb(int s,
|
|||
clicon_err(OE_PLUGIN, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if (clicon_xml2cbuf(cb, xn, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(cb, xn, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
/* Send it to listening client on stdout */
|
||||
if (netconf_output_encap(1, cb, "notification") < 0){
|
||||
|
|
@ -599,7 +599,7 @@ netconf_application_rpc(clicon_handle h,
|
|||
if (ret > 0 && (ret = xml_yang_validate_add(h, xn, &xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
if (clicon_xml2cbuf(cbret, xerr, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(cbret, xerr, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
netconf_output_encap(1, cbret, "rpc-error");
|
||||
goto ok;
|
||||
|
|
@ -632,7 +632,7 @@ netconf_application_rpc(clicon_handle h,
|
|||
if (ret > 0 && (ret = xml_yang_validate_add(h, xoutput, &xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
if (clicon_xml2cbuf(cbret, xerr, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(cbret, xerr, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
clicon_log(LOG_WARNING, "Errors in output netconf %s", cbuf_get(cbret));
|
||||
goto ok;
|
||||
|
|
|
|||
|
|
@ -496,7 +496,7 @@ api_return_err(clicon_handle h,
|
|||
FCGX_FPrintF(r->out, "Content-Type: %s\r\n\r\n", restconf_media_int2str(media));
|
||||
switch (media){
|
||||
case YANG_DATA_XML:
|
||||
if (clicon_xml2cbuf(cb, xerr, 2, pretty) < 0)
|
||||
if (clicon_xml2cbuf(cb, xerr, 2, pretty, -1) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s code:%d err:%s", __FUNCTION__, code, cbuf_get(cb));
|
||||
if (pretty){
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ api_root(clicon_handle h,
|
|||
goto done;
|
||||
switch (media_out){
|
||||
case YANG_DATA_XML:
|
||||
if (clicon_xml2cbuf(cb, xt, 0, pretty) < 0)
|
||||
if (clicon_xml2cbuf(cb, xt, 0, pretty, -1) < 0)
|
||||
goto done;
|
||||
break;
|
||||
case YANG_DATA_JSON:
|
||||
|
|
@ -292,7 +292,7 @@ api_yang_library_version(clicon_handle h,
|
|||
}
|
||||
switch (media_out){
|
||||
case YANG_DATA_XML:
|
||||
if (clicon_xml2cbuf(cb, xt, 0, pretty) < 0)
|
||||
if (clicon_xml2cbuf(cb, xt, 0, pretty, -1) < 0)
|
||||
goto done;
|
||||
break;
|
||||
case YANG_DATA_JSON:
|
||||
|
|
|
|||
|
|
@ -326,7 +326,7 @@ api_data_write(clicon_handle h,
|
|||
#if 0
|
||||
if (debug){
|
||||
cbuf *ccc=cbuf_new();
|
||||
if (clicon_xml2cbuf(ccc, xret, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(ccc, xret, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s XRET: %s", __FUNCTION__, cbuf_get(ccc));
|
||||
cbuf_free(ccc);
|
||||
|
|
@ -457,7 +457,7 @@ api_data_write(clicon_handle h,
|
|||
#if 0
|
||||
if (debug){
|
||||
cbuf *ccc=cbuf_new();
|
||||
if (clicon_xml2cbuf(ccc, xdata, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(ccc, xdata, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s DATA:%s", __FUNCTION__, cbuf_get(ccc));
|
||||
cbuf_free(ccc);
|
||||
|
|
@ -620,7 +620,7 @@ api_data_write(clicon_handle h,
|
|||
NETCONF_BASE_NAMESPACE); /* bind nc to netconf namespace */
|
||||
cprintf(cbx, "<edit-config><target><candidate /></target>");
|
||||
cprintf(cbx, "<default-operation>none</default-operation>");
|
||||
if (clicon_xml2cbuf(cbx, xtop, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(cbx, xtop, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
cprintf(cbx, "</edit-config></rpc>");
|
||||
clicon_debug(1, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path);
|
||||
|
|
@ -891,7 +891,7 @@ api_data_delete(clicon_handle h,
|
|||
NETCONF_BASE_NAMESPACE); /* bind nc to netconf namespace */
|
||||
cprintf(cbx, "<edit-config><target><candidate /></target>");
|
||||
cprintf(cbx, "<default-operation>none</default-operation>");
|
||||
if (clicon_xml2cbuf(cbx, xtop, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(cbx, xtop, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
cprintf(cbx, "</edit-config></rpc>");
|
||||
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0)
|
||||
|
|
|
|||
|
|
@ -114,8 +114,9 @@ api_data_get2(clicon_handle h,
|
|||
int ret;
|
||||
char *namespace = NULL;
|
||||
cvec *nsc = NULL;
|
||||
char *str;
|
||||
char *attr; /* attribute value string */
|
||||
netconf_content content = CONTENT_ALL;
|
||||
int32_t depth = -1; /* Nr of levels to print, -1 is all, 0 is none */
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
|
|
@ -123,9 +124,9 @@ api_data_get2(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
/* Check for content attribute */
|
||||
if ((str = cvec_find_str(qvec, "content")) != NULL){
|
||||
clicon_debug(1, "%s content=%s", __FUNCTION__, str);
|
||||
if ((content = netconf_content_str2int(str)) == -1){
|
||||
if ((attr = cvec_find_str(qvec, "content")) != NULL){
|
||||
clicon_debug(1, "%s content=%s", __FUNCTION__, attr);
|
||||
if ((content = netconf_content_str2int(attr)) == -1){
|
||||
if (netconf_bad_attribute_xml(&xerr, "application",
|
||||
"<bad-attribute>content</bad-attribute>", "Unrecognized value of content attribute") < 0)
|
||||
goto done;
|
||||
|
|
@ -138,7 +139,29 @@ api_data_get2(clicon_handle h,
|
|||
goto ok;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for depth attribute */
|
||||
if ((attr = cvec_find_str(qvec, "depth")) != NULL){
|
||||
clicon_debug(1, "%s depth=%s", __FUNCTION__, attr);
|
||||
if (strcmp(attr, "unbounded") != 0){
|
||||
char *reason = NULL;
|
||||
if ((ret = parse_int32(attr, &depth, &reason)) < 0){
|
||||
clicon_err(OE_XML, errno, "parse_int32");
|
||||
goto done;
|
||||
}
|
||||
if (ret==0){
|
||||
if (netconf_bad_attribute_xml(&xerr, "application",
|
||||
"<bad-attribute>depth</bad-attribute>", "Unrecognized value of depth attribute") < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
if (api_return_err(h, r, xe, pretty, media_out, 0) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((cbpath = cbuf_new()) == NULL)
|
||||
goto done;
|
||||
cprintf(cbpath, "/");
|
||||
|
|
@ -165,13 +188,13 @@ api_data_get2(clicon_handle h,
|
|||
goto done;
|
||||
switch (content){
|
||||
case CONTENT_CONFIG:
|
||||
ret = clicon_rpc_get_config(h, "running", xpath, namespace, &xret);
|
||||
ret = clicon_rpc_get(h, xpath, namespace, CONTENT_CONFIG, depth, &xret);
|
||||
break;
|
||||
case CONTENT_NONCONFIG:
|
||||
ret = clicon_rpc_get(h, xpath, namespace, CONTENT_NONCONFIG, &xret);
|
||||
ret = clicon_rpc_get(h, xpath, namespace, CONTENT_NONCONFIG, depth, &xret);
|
||||
break;
|
||||
case CONTENT_ALL:
|
||||
ret = clicon_rpc_get(h, xpath, namespace, CONTENT_ALL, &xret);
|
||||
ret = clicon_rpc_get(h, xpath, namespace, CONTENT_ALL, depth, &xret);
|
||||
break;
|
||||
default:
|
||||
clicon_err(OE_XML, EINVAL, "Invalid content attribute %d", content);
|
||||
|
|
@ -196,7 +219,7 @@ api_data_get2(clicon_handle h,
|
|||
#if 0 /* DEBUG */
|
||||
if (debug){
|
||||
cbuf *cb = cbuf_new();
|
||||
clicon_xml2cbuf(cb, xret, 0, 0);
|
||||
clicon_xml2cbuf(cb, xret, 0, 0, -1);
|
||||
clicon_debug(1, "%s xret:%s", __FUNCTION__, cbuf_get(cb));
|
||||
cbuf_free(cb);
|
||||
}
|
||||
|
|
@ -219,7 +242,7 @@ api_data_get2(clicon_handle h,
|
|||
if (xpath==NULL || strcmp(xpath,"/")==0){ /* Special case: data root */
|
||||
switch (media_out){
|
||||
case YANG_DATA_XML:
|
||||
if (clicon_xml2cbuf(cbx, xret, 0, pretty) < 0) /* Dont print top object? */
|
||||
if (clicon_xml2cbuf(cbx, xret, 0, pretty, -1) < 0) /* Dont print top object? */
|
||||
goto done;
|
||||
break;
|
||||
case YANG_DATA_JSON:
|
||||
|
|
@ -268,7 +291,7 @@ api_data_get2(clicon_handle h,
|
|||
if (namespace2 && xmlns_set(x, prefix, namespace2) < 0)
|
||||
goto done;
|
||||
}
|
||||
if (clicon_xml2cbuf(cbx, x, 0, pretty) < 0) /* Dont print top object? */
|
||||
if (clicon_xml2cbuf(cbx, x, 0, pretty, -1) < 0) /* Dont print top object? */
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ api_data_post(clicon_handle h,
|
|||
#if 1
|
||||
if (debug){
|
||||
cbuf *ccc=cbuf_new();
|
||||
if (clicon_xml2cbuf(ccc, xtop, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(ccc, xtop, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s XURI:%s", __FUNCTION__, cbuf_get(ccc));
|
||||
cbuf_free(ccc);
|
||||
|
|
@ -309,7 +309,7 @@ api_data_post(clicon_handle h,
|
|||
#if 1
|
||||
if (debug){
|
||||
cbuf *ccc=cbuf_new();
|
||||
if (clicon_xml2cbuf(ccc, xdata, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(ccc, xdata, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s XDATA:%s", __FUNCTION__, cbuf_get(ccc));
|
||||
cbuf_free(ccc);
|
||||
|
|
@ -330,7 +330,7 @@ api_data_post(clicon_handle h,
|
|||
NETCONF_BASE_NAMESPACE); /* bind nc to netconf namespace */
|
||||
cprintf(cbx, "<edit-config><target><candidate /></target>");
|
||||
cprintf(cbx, "<default-operation>none</default-operation>");
|
||||
if (clicon_xml2cbuf(cbx, xtop, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(cbx, xtop, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
cprintf(cbx, "</edit-config></rpc>");
|
||||
clicon_debug(1, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path);
|
||||
|
|
@ -507,7 +507,7 @@ api_operations_post_input(clicon_handle h,
|
|||
#if 1
|
||||
if (debug){
|
||||
cbuf *ccc=cbuf_new();
|
||||
if (clicon_xml2cbuf(ccc, xdata, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(ccc, xdata, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s DATA:%s", __FUNCTION__, cbuf_get(ccc));
|
||||
cbuf_free(ccc);
|
||||
|
|
@ -614,7 +614,7 @@ api_operations_post_output(clicon_handle h,
|
|||
#if 1
|
||||
if (debug){
|
||||
cbuf *ccc=cbuf_new();
|
||||
if (clicon_xml2cbuf(ccc, xoutput, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(ccc, xoutput, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s XOUTPUT:%s", __FUNCTION__, cbuf_get(ccc));
|
||||
cbuf_free(ccc);
|
||||
|
|
@ -855,7 +855,7 @@ api_operations_post(clicon_handle h,
|
|||
#if 1
|
||||
if (debug){
|
||||
cbuf *ccc=cbuf_new();
|
||||
if (clicon_xml2cbuf(ccc, xtop, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(ccc, xtop, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s 5. Translate input args: %s",
|
||||
__FUNCTION__, cbuf_get(ccc));
|
||||
|
|
@ -882,7 +882,7 @@ api_operations_post(clicon_handle h,
|
|||
#if 0
|
||||
if (debug){
|
||||
cbuf *ccc=cbuf_new();
|
||||
if (clicon_xml2cbuf(ccc, xtop, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(ccc, xtop, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s 6. Validate and defaults:%s", __FUNCTION__, cbuf_get(ccc));
|
||||
cbuf_free(ccc);
|
||||
|
|
@ -922,7 +922,7 @@ api_operations_post(clicon_handle h,
|
|||
#if 1
|
||||
if (debug){
|
||||
cbuf *ccc=cbuf_new();
|
||||
if (clicon_xml2cbuf(ccc, xret, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(ccc, xret, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s 8. Receive reply:%s", __FUNCTION__, cbuf_get(ccc));
|
||||
cbuf_free(ccc);
|
||||
|
|
@ -942,7 +942,7 @@ api_operations_post(clicon_handle h,
|
|||
cbuf_reset(cbret);
|
||||
switch (media_out){
|
||||
case YANG_DATA_XML:
|
||||
if (clicon_xml2cbuf(cbret, xoutput, 0, pretty) < 0)
|
||||
if (clicon_xml2cbuf(cbret, xoutput, 0, pretty, -1) < 0)
|
||||
goto done;
|
||||
/* xoutput should now look: <output xmlns="uri"><x>0</x></output> */
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ restconf_stream_cb(int s,
|
|||
FCGX_FPrintF(r->out, "M#id: %02d:0\r\n", tv.tv_sec);
|
||||
}
|
||||
#endif
|
||||
if (clicon_xml2cbuf(cb, xn, 0, pretty) < 0)
|
||||
if (clicon_xml2cbuf(cb, xn, 0, pretty, -1) < 0)
|
||||
goto done;
|
||||
FCGX_FPrintF(r->out, "data: %s\r\n", cbuf_get(cb));
|
||||
FCGX_FPrintF(r->out, "\r\n");
|
||||
|
|
|
|||
|
|
@ -248,7 +248,7 @@ example_rpc(clicon_handle h, /* Clicon handle */
|
|||
else while ((x = xml_child_each(xe, x, CX_ELMNT)) != NULL) {
|
||||
if (xmlns_set(x, NULL, namespace) < 0)
|
||||
goto done;
|
||||
if (clicon_xml2cbuf(cbret, x, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(cbret, x, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
}
|
||||
cprintf(cbret, "</rpc-reply>");
|
||||
|
|
|
|||
|
|
@ -64,11 +64,12 @@ plugin_exit(clicon_handle h)
|
|||
|
||||
/*! Local example netconf rpc callback
|
||||
*/
|
||||
int netconf_client_rpc(clicon_handle h,
|
||||
cxobj *xe,
|
||||
cbuf *cbret,
|
||||
void *arg,
|
||||
void *regarg)
|
||||
int
|
||||
netconf_client_rpc(clicon_handle h,
|
||||
cxobj *xe,
|
||||
cbuf *cbret,
|
||||
void *arg,
|
||||
void *regarg)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *x = NULL;
|
||||
|
|
@ -85,7 +86,7 @@ int netconf_client_rpc(clicon_handle h,
|
|||
else while ((x = xml_child_each(xe, x, CX_ELMNT)) != NULL) {
|
||||
if (xmlns_set(x, NULL, namespace) < 0)
|
||||
goto done;
|
||||
if (clicon_xml2cbuf(cbret, x, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(cbret, x, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
}
|
||||
cprintf(cbret, "</rpc-reply>");
|
||||
|
|
|
|||
|
|
@ -287,7 +287,7 @@ restconf_client_rpc(clicon_handle h,
|
|||
else while ((x = xml_child_each(xe, x, CX_ELMNT)) != NULL) {
|
||||
if (xmlns_set(x, NULL, namespace) < 0)
|
||||
goto done;
|
||||
if (clicon_xml2cbuf(cbret, x, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(cbret, x, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
}
|
||||
cprintf(cbret, "</rpc-reply>");
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ 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, cxobj **xret);
|
||||
int clicon_rpc_get(clicon_handle h, char *xpath, char *namespace, 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);
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ int xml_free(cxobj *xn);
|
|||
|
||||
int xml_print(FILE *f, cxobj *xn);
|
||||
int clicon_xml2file(FILE *f, cxobj *xn, int level, int prettyprint);
|
||||
int clicon_xml2cbuf(cbuf *xf, cxobj *xn, int level, int prettyprint);
|
||||
int clicon_xml2cbuf(cbuf *xf, cxobj *xn, int level, int prettyprint, int32_t depth);
|
||||
int xml_parse_file(int fd, char *endtag, yang_stmt *yspec, cxobj **xt);
|
||||
int xml_parse_string(const char *str, yang_stmt *yspec, cxobj **xml_top);
|
||||
#if defined(__GNUC__) && __GNUC__ >= 3
|
||||
|
|
|
|||
|
|
@ -113,7 +113,8 @@ typedef struct xpath_tree xpath_tree;
|
|||
* Prototypes
|
||||
*/
|
||||
char* xpath_tree_int2str(int nodetype);
|
||||
int xpath_tree_print(cbuf *cb, xpath_tree *xs);
|
||||
int xpath_tree_print_cb(cbuf *cb, xpath_tree *xs);
|
||||
int xpath_tree_print(FILE *f, xpath_tree *xs);
|
||||
int xpath_tree_free(xpath_tree *xs);
|
||||
int xpath_parse(cvec *nsc, char *xpath, xpath_tree **xptree);
|
||||
int xpath_vec_ctx(cxobj *xcur, cvec *nsc, char *xpath, xp_ctx **xrp);
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ netconf_invalid_value(cbuf *cb,
|
|||
|
||||
if (netconf_invalid_value_xml(&xret, type, message) < 0)
|
||||
goto done;
|
||||
if (clicon_xml2cbuf(cb, xret, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
@ -276,7 +276,7 @@ netconf_bad_attribute(cbuf *cb,
|
|||
|
||||
if (netconf_bad_attribute_xml(&xret, type, info, message) < 0)
|
||||
goto done;
|
||||
if (clicon_xml2cbuf(cb, xret, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
@ -441,7 +441,7 @@ netconf_missing_element(cbuf *cb,
|
|||
if (netconf_common_xml(&xret, type, "missing-element",
|
||||
"bad-element", element, message) < 0)
|
||||
goto done;
|
||||
if (clicon_xml2cbuf(cb, xret, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
@ -487,7 +487,7 @@ netconf_bad_element(cbuf *cb,
|
|||
if (netconf_common_xml(&xret, type, "bad-element",
|
||||
"bad-element",element, message) < 0)
|
||||
goto done;
|
||||
if (clicon_xml2cbuf(cb, xret, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
@ -525,7 +525,7 @@ netconf_unknown_element(cbuf *cb,
|
|||
if (netconf_common_xml(&xret, type, "unknown-element",
|
||||
"bad-element", element, message) < 0)
|
||||
goto done;
|
||||
if (clicon_xml2cbuf(cb, xret, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
@ -572,7 +572,7 @@ netconf_unknown_namespace(cbuf *cb,
|
|||
if (netconf_common_xml(&xret, type, "unknown-namespace",
|
||||
"bad-namespace", namespace, message) < 0)
|
||||
goto done;
|
||||
if (clicon_xml2cbuf(cb, xret, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
@ -610,7 +610,7 @@ netconf_access_denied(cbuf *cb,
|
|||
|
||||
if (netconf_access_denied_xml(&xret, type, message) < 0)
|
||||
goto done;
|
||||
if (clicon_xml2cbuf(cb, xret, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
@ -846,7 +846,7 @@ netconf_data_missing(cbuf *cb,
|
|||
|
||||
if (netconf_data_missing_xml(&xret, missing_choice, message) < 0)
|
||||
goto done;
|
||||
if (clicon_xml2cbuf(cb, xret, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
@ -967,7 +967,7 @@ netconf_operation_failed(cbuf *cb,
|
|||
|
||||
if (netconf_operation_failed_xml(&xret, type, message) < 0)
|
||||
goto done;
|
||||
if (clicon_xml2cbuf(cb, xret, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
@ -1045,7 +1045,7 @@ netconf_malformed_message(cbuf *cb,
|
|||
|
||||
if (netconf_malformed_message_xml(&xret, message) < 0)
|
||||
goto done;
|
||||
if (clicon_xml2cbuf(cb, xret, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
@ -1148,7 +1148,7 @@ netconf_data_not_unique_xml(cxobj **xret,
|
|||
while ((cvi = cvec_each(cvk, cvi)) != NULL){
|
||||
if ((xi = xml_find(x, cv_string_get(cvi))) == NULL)
|
||||
continue; /* ignore, shouldnt happen */
|
||||
clicon_xml2cbuf(cb, xi, 0, 0);
|
||||
clicon_xml2cbuf(cb, xi, 0, 0, -1);
|
||||
if (xml_parse_va(&xinfo, NULL, "<non-unique>%s</non-unique>", cbuf_get(cb)) < 0)
|
||||
goto done;
|
||||
cbuf_reset(cb);
|
||||
|
|
@ -1369,7 +1369,7 @@ netconf_err2cb(cxobj *xerr,
|
|||
if ((x=xpath_first(xerr, "error-message"))!=NULL)
|
||||
cprintf(cb, "%s ", xml_body(x));
|
||||
if ((x=xpath_first(xerr, "error-info"))!=NULL)
|
||||
clicon_xml2cbuf(cb, xml_child_i(x,0), 0, 0);
|
||||
clicon_xml2cbuf(cb, xml_child_i(x,0), 0, 0, -1);
|
||||
*cberr = cb;
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
|
|||
|
|
@ -606,7 +606,7 @@ send_msg_notify_xml(int s,
|
|||
clicon_err(OE_PLUGIN, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if (clicon_xml2cbuf(cb, xev, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(cb, xev, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
if (send_msg_notify(s, cbuf_get(cb)) < 0)
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ clicon_rpc_netconf_xml(clicon_handle h,
|
|||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if (clicon_xml2cbuf(cb, xml, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(cb, xml, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
if (clicon_rpc_netconf(h, cbuf_get(cb), xret, sp) < 0)
|
||||
goto done;
|
||||
|
|
@ -541,7 +541,8 @@ 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] content CLixon extension: all, config, noconfig. -1 means all
|
||||
* @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.
|
||||
* Either <config> or <rpc-error>.
|
||||
* @retval 0 OK
|
||||
|
|
@ -550,7 +551,7 @@ clicon_rpc_unlock(clicon_handle h,
|
|||
* 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, &xt) < 0)
|
||||
* 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);
|
||||
|
|
@ -563,11 +564,12 @@ clicon_rpc_unlock(clicon_handle h,
|
|||
* @see clicon_rpc_generate_error
|
||||
*/
|
||||
int
|
||||
clicon_rpc_get(clicon_handle h,
|
||||
char *xpath,
|
||||
char *namespace,
|
||||
clicon_rpc_get(clicon_handle h,
|
||||
char *xpath,
|
||||
char *namespace,
|
||||
netconf_content content,
|
||||
cxobj **xt)
|
||||
int32_t depth,
|
||||
cxobj **xt)
|
||||
{
|
||||
int retval = -1;
|
||||
struct clicon_msg *msg = NULL;
|
||||
|
|
@ -584,11 +586,12 @@ clicon_rpc_get(clicon_handle h,
|
|||
if (namespace)
|
||||
cprintf(cb, " xmlns:nc=\"%s\"", NETCONF_BASE_NAMESPACE);
|
||||
cprintf(cb, "><get");
|
||||
#if 1
|
||||
/* Clixon extension, content all, config, nonconfig */
|
||||
/* Clixon extension, content=all,config, or nonconfig */
|
||||
if (content != -1)
|
||||
cprintf(cb, " content=\"%s\"", netconf_content_int2str(content));
|
||||
#endif
|
||||
/* Clixon extension, depth=<level> */
|
||||
if (depth != -1)
|
||||
cprintf(cb, " depth=\"%d\"", depth);
|
||||
cprintf(cb, ">");
|
||||
if (xpath && strlen(xpath)) {
|
||||
if (namespace)
|
||||
|
|
|
|||
|
|
@ -984,7 +984,7 @@ stream_publish_cb(clicon_handle h,
|
|||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if (clicon_xml2cbuf(d, event, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(d, event, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
if (url_post(cbuf_get(u), /* url+stream */
|
||||
cbuf_get(d), /* postfields */
|
||||
|
|
|
|||
|
|
@ -1651,13 +1651,14 @@ xml_print(FILE *f,
|
|||
*
|
||||
* @param[in,out] cb Cligen buffer to write to
|
||||
* @param[in] xn Clicon xml tree
|
||||
* @param[in] level Indentation level
|
||||
* @param[in] level Indentation level for prettyprint
|
||||
* @param[in] prettyprint insert \n and spaces tomake the xml more readable.
|
||||
* @param[in] depth Limit levels of child resources: -1 is all, 0 is none, 1 is node itself
|
||||
*
|
||||
* @code
|
||||
* cbuf *cb;
|
||||
* cb = cbuf_new();
|
||||
* if (clicon_xml2cbuf(cb, xn, 0, 1) < 0)
|
||||
* if (clicon_xml2cbuf(cb, xn, 0, 1, -1) < 0)
|
||||
* goto err;
|
||||
* fprintf(stderr, "%s", cbuf_get(cb));
|
||||
* cbuf_free(cb);
|
||||
|
|
@ -1665,10 +1666,11 @@ xml_print(FILE *f,
|
|||
* @see clicon_xml2file
|
||||
*/
|
||||
int
|
||||
clicon_xml2cbuf(cbuf *cb,
|
||||
cxobj *x,
|
||||
int level,
|
||||
int prettyprint)
|
||||
clicon_xml2cbuf(cbuf *cb,
|
||||
cxobj *x,
|
||||
int level,
|
||||
int prettyprint,
|
||||
int32_t depth)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *xc;
|
||||
|
|
@ -1679,6 +1681,8 @@ clicon_xml2cbuf(cbuf *cb,
|
|||
char *encstr = NULL; /* xml encoded string */
|
||||
char *val;
|
||||
|
||||
if (depth == 0)
|
||||
goto ok;
|
||||
name = xml_name(x);
|
||||
namespace = xml_prefix(x);
|
||||
switch(xml_type(x)){
|
||||
|
|
@ -1707,7 +1711,7 @@ clicon_xml2cbuf(cbuf *cb,
|
|||
while ((xc = xml_child_each(x, xc, -1)) != NULL)
|
||||
switch (xc->x_type){
|
||||
case CX_ATTR:
|
||||
if (clicon_xml2cbuf(cb, xc, level+1, prettyprint) < 0)
|
||||
if (clicon_xml2cbuf(cb, xc, level+1, prettyprint, -1) < 0)
|
||||
goto done;
|
||||
break;
|
||||
case CX_BODY:
|
||||
|
|
@ -1729,7 +1733,7 @@ clicon_xml2cbuf(cbuf *cb,
|
|||
xc = NULL;
|
||||
while ((xc = xml_child_each(x, xc, -1)) != NULL)
|
||||
if (xml_type(xc) != CX_ATTR)
|
||||
if (clicon_xml2cbuf(cb, xc, level+1, prettyprint) < 0)
|
||||
if (clicon_xml2cbuf(cb, xc, level+1, prettyprint, depth-1) < 0)
|
||||
goto done;
|
||||
if (prettyprint && hasbody == 0)
|
||||
cprintf(cb, "%*s", level*XML_INDENT, "");
|
||||
|
|
@ -1744,6 +1748,7 @@ clicon_xml2cbuf(cbuf *cb,
|
|||
default:
|
||||
break;
|
||||
}/* switch */
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
if (encstr)
|
||||
|
|
@ -2522,7 +2527,7 @@ clicon_log_xml(int level,
|
|||
/* Print xml as cbuf */
|
||||
if ((cb = cbuf_new()) == NULL)
|
||||
goto done;
|
||||
if (clicon_xml2cbuf(cb, x, 0, 0) < 0)
|
||||
if (clicon_xml2cbuf(cb, x, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
|
||||
/* first round: compute length of debug message */
|
||||
|
|
|
|||
|
|
@ -148,17 +148,40 @@ xpath_tree_print0(cbuf *cb,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*! Print a xpath_tree
|
||||
/*! Print a xpath_tree to CLIgen buf
|
||||
* @param[out] cb CLIgen buffer
|
||||
* @param[in] xs XPATH tree
|
||||
*/
|
||||
int
|
||||
xpath_tree_print(cbuf *cb,
|
||||
xpath_tree *xs)
|
||||
xpath_tree_print_cb(cbuf *cb,
|
||||
xpath_tree *xs)
|
||||
{
|
||||
xpath_tree_print0(cb, xs, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Print a xpath_tree
|
||||
* @param[in] f UNIX output stream
|
||||
* @param[in] xs XPATH tree
|
||||
*/
|
||||
int
|
||||
xpath_tree_print(FILE *f,
|
||||
xpath_tree *xs)
|
||||
{
|
||||
int retval = -1;
|
||||
cbuf *cb = NULL;
|
||||
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if (xpath_tree_print0(cb, xs, 0) < 0)
|
||||
goto done;
|
||||
fprintf(f, "%s", cbuf_get(cb));
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Free a xpath_tree
|
||||
* @param[in] xs XPATH tree
|
||||
|
|
@ -203,7 +226,8 @@ xpath_parse(cvec *nsc,
|
|||
{
|
||||
int retval = -1;
|
||||
struct clicon_xpath_yacc_arg xy = {0,};
|
||||
|
||||
cbuf *cb = NULL;
|
||||
|
||||
xy.xy_parse_string = xpath;
|
||||
xy.xy_name = "xpath parser";
|
||||
xy.xy_linenum = 1;
|
||||
|
|
@ -219,17 +243,20 @@ xpath_parse(cvec *nsc,
|
|||
goto done;
|
||||
}
|
||||
if (debug > 1){
|
||||
cbuf *cb = cbuf_new();
|
||||
xpath_tree_print(cb, xy.xy_top);
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
xpath_tree_print_cb(cb, xy.xy_top);
|
||||
clicon_debug(2, "xpath parse tree:\n%s", cbuf_get(cb));
|
||||
cbuf_free(cb);
|
||||
}
|
||||
/* done: */
|
||||
xpath_parse_exit(&xy);
|
||||
xpath_scan_exit(&xy);
|
||||
*xptree = xy.xy_top;
|
||||
retval = 0;
|
||||
done:
|
||||
if (cb)
|
||||
cbuf_free(cb);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -100,7 +100,8 @@ new "B.1.2. Retrieve the Server Module Information"
|
|||
expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/ietf-yang-library:modules-state)" 0 "HTTP/1.1 200 OK" 'Cache-Control: no-cache' "Content-Type: application/yang-data+json" '{"ietf-yang-library:modules-state":{"module-set-id":' '"module":\[{"name":"example-events","revision":\[null\],"namespace":"urn:example:events","conformance-type":"implement"},{"name":"example-jukebox","revision":"2016-08-15","namespace":"http://example.com/ns/example-jukebox","conformance-type":"implement"}'
|
||||
|
||||
new "B.1.3. Retrieve the Server Capability Information"
|
||||
expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+xml' http://localhost/restconf/data/ietf-restconf-monitoring:restconf-state/capabilities)" 0 "HTTP/1.1 200 OK" "Content-Type: application/yang-data+xml" 'Cache-Control: no-cache' '<capabilities xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf-monitoring"><capability>urn:ietf:params:restconf:capability:defaults:1.0?basic-mode=explicit</capability></capabilities>'
|
||||
expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+xml' http://localhost/restconf/data/ietf-restconf-monitoring:restconf-state/capabilities)" 0 "HTTP/1.1 200 OK" "Content-Type: application/yang-data+xml" 'Cache-Control: no-cache' '<capabilities xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf-monitoring"><capability>urn:ietf:params:restconf:capability:defaults:1.0?basic-mode=explicit</capability><capability>urn:ietf:params:restconf:capability:depth</capability>
|
||||
</capabilities>'
|
||||
|
||||
new "B.2.1. Create New Data Resources (artist+json)"
|
||||
expectpart "$(curl -si -X POST -H 'Content-Type: application/yang-data+json' http://localhost/restconf/data/example-jukebox:jukebox/library -d '{"example-jukebox:artist":[{"name":"Foo Fighters"}]}')" 0 "HTTP/1.1 201 Created" "Location: http://localhost/restconf/data/example-jukebox:jukebox/library/artist=Foo%20Fighters"
|
||||
|
|
@ -165,9 +166,28 @@ expectpart "$(curl -si -X GET http://localhost/restconf/data/example-events:even
|
|||
new 'B.3.1. "content" Parameter example 3: content=nonconfig'
|
||||
expectpart "$(curl -si -X GET http://localhost/restconf/data/example-events:events?content=nonconfig -H 'Accept: application/yang-data+json')" 0 'HTTP/1.1 200 OK' '{"example-events:events":{"event":\[{"name":"interface-down","event-count":90},{"name":"interface-up","event-count":77}\]}}'
|
||||
|
||||
#new "restconf DELETE whole datastore"
|
||||
#expectfn 'curl -s -X DELETE http://localhost/restconf/data' 0 ""
|
||||
|
||||
new 'B.3.2. "depth" Parameter example 1 unbound'
|
||||
expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/example-jukebox:jukebox?depth=unbounded)" 0 "HTTP/1.1 200 OK" '{"example-jukebox:jukebox":{"library":{"artist":\[{"name":"Foo Fighters","album":\[{"name":"One by One","year":2012}\]},{"name":"Nick Cave and the Bad Seeds","album":\[{"name":"Tender Prey","year":1988},{"name":"The Good Son","year":1990}\]}\]}}}'
|
||||
|
||||
new 'B.3.2. "depth" Parameter example 2 depth=1'
|
||||
expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/example-jukebox:jukebox?depth=1)" 0 "HTTP/1.1 200 OK" '{"example-jukebox:jukebox":{}}'
|
||||
|
||||
new 'B.3.2. "depth" Parameter depth=2'
|
||||
expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/example-jukebox:jukebox?depth=2)" 0 "HTTP/1.1 200 OK" '{"example-jukebox:jukebox":{"library":{}}}'
|
||||
|
||||
# Maybe this is not correct w [null,null]but I have no good examples
|
||||
new 'B.3.2. "depth" Parameter depth=3'
|
||||
expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/example-jukebox:jukebox?depth=3)" 0 "HTTP/1.1 200 OK" '{"example-jukebox:jukebox":{"artist":\[null,null\]}}}
|
||||
'
|
||||
|
||||
new "restconf DELETE whole datastore"
|
||||
expectfn 'curl -s -X DELETE http://localhost/restconf/data' 0 ""
|
||||
|
||||
#new 'B.3.3. "fields" Parameter'
|
||||
|
||||
new 'B.3.4. "insert" Parameter'
|
||||
JSON="{\"example-jukebox:song\":[{\"index\":1,\"id\":\"/example-jukebox:jukebox/library/artist[name='Foo Fighters']/album[name='Wasting Light']/song[name='Rope']\"}]}"
|
||||
expectpart "$(curl -si -X POST -H 'Content-Type: application/yang-data+json' http://localhost/restconf/data/example-jukebox:jukebox/playlist=Foo-One?insert=first -d "$JSON")" 0 "HTTP/1.1 201 Created" 'Location: http://localhost/restconf/data/example-jukebox:jukebox/playlist=Foo-One/song=1'
|
||||
|
|
@ -224,7 +244,6 @@ expectpart "$(curl -si -X GET http://localhost/restconf/data/example-jukebox:ext
|
|||
if false; then # NYI
|
||||
|
||||
new "B.2.2. Detect Datastore Resource Entity-Tag Change" # XXX done except entity-changed
|
||||
new 'B.3.2. "depth" Parameter'
|
||||
new 'B.3.3. "fields" Parameter'
|
||||
new 'B.3.6. "filter" Parameter'
|
||||
new 'B.3.7. "start-time" Parameter'
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ main(int argc,
|
|||
if (json)
|
||||
xml2json_cbuf(cb, xc, pretty); /* print xml */
|
||||
else
|
||||
clicon_xml2cbuf(cb, xc, 0, pretty); /* print xml */
|
||||
clicon_xml2cbuf(cb, xc, 0, pretty, -1); /* print xml */
|
||||
fprintf(stdout, "%s", cbuf_get(cb));
|
||||
fflush(stdout);
|
||||
retval = 0;
|
||||
|
|
|
|||
|
|
@ -256,7 +256,7 @@ main(int argc,
|
|||
if (jsonout)
|
||||
xml2json_cbuf(cb, xc, pretty); /* print xml */
|
||||
else
|
||||
clicon_xml2cbuf(cb, xc, 0, pretty); /* print xml */
|
||||
clicon_xml2cbuf(cb, xc, 0, pretty, -1); /* print xml */
|
||||
fprintf(stdout, "%s", cbuf_get(cb));
|
||||
fflush(stdout);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ See https://www.w3.org/TR/xpath/
|
|||
#include <assert.h>
|
||||
#include <syslog.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/* cligen */
|
||||
#include <cligen/cligen.h>
|
||||
|
|
@ -68,6 +69,8 @@ usage(char *argv0)
|
|||
"\t-f <file> \tXML file\n"
|
||||
"\t-p <xpath> \tPrimary XPATH string\n"
|
||||
"\t-i <xpath0>\t(optional) Initial XPATH string\n"
|
||||
"\t-y <filename> \tYang filename or dir (load all files)\n"
|
||||
"\t-Y <dir> \tYang dirs (can be several)\n"
|
||||
"and the following extra rules:\n"
|
||||
"\tif -f is not given, XML input is expected on stdin\n"
|
||||
"\tif -p is not given, <xpath> is expected as the first line on stdin\n"
|
||||
|
|
@ -88,7 +91,7 @@ ctx_print2(cbuf *cb,
|
|||
case XT_NODESET:
|
||||
for (i=0; i<xc->xc_size; i++){
|
||||
cprintf(cb, "%d:", i);
|
||||
clicon_xml2cbuf(cb, xc->xc_nodeset[i], 0, 0);
|
||||
clicon_xml2cbuf(cb, xc->xc_nodeset[i], 0, 0, -1);
|
||||
}
|
||||
break;
|
||||
case XT_BOOL:
|
||||
|
|
@ -105,7 +108,8 @@ ctx_print2(cbuf *cb,
|
|||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
main(int argc,
|
||||
char **argv)
|
||||
{
|
||||
int retval = -1;
|
||||
char *argv0 = argv[0];
|
||||
|
|
@ -118,16 +122,24 @@ main(int argc, char **argv)
|
|||
char *buf = NULL;
|
||||
int ret;
|
||||
int fd = 0; /* unless overriden by argv[1] */
|
||||
char *yang_file_dir = NULL;
|
||||
yang_stmt *yspec = NULL;
|
||||
char *xpath = NULL;
|
||||
char *xpath0 = NULL;
|
||||
char *filename;
|
||||
xp_ctx *xc = NULL;
|
||||
cbuf *cb = NULL;
|
||||
|
||||
clicon_handle h;
|
||||
struct stat st;
|
||||
|
||||
clicon_log_init("xpath", LOG_DEBUG, CLICON_LOG_STDERR);
|
||||
|
||||
if ((h = clicon_handle_init()) == NULL)
|
||||
goto done;
|
||||
|
||||
optind = 1;
|
||||
opterr = 0;
|
||||
while ((c = getopt(argc, argv, "hD:f:p:i:")) != -1)
|
||||
while ((c = getopt(argc, argv, "hD:f:p:i:y:Y:")) != -1)
|
||||
switch (c) {
|
||||
case 'h':
|
||||
usage(argv0);
|
||||
|
|
@ -149,10 +161,35 @@ main(int argc, char **argv)
|
|||
case 'i': /* Optional initial XPATH string */
|
||||
xpath0 = optarg;
|
||||
break;
|
||||
case 'y':
|
||||
yang_file_dir = optarg;
|
||||
break;
|
||||
case 'Y':
|
||||
if (clicon_option_add(h, "CLICON_YANG_DIR", optarg) < 0)
|
||||
goto done;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
break;
|
||||
}
|
||||
/* Parse yang */
|
||||
if (yang_file_dir){
|
||||
if ((yspec = yspec_new()) == NULL)
|
||||
goto done;
|
||||
if (stat(yang_file_dir, &st) < 0){
|
||||
clicon_err(OE_YANG, errno, "%s not found", yang_file_dir);
|
||||
goto done;
|
||||
}
|
||||
if (S_ISDIR(st.st_mode)){
|
||||
if (yang_spec_load_dir(h, yang_file_dir, yspec) < 0)
|
||||
goto done;
|
||||
}
|
||||
else{
|
||||
if (yang_spec_parse_file(h, yang_file_dir, yspec) < 0)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (xpath==NULL){
|
||||
/* First read xpath */
|
||||
len = 1024; /* any number is fine */
|
||||
|
|
@ -192,7 +229,37 @@ main(int argc, char **argv)
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* If xpath0 given, position current x */
|
||||
/* Validate XML as well */
|
||||
if (yang_file_dir){
|
||||
cbuf *cbret = NULL;
|
||||
cxobj *x1;
|
||||
cxobj *xerr = NULL; /* malloced must be freed */
|
||||
|
||||
x1 = xml_child_i(x0, 0);
|
||||
/* Populate */
|
||||
if (xml_apply0(x1, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
||||
goto done;
|
||||
/* Sort */
|
||||
if (xml_apply0(x1, CX_ELMNT, xml_sort, h) < 0)
|
||||
goto done;
|
||||
/* Add default values */
|
||||
if (xml_apply(x1, CX_ELMNT, xml_default, h) < 0)
|
||||
goto done;
|
||||
if (xml_apply0(x1, -1, xml_sort_verify, h) < 0)
|
||||
clicon_log(LOG_NOTICE, "%s: sort verify failed", __FUNCTION__);
|
||||
if ((ret = xml_yang_validate_all_top(h, x1, &xerr)) < 0)
|
||||
goto done;
|
||||
if (ret > 0 && (ret = xml_yang_validate_add(h, x1, &xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
if (netconf_err2cb(xerr, &cbret) < 0)
|
||||
goto done;
|
||||
fprintf(stderr, "xml validation error: %s\n", cbuf_get(cbret));
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* If xpath0 given, position current x (ie somewhere else than root) */
|
||||
if (xpath0){
|
||||
if ((x = xpath_first(x0, "%s", xpath0)) == NULL){
|
||||
fprintf(stderr, "Error: xpath0 returned NULL\n");
|
||||
|
|
@ -202,7 +269,7 @@ main(int argc, char **argv)
|
|||
else
|
||||
x = x0;
|
||||
|
||||
/* Parse XML (use nsc == NULL to indicate dont use) */
|
||||
/* Parse XPATH (use nsc == NULL to indicate dont use) */
|
||||
if (xpath_vec_ctx(x, NULL, xpath, &xc) < 0)
|
||||
return -1;
|
||||
/* Print results */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue