Added basic rfc8527 support
Added basic rfc8527 support, but without support for: * ds:operational * with-origin * clixon/test/test_rfc8527_*.sh The current level of rfc8527 support is intended to allow commit operations on the 'candidate' datastore without rewriting the 'startup' datastore.
This commit is contained in:
parent
a1f54d71ac
commit
cd45f277ef
9 changed files with 152 additions and 47 deletions
|
|
@ -56,6 +56,18 @@ enum restconf_media{
|
||||||
};
|
};
|
||||||
typedef enum restconf_media restconf_media;
|
typedef enum restconf_media restconf_media;
|
||||||
|
|
||||||
|
/* @See https://tools.ietf.org/html/rfc8342, ietf-datastores@2018-02-14.yang */
|
||||||
|
enum ietf_ds {
|
||||||
|
IETF_DS_NONE = 0,
|
||||||
|
IETF_DS_RUNNING,
|
||||||
|
IETF_DS_CANDIDATE,
|
||||||
|
IETF_DS_STARTUP,
|
||||||
|
IETF_DS_INTENDED,
|
||||||
|
IETF_DS_DYNAMIC,
|
||||||
|
IETF_DS_OPERATIONAL
|
||||||
|
};
|
||||||
|
typedef enum ietf_ds ietf_ds_t;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prototypes
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -230,6 +230,7 @@ match_list_keys(yang_stmt *y,
|
||||||
* PUT: If it does not, set op to create, otherwise replace
|
* PUT: If it does not, set op to create, otherwise replace
|
||||||
* PATCH: If it does not, fail, otherwise replace/merge
|
* PATCH: If it does not, fail, otherwise replace/merge
|
||||||
* @param[in] plain_patch fail if object does not exists AND merge (not replace)
|
* @param[in] plain_patch fail if object does not exists AND merge (not replace)
|
||||||
|
* @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
api_data_write(clicon_handle h,
|
api_data_write(clicon_handle h,
|
||||||
|
|
@ -242,7 +243,8 @@ api_data_write(clicon_handle h,
|
||||||
int pretty,
|
int pretty,
|
||||||
restconf_media media_in,
|
restconf_media media_in,
|
||||||
restconf_media media_out,
|
restconf_media media_out,
|
||||||
int plain_patch)
|
int plain_patch,
|
||||||
|
ietf_ds_t ds)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
enum operation_type op;
|
enum operation_type op;
|
||||||
|
|
@ -596,12 +598,12 @@ api_data_write(clicon_handle h,
|
||||||
NETCONF_BASE_NAMESPACE); /* bind nc to netconf namespace */
|
NETCONF_BASE_NAMESPACE); /* bind nc to netconf namespace */
|
||||||
cprintf(cbx, "<edit-config");
|
cprintf(cbx, "<edit-config");
|
||||||
/* RFC8040 Sec 1.4:
|
/* RFC8040 Sec 1.4:
|
||||||
* If the NETCONF server supports :startup, the RESTCONF server MUST
|
* If this is a "data" request and the NETCONF server supports :startup,
|
||||||
* automatically update the non-volatile startup configuration
|
* the RESTCONF server MUST automatically update the non-volatile startup
|
||||||
* datastore, after the "running" datastore has been altered as a
|
* configuration datastore, after the "running" datastore has been altered
|
||||||
* consequence of a RESTCONF edit operation.
|
* as a consequence of a RESTCONF edit operation.
|
||||||
*/
|
*/
|
||||||
if (if_feature(yspec, "ietf-netconf", "startup"))
|
if ((IETF_DS_NONE == ds) && if_feature(yspec, "ietf-netconf", "startup"))
|
||||||
cprintf(cbx, " copystartup=\"true\"");
|
cprintf(cbx, " copystartup=\"true\"");
|
||||||
cprintf(cbx, " autocommit=\"true\"");
|
cprintf(cbx, " autocommit=\"true\"");
|
||||||
cprintf(cbx, "><target><candidate /></target>");
|
cprintf(cbx, "><target><candidate /></target>");
|
||||||
|
|
@ -695,13 +697,14 @@ api_data_put(clicon_handle h,
|
||||||
cvec *qvec,
|
cvec *qvec,
|
||||||
char *data,
|
char *data,
|
||||||
int pretty,
|
int pretty,
|
||||||
restconf_media media_out)
|
restconf_media media_out,
|
||||||
|
ietf_ds_t ds)
|
||||||
{
|
{
|
||||||
restconf_media media_in;
|
restconf_media media_in;
|
||||||
|
|
||||||
media_in = restconf_content_type(h);
|
media_in = restconf_content_type(h);
|
||||||
return api_data_write(h, req, api_path0, pcvec, pi, qvec, data, pretty,
|
return api_data_write(h, req, api_path0, pcvec, pi, qvec, data, pretty,
|
||||||
media_in, media_out, 0);
|
media_in, media_out, 0, ds);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Generic REST PATCH method for plain patch
|
/*! Generic REST PATCH method for plain patch
|
||||||
|
|
@ -730,7 +733,8 @@ api_data_patch(clicon_handle h,
|
||||||
cvec *qvec,
|
cvec *qvec,
|
||||||
char *data,
|
char *data,
|
||||||
int pretty,
|
int pretty,
|
||||||
restconf_media media_out)
|
restconf_media media_out,
|
||||||
|
ietf_ds_t ds)
|
||||||
{
|
{
|
||||||
restconf_media media_in;
|
restconf_media media_in;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
@ -740,7 +744,7 @@ api_data_patch(clicon_handle h,
|
||||||
case YANG_DATA_XML:
|
case YANG_DATA_XML:
|
||||||
case YANG_DATA_JSON: /* plain patch */
|
case YANG_DATA_JSON: /* plain patch */
|
||||||
ret = api_data_write(h, req, api_path0, pcvec, pi, qvec, data, pretty,
|
ret = api_data_write(h, req, api_path0, pcvec, pi, qvec, data, pretty,
|
||||||
media_in, media_out, 1);
|
media_in, media_out, 1, ds);
|
||||||
break;
|
break;
|
||||||
case YANG_PATCH_XML:
|
case YANG_PATCH_XML:
|
||||||
case YANG_PATCH_JSON: /* RFC 8072 patch */
|
case YANG_PATCH_JSON: /* RFC 8072 patch */
|
||||||
|
|
@ -760,6 +764,7 @@ api_data_patch(clicon_handle h,
|
||||||
* @param[in] pi Offset, where path starts
|
* @param[in] pi Offset, where path starts
|
||||||
* @param[in] pretty Set to 1 for pretty-printed xml/json output
|
* @param[in] pretty Set to 1 for pretty-printed xml/json output
|
||||||
* @param[in] media_out Output media
|
* @param[in] media_out Output media
|
||||||
|
* @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource
|
||||||
* See RFC 8040 Sec 4.7
|
* See RFC 8040 Sec 4.7
|
||||||
* Example:
|
* Example:
|
||||||
* curl -X DELETE http://127.0.0.1/restconf/data/interfaces/interface=eth0
|
* curl -X DELETE http://127.0.0.1/restconf/data/interfaces/interface=eth0
|
||||||
|
|
@ -771,7 +776,8 @@ api_data_delete(clicon_handle h,
|
||||||
char *api_path,
|
char *api_path,
|
||||||
int pi,
|
int pi,
|
||||||
int pretty,
|
int pretty,
|
||||||
restconf_media media_out)
|
restconf_media media_out,
|
||||||
|
ietf_ds_t ds)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
int i;
|
int i;
|
||||||
|
|
@ -834,12 +840,12 @@ api_data_delete(clicon_handle h,
|
||||||
|
|
||||||
cprintf(cbx, "<edit-config");
|
cprintf(cbx, "<edit-config");
|
||||||
/* RFC8040 Sec 1.4:
|
/* RFC8040 Sec 1.4:
|
||||||
* If the NETCONF server supports :startup, the RESTCONF server MUST
|
* If this is a "data" request and the NETCONF server supports :startup,
|
||||||
* automatically update the non-volatile startup configuration
|
* the RESTCONF server MUST automatically update the non-volatile startup
|
||||||
* datastore, after the "running" datastore has been altered as a
|
* configuration datastore, after the "running" datastore has been altered
|
||||||
* consequence of a RESTCONF edit operation.
|
* as a consequence of a RESTCONF edit operation.
|
||||||
*/
|
*/
|
||||||
if (if_feature(yspec, "ietf-netconf", "startup"))
|
if ((IETF_DS_NONE == ds) && if_feature(yspec, "ietf-netconf", "startup"))
|
||||||
cprintf(cbx, " copystartup=\"true\"");
|
cprintf(cbx, " copystartup=\"true\"");
|
||||||
cprintf(cbx, " autocommit=\"true\"");
|
cprintf(cbx, " autocommit=\"true\"");
|
||||||
cprintf(cbx, "><target><candidate /></target>");
|
cprintf(cbx, "><target><candidate /></target>");
|
||||||
|
|
|
||||||
|
|
@ -46,14 +46,14 @@ int api_data_options(clicon_handle h, void *req);
|
||||||
int api_data_put(clicon_handle h, void *req, char *api_path,
|
int api_data_put(clicon_handle h, void *req, char *api_path,
|
||||||
cvec *pcvec, int pi,
|
cvec *pcvec, int pi,
|
||||||
cvec *qvec, char *data,
|
cvec *qvec, char *data,
|
||||||
int pretty, restconf_media media_out);
|
int pretty, restconf_media media_out, ietf_ds_t ds);
|
||||||
|
|
||||||
int api_data_patch(clicon_handle h, void *req, char *api_path,
|
int api_data_patch(clicon_handle h, void *req, char *api_path,
|
||||||
cvec *pcvec, int pi,
|
cvec *pcvec, int pi,
|
||||||
cvec *qvec, char *data, int pretty,
|
cvec *qvec, char *data, int pretty,
|
||||||
restconf_media media_out);
|
restconf_media media_out, ietf_ds_t ds);
|
||||||
|
|
||||||
int api_data_delete(clicon_handle h, void *req, char *api_path, int pi,
|
int api_data_delete(clicon_handle h, void *req, char *api_path, int pi,
|
||||||
int pretty, restconf_media media_out);
|
int pretty, restconf_media media_out, ietf_ds_t ds);
|
||||||
|
|
||||||
#endif /* _RESTCONF_METHODS_H_ */
|
#endif /* _RESTCONF_METHODS_H_ */
|
||||||
|
|
|
||||||
|
|
@ -363,7 +363,8 @@ api_data_head(clicon_handle h,
|
||||||
int pi,
|
int pi,
|
||||||
cvec *qvec,
|
cvec *qvec,
|
||||||
int pretty,
|
int pretty,
|
||||||
restconf_media media_out)
|
restconf_media media_out,
|
||||||
|
ietf_ds_t ds)
|
||||||
{
|
{
|
||||||
return api_data_get2(h, req, api_path, pcvec, pi, qvec, pretty, media_out, 1);
|
return api_data_get2(h, req, api_path, pcvec, pi, qvec, pretty, media_out, 1);
|
||||||
}
|
}
|
||||||
|
|
@ -402,7 +403,8 @@ api_data_get(clicon_handle h,
|
||||||
int pi,
|
int pi,
|
||||||
cvec *qvec,
|
cvec *qvec,
|
||||||
int pretty,
|
int pretty,
|
||||||
restconf_media media_out)
|
restconf_media media_out,
|
||||||
|
ietf_ds_t ds)
|
||||||
{
|
{
|
||||||
return api_data_get2(h, req, api_path, pcvec, pi, qvec, pretty, media_out, 0);
|
return api_data_get2(h, req, api_path, pcvec, pi, qvec, pretty, media_out, 0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,9 +42,9 @@
|
||||||
* Prototypes
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
int api_data_head(clicon_handle h, void *req, char *api_path, cvec *pcvec, int pi,
|
int api_data_head(clicon_handle h, void *req, char *api_path, cvec *pcvec, int pi,
|
||||||
cvec *qvec, int pretty, restconf_media media_out);
|
cvec *qvec, int pretty, restconf_media media_out, ietf_ds_t ds);
|
||||||
int api_data_get(clicon_handle h, void *req, char *api_path, cvec *pcvec, int pi,
|
int api_data_get(clicon_handle h, void *req, char *api_path, cvec *pcvec, int pi,
|
||||||
cvec *qvec, int pretty, restconf_media media_out);
|
cvec *qvec, int pretty, restconf_media media_out, ietf_ds_t ds);
|
||||||
int api_operations_get(clicon_handle h, void *req,
|
int api_operations_get(clicon_handle h, void *req,
|
||||||
char *api_path, int pi, cvec *qvec, char *data,
|
char *api_path, int pi, cvec *qvec, char *data,
|
||||||
int pretty, restconf_media media_out);
|
int pretty, restconf_media media_out);
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,8 @@ api_data_post(clicon_handle h,
|
||||||
cvec *qvec,
|
cvec *qvec,
|
||||||
char *data,
|
char *data,
|
||||||
int pretty,
|
int pretty,
|
||||||
restconf_media media_out)
|
restconf_media media_out,
|
||||||
|
ietf_ds_t ds)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
enum operation_type op = OP_CREATE;
|
enum operation_type op = OP_CREATE;
|
||||||
|
|
@ -377,12 +378,12 @@ api_data_post(clicon_handle h,
|
||||||
|
|
||||||
cprintf(cbx, "<edit-config");
|
cprintf(cbx, "<edit-config");
|
||||||
/* RFC8040 Sec 1.4:
|
/* RFC8040 Sec 1.4:
|
||||||
* If the NETCONF server supports :startup, the RESTCONF server MUST
|
* If this is a "data" request and the NETCONF server supports :startup,
|
||||||
* automatically update the non-volatile startup configuration
|
* the RESTCONF server MUST automatically update the non-volatile startup
|
||||||
* datastore, after the "running" datastore has been altered as a
|
* configuration datastore, after the "running" datastore has been altered
|
||||||
* consequence of a RESTCONF edit operation.
|
* as a consequence of a RESTCONF edit operation.
|
||||||
*/
|
*/
|
||||||
if (if_feature(yspec, "ietf-netconf", "startup"))
|
if ((IETF_DS_NONE == ds) && if_feature(yspec, "ietf-netconf", "startup"))
|
||||||
cprintf(cbx, " copystartup=\"true\"");
|
cprintf(cbx, " copystartup=\"true\"");
|
||||||
cprintf(cbx, " autocommit=\"true\"");
|
cprintf(cbx, " autocommit=\"true\"");
|
||||||
cprintf(cbx, "><target><candidate /></target>");
|
cprintf(cbx, "><target><candidate /></target>");
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@
|
||||||
int api_data_post(clicon_handle h, void *req, char *api_path,
|
int api_data_post(clicon_handle h, void *req, char *api_path,
|
||||||
int pi, cvec *qvec, char *data,
|
int pi, cvec *qvec, char *data,
|
||||||
int pretty,
|
int pretty,
|
||||||
restconf_media media_out);
|
restconf_media media_out, ietf_ds_t ds);
|
||||||
|
|
||||||
int api_operations_post(clicon_handle h, void *req, char *api_path,
|
int api_operations_post(clicon_handle h, void *req, char *api_path,
|
||||||
int pi, cvec *qvec, char *data,
|
int pi, cvec *qvec, char *data,
|
||||||
|
|
|
||||||
|
|
@ -153,7 +153,8 @@ api_root_restconf_exact(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (clixon_xml_parse_string("<restconf xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"><data/>"
|
if (clixon_xml_parse_string("<restconf xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"><data/>"
|
||||||
"<operations/><yang-library-version>2016-06-21</yang-library-version></restconf>",
|
"<operations/><yang-library-version>" IETF_YANG_LIBRARY_REVISION
|
||||||
|
"</yang-library-version></restconf>",
|
||||||
YB_MODULE, yspec, &xt, NULL) < 0)
|
YB_MODULE, yspec, &xt, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
|
@ -187,6 +188,24 @@ api_root_restconf_exact(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** A stub implementation of the operational state datastore. The full
|
||||||
|
* implementation is required by https://tools.ietf.org/html/rfc8527#section-3.1
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
api_operational_state(clicon_handle h,
|
||||||
|
void *req,
|
||||||
|
char *request_method,
|
||||||
|
int pretty,
|
||||||
|
restconf_media media_out)
|
||||||
|
|
||||||
|
{
|
||||||
|
clicon_debug(1, "%s request method:%s", __FUNCTION__, request_method);
|
||||||
|
|
||||||
|
/* We are not implementing this method at this time, 20201105 despite it
|
||||||
|
* being mandatory https://tools.ietf.org/html/rfc8527#section-3.1 */
|
||||||
|
return restconf_notimplemented(req);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* See https://tools.ietf.org/html/rfc7895
|
* See https://tools.ietf.org/html/rfc7895
|
||||||
*/
|
*/
|
||||||
|
|
@ -200,7 +219,6 @@ api_yang_library_version(clicon_handle h,
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *xt = NULL;
|
cxobj *xt = NULL;
|
||||||
cbuf *cb = NULL;
|
cbuf *cb = NULL;
|
||||||
char *ietf_yang_library_revision = "2016-06-21"; /* XXX */
|
|
||||||
|
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
if (restconf_reply_header(req, "Content-Type", "%s", restconf_media_int2str(media_out)) < 0)
|
if (restconf_reply_header(req, "Content-Type", "%s", restconf_media_int2str(media_out)) < 0)
|
||||||
|
|
@ -209,7 +227,7 @@ api_yang_library_version(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
if (clixon_xml_parse_va(YB_NONE, NULL, &xt, NULL,
|
if (clixon_xml_parse_va(YB_NONE, NULL, &xt, NULL,
|
||||||
"<yang-library-version>%s</yang-library-version>",
|
"<yang-library-version>%s</yang-library-version>",
|
||||||
ietf_yang_library_revision) < 0)
|
IETF_YANG_LIBRARY_REVISION) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (xml_rootchild(xt, 0, &xt) < 0)
|
if (xml_rootchild(xt, 0, &xt) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -250,6 +268,7 @@ api_yang_library_version(clicon_handle h,
|
||||||
* @param[in] pretty Set to 1 for pretty-printed xml/json output
|
* @param[in] pretty Set to 1 for pretty-printed xml/json output
|
||||||
* @param[in] media_in Input media
|
* @param[in] media_in Input media
|
||||||
* @param[in] media_out Output media
|
* @param[in] media_out Output media
|
||||||
|
* @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
api_data(clicon_handle h,
|
api_data(clicon_handle h,
|
||||||
|
|
@ -260,28 +279,58 @@ api_data(clicon_handle h,
|
||||||
cvec *qvec,
|
cvec *qvec,
|
||||||
char *data,
|
char *data,
|
||||||
int pretty,
|
int pretty,
|
||||||
restconf_media media_out)
|
restconf_media media_out,
|
||||||
|
ietf_ds_t ds)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
int read_only = 0, dynamic = 0;
|
||||||
char *request_method;
|
char *request_method;
|
||||||
|
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
request_method = restconf_param_get(h, "REQUEST_METHOD");
|
request_method = restconf_param_get(h, "REQUEST_METHOD");
|
||||||
clicon_debug(1, "%s method:%s", __FUNCTION__, request_method);
|
clicon_debug(1, "%s method:%s", __FUNCTION__, request_method);
|
||||||
|
|
||||||
|
/* https://tools.ietf.org/html/rfc8527#section-3.2 */
|
||||||
|
/* We assume that dynamic datastores are read only at this time 20201105 */
|
||||||
|
if (IETF_DS_DYNAMIC == ds)
|
||||||
|
dynamic = 1;
|
||||||
|
if ((IETF_DS_INTENDED == ds) || (IETF_DS_RUNNING == ds)
|
||||||
|
|| (IETF_DS_DYNAMIC == ds) || (IETF_DS_OPERATIONAL == ds)) {
|
||||||
|
read_only = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (strcmp(request_method, "OPTIONS")==0)
|
if (strcmp(request_method, "OPTIONS")==0)
|
||||||
retval = api_data_options(h, req);
|
retval = api_data_options(h, req);
|
||||||
else if (strcmp(request_method, "HEAD")==0)
|
else if (strcmp(request_method, "HEAD")==0) {
|
||||||
retval = api_data_head(h, req, api_path, pcvec, pi, qvec, pretty, media_out);
|
if (dynamic) {
|
||||||
else if (strcmp(request_method, "GET")==0)
|
retval = restconf_method_notallowed(req, "GET,POST");
|
||||||
retval = api_data_get(h, req, api_path, pcvec, pi, qvec, pretty, media_out);
|
}
|
||||||
else if (strcmp(request_method, "POST")==0)
|
retval = api_data_head(h, req, api_path, pcvec, pi, qvec, pretty, media_out, ds);
|
||||||
retval = api_data_post(h, req, api_path, pi, qvec, data, pretty, media_out);
|
}
|
||||||
else if (strcmp(request_method, "PUT")==0)
|
else if (strcmp(request_method, "GET")==0) {
|
||||||
retval = api_data_put(h, req, api_path, pcvec, pi, qvec, data, pretty, media_out);
|
retval = api_data_get(h, req, api_path, pcvec, pi, qvec, pretty, media_out, ds);
|
||||||
else if (strcmp(request_method, "PATCH")==0)
|
}
|
||||||
retval = api_data_patch(h, req, api_path, pcvec, pi, qvec, data, pretty, media_out);
|
else if (strcmp(request_method, "POST")==0) {
|
||||||
else if (strcmp(request_method, "DELETE")==0)
|
retval = api_data_post(h, req, api_path, pi, qvec, data, pretty, media_out, ds);
|
||||||
retval = api_data_delete(h, req, api_path, pi, pretty, media_out);
|
}
|
||||||
|
else if (strcmp(request_method, "PUT")==0) {
|
||||||
|
if (read_only) {
|
||||||
|
retval = restconf_method_notallowed(req, "GET,POST");
|
||||||
|
}
|
||||||
|
retval = api_data_put(h, req, api_path, pcvec, pi, qvec, data, pretty, media_out, ds);
|
||||||
|
}
|
||||||
|
else if (strcmp(request_method, "PATCH")==0) {
|
||||||
|
if (read_only) {
|
||||||
|
retval = restconf_method_notallowed(req, "GET,POST");
|
||||||
|
}
|
||||||
|
retval = api_data_patch(h, req, api_path, pcvec, pi, qvec, data, pretty, media_out, ds);
|
||||||
|
}
|
||||||
|
else if (strcmp(request_method, "DELETE")==0) {
|
||||||
|
if (read_only) {
|
||||||
|
retval = restconf_method_notallowed(req, "GET,POST");
|
||||||
|
}
|
||||||
|
retval = api_data_delete(h, req, api_path, pi, pretty, media_out, ds);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
retval = restconf_notfound(h, req);
|
retval = restconf_notfound(h, req);
|
||||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||||
|
|
@ -441,7 +490,41 @@ api_root_restconf(clicon_handle h,
|
||||||
}
|
}
|
||||||
else if (strcmp(api_resource, "data") == 0){ /* restconf, skip /api/data */
|
else if (strcmp(api_resource, "data") == 0){ /* restconf, skip /api/data */
|
||||||
if (api_data(h, req, path, pcvec, 2, qvec, indata,
|
if (api_data(h, req, path, pcvec, 2, qvec, indata,
|
||||||
pretty, media_out) < 0)
|
pretty, media_out, IETF_DS_NONE) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
else if (strcmp(api_resource, "ds") == 0) {
|
||||||
|
/* We should really be getting the supported datastore types from the
|
||||||
|
* application model, but at this time the datastore model of startup/
|
||||||
|
* running/cadidate is hardcoded into the clixon implementation. 20201104 */
|
||||||
|
ietf_ds_t ds = IETF_DS_NONE;
|
||||||
|
|
||||||
|
if (4 > pn) { /* Malformed request, no "ietf-datastores:<datastore>" component */
|
||||||
|
restconf_notfound(h, req);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assign ds; See https://tools.ietf.org/html/rfc8342#section-7 */
|
||||||
|
if (0 == strcmp(pvec[3], "ietf-datastores:running"))
|
||||||
|
ds = IETF_DS_RUNNING;
|
||||||
|
else if (0 == strcmp(pvec[3], "ietf-datastores:candidate"))
|
||||||
|
ds = IETF_DS_CANDIDATE;
|
||||||
|
else if (0 == strcmp(pvec[3], "ietf-datastores:startup"))
|
||||||
|
ds = IETF_DS_STARTUP;
|
||||||
|
else if (0 == strcmp(pvec[3], "ietf-datastores:operational")) {
|
||||||
|
/* See https://tools.ietf.org/html/rfc8527#section-3.1
|
||||||
|
* https://tools.ietf.org/html/rfc8342#section-5.3 */
|
||||||
|
if (0 > api_operational_state(h, req, request_method, pretty, media_out)) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
goto ok;
|
||||||
|
}
|
||||||
|
else { /* Malformed request, unsupported datastore type */
|
||||||
|
restconf_notfound(h, req);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
/* ds is assigned at this point */
|
||||||
|
if (0 > api_data(h, req, path, pcvec, 3, qvec, indata, pretty, media_out, ds))
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else if (strcmp(api_resource, "operations") == 0){ /* rpc */
|
else if (strcmp(api_resource, "operations") == 0){ /* rpc */
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@
|
||||||
* Constants
|
* Constants
|
||||||
*/
|
*/
|
||||||
#define RESTCONF_API "restconf"
|
#define RESTCONF_API "restconf"
|
||||||
|
#define IETF_YANG_LIBRARY_REVISION "2019-01-04"
|
||||||
|
|
||||||
/* RESTCONF enables deployments to specify where the RESTCONF API is
|
/* RESTCONF enables deployments to specify where the RESTCONF API is
|
||||||
located. The client discovers this by getting the "/.well-known/host-meta"
|
located. The client discovers this by getting the "/.well-known/host-meta"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue