New configuration option: CLICON_RESTCONF_PRETTY
Changed RESTCONF GET to return object referenced. ie, GET /restconf/data/X returns X.
This commit is contained in:
parent
cefaf4717f
commit
363bd5d19d
7 changed files with 169 additions and 102 deletions
|
|
@ -10,6 +10,9 @@
|
||||||
* Configuration files (non-XML) prior to 3.3.3. As enabled with `configure --with-config-compat`. The template clicon.conf.cpp files are also removed.
|
* Configuration files (non-XML) prior to 3.3.3. As enabled with `configure --with-config-compat`. The template clicon.conf.cpp files are also removed.
|
||||||
* Clixon XML C-lib prior to 3.4.0. As enabled with `configure --with-xml-compat`
|
* Clixon XML C-lib prior to 3.4.0. As enabled with `configure --with-xml-compat`
|
||||||
|
|
||||||
|
* new configuration option: CLICON_RESTCONF_PRETTY
|
||||||
|
* Changed RESTCONF GET to return object referenced. ie, GET /restconf/data/X returns X.
|
||||||
|
|
||||||
### Corrected Bugs
|
### Corrected Bugs
|
||||||
* Corrected "No yang spec" printed on tty on leafref CLI usage
|
* Corrected "No yang spec" printed on tty on leafref CLI usage
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,6 @@
|
||||||
* @param[out] commands vector of function pointers to callback functions
|
* @param[out] commands vector of function pointers to callback functions
|
||||||
* @param[out] helptxt vector of pointers to helptexts
|
* @param[out] helptxt vector of pointers to helptexts
|
||||||
* @see cli_expand_var_generate This is where arg is generated
|
* @see cli_expand_var_generate This is where arg is generated
|
||||||
* XXX: helptexts?
|
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
expand_dbvar(void *h,
|
expand_dbvar(void *h,
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ There is currently (2017) a [RFC 8040: RESTCONF Protocol](https://tools.ietf.org
|
||||||
including:
|
including:
|
||||||
- query parameters (section 4.9)
|
- query parameters (section 4.9)
|
||||||
- notifications (sec 6)
|
- notifications (sec 6)
|
||||||
|
- GET /restconf/ (sec 3.3)
|
||||||
|
- GET /restconf/yang-library-version (sec 3.3.3)
|
||||||
- only rudimentary error reporting exists (sec 7)
|
- only rudimentary error reporting exists (sec 7)
|
||||||
|
|
||||||
### Installation using Nginx
|
### Installation using Nginx
|
||||||
|
|
|
||||||
|
|
@ -140,82 +140,139 @@ api_data_options(clicon_handle h,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Generic GET (both HEAD and GET)
|
/*! Return error on get/head request
|
||||||
|
* @param[in] h Clixon handle
|
||||||
|
* @param[in] r Fastcgi request handle
|
||||||
|
* @param[in] xerr XML error message from backend
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
api_data_get_gen(clicon_handle h,
|
api_data_get_err(clicon_handle h,
|
||||||
FCGX_Request *r,
|
FCGX_Request *r,
|
||||||
cvec *pcvec,
|
cxobj *xerr)
|
||||||
int pi,
|
|
||||||
cvec *qvec,
|
|
||||||
int head)
|
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cbuf *path = NULL;
|
cbuf *cbj = NULL;
|
||||||
|
cxobj *xtag;
|
||||||
|
int code;
|
||||||
|
const char *reason_phrase;
|
||||||
|
|
||||||
|
if ((cbj = cbuf_new()) == NULL)
|
||||||
|
goto done;
|
||||||
|
if ((xtag = xpath_first(xerr, "/error-tag")) == NULL){
|
||||||
|
notfound(r); /* bad reply? */
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
code = restconf_err2code(xml_body(xtag));
|
||||||
|
if ((reason_phrase = restconf_code2reason(code)) == NULL)
|
||||||
|
reason_phrase="";
|
||||||
|
clicon_debug(1, "%s code:%d reason phrase:%s",
|
||||||
|
__FUNCTION__, code, reason_phrase);
|
||||||
|
|
||||||
|
if (xml_name_set(xerr, "error") < 0)
|
||||||
|
goto done;
|
||||||
|
if (xml2json_cbuf(cbj, xerr, 1) < 0)
|
||||||
|
goto done;
|
||||||
|
FCGX_FPrintF(r->out, "Status: %d %s\r\n", code, reason_phrase);
|
||||||
|
FCGX_FPrintF(r->out, "Content-Type: application/yang-data+json\r\n\r\n");
|
||||||
|
FCGX_FPrintF(r->out, "\r\n");
|
||||||
|
FCGX_FPrintF(r->out, "{\r\n");
|
||||||
|
FCGX_FPrintF(r->out, " \"ietf-restconf:errors\" : {\r\n");
|
||||||
|
FCGX_FPrintF(r->out, " %s", cbuf_get(cbj));
|
||||||
|
FCGX_FPrintF(r->out, " }\r\n");
|
||||||
|
FCGX_FPrintF(r->out, "}\r\n");
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (cbj)
|
||||||
|
cbuf_free(cbj);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Generic GET (both HEAD and GET)
|
||||||
|
* According to restconf
|
||||||
|
* @param[in] h Clixon handle
|
||||||
|
* @param[in] r Fastcgi request handle
|
||||||
|
* @param[in] pcvec Vector of path ie DOCUMENT_URI element
|
||||||
|
* @param[in] pi Offset, where path starts
|
||||||
|
* @param[in] qvec Vector of query string (QUERY_STRING)
|
||||||
|
* @param[in] head If 1 is HEAD, otherwise GET
|
||||||
|
* @code
|
||||||
|
* curl -G http://localhost/restconf/data/interfaces/interface=eth0
|
||||||
|
* @endcode
|
||||||
|
* XXX: cant find a way to use Accept request field to choose Content-Type
|
||||||
|
* I would like to support both xml and json.
|
||||||
|
* Request may contain
|
||||||
|
* Accept: application/yang.data+json,application/yang.data+xml
|
||||||
|
* Response contains one of:
|
||||||
|
* Content-Type: application/yang-data+xml
|
||||||
|
* Content-Type: application/yang-data+json
|
||||||
|
* NOTE: If a retrieval request for a data resource representing a YANG leaf-
|
||||||
|
* list or list object identifies more than one instance, and XML
|
||||||
|
* encoding is used in the response, then an error response containing a
|
||||||
|
* "400 Bad Request" status-line MUST be returned by the server.
|
||||||
|
* Netconf: <get-config>, <get>
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
api_data_get2(clicon_handle h,
|
||||||
|
FCGX_Request *r,
|
||||||
|
cvec *pcvec,
|
||||||
|
int pi,
|
||||||
|
cvec *qvec,
|
||||||
|
int head)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cbuf *cbpath = NULL;
|
||||||
|
char *path;
|
||||||
cbuf *cbx = NULL;
|
cbuf *cbx = NULL;
|
||||||
cxobj **vec = NULL;
|
|
||||||
yang_spec *yspec;
|
yang_spec *yspec;
|
||||||
cxobj *xret = NULL;
|
cxobj *xret = NULL;
|
||||||
cxobj *xerr;
|
cxobj *xerr;
|
||||||
cxobj *xtag;
|
|
||||||
cbuf *cbj = NULL;;
|
|
||||||
int code;
|
|
||||||
const char *reason_phrase;
|
|
||||||
char *media_accept;
|
char *media_accept;
|
||||||
int use_xml = 0; /* By default use JSON */
|
int use_xml = 0; /* By default use JSON */
|
||||||
|
cxobj **xvec = NULL;
|
||||||
|
size_t xlen;
|
||||||
|
int pretty;
|
||||||
|
int i;
|
||||||
|
cxobj *x;
|
||||||
|
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
|
pretty = clicon_option_bool(h, "CLICON_RESTCONF_PRETTY");
|
||||||
media_accept = FCGX_GetParam("HTTP_ACCEPT", r->envp);
|
media_accept = FCGX_GetParam("HTTP_ACCEPT", r->envp);
|
||||||
if (strcmp(media_accept, "application/yang-data+xml")==0)
|
if (strcmp(media_accept, "application/yang-data+xml")==0)
|
||||||
use_xml++;
|
use_xml++;
|
||||||
yspec = clicon_dbspec_yang(h);
|
yspec = clicon_dbspec_yang(h);
|
||||||
if ((path = cbuf_new()) == NULL)
|
if ((cbpath = cbuf_new()) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
cprintf(path, "/");
|
cprintf(cbpath, "/");
|
||||||
if (api_path2xpath_cvv(yspec, pcvec, pi, path) < 0){
|
clicon_debug(1, "%s pi:%d", __FUNCTION__, pi);
|
||||||
|
/* We know "data" is element pi-1 */
|
||||||
|
if (api_path2xpath_cvv(yspec, pcvec, pi, cbpath) < 0){
|
||||||
notfound(r);
|
notfound(r);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
clicon_debug(1, "%s path:%s", __FUNCTION__, cbuf_get(path));
|
path = cbuf_get(cbpath);
|
||||||
if (clicon_rpc_get(h, cbuf_get(path), &xret) < 0){
|
clicon_debug(1, "%s path:%s", __FUNCTION__, path);
|
||||||
|
if (clicon_rpc_get(h, path, &xret) < 0){
|
||||||
notfound(r);
|
notfound(r);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
#if 0 /* DEBUG */
|
/* We get return via netconf which is complete tree from root
|
||||||
|
* We need to cut that tree to only the object.
|
||||||
|
*/
|
||||||
|
#if 1 /* DEBUG */
|
||||||
{
|
{
|
||||||
cbuf *cb = cbuf_new();
|
cbuf *cb = cbuf_new();
|
||||||
xml2json_cbuf(cb, xret, 1);
|
clicon_xml2cbuf(cb, xret, 0, 0);
|
||||||
clicon_debug(1, "%s xret:%s", __FUNCTION__, cbuf_get(cb));
|
clicon_debug(1, "%s xret:%s", __FUNCTION__, cbuf_get(cb));
|
||||||
cbuf_free(cb);
|
cbuf_free(cb);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
/* Check if error return */
|
||||||
if ((xerr = xpath_first(xret, "/rpc-error")) != NULL){
|
if ((xerr = xpath_first(xret, "/rpc-error")) != NULL){
|
||||||
if ((cbj = cbuf_new()) == NULL)
|
if (api_data_get_err(h, r, xerr) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xtag = xpath_first(xerr, "/error-tag")) == NULL){
|
|
||||||
notfound(r); /* bad reply? */
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
code = restconf_err2code(xml_body(xtag));
|
|
||||||
if ((reason_phrase = restconf_code2reason(code)) == NULL)
|
|
||||||
reason_phrase="";
|
|
||||||
clicon_debug(1, "%s code:%d reason phrase:%s",
|
|
||||||
__FUNCTION__, code, reason_phrase);
|
|
||||||
|
|
||||||
if (xml_name_set(xerr, "error") < 0)
|
|
||||||
goto done;
|
|
||||||
if (xml2json_cbuf(cbj, xerr, 1) < 0)
|
|
||||||
goto done;
|
|
||||||
FCGX_FPrintF(r->out, "Status: %d %s\r\n", code, reason_phrase);
|
|
||||||
FCGX_FPrintF(r->out, "Content-Type: application/yang-data+json\r\n\r\n");
|
|
||||||
FCGX_FPrintF(r->out, "\r\n");
|
|
||||||
FCGX_FPrintF(r->out, "{\r\n");
|
|
||||||
FCGX_FPrintF(r->out, " \"ietf-restconf:errors\" : {\r\n");
|
|
||||||
FCGX_FPrintF(r->out, " %s", cbuf_get(cbj));
|
|
||||||
FCGX_FPrintF(r->out, " }\r\n");
|
|
||||||
FCGX_FPrintF(r->out, "}\r\n");
|
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
|
/* Normal return, no error */
|
||||||
if ((cbx = cbuf_new()) == NULL)
|
if ((cbx = cbuf_new()) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
FCGX_SetExitStatus(200, r->out); /* OK */
|
FCGX_SetExitStatus(200, r->out); /* OK */
|
||||||
|
|
@ -223,17 +280,39 @@ api_data_get_gen(clicon_handle h,
|
||||||
FCGX_FPrintF(r->out, "\r\n");
|
FCGX_FPrintF(r->out, "\r\n");
|
||||||
if (head)
|
if (head)
|
||||||
goto ok;
|
goto ok;
|
||||||
clicon_debug(1, "%s name:%s child:%d", __FUNCTION__, xml_name(xret), xml_child_nr(xret));
|
if (path==NULL || strcmp(path,"/")==0){ /* Special case: data root */
|
||||||
|
if (use_xml){
|
||||||
clicon_debug(1, "%s xretnr:%d", __FUNCTION__, xml_child_nr(xret));
|
if (clicon_xml2cbuf(cbx, xret, 0, pretty) < 0) /* Dont print top object? */
|
||||||
if (use_xml){
|
goto done;
|
||||||
if (clicon_xml2cbuf(cbx, xret, 0, 1) < 0) /* Dont print top object? */
|
}
|
||||||
goto done;
|
else{
|
||||||
|
if (xml2json_cbuf(cbx, xret, pretty) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
vec = xml_childvec_get(xret);
|
if (xpath_vec(xret, path, &xvec, &xlen) < 0)
|
||||||
if (xml2json_cbuf_vec(cbx, vec, xml_child_nr(xret), 0) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
|
clicon_debug(1, "%s: xpath:%s xlen:%d", __FUNCTION__, path, xlen);
|
||||||
|
for (i=0; i<xlen; i++){
|
||||||
|
x = xvec[i];
|
||||||
|
#if 1 /* DEBUG */
|
||||||
|
{
|
||||||
|
cbuf *cb = cbuf_new();
|
||||||
|
clicon_xml2cbuf(cb, x, 0, 0);
|
||||||
|
clicon_debug(1, "%s x:%s", __FUNCTION__, cbuf_get(cb));
|
||||||
|
cbuf_free(cb);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (use_xml){
|
||||||
|
if (clicon_xml2cbuf(cbx, x, 0, pretty) < 0) /* Dont print top object? */
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if (xml2json_cbuf(cbx, x, pretty) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
clicon_debug(1, "%s cbuf:%s", __FUNCTION__, cbuf_get(cbx));
|
clicon_debug(1, "%s cbuf:%s", __FUNCTION__, cbuf_get(cbx));
|
||||||
FCGX_FPrintF(r->out, "%s", cbx?cbuf_get(cbx):"");
|
FCGX_FPrintF(r->out, "%s", cbx?cbuf_get(cbx):"");
|
||||||
|
|
@ -244,12 +323,12 @@ api_data_get_gen(clicon_handle h,
|
||||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||||
if (cbx)
|
if (cbx)
|
||||||
cbuf_free(cbx);
|
cbuf_free(cbx);
|
||||||
if (cbj)
|
if (cbpath)
|
||||||
cbuf_free(cbj);
|
cbuf_free(cbpath);
|
||||||
if (path)
|
|
||||||
cbuf_free(path);
|
|
||||||
if (xret)
|
if (xret)
|
||||||
xml_free(xret);
|
xml_free(xret);
|
||||||
|
if (xvec)
|
||||||
|
free(xvec);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -271,7 +350,7 @@ api_data_head(clicon_handle h,
|
||||||
int pi,
|
int pi,
|
||||||
cvec *qvec)
|
cvec *qvec)
|
||||||
{
|
{
|
||||||
return api_data_get_gen(h, r, pcvec, pi, qvec, 1);
|
return api_data_get2(h, r, pcvec, pi, qvec, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! REST GET method
|
/*! REST GET method
|
||||||
|
|
@ -304,7 +383,7 @@ api_data_get(clicon_handle h,
|
||||||
int pi,
|
int pi,
|
||||||
cvec *qvec)
|
cvec *qvec)
|
||||||
{
|
{
|
||||||
return api_data_get_gen(h, r, pcvec, pi, qvec, 0);
|
return api_data_get2(h, r, pcvec, pi, qvec, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! REST POST method
|
/*! REST POST method
|
||||||
|
|
|
||||||
|
|
@ -549,6 +549,7 @@ match_base_child(cxobj *x0,
|
||||||
char **keyval = NULL;
|
char **keyval = NULL;
|
||||||
char **keyvec = NULL;
|
char **keyvec = NULL;
|
||||||
int i;
|
int i;
|
||||||
|
int yorder;
|
||||||
|
|
||||||
*x0cp = NULL; /* return value */
|
*x0cp = NULL; /* return value */
|
||||||
switch (yc->ys_keyword){
|
switch (yc->ys_keyword){
|
||||||
|
|
@ -591,51 +592,21 @@ match_base_child(cxobj *x0,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Get match */
|
/* Get match */
|
||||||
{
|
if (xml_child_sort==0)
|
||||||
int yorder;
|
*x0cp = xml_match(x0, xml_name(x1c), yc->ys_keyword, keynr, keyvec, keyval);
|
||||||
|
else{
|
||||||
/* XXX: No we cant do this. on uppermost layer it can look like this:
|
if (xml_child_nr(x0)==0 || xml_spec(xml_child_i(x0,0))!=NULL){
|
||||||
* config
|
yorder = yang_order(yc);
|
||||||
* ximport-----ymod = ietf
|
*x0cp = xml_search(x0, xml_name(x1c), yorder, yc->ys_keyword, keynr, keyvec, keyval);
|
||||||
* interfaces--ymod = example
|
}
|
||||||
* Which means yang order can be different for different children in the
|
|
||||||
* same childvec.
|
|
||||||
*/
|
|
||||||
if (xml_child_sort==0)
|
|
||||||
*x0cp = xml_match(x0, xml_name(x1c), yc->ys_keyword, keynr, keyvec, keyval);
|
|
||||||
else{
|
else{
|
||||||
#if 1
|
|
||||||
if (xml_child_nr(x0)==0 || xml_spec(xml_child_i(x0,0))!=NULL){
|
|
||||||
yorder = yang_order(yc);
|
|
||||||
*x0cp = xml_search(x0, xml_name(x1c), yorder, yc->ys_keyword, keynr, keyvec, keyval);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
#if 1 /* This is just a warning, but a catcher for when xml tree is not
|
#if 1 /* This is just a warning, but a catcher for when xml tree is not
|
||||||
populated with yang spec. If you see this, a previous inovation of,
|
populated with yang spec. If you see this, a previous invacation of,
|
||||||
for example xml_spec_populate() may be missing
|
for example xml_spec_populate() may be missing
|
||||||
*/
|
*/
|
||||||
clicon_log(LOG_WARNING, "%s No yspec", __FUNCTION__);
|
clicon_log(LOG_WARNING, "%s No yspec", __FUNCTION__);
|
||||||
#endif
|
#endif
|
||||||
*x0cp = xml_match(x0, xml_name(x1c), yc->ys_keyword, keynr, keyvec, keyval);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
cxobj *xx;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
*x0cp = xml_match(x0, xml_name(x1c), yc->ys_keyword, keynr, keyvec, keyval);
|
*x0cp = xml_match(x0, xml_name(x1c), yc->ys_keyword, keynr, keyvec, keyval);
|
||||||
if (xml_child_nr(x0) && xml_spec(xml_child_i(x0,0))!=NULL){
|
|
||||||
xx = xml_search(x0, xml_name(x1c), yorder, yc->ys_keyword, keynr, keyvec, keyval);
|
|
||||||
if (xx!=*x0cp){
|
|
||||||
clicon_log(LOG_WARNING, "%s mismatch", __FUNCTION__);
|
|
||||||
fprintf(stderr, "mismatch\n");
|
|
||||||
xml_search(x0, xml_name(x1c), yorder, yc->ys_keyword, keynr, keyvec, keyval);
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
clicon_log(LOG_WARNING, "%s No yspec", __FUNCTION__);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ok:
|
ok:
|
||||||
|
|
|
||||||
|
|
@ -1046,10 +1046,10 @@ xpath_each(cxobj *xcur,
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xpath_vec(cxobj *xcur,
|
xpath_vec(cxobj *xcur,
|
||||||
char *format,
|
char *format,
|
||||||
cxobj ***vec,
|
cxobj ***vec,
|
||||||
size_t *veclen,
|
size_t *veclen,
|
||||||
...)
|
...)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ module clixon-config {
|
||||||
description
|
description
|
||||||
"Clixon configuration file
|
"Clixon configuration file
|
||||||
***** BEGIN LICENSE BLOCK *****
|
***** BEGIN LICENSE BLOCK *****
|
||||||
Copyright (C) 2009-2017 Olof Hagsand and Benny Holmgren
|
Copyright (C) 2009-2018 Olof Hagsand and Benny Holmgren
|
||||||
|
|
||||||
This file is part of CLIXON
|
This file is part of CLIXON
|
||||||
|
|
||||||
|
|
@ -130,6 +130,19 @@ module clixon-config {
|
||||||
"FastCGI unix socket. Should be specified in webserver
|
"FastCGI unix socket. Should be specified in webserver
|
||||||
Eg in nginx: fastcgi_pass unix:/www-data/clicon_restconf.sock";
|
Eg in nginx: fastcgi_pass unix:/www-data/clicon_restconf.sock";
|
||||||
}
|
}
|
||||||
|
leaf CLICON_RESTCONF_PRETTY {
|
||||||
|
type boolean;
|
||||||
|
default true;
|
||||||
|
description
|
||||||
|
"Restconf return value pretty print.
|
||||||
|
Restconf clients may add HTTP header:
|
||||||
|
Accept: application/yang-data+json, or
|
||||||
|
Accept: application/yang-data+xml
|
||||||
|
to get return value in XML or JSON.
|
||||||
|
RFC 8040 examples print XML and JSON in pretty-printed form.
|
||||||
|
Setting this value to false makes restconf return not pretty-printed
|
||||||
|
which may be desirable for performance or tests";
|
||||||
|
}
|
||||||
leaf CLICON_CLI_DIR {
|
leaf CLICON_CLI_DIR {
|
||||||
type string;
|
type string;
|
||||||
description
|
description
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue