- removed api_path extension from internal netconf
- Strings in xmldb_put not properly encoded, eg eth/0 became eth.00000
This commit is contained in:
parent
683376610c
commit
3453dae0db
36 changed files with 1048 additions and 1307 deletions
|
|
@ -256,8 +256,6 @@ from_client_get_config(clicon_handle h,
|
|||
* @param[in] xe Netconf request xml tree
|
||||
* @param[in] mypid Process/session id of calling client
|
||||
* @param[out] cbret Return xml value cligen buffer
|
||||
* CLIXON addition:
|
||||
* <filter type="restconf" select="/data/profile=a" />
|
||||
*/
|
||||
static int
|
||||
from_client_edit_config(clicon_handle h,
|
||||
|
|
@ -270,10 +268,8 @@ from_client_edit_config(clicon_handle h,
|
|||
cbuf *cb = NULL;
|
||||
cxobj *xret = NULL;
|
||||
cxobj *xc;
|
||||
cxobj *xfilter;
|
||||
cxobj *x;
|
||||
enum operation_type operation = OP_MERGE;
|
||||
char *api_path = NULL;
|
||||
int piddb;
|
||||
|
||||
if ((target = netconf_db_find(xn, "target")) == NULL){
|
||||
|
|
@ -293,9 +289,6 @@ from_client_edit_config(clicon_handle h,
|
|||
piddb);
|
||||
goto ok;
|
||||
}
|
||||
/* ie <filter type="restconf" select=<api-path> /> */
|
||||
if ((xfilter = xpath_first(xn, "filter")) != NULL)
|
||||
api_path = xml_find_value(xfilter, "select");
|
||||
if ((x = xpath_first(xn, "default-operation")) != NULL){
|
||||
if (xml_operation(xml_body(x), &operation) < 0){
|
||||
cprintf(cbret, "<rpc-reply><rpc-error>"
|
||||
|
|
@ -307,7 +300,7 @@ from_client_edit_config(clicon_handle h,
|
|||
}
|
||||
}
|
||||
if ((xc = xpath_first(xn, "config")) != NULL){
|
||||
if (xmldb_put(h, target, operation, api_path, xc) < 0){
|
||||
if (xmldb_put(h, target, operation, xc) < 0){
|
||||
cprintf(cbret, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>operation-failed</error-tag>"
|
||||
"<error-type>protocol</error-type>"
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@ rundb_main(clicon_handle h,
|
|||
if (clicon_xml_parse_file(fd, &xt, "</clicon>") < 0)
|
||||
goto done;
|
||||
if ((xn = xml_child_i(xt, 0)) != NULL)
|
||||
if (xmldb_put(h, "tmp", OP_MERGE, NULL, xn) < 0)
|
||||
if (xmldb_put(h, "tmp", OP_MERGE, xn) < 0)
|
||||
goto done;
|
||||
if (candidate_commit(h, "tmp") < 0)
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -207,38 +207,64 @@ cli_dbxml(clicon_handle h,
|
|||
{
|
||||
int retval = -1;
|
||||
char *str = NULL;
|
||||
char *xkfmt; /* xml key format */
|
||||
char *xk = NULL; /* xml key */
|
||||
char *api_path_fmt; /* xml key format */
|
||||
char *api_path = NULL; /* xml key */
|
||||
cg_var *cval;
|
||||
int len;
|
||||
cg_var *arg;
|
||||
cbuf *cb = NULL;
|
||||
yang_spec *yspec;
|
||||
cxobj *xbot = NULL; /* xpath, NULL if datastore */
|
||||
yang_node *y = NULL; /* yang spec of xpath */
|
||||
cxobj *xtop = NULL; /* xpath root */
|
||||
cxobj *xa; /* attribute */
|
||||
cxobj *xb; /* body */
|
||||
|
||||
if (cvec_len(argv) != 1){
|
||||
clicon_err(OE_PLUGIN, 0, "%s: Requires one element to be xml key format string", __FUNCTION__);
|
||||
goto done;
|
||||
}
|
||||
arg = cvec_i(argv, 0);
|
||||
xkfmt = cv_string_get(arg);
|
||||
if (xmlkeyfmt2key(xkfmt, cvv, &xk) < 0)
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||
goto done;
|
||||
len = cvec_len(cvv);
|
||||
if (len > 1){
|
||||
cval = cvec_i(cvv, len-1);
|
||||
if ((str = cv2str_dup(cval)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cv2str_dup");
|
||||
goto done;
|
||||
}
|
||||
arg = cvec_i(argv, 0);
|
||||
api_path_fmt = cv_string_get(arg);
|
||||
if (api_path_fmt2api_path(api_path_fmt, cvv, &api_path) < 0)
|
||||
goto done;
|
||||
/* Create config top-of-tree */
|
||||
if ((xtop = xml_new("config", NULL)) == NULL)
|
||||
goto done;
|
||||
xbot = xtop;
|
||||
if (api_path && api_path2xml(api_path, yspec, xtop, &xbot, &y) < 0)
|
||||
goto done;
|
||||
if ((xa = xml_new("operation", xbot)) == NULL)
|
||||
goto done;
|
||||
xml_type_set(xa, CX_ATTR);
|
||||
if (xml_value_set(xa, xml_operation2str(op)) < 0)
|
||||
goto done;
|
||||
if (y->yn_keyword != Y_LIST){
|
||||
len = cvec_len(cvv);
|
||||
if (len > 1){
|
||||
cval = cvec_i(cvv, len-1);
|
||||
if ((str = cv2str_dup(cval)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cv2str_dup");
|
||||
goto done;
|
||||
}
|
||||
if ((xb = xml_new("body", xbot)) == NULL)
|
||||
goto done;
|
||||
xml_type_set(xb, CX_BODY);
|
||||
if (xml_value_set(xb, str) < 0)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if (str)
|
||||
cprintf(cb, "<config>%s</config>", str);
|
||||
else
|
||||
cprintf(cb, "<config/>");
|
||||
if (clicon_rpc_edit_config(h, "candidate", op, xk, cbuf_get(cb)) < 0)
|
||||
if (clicon_xml2cbuf(cb, xtop, 0, 0) < 0)
|
||||
goto done;
|
||||
if (clicon_rpc_edit_config(h, "candidate", OP_NONE, cbuf_get(cb)) < 0)
|
||||
goto done;
|
||||
if (clicon_autocommit(h)) {
|
||||
if (clicon_rpc_commit(h) < 0)
|
||||
|
|
@ -250,8 +276,10 @@ cli_dbxml(clicon_handle h,
|
|||
cbuf_free(cb);
|
||||
if (str)
|
||||
free(str);
|
||||
if (xk)
|
||||
free(xk);
|
||||
if (api_path)
|
||||
free(api_path);
|
||||
if (xtop)
|
||||
xml_free(xtop);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -287,6 +315,31 @@ int cli_mergev(clicon_handle h, cvec *vars, cvec *argv)
|
|||
return cli_merge(h, vars, argv);
|
||||
}
|
||||
|
||||
int
|
||||
cli_create(clicon_handle h, cvec *cvv, cvec *argv)
|
||||
{
|
||||
int retval = -1;
|
||||
|
||||
if (cli_dbxml(h, cvv, argv, OP_CREATE) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
/*!
|
||||
* @see cli_del
|
||||
*/
|
||||
int
|
||||
cli_remove(clicon_handle h, cvec *cvv, cvec *argv)
|
||||
{
|
||||
int retval = -1;
|
||||
|
||||
if (cli_dbxml(h, cvv, argv, OP_REMOVE) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
cli_del(clicon_handle h, cvec *cvv, cvec *argv)
|
||||
|
|
@ -704,7 +757,6 @@ load_config_file(clicon_handle h,
|
|||
}
|
||||
if (clicon_rpc_edit_config(h, "candidate",
|
||||
replace?OP_REPLACE:OP_MERGE,
|
||||
"",
|
||||
cbuf_get(cbxml)) < 0)
|
||||
goto done;
|
||||
cbuf_free(cbxml);
|
||||
|
|
@ -1135,7 +1187,7 @@ cli_copy_config(clicon_handle h,
|
|||
cbuf_reset(cb);
|
||||
/* create xml copy tree and merge it with database configuration */
|
||||
clicon_xml2cbuf(cb, x2, 0, 0);
|
||||
if (clicon_rpc_edit_config(h, db, OP_MERGE, NULL, cbuf_get(cb)) < 0)
|
||||
if (clicon_rpc_edit_config(h, db, OP_MERGE, cbuf_get(cb)) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@
|
|||
#include "cli_generate.h"
|
||||
|
||||
/* This is the default callback function. But this is typically overwritten */
|
||||
#define GENERATE_CALLBACK "cli_set"
|
||||
#define GENERATE_CALLBACK "overwrite_me"
|
||||
|
||||
/* variable expand function */
|
||||
#define GENERATE_EXPAND_XMLDB "expand_dbvar"
|
||||
|
|
@ -115,13 +115,12 @@ cli_expand_var_generate(clicon_handle h,
|
|||
enum cv_type cvtype,
|
||||
cbuf *cb0,
|
||||
int options,
|
||||
uint8_t fraction_digits
|
||||
)
|
||||
uint8_t fraction_digits)
|
||||
{
|
||||
int retval = -1;
|
||||
char *xkfmt = NULL;
|
||||
char *api_path_fmt = NULL;
|
||||
|
||||
if (yang2xmlkeyfmt(ys, 1, &xkfmt) < 0)
|
||||
if (yang2api_path_fmt(ys, 1, &api_path_fmt) < 0)
|
||||
goto done;
|
||||
cprintf(cb0, "|<%s:%s", ys->ys_argument,
|
||||
cv_type2str(cvtype));
|
||||
|
|
@ -129,15 +128,15 @@ cli_expand_var_generate(clicon_handle h,
|
|||
cprintf(cb0, " fraction-digits:%u", fraction_digits);
|
||||
cprintf(cb0, " %s(\"candidate\",\"%s\")>",
|
||||
GENERATE_EXPAND_XMLDB,
|
||||
xkfmt);
|
||||
api_path_fmt);
|
||||
retval = 0;
|
||||
done:
|
||||
if (xkfmt)
|
||||
free(xkfmt);
|
||||
if (api_path_fmt)
|
||||
free(api_path_fmt);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Create callback with xmlkey format string as argument
|
||||
/*! Create callback with api_path format string as argument
|
||||
* @param[in] h clicon handle
|
||||
* @param[in] ys yang_stmt of the node at hand
|
||||
* @param[in] cb0 The string where the result format string is inserted.
|
||||
|
|
@ -149,15 +148,16 @@ cli_callback_generate(clicon_handle h,
|
|||
cbuf *cb0)
|
||||
{
|
||||
int retval = -1;
|
||||
char *xkfmt = NULL;
|
||||
char *api_path_fmt = NULL;
|
||||
|
||||
if (yang2xmlkeyfmt(ys, 0, &xkfmt) < 0)
|
||||
if (yang2api_path_fmt(ys, 0, &api_path_fmt) < 0)
|
||||
goto done;
|
||||
cprintf(cb0, ",%s(\"%s\")", GENERATE_CALLBACK, xkfmt);
|
||||
cprintf(cb0, ",%s(\"%s\")", GENERATE_CALLBACK,
|
||||
api_path_fmt);
|
||||
retval = 0;
|
||||
done:
|
||||
if (xkfmt)
|
||||
free(xkfmt);
|
||||
if (api_path_fmt)
|
||||
free(api_path_fmt);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -166,8 +166,7 @@ static int yang2cli_stmt(clicon_handle h, yang_stmt *ys,
|
|||
enum genmodel_type gt,
|
||||
int level);
|
||||
|
||||
/*
|
||||
* Check for completion (of already existent values), ranges (eg range[min:max]) and
|
||||
/*! Check for completion (of already existent values), ranges (eg range[min:max]) and
|
||||
* patterns, (eg regexp:"[0.9]*").
|
||||
*/
|
||||
static int
|
||||
|
|
@ -403,7 +402,6 @@ yang2cli_leaf(clicon_handle h,
|
|||
return retval;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
yang2cli_container(clicon_handle h,
|
||||
yang_stmt *ys,
|
||||
|
|
|
|||
|
|
@ -99,10 +99,10 @@ expand_dbvar(void *h,
|
|||
cvec *helptexts)
|
||||
{
|
||||
int retval = -1;
|
||||
char *xkfmt;
|
||||
char *api_path;
|
||||
char *dbstr;
|
||||
cxobj *xt = NULL;
|
||||
char *xkpath = NULL;
|
||||
char *xpath = NULL;
|
||||
cxobj **xvec = NULL;
|
||||
size_t xlen = 0;
|
||||
cxobj *x;
|
||||
|
|
@ -129,23 +129,24 @@ expand_dbvar(void *h,
|
|||
goto done;
|
||||
}
|
||||
if ((cv = cvec_i(argv, 1)) == NULL){
|
||||
clicon_err(OE_PLUGIN, 0, "%s: Error when accessing argument <xkfmt>");
|
||||
clicon_err(OE_PLUGIN, 0, "%s: Error when accessing argument <api_path>");
|
||||
goto done;
|
||||
}
|
||||
xkfmt = cv_string_get(cv);
|
||||
/* xkfmt = /interface/%s/address/%s
|
||||
api_path = cv_string_get(cv);
|
||||
/* api_path = /interface/%s/address/%s
|
||||
--> ^/interface/eth0/address/.*$
|
||||
--> /interface/[name=eth0]/address
|
||||
*/
|
||||
if (xmlkeyfmt2xpath(xkfmt, cvv, &xkpath) < 0)
|
||||
if (api_path_fmt2xpath(api_path, cvv, &xpath) < 0)
|
||||
goto done;
|
||||
/* XXX read whole configuration, why not send xpath? */
|
||||
if (clicon_rpc_get_config(h, dbstr, "/", &xt) < 0)
|
||||
goto done;
|
||||
/* One round to detect duplicates
|
||||
* XXX The code below would benefit from some cleanup
|
||||
*/
|
||||
j = 0;
|
||||
if (xpath_vec(xt, xkpath, &xvec, &xlen) < 0)
|
||||
if (xpath_vec(xt, xpath, &xvec, &xlen) < 0)
|
||||
goto done;
|
||||
for (i = 0; i < xlen; i++) {
|
||||
char *str;
|
||||
|
|
@ -190,8 +191,8 @@ expand_dbvar(void *h,
|
|||
free(xvec);
|
||||
if (xt)
|
||||
xml_free(xt);
|
||||
if (xkpath)
|
||||
free(xkpath);
|
||||
if (xpath)
|
||||
free(xpath);
|
||||
return retval;
|
||||
}
|
||||
int
|
||||
|
|
|
|||
|
|
@ -82,6 +82,9 @@ int cli_setv(clicon_handle h, cvec *vars, cvec *argv);
|
|||
int cli_merge(clicon_handle h, cvec *vars, cvec *argv);
|
||||
int cli_mergev(clicon_handle h, cvec *vars, cvec *argv);
|
||||
|
||||
int cli_create(clicon_handle h, cvec *vars, cvec *argv);
|
||||
int cli_remove(clicon_handle h, cvec *vars, cvec *argv);
|
||||
|
||||
int cli_del(clicon_handle h, cvec *vars, cvec *argv);
|
||||
int cli_delv(clicon_handle h, cvec *vars, cvec *argv);
|
||||
|
||||
|
|
|
|||
|
|
@ -67,8 +67,7 @@ curl -sX POST -d '{"clicon":{"interfaces":{"interface":{"name":"eth1","type":"et
|
|||
|
||||
Start the restconf fastcgi program with debug flag:
|
||||
```
|
||||
sudo su -c "/www-data/clixon_restconf -Df /usr/local/etc/routing.conf" -s /bin/sh www-
|
||||
data
|
||||
sudo su -c "/www-data/clixon_restconf -Df /usr/local/etc/routing.conf" -s /bin/sh www-data
|
||||
```
|
||||
Look at syslog:
|
||||
```
|
||||
|
|
|
|||
|
|
@ -69,11 +69,12 @@ notfound(FCGX_Request *r)
|
|||
path = FCGX_GetParam("DOCUMENT_URI", r->envp);
|
||||
FCGX_FPrintF(r->out, "Status: 404\r\n"); /* 404 not found */
|
||||
FCGX_FPrintF(r->out, "Content-Type: text/html\r\n\r\n");
|
||||
FCGX_FPrintF(r->out, "<h1>Clixon Not Found</h1>\n");
|
||||
FCGX_FPrintF(r->out, "<h1>Not Found</h1>\n");
|
||||
FCGX_FPrintF(r->out, "The requested URL %s was not found on this server.\n",
|
||||
path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
badrequest(FCGX_Request *r)
|
||||
{
|
||||
|
|
@ -89,6 +90,16 @@ badrequest(FCGX_Request *r)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
conflict(FCGX_Request *r)
|
||||
{
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
FCGX_FPrintF(r->out, "Status: 409\r\n"); /* 409 Conflict */
|
||||
FCGX_FPrintF(r->out, "Content-Type: text/html\r\n\r\n");
|
||||
FCGX_FPrintF(r->out, "<h1>Data resource already exists</h1>\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Specialization of clicon_debug with xml tree */
|
||||
int
|
||||
clicon_debug_xml(int dbglevel,
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@
|
|||
*/
|
||||
int notfound(FCGX_Request *r);
|
||||
int badrequest(FCGX_Request *r);
|
||||
int conflict(FCGX_Request *r);
|
||||
int clicon_debug_xml(int dbglevel, char *str, cxobj *cx);
|
||||
int test(FCGX_Request *r, int dbg);
|
||||
cbuf *readdata(FCGX_Request *r);
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ request_process(clicon_handle h,
|
|||
int auth = 0;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
path = FCGX_GetParam("DOCUMENT_URI", r->envp);
|
||||
path = FCGX_GetParam("REQUEST_URI", r->envp);
|
||||
query = FCGX_GetParam("QUERY_STRING", r->envp);
|
||||
if ((pvec = clicon_strsep(path, "/", &pn)) == NULL)
|
||||
goto done;
|
||||
|
|
@ -359,7 +359,7 @@ main(int argc,
|
|||
goto done;
|
||||
}
|
||||
clicon_debug(1, "------------");
|
||||
if ((path = FCGX_GetParam("DOCUMENT_URI", r->envp)) != NULL){
|
||||
if ((path = FCGX_GetParam("REQUEST_URI", r->envp)) != NULL){
|
||||
if (strncmp(path, RESTCONF_API_ROOT, strlen(RESTCONF_API_ROOT)) == 0 ||
|
||||
strncmp(path, RESTCONF_API_ROOT, strlen(RESTCONF_API_ROOT)-1) == 0)
|
||||
request_process(h, r);
|
||||
|
|
|
|||
|
|
@ -34,8 +34,7 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* See draft-ietf-netconf-restconf-13.txt [draft]
|
||||
* See draft-ietf-netconf-restconf-17.txt [draft]
|
||||
* See rfc8040
|
||||
|
||||
* sudo apt-get install libfcgi-dev
|
||||
* gcc -o fastcgi fastcgi.c -lfcgi
|
||||
|
|
@ -120,7 +119,7 @@ Mapping netconf error-tag -> status code
|
|||
#include "restconf_methods.h"
|
||||
|
||||
/*! REST OPTIONS method
|
||||
* According to restconf (Sec 3.5.1.1 in [draft])
|
||||
* According to restconf
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] r Fastcgi request handle
|
||||
* @code
|
||||
|
|
@ -227,7 +226,7 @@ api_data_head(clicon_handle h,
|
|||
}
|
||||
|
||||
/*! REST GET method
|
||||
* According to restconf (Sec 3.5.1.1 in [draft])
|
||||
* According to restconf
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] r Fastcgi request handle
|
||||
* @param[in] pcvec Vector of path ie DOCUMENT_URI element
|
||||
|
|
@ -259,77 +258,23 @@ api_data_get(clicon_handle h,
|
|||
return api_data_get_gen(h, r, pcvec, pi, qvec, 0);
|
||||
}
|
||||
|
||||
/*! Generic edit-config method: PUT/POST/PATCH
|
||||
*/
|
||||
static int
|
||||
api_data_edit(clicon_handle h,
|
||||
FCGX_Request *r,
|
||||
char *api_path,
|
||||
cvec *pcvec,
|
||||
int pi,
|
||||
cvec *qvec,
|
||||
char *data,
|
||||
enum operation_type operation)
|
||||
{
|
||||
int retval = -1;
|
||||
int i;
|
||||
cxobj *xdata = NULL;
|
||||
cbuf *cbx = NULL;
|
||||
cxobj *x;
|
||||
|
||||
clicon_debug(1, "%s api_path:\"%s\" json:\"%s\"",
|
||||
__FUNCTION__,
|
||||
api_path, data);
|
||||
for (i=0; i<pi; i++)
|
||||
api_path = index(api_path+1, '/');
|
||||
/* Parse input data as json into xml */
|
||||
if (json_parse_str(data, &xdata) < 0){
|
||||
clicon_debug(1, "%s json parse fail: %s", __FUNCTION__, data);
|
||||
goto done;
|
||||
}
|
||||
if ((cbx = cbuf_new()) == NULL)
|
||||
goto done;
|
||||
cprintf(cbx, "<config>");
|
||||
x = NULL;
|
||||
while ((x = xml_child_each(xdata, x, -1)) != NULL) {
|
||||
if (clicon_xml2cbuf(cbx, x, 0, 0) < 0)
|
||||
goto done;
|
||||
}
|
||||
cprintf(cbx, "</config>");
|
||||
clicon_debug(1, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path);
|
||||
if (clicon_rpc_edit_config(h, "candidate",
|
||||
operation,
|
||||
api_path,
|
||||
cbuf_get(cbx)) < 0){
|
||||
notfound(r);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (clicon_rpc_commit(h) < 0)
|
||||
goto done;
|
||||
FCGX_SetExitStatus(201, r->out); /* Created */
|
||||
FCGX_FPrintF(r->out, "Content-Type: text/plain\r\n");
|
||||
FCGX_FPrintF(r->out, "\r\n");
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
if (xdata)
|
||||
xml_free(xdata);
|
||||
if (cbx)
|
||||
cbuf_free(cbx);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*! REST POST method
|
||||
* @param[in] h CLIXON handle
|
||||
* @param[in] r Fastcgi request handle
|
||||
* @param[in] api_path According to restconf (Sec 3.5.1.1 in [draft])
|
||||
* @param[in] api_path According to restconf (Sec 3.5.3.1 in rfc8040)
|
||||
* @param[in] pcvec Vector of path ie DOCUMENT_URI element
|
||||
* @param[in] pi Offset, where to start pcvec
|
||||
* @param[in] qvec Vector of query string (QUERY_STRING)
|
||||
* @param[in] data Stream input data
|
||||
* @note We map post to edit-config create.
|
||||
POST:
|
||||
target resource type is datastore --> create a top-level resource
|
||||
target resource type is data resource --> create child resource
|
||||
|
||||
The message-body MUST contain exactly one instance of the
|
||||
expected data resource. The data model for the child tree is the
|
||||
subtree, as defined by YANG for the child resource.
|
||||
|
||||
If the POST method succeeds, a "201 Created" status-line is returned
|
||||
and there is no response message-body. A "Location" header
|
||||
identifying the child resource that was created MUST be present in
|
||||
|
|
@ -338,7 +283,6 @@ api_data_edit(clicon_handle h,
|
|||
If the data resource already exists, then the POST request MUST fail
|
||||
and a "409 Conflict" status-line MUST be returned.
|
||||
* Netconf: <edit-config> (nc:operation="create") | invoke an RPC operation * @example
|
||||
|
||||
*/
|
||||
int
|
||||
api_data_post(clicon_handle h,
|
||||
|
|
@ -349,13 +293,91 @@ api_data_post(clicon_handle h,
|
|||
cvec *qvec,
|
||||
char *data)
|
||||
{
|
||||
return api_data_edit(h, r, api_path, pcvec, pi, qvec, data, OP_CREATE);
|
||||
enum operation_type op = OP_CREATE;
|
||||
int retval = -1;
|
||||
int i;
|
||||
cxobj *xdata = NULL;
|
||||
cxobj *xtop = NULL; /* xpath root */
|
||||
cbuf *cbx = NULL;
|
||||
cxobj *xbot = NULL;
|
||||
cxobj *x;
|
||||
yang_node *y = NULL;
|
||||
yang_spec *yspec;
|
||||
cxobj *xa;
|
||||
|
||||
clicon_debug(1, "%s api_path:\"%s\" json:\"%s\"",
|
||||
__FUNCTION__,
|
||||
api_path, data);
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||
goto done;
|
||||
}
|
||||
for (i=0; i<pi; i++)
|
||||
api_path = index(api_path+1, '/');
|
||||
/* Create config top-of-tree */
|
||||
if ((xtop = xml_new("config", NULL)) == NULL)
|
||||
goto done;
|
||||
xbot = xtop;
|
||||
if (api_path && api_path2xml(api_path, yspec, xtop, &xbot, &y) < 0)
|
||||
goto done;
|
||||
/* Parse input data as json into xml */
|
||||
if (json_parse_str(data, &xdata) < 0){
|
||||
clicon_debug(1, "%s json parse fail: %s", __FUNCTION__, data);
|
||||
goto done;
|
||||
}
|
||||
/* Add xdata to xbot */
|
||||
x = NULL;
|
||||
while ((x = xml_child_each(xdata, x, CX_ELMNT)) != NULL) {
|
||||
if ((xa = xml_new("operation", x)) == NULL)
|
||||
goto done;
|
||||
xml_type_set(xa, CX_ATTR);
|
||||
if (xml_value_set(xa, xml_operation2str(op)) < 0)
|
||||
goto done;
|
||||
if (xml_addsub(xbot, x) < 0)
|
||||
goto done;
|
||||
}
|
||||
xdata = NULL;
|
||||
if ((cbx = cbuf_new()) == NULL)
|
||||
goto done;
|
||||
if (clicon_xml2cbuf(cbx, xtop, 0, 0) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s xml: %s",__FUNCTION__, cbuf_get(cbx));
|
||||
if (clicon_rpc_edit_config(h, "candidate",
|
||||
OP_NONE,
|
||||
cbuf_get(cbx)) < 0){
|
||||
// notfound(r); /* XXX */
|
||||
conflict(r);
|
||||
goto done;
|
||||
}
|
||||
if (clicon_rpc_validate(h, "candidate") < 0){
|
||||
if (clicon_rpc_discard_changes(h) < 0)
|
||||
goto done;
|
||||
badrequest(r);
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
if (clicon_rpc_commit(h) < 0)
|
||||
goto done;
|
||||
FCGX_SetExitStatus(201, r->out); /* Created */
|
||||
FCGX_FPrintF(r->out, "Content-Type: text/plain\r\n");
|
||||
// XXX api_path can be null FCGX_FPrintF(r->out, "Location: %s\r\n", api_path);
|
||||
FCGX_FPrintF(r->out, "\r\n");
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
if (xtop)
|
||||
xml_free(xtop);
|
||||
if (xdata)
|
||||
xml_free(xdata);
|
||||
if (cbx)
|
||||
cbuf_free(cbx);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Generic REST PUT method
|
||||
* @param[in] h CLIXON handle
|
||||
* @param[in] r Fastcgi request handle
|
||||
* @param[in] api_path According to restconf (Sec 3.5.1.1 in [draft])
|
||||
* @param[in] api_path According to restconf (Sec 3.5.3.1 in rfc8040)
|
||||
* @param[in] pcvec Vector of path ie DOCUMENT_URI element
|
||||
* @param[in] pi Offset, where to start pcvec
|
||||
* @param[in] qvec Vector of query string (QUERY_STRING)
|
||||
|
|
@ -379,14 +401,96 @@ api_data_put(clicon_handle h,
|
|||
cvec *qvec,
|
||||
char *data)
|
||||
{
|
||||
/* XXX: OP_CREATE? */
|
||||
return api_data_edit(h, r, api_path, pcvec, pi, qvec, data, OP_REPLACE);
|
||||
int retval = -1;
|
||||
enum operation_type op = OP_REPLACE;
|
||||
int i;
|
||||
cxobj *xdata = NULL;
|
||||
cbuf *cbx = NULL;
|
||||
cxobj *x;
|
||||
cxobj *xbot = NULL;
|
||||
cxobj *xtop;
|
||||
cxobj *xp;
|
||||
yang_node *y = NULL;
|
||||
yang_spec *yspec;
|
||||
cxobj *xa;
|
||||
|
||||
clicon_debug(1, "%s api_path:\"%s\" json:\"%s\"",
|
||||
__FUNCTION__,
|
||||
api_path, data);
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||
goto done;
|
||||
}
|
||||
for (i=0; i<pi; i++)
|
||||
api_path = index(api_path+1, '/');
|
||||
/* Create config top-of-tree */
|
||||
if ((xtop = xml_new("config", NULL)) == NULL)
|
||||
goto done;
|
||||
xbot = xtop;
|
||||
if (api_path && api_path2xml(api_path, yspec, xtop, &xbot, &y) < 0)
|
||||
goto done;
|
||||
/* Parse input data as json into xml */
|
||||
if (json_parse_str(data, &xdata) < 0){
|
||||
clicon_debug(1, "%s json parse fail: %s", __FUNCTION__, data);
|
||||
goto done;
|
||||
}
|
||||
if (xml_child_nr(xdata) != 1){
|
||||
badrequest(r);
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
x = xml_child_i(xdata,0);
|
||||
if ((xa = xml_new("operation", x)) == NULL)
|
||||
goto done;
|
||||
xml_type_set(xa, CX_ATTR);
|
||||
if (xml_value_set(xa, xml_operation2str(op)) < 0)
|
||||
goto done;
|
||||
/* Replace xbot with x */
|
||||
xp = xml_parent(xbot);
|
||||
xml_purge(xbot);
|
||||
if (xml_addsub(xp, x) < 0)
|
||||
goto done;
|
||||
if ((cbx = cbuf_new()) == NULL)
|
||||
goto done;
|
||||
if (clicon_xml2cbuf(cbx, xtop, 0, 0) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path);
|
||||
if (clicon_rpc_edit_config(h, "candidate",
|
||||
OP_NONE,
|
||||
cbuf_get(cbx)) < 0){
|
||||
notfound(r);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (clicon_rpc_validate(h, "candidate") < 0){
|
||||
if (clicon_rpc_discard_changes(h) < 0)
|
||||
goto done;
|
||||
badrequest(r);
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
if (clicon_rpc_commit(h) < 0)
|
||||
goto done;
|
||||
FCGX_SetExitStatus(201, r->out); /* Created */
|
||||
FCGX_FPrintF(r->out, "Content-Type: text/plain\r\n");
|
||||
FCGX_FPrintF(r->out, "\r\n");
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
if (xtop)
|
||||
xml_free(xtop);
|
||||
if (xdata)
|
||||
xml_free(xdata);
|
||||
if (cbx)
|
||||
cbuf_free(cbx);
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
/*! Generic REST PATCH method
|
||||
* @param[in] h CLIXON handle
|
||||
* @param[in] r Fastcgi request handle
|
||||
* @param[in] api_path According to restconf (Sec 3.5.1.1 in [draft])
|
||||
* @param[in] api_path According to restconf (Sec 3.5.3.1 in rfc8040)
|
||||
* @param[in] pcvec Vector of path ie DOCUMENT_URI element
|
||||
* @param[in] pi Offset, where to start pcvec
|
||||
* @param[in] qvec Vector of query string (QUERY_STRING)
|
||||
|
|
@ -402,13 +506,15 @@ api_data_patch(clicon_handle h,
|
|||
cvec *qvec,
|
||||
char *data)
|
||||
{
|
||||
return api_data_edit(h, r, api_path, pcvec, pi, qvec, data, OP_MERGE);
|
||||
badrequest(r);
|
||||
// return api_data_edit(h, r, api_path, pcvec, pi, qvec, data, OP_MERGE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Generic REST DELETE method
|
||||
* @param[in] h CLIXON handle
|
||||
* @param[in] r Fastcgi request handle
|
||||
* @param[in] api_path According to restconf (Sec 3.5.1.1 in [draft])
|
||||
* @param[in] api_path According to restconf (Sec 3.5.3.1 in rfc8040)
|
||||
* @param[in] pi Offset, where path starts
|
||||
* Example:
|
||||
* curl -X DELETE http://127.0.0.1/restconf/data/interfaces/interface=eth0
|
||||
|
|
@ -422,14 +528,39 @@ api_data_delete(clicon_handle h,
|
|||
{
|
||||
int retval = -1;
|
||||
int i;
|
||||
cxobj *xtop = NULL; /* xpath root */
|
||||
cxobj *xbot = NULL;
|
||||
cxobj *xa;
|
||||
cbuf *cbx = NULL;
|
||||
yang_node *y = NULL;
|
||||
yang_spec *yspec;
|
||||
enum operation_type op = OP_DELETE;
|
||||
|
||||
clicon_debug(1, "%s api_path:%s", __FUNCTION__, api_path);
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||
goto done;
|
||||
}
|
||||
for (i=0; i<pi; i++)
|
||||
api_path = index(api_path+1, '/');
|
||||
/* Create config top-of-tree */
|
||||
if ((xtop = xml_new("config", NULL)) == NULL)
|
||||
goto done;
|
||||
xbot = xtop;
|
||||
if (api_path && api_path2xml(api_path, yspec, xtop, &xbot, &y) < 0)
|
||||
goto done;
|
||||
if ((xa = xml_new("operation", xbot)) == NULL)
|
||||
goto done;
|
||||
xml_type_set(xa, CX_ATTR);
|
||||
if (xml_value_set(xa, xml_operation2str(op)) < 0)
|
||||
goto done;
|
||||
if ((cbx = cbuf_new()) == NULL)
|
||||
goto done;
|
||||
if (clicon_xml2cbuf(cbx, xtop, 0, 0) < 0)
|
||||
goto done;
|
||||
if (clicon_rpc_edit_config(h, "candidate",
|
||||
OP_DELETE,
|
||||
api_path,
|
||||
"<config/>") < 0){
|
||||
OP_NONE,
|
||||
cbuf_get(cbx)) < 0){
|
||||
notfound(r);
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -440,6 +571,10 @@ api_data_delete(clicon_handle h,
|
|||
FCGX_FPrintF(r->out, "\r\n");
|
||||
retval = 0;
|
||||
done:
|
||||
if (cbx)
|
||||
cbuf_free(cbx);
|
||||
if (xtop)
|
||||
xml_free(xtop);
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
return retval;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue