From 8db716ca0762bd4868d534ed84a47183992d0243 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Sun, 15 Aug 2021 20:38:45 +0200 Subject: [PATCH] - Moved yang patch code to new files restconf_methods_patch.[ch] - Started modifying patch code to style guidelines - Made patch test independent of example - Added developers style guidelines --- CHANGELOG.md | 2 +- apps/restconf/Makefile.in | 1 + apps/restconf/restconf_err.c | 2 + apps/restconf/restconf_methods.c | 711 +---------- apps/restconf/restconf_methods.h | 7 +- apps/restconf/restconf_methods_patch.c | 783 ++++++++++++ apps/restconf/restconf_methods_patch.h | 50 + apps/restconf/restconf_methods_post.c | 2 + apps/restconf/restconf_root.c | 4 + doc/DEVELOP.md | 76 ++ test/example.sh | 234 ---- test/interfaces.sh | 1130 ----------------- ..._patch.sh => test_restconf_plain_patch.sh} | 2 + test/test_restconf_yang_patch.sh | 44 +- test/test_restconf_yang_patch_xml.sh | 4 +- 15 files changed, 954 insertions(+), 2098 deletions(-) create mode 100644 apps/restconf/restconf_methods_patch.c create mode 100644 apps/restconf/restconf_methods_patch.h delete mode 100755 test/example.sh delete mode 100755 test/interfaces.sh rename test/{test_restconf_patch.sh => test_restconf_plain_patch.sh} (99%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1215d15c..554fef62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,7 +35,7 @@ Expected: September, 2021 ### New features -* Restconf YANG PATCH according to RFC 8072 +* Restconf YANG PATCH according to RFC 8072 (Work in progress) * Experimental: enable by setting YANG_PATCH in include/clixon_custom.h * Thanks to Alan Yaniger for providing this patch diff --git a/apps/restconf/Makefile.in b/apps/restconf/Makefile.in index 290cc9db..93d4a8d9 100644 --- a/apps/restconf/Makefile.in +++ b/apps/restconf/Makefile.in @@ -97,6 +97,7 @@ APPSRC += restconf_err.c APPSRC += restconf_methods.c APPSRC += restconf_methods_post.c APPSRC += restconf_methods_get.c +APPSRC += restconf_methods_patch.c APPSRC += restconf_root.c APPSRC += restconf_main_$(with_restconf).c ifeq ($(with_restconf),native) diff --git a/apps/restconf/restconf_err.c b/apps/restconf/restconf_err.c index 1a7aaee3..d315a85a 100644 --- a/apps/restconf/restconf_err.c +++ b/apps/restconf/restconf_err.c @@ -265,6 +265,7 @@ api_return_err(clicon_handle h, goto done; switch (media){ case YANG_DATA_XML: + case YANG_PATCH_XML: clicon_debug(1, "%s code:%d", __FUNCTION__, code); if (pretty){ cprintf(cb, " \n"); @@ -280,6 +281,7 @@ api_return_err(clicon_handle h, } break; case YANG_DATA_JSON: + case YANG_PATCH_JSON: clicon_debug(1, "%s code:%d", __FUNCTION__, code); if (pretty){ cprintf(cb, "{\n\"ietf-restconf:errors\" : "); diff --git a/apps/restconf/restconf_methods.c b/apps/restconf/restconf_methods.c index fff0275c..df98c59d 100644 --- a/apps/restconf/restconf_methods.c +++ b/apps/restconf/restconf_methods.c @@ -65,8 +65,6 @@ /* cligen */ #include -// TODO - remove this include if cbuf_trunc() is added to cligen repo -#include "../cligen/cligen_buf_internal.h" /* clicon */ #include @@ -75,8 +73,9 @@ #include "restconf_handle.h" #include "restconf_api.h" #include "restconf_err.h" -#include "restconf_methods.h" #include "restconf_methods_post.h" +#include "restconf_methods_patch.h" +#include "restconf_methods.h" /*! REST OPTIONS method * According to restconf @@ -188,7 +187,7 @@ match_list_keys(yang_stmt *y, * @param[in] media_in Restconf input media * @param[in] media_out Restconf output media */ -static int +int api_data_write(clicon_handle h, void *req, char *api_path0, @@ -582,710 +581,6 @@ api_data_write(clicon_handle h, return retval; } /* api_data_write */ -#ifdef YANG_PATCH - -/*! Free memory after a NULL pointer check - * - * @param [in] str void pointer to memory to be freed - * - */ -static void yang_patch_free_mem(void *p) -{ - if (p != NULL) - free(p); -} - -/*! Return a value within XML tags - * @param [in] nsc namespace context - * @param [in] xn cxobj containing XML with the current edit - * @param [in] val cbuf to which the value will be written - * @param [in] key string containing the tag - * @retval 0 success - * @retval <0 failure - */ -static int yang_patch_get_xval( - cvec* nsc, - cxobj* xn, - cbuf* val, - const char* key - ) -{ - cxobj **vec = NULL; - size_t veclen = 0; - char* tmp_val = NULL; - int ret = xpath_vec(xn, nsc, "%s", &vec, &veclen, key); - if (ret < 0) { - return ret; - } - cxobj *xn_tmp = NULL; - if (veclen == 1) { //veclen should always be 1 - xn_tmp = vec[0]; - } - if (xn_tmp != NULL) { - tmp_val = xml_body(xn_tmp); - cbuf_append_str(val, tmp_val); - } - return 0; -} - -// TODO - add this to cligen repo if it is approved -/*! Truncate a cbuf - * - * @param [in] cb cligen buffer allocated by cbuf_new(), may be reallocated. - * @param [in] int pos position at which to truncate - * @retval new cbuf containing the truncated string (old buffer remains as it was) - * @retval NULL Error - */ -cbuf* -cbuf_trunc(cbuf *cb, - int pos) -{ - if (pos < 0 || pos > cb->cb_strlen){ - errno = EINVAL; - return NULL; - } - /* Ensure buffer is right size */ - cbuf* new_buf = cbuf_new_alloc(pos + 1); - if (new_buf == NULL) - return NULL; - strncpy(new_buf->cb_buffer, cb->cb_buffer, pos); - new_buf->cb_strlen = pos; - return new_buf; -} - -/*! Add square brackets after the surrounding curly brackets in JSON - * Needed, in order to modify the result of xml2json_cbuf() to be valid input - * to api_dta_post() and api_dta_write() - * @param [in] x_simple_patch a cxobj to pass to xml2json_cbuf() - * @retval new cbuf with the modified json - * @retval NULL Error - */ - -static cbuf* yang_patch_xml2json_modified_cbuf(cxobj* x_simple_patch) -{ - cbuf *json_simple_patch = cbuf_new(); - if (json_simple_patch == NULL) - return NULL; - cbuf* cb = cbuf_new(); - xml2json_cbuf(cb, x_simple_patch, 1); - - // Insert a '[' after the first '{' to get the JSON to match what api_data_post/write() expect - char *json_simple_patch_tmp = cbuf_get(cb); - int brace_count = 0; - for (int l = 0; l < strlen(json_simple_patch_tmp); l++) { - char c = json_simple_patch_tmp[l]; - if (c == '{') { - brace_count++; - if (brace_count == 2) { // We've reached the second brace, insert a '[' before it - cbuf_append(json_simple_patch,(int)'['); - } - } - cbuf_append(json_simple_patch,(int)c); - } - cbuf* json_simple_patch_2 = NULL; - - // Insert a ']' before the last '}' to get the JSON to match what api_data_post() expects - for (int l = cbuf_len(json_simple_patch) - 1; l >= 0; l--) { - char c = cbuf_get(json_simple_patch)[l]; - if (c == '}') { - // Truncate and add a string, as there is not a function to insert a char into a cbuf - json_simple_patch_2 = cbuf_trunc(json_simple_patch, l); - cbuf_append_str(json_simple_patch_2, "]}"); - break; - } - } - cbuf_free(json_simple_patch); - cbuf_free(cb); - return json_simple_patch_2; -} - -/*!yang_patch_strip_after_last_slash - * - * Strip /... from end of val - * so that e.g. "/interface=eth2" becomes "/" - * or "/interface_list=mylist/interface=eth2" becomes "/interface_list=mylist/" - * - * @param[in] val value to strip - * @retval new cbuf with the stripped string - * @retval NULL error - */ -static cbuf* yang_patch_strip_after_last_slash(cbuf* val) -{ - cbuf *cb = cbuf_new(); - cbuf* val_tmp = cbuf_new(); - cbuf_append_str(val_tmp, cbuf_get(val)); - int idx = cbuf_len(val_tmp); - for (int l = cbuf_len(val_tmp) - 1; l>= 0; l--) { - if (cbuf_get(val_tmp)[l] == '/') { - idx = l; - break; - } - } - if (idx == cbuf_len(val_tmp)) // Didn't find a slash in the loop above - return NULL; - cbuf* val_tmp_2 = cbuf_trunc(val_tmp, idx + 1); - if (cbuf_append_str(cb, cbuf_get(val_tmp_2)) < 0) - return NULL; - cbuf_free(val_tmp); - cbuf_free(val_tmp_2); - return cb; -} - -/*! YANG PATCH replace method - * @param[in] h Clixon handle - * @param[in] req Generic Www handle - * @param[in] pi Offset, where to start pcvec - * @param[in] qvec Vector of query string (QUERY_STRING) - * @param[in] pretty Set to 1 for pretty-printed xml/json output - * @param[in] media_out Output media - * @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource - * @param[in] simplepatch_request_uri URI for patch request, e.g. "/restconf/data/ietf-interfaces:interfaces" - * @param[in] target_val value in "target" field of edit in YANG patch - * @param[in] value_vec_len number of elements in the "value" array of an edit in YANG patch - * @param[in] value_vec pointer to the "value" array of an edit in YANG patch - * @param[in] x_simple_patch pointer to XML containing module name, e.g. - */ -static int yang_patch_do_replace ( - clicon_handle h, - void *req, - int pi, - cvec *qvec, - int pretty, - restconf_media media_out, - ietf_ds_t ds, - cbuf* simple_patch_request_uri, - cbuf* target_val, - int value_vec_len, - cxobj** value_vec, - cxobj *x_simple_patch - ) -{ - cxobj * value_vec_tmp = NULL; - cbuf* delete_req_uri = cbuf_new(); - if (delete_req_uri == NULL) - return 1; - - // Make delete_req_uri something like "/restconf/data/ietf-interfaces:interfaces" - if (cbuf_append_str(delete_req_uri, cbuf_get(simple_patch_request_uri)) < 0) - return 1; - - // Add the target to delete_req_uri, - // so it's something like "/restconf/data/ietf-interfaces:interfaces/interface=eth2" - if (cbuf_append_str(delete_req_uri, cbuf_get(target_val)) < 0) - return 1; - - // Delete the object with the old values - int ret = api_data_delete(h, req, cbuf_get(delete_req_uri), pi, pretty, YANG_DATA_JSON, ds ); - cbuf_free(delete_req_uri); - if (ret != 0) - return ret; - - // Now set up for the post request. - // Strip /... from end of target val - // so that e.g. "/interface=eth2" becomes "/" - // or "/interface_list=mylist/interface=eth2" becomes "/interface_list=mylist/" - cbuf* post_req_uri = yang_patch_strip_after_last_slash(target_val); - - // Make post_req_uri something like "/restconf/data/ietf-interfaces:interfaces" - if (cbuf_append_str(simple_patch_request_uri, cbuf_get(post_req_uri))) - return 1; - cbuf_free(post_req_uri); - - // Now insert the new values into the data - // (which will include the key value and all other mandatory values) - for (int k = 0; k < value_vec_len; k++) { - if (value_vec[k] != NULL) { - value_vec_tmp = xml_dup(value_vec[k]); - xml_addsub(x_simple_patch, value_vec_tmp); - } - } - // Convert the data to json - cbuf *json_simple_patch = cbuf_new(); - if (json_simple_patch == NULL) - return 1; - xml2json_cbuf(json_simple_patch, x_simple_patch, 1); - - // Send the POST request - ret = api_data_post(h, req, cbuf_get(simple_patch_request_uri), pi, qvec, cbuf_get(json_simple_patch), pretty, YANG_DATA_JSON, media_out, ds ); - - cbuf_free(json_simple_patch); - xml_free(value_vec_tmp); - return ret; -} - -/*! YANG PATCH create method - * @param[in] h Clixon handle - * @param[in] req Generic Www handle - * @param[in] pi Offset, where to start pcvec - * @param[in] qvec Vector of query string (QUERY_STRING) - * @param[in] pretty Set to 1 for pretty-printed xml/json output - * @param[in] media_out Output media - * @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource - * @param[in] simplepatch_request_uri URI for patch request, e.g. "/restconf/data/ietf-interfaces:interfaces" - * @param[in] value_vec_len number of elements in the "value" array of an edit in YANG patch - * @param[in] value_vec pointer to the "value" array of an edit in YANG patch - * @param[in] x_simple_patch pointer to XML containing module name, e.g. - */ -static int yang_patch_do_create ( - clicon_handle h, - void *req, - int pi, - cvec *qvec, - int pretty, - restconf_media media_out, - ietf_ds_t ds, - cbuf* simple_patch_request_uri, - int value_vec_len, - cxobj** value_vec, - cxobj *x_simple_patch - ) -{ - cxobj * value_vec_tmp = NULL; - for (int k = 0; k < value_vec_len; k++) { - if (value_vec[k] != NULL) { - value_vec_tmp = xml_dup(value_vec[k]); - xml_addsub(x_simple_patch, value_vec_tmp); - } - } - - // Send the POST request - cbuf* cb = cbuf_new(); - xml2json_cbuf(cb, x_simple_patch, 1); - char *json_simple_patch = cbuf_get(cb); - int ret = api_data_post(h, req, cbuf_get(simple_patch_request_uri), pi, qvec, json_simple_patch, pretty, YANG_DATA_JSON, media_out, ds ); - xml_free(value_vec_tmp); - return ret; -} - -/*! YANG PATCH insert method - * @param[in] h Clixon handle - * @param[in] req Generic Www handle - * @param[in] pi Offset, where to start pcvec - * @param[in] pretty Set to 1 for pretty-printed xml/json output - * @param[in] media_out Output media - * @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource - * @param[in] simple_patch_request_uri URI for patch request, e.g. "/restconf/data/ietf-interfaces:interfaces" - * @param[in] value_vec_len number of elements in the "value" array of an edit in YANG patch - * @param[in] value_vec pointer to the "value" array of an edit in YANG patch - * @param[in] x_simple_patch pointer to XML containing module name, e.g. - * @param[in] where_val value in "where" field of edit in YANG patch - * @param[in] api_path full API path, e.g. "/restconf/data/example-jukebox:jukebox/playlist=Foo-One" - * @param[in] point_val value in "point" field of edit in YANG patch - */ -static int yang_patch_do_insert ( - clicon_handle h, - void *req, - int pi, - int pretty, - restconf_media media_out, - ietf_ds_t ds, - cbuf* simple_patch_request_uri, - int value_vec_len, - cxobj** value_vec, - cxobj *x_simple_patch, - cbuf* where_val, - char* api_path, - cbuf *point_val - ) -{ - cxobj * value_vec_tmp = NULL; - - // Loop through the XML, and get each value - for (int k = 0; k < value_vec_len; k++) { - if (value_vec[k] != NULL) { - value_vec_tmp = xml_dup(value_vec[k]); - xml_addsub(x_simple_patch, value_vec_tmp); - } - } - cbuf *json_simple_patch = yang_patch_xml2json_modified_cbuf(x_simple_patch); - if (json_simple_patch == NULL) - return 1; - - // Set the insert attributes - cvec* qvec_tmp = NULL; - qvec_tmp = cvec_new(0); - if (qvec_tmp == NULL) - return 1; - cg_var *cv; - if ((cv = cvec_add(qvec_tmp, CGV_STRING)) == NULL){ - return 1; - } - cv_name_set(cv, "insert"); - cv_string_set(cv, cbuf_get(where_val)); - cbuf *point_str = cbuf_new(); - if (point_str == NULL) - return 1; - cbuf_append_str(point_str, api_path); - cbuf_append_str(point_str, cbuf_get(point_val)); - if ((cv = cvec_add(qvec_tmp, CGV_STRING)) == NULL){ - return 1; - } - cv_name_set(cv, "point"); - cv_string_set(cv, cbuf_get(point_str)); - - // Send the POST request - int ret = api_data_post(h, req, cbuf_get(simple_patch_request_uri), pi, qvec_tmp, cbuf_get(json_simple_patch), pretty, YANG_DATA_JSON, media_out, ds ); - xml_free(value_vec_tmp); - cbuf_free(point_str); - cbuf_free(json_simple_patch); - return ret; -} - -/*! YANG PATCH merge method - * @param[in] h Clixon handle - * @param[in] req Generic Www handle - * @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] pretty Set to 1 for pretty-printed xml/json output - * @param[in] media_out Output media - * @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource - * @param[in] simple_patch_request_uri URI for patch request, e.g. "/restconf/data/ietf-interfaces:interfaces" - * @param[in] value_vec_len number of elements in the "value" array of an edit in YANG patch - * @param[in] value_vec pointer to the "value" array of an edit in YANG patch - * @param[in] x_simple_patch pointer to XML containing module name, e.g. "" - * @param[in] where_val value in "where" field of edit in YANG patch - * @param[in] key_xn XML with key tag and value, e.g. "Foo-One" - */ -static int yang_patch_do_merge ( - clicon_handle h, - void *req, - cvec *pcvec, - int pi, - cvec *qvec, - int pretty, - restconf_media media_out, - ietf_ds_t ds, - cbuf* simple_patch_request_uri, - int value_vec_len, - cxobj** value_vec, - cxobj *x_simple_patch, - cxobj *key_xn - ) -{ - int ret = -1; - cxobj * value_vec_tmp = NULL; - if (key_xn != NULL) - xml_addsub(x_simple_patch, key_xn); - - // Loop through the XML, create JSON from each one, and submit a simple patch - for (int k = 0; k < value_vec_len; k++) { - if (value_vec[k] != NULL) { - value_vec_tmp = xml_dup(value_vec[k]); - xml_addsub(x_simple_patch, value_vec_tmp); - } - cbuf* cb = cbuf_new(); - xml2json_cbuf(cb, x_simple_patch, 1); - - cbuf *json_simple_patch = yang_patch_xml2json_modified_cbuf(x_simple_patch); - if (json_simple_patch == NULL) - return 1; - xml_free(value_vec_tmp); - // Send the simple patch request - ret = api_data_write(h, req, cbuf_get(simple_patch_request_uri), pcvec, pi, qvec, cbuf_get(json_simple_patch), pretty, YANG_DATA_JSON, media_out, 1, ds ); - cbuf_free(cb); - cbuf_free(json_simple_patch); - } - return ret; -} - -/*! YANG PATCH method - * @param[in] h Clixon handle - * @param[in] req Generic Www handle - * @param[in] api_path0 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 - * @param[in] pretty Set to 1 for pretty-printed xml/json output - * @param[in] media_out Output media - * Netconf: (nc:operation="merge") - * See RFC8072 - * YANG patch can be used to "create", "delete", "insert", "merge", "move", "replace", and/or - "remove" a resource within the target resource. - * Currently "move" not supported - */ -static int -api_data_yang_patch(clicon_handle h, - void *req, - char *api_path0, - cvec *pcvec, - int pi, - cvec *qvec, - char *data, - int pretty, - restconf_media media_out, - ietf_ds_t ds) -{ - int retval = -1; - int i; - cxobj *xdata0 = NULL; /* Original -d data struct (including top symbol) */ - cbuf *cbx = NULL; - cxobj *xtop = NULL; /* top of api-path */ - cxobj *xbot = NULL; /* bottom of api-path */ - yang_stmt *ybot = NULL; /* yang of xbot */ - cxobj *xbot_tmp = NULL; - yang_stmt *yspec; - char *api_path; - cxobj *xret = NULL; - cxobj *xretcom = NULL; /* return from commit */ - cxobj *xretdis = NULL; /* return from discard-changes */ - cxobj *xerr = NULL; /* malloced must be freed */ - int ret; - cvec *nsc = NULL; - yang_bind yb; - char *xpath = NULL; - cbuf *path_orig_1 = NULL; - - clicon_debug(1, "%s api_path:\"%s\"", __FUNCTION__, api_path0); - if ((yspec = clicon_dbspec_yang(h)) == NULL){ - clicon_err(OE_FATAL, 0, "No DB_SPEC"); - goto done; - } - api_path=api_path0; - /* strip /... from start */ - for (i=0; i +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* cligen */ +#include + +/* clicon */ +#include + +#include "restconf_lib.h" +#include "restconf_handle.h" +#include "restconf_api.h" +#include "restconf_err.h" +#include "restconf_methods.h" +#include "restconf_methods_post.h" +#include "restconf_methods_patch.h" + +#ifdef YANG_PATCH + +/*! Return a value within XML tags + * @param [in] nsc namespace context + * @param [in] xn cxobj containing XML with the current edit + * @param [in] val cbuf to which the value will be written + * @param [in] key string containing the tag + * @retval 0 success + * @retval <0 failure + */ +static int +yang_patch_get_xval(cvec *nsc, + cxobj *xn, + cbuf *val, + const char *key) +{ + cxobj **vec = NULL; + size_t veclen = 0; + char* tmp_val = NULL; + int ret; + cxobj *xn_tmp = NULL; + + if ((ret = xpath_vec(xn, nsc, "%s", &vec, &veclen, key)) < 0) + return ret; + if (veclen == 1){ //veclen should always be 1 + xn_tmp = vec[0]; + tmp_val = xml_body(xn_tmp); + cbuf_append_str(val, tmp_val); + } + return 0; +} + +/*! Add square brackets after the surrounding curly brackets in JSON + * Needed, in order to modify the result of xml2json_cbuf() to be valid input + * to api_data_post() and api_data_write() + * @param [in] x_simple_patch a cxobj to pass to xml2json_cbuf() + * @retval new cbuf with the modified json + * @retval NULL Error + */ +static cbuf* +yang_patch_xml2json_modified_cbuf(cxobj *x_simple_patch) +{ + cbuf *json_simple_patch = NULL; + cbuf *cb = NULL; + char *json_simple_patch_tmp; + int brace_count = 0; + + json_simple_patch = cbuf_new(); + if (json_simple_patch == NULL) + return NULL; + cb = cbuf_new(); + xml2json_cbuf(cb, x_simple_patch, 1); + + // Insert a '[' after the first '{' to get the JSON to match what api_data_post/write() expect + json_simple_patch_tmp = cbuf_get(cb); + for (int l = 0; l < strlen(json_simple_patch_tmp); l++) { + char c = json_simple_patch_tmp[l]; + if (c == '{') { + brace_count++; + if (brace_count == 2) { // We've reached the second brace, insert a '[' before it + cbuf_append(json_simple_patch,(int)'['); + } + } + cbuf_append(json_simple_patch,(int)c); + } + + // Insert a ']' before the last '}' to get the JSON to match what api_data_post() expects + for (int l = cbuf_len(json_simple_patch) - 1; l >= 0; l--) { + char c = cbuf_get(json_simple_patch)[l]; + if (c == '}') { + // Truncate and add a string, as there is not a function to insert a char into a cbuf + cbuf_trunc(json_simple_patch, l); + cbuf_append_str(json_simple_patch, "]}"); + break; + } + } + cbuf_free(cb); + return json_simple_patch; +} + +/*!yang_patch_strip_after_last_slash + * + * Strip /... from end of val + * so that e.g. "/interface=eth2" becomes "/" + * or "/interface_list=mylist/interface=eth2" becomes "/interface_list=mylist/" + * + * @param[in] val value to strip + * @retval new cbuf with the stripped string + * @retval NULL error + */ +static cbuf* +yang_patch_strip_after_last_slash(cbuf* val) +{ + cbuf *cb; + cbuf *val_tmp; + int idx; + + cb = cbuf_new(); + val_tmp = cbuf_new(); + cbuf_append_str(val_tmp, cbuf_get(val)); + idx = cbuf_len(val_tmp); + for (int l = cbuf_len(val_tmp) - 1; l>= 0; l--) { + if (cbuf_get(val_tmp)[l] == '/') { + idx = l; + break; + } + } + if (idx == cbuf_len(val_tmp)) // Didn't find a slash in the loop above + return NULL; + cbuf_trunc(val_tmp, idx + 1); + if (cbuf_append_str(cb, cbuf_get(val_tmp)) < 0) + return NULL; + cbuf_free(val_tmp); + return cb; +} + +/*! YANG PATCH replace method + * @param[in] h Clixon handle + * @param[in] req Generic Www handle + * @param[in] pi Offset, where to start pcvec + * @param[in] qvec Vector of query string (QUERY_STRING) + * @param[in] pretty Set to 1 for pretty-printed xml/json output + * @param[in] media_out Output media + * @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource + * @param[in] simplepatch_request_uri URI for patch request, e.g. "/restconf/data/ietf-interfaces:interfaces" + * @param[in] target_val value in "target" field of edit in YANG patch + * @param[in] value_vec_len number of elements in the "value" array of an edit in YANG patch + * @param[in] value_vec pointer to the "value" array of an edit in YANG patch + * @param[in] x_simple_patch pointer to XML containing module name, e.g. + */ +static int +yang_patch_do_replace (clicon_handle h, + void *req, + int pi, + cvec *qvec, + int pretty, + restconf_media media_out, + ietf_ds_t ds, + cbuf *simple_patch_request_uri, + cbuf *target_val, + int value_vec_len, + cxobj **value_vec, + cxobj *x_simple_patch + ) +{ + cxobj *value_vec_tmp = NULL; + cbuf *delete_req_uri = NULL; + int ret; + cbuf *post_req_uri = NULL; + cbuf *json_simple_patch = NULL; + + delete_req_uri = cbuf_new(); + if (delete_req_uri == NULL) + return 1; + + // Make delete_req_uri something like "/restconf/data/ietf-interfaces:interfaces" + if (cbuf_append_str(delete_req_uri, cbuf_get(simple_patch_request_uri)) < 0) + return 1; + + // Add the target to delete_req_uri, + // so it's something like "/restconf/data/ietf-interfaces:interfaces/interface=eth2" + if (cbuf_append_str(delete_req_uri, cbuf_get(target_val)) < 0) + return 1; + + // Delete the object with the old values + ret = api_data_delete(h, req, cbuf_get(delete_req_uri), pi, pretty, YANG_DATA_JSON, ds ); + cbuf_free(delete_req_uri); + if (ret != 0) + return ret; + + // Now set up for the post request. + // Strip /... from end of target val + // so that e.g. "/interface=eth2" becomes "/" + // or "/interface_list=mylist/interface=eth2" becomes "/interface_list=mylist/" + post_req_uri = yang_patch_strip_after_last_slash(target_val); + + // Make post_req_uri something like "/restconf/data/ietf-interfaces:interfaces" + if (cbuf_append_str(simple_patch_request_uri, cbuf_get(post_req_uri))) + return 1; + cbuf_free(post_req_uri); + + // Now insert the new values into the data + // (which will include the key value and all other mandatory values) + for (int k = 0; k < value_vec_len; k++) { + if (value_vec[k] != NULL) { + value_vec_tmp = xml_dup(value_vec[k]); + xml_addsub(x_simple_patch, value_vec_tmp); + } + } + // Convert the data to json + json_simple_patch = cbuf_new(); + if (json_simple_patch == NULL) + return 1; + xml2json_cbuf(json_simple_patch, x_simple_patch, 1); + + // Send the POST request + ret = api_data_post(h, req, cbuf_get(simple_patch_request_uri), pi, qvec, cbuf_get(json_simple_patch), pretty, YANG_DATA_JSON, media_out, ds ); + + cbuf_free(json_simple_patch); + xml_free(value_vec_tmp); + return ret; +} + +/*! YANG PATCH create method + * @param[in] h Clixon handle + * @param[in] req Generic Www handle + * @param[in] pi Offset, where to start pcvec + * @param[in] qvec Vector of query string (QUERY_STRING) + * @param[in] pretty Set to 1 for pretty-printed xml/json output + * @param[in] media_out Output media + * @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource + * @param[in] simplepatch_request_uri URI for patch request, e.g. "/restconf/data/ietf-interfaces:interfaces" + * @param[in] value_vec_len number of elements in the "value" array of an edit in YANG patch + * @param[in] value_vec pointer to the "value" array of an edit in YANG patch + * @param[in] x_simple_patch pointer to XML containing module name, e.g. + */ +static int +yang_patch_do_create (clicon_handle h, + void *req, + int pi, + cvec *qvec, + int pretty, + restconf_media media_out, + ietf_ds_t ds, + cbuf *simple_patch_request_uri, + int value_vec_len, + cxobj **value_vec, + cxobj *x_simple_patch + ) +{ + int retval = -1; + cxobj *value_vec_tmp = NULL; + cbuf *cb = NULL; + char *json_simple_patch; + + for (int k = 0; k < value_vec_len; k++) { + if (value_vec[k] != NULL) { + value_vec_tmp = xml_dup(value_vec[k]); + xml_addsub(x_simple_patch, value_vec_tmp); + } + } + // Send the POST request + if ((cb = cbuf_new()) == NULL){ + clicon_err(OE_UNIX, errno, "cbuf_new"); + goto done; + } + if (xml2json_cbuf(cb, x_simple_patch, 1) < 0) + goto done; + json_simple_patch = cbuf_get(cb); + if (api_data_post(h, req, cbuf_get(simple_patch_request_uri), + pi, qvec, + json_simple_patch, pretty, YANG_DATA_JSON, media_out, ds) < 0) + goto done; + xml_free(value_vec_tmp); + retval = 0; + done: + return retval; +} + +/*! YANG PATCH insert method + * @param[in] h Clixon handle + * @param[in] req Generic Www handle + * @param[in] pi Offset, where to start pcvec + * @param[in] pretty Set to 1 for pretty-printed xml/json output + * @param[in] media_out Output media + * @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource + * @param[in] simple_patch_request_uri URI for patch request, e.g. "/restconf/data/ietf-interfaces:interfaces" + * @param[in] value_vec_len number of elements in the "value" array of an edit in YANG patch + * @param[in] value_vec pointer to the "value" array of an edit in YANG patch + * @param[in] x_simple_patch pointer to XML containing module name, e.g. + * @param[in] where_val value in "where" field of edit in YANG patch + * @param[in] api_path full API path, e.g. "/restconf/data/example-jukebox:jukebox/playlist=Foo-One" + * @param[in] point_val value in "point" field of edit in YANG patch + */ +static int +yang_patch_do_insert (clicon_handle h, + void *req, + int pi, + int pretty, + restconf_media media_out, + ietf_ds_t ds, + cbuf *simple_patch_request_uri, + int value_vec_len, + cxobj **value_vec, + cxobj *x_simple_patch, + cbuf *where_val, + char *api_path, + cbuf *point_val + ) +{ + cxobj *value_vec_tmp = NULL; + cbuf *json_simple_patch; + cg_var *cv; + cbuf *point_str = NULL; + int ret; + + // Loop through the XML, and get each value + for (int k = 0; k < value_vec_len; k++) { + if (value_vec[k] != NULL) { + value_vec_tmp = xml_dup(value_vec[k]); + xml_addsub(x_simple_patch, value_vec_tmp); + } + } + json_simple_patch = yang_patch_xml2json_modified_cbuf(x_simple_patch); + if (json_simple_patch == NULL) + return 1; + + // Set the insert attributes + cvec* qvec_tmp = NULL; + qvec_tmp = cvec_new(0); + if (qvec_tmp == NULL) + return 1; + + if ((cv = cvec_add(qvec_tmp, CGV_STRING)) == NULL){ + return 1; + } + cv_name_set(cv, "insert"); + cv_string_set(cv, cbuf_get(where_val)); + point_str = cbuf_new(); + if (point_str == NULL) + return 1; + cbuf_append_str(point_str, api_path); + cbuf_append_str(point_str, cbuf_get(point_val)); + if ((cv = cvec_add(qvec_tmp, CGV_STRING)) == NULL){ + return 1; + } + cv_name_set(cv, "point"); + cv_string_set(cv, cbuf_get(point_str)); + + // Send the POST request + ret = api_data_post(h, req, cbuf_get(simple_patch_request_uri), pi, qvec_tmp, cbuf_get(json_simple_patch), pretty, YANG_DATA_JSON, media_out, ds ); + xml_free(value_vec_tmp); + cbuf_free(point_str); + cbuf_free(json_simple_patch); + return ret; +} + +/*! YANG PATCH merge method + * @param[in] h Clixon handle + * @param[in] req Generic Www handle + * @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] pretty Set to 1 for pretty-printed xml/json output + * @param[in] media_out Output media + * @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource + * @param[in] simple_patch_request_uri URI for patch request, e.g. "/restconf/data/ietf-interfaces:interfaces" + * @param[in] value_vec_len number of elements in the "value" array of an edit in YANG patch + * @param[in] value_vec pointer to the "value" array of an edit in YANG patch + * @param[in] x_simple_patch pointer to XML containing module name, e.g. "" + * @param[in] where_val value in "where" field of edit in YANG patch + * @param[in] key_xn XML with key tag and value, e.g. "Foo-One" + */ +static int +yang_patch_do_merge(clicon_handle h, + void *req, + cvec *pcvec, + int pi, + cvec *qvec, + int pretty, + restconf_media media_out, + ietf_ds_t ds, + cbuf* simple_patch_request_uri, + int value_vec_len, + cxobj** value_vec, + cxobj *x_simple_patch, + cxobj *key_xn + ) +{ + int ret = -1; + cxobj *value_vec_tmp = NULL; + cbuf *cb = NULL; + cbuf *json_simple_patch = NULL; + + if (key_xn != NULL) + xml_addsub(x_simple_patch, key_xn); + + // Loop through the XML, create JSON from each one, and submit a simple patch + for (int k = 0; k < value_vec_len; k++) { + if (value_vec[k] != NULL) { + value_vec_tmp = xml_dup(value_vec[k]); + xml_addsub(x_simple_patch, value_vec_tmp); + } + cb = cbuf_new(); + xml2json_cbuf(cb, x_simple_patch, 1); + + json_simple_patch = yang_patch_xml2json_modified_cbuf(x_simple_patch); + if (json_simple_patch == NULL) + return 1; + xml_free(value_vec_tmp); + // Send the simple patch request + ret = api_data_write(h, req, cbuf_get(simple_patch_request_uri), pcvec, pi, qvec, cbuf_get(json_simple_patch), pretty, YANG_DATA_JSON, media_out, 1, ds ); + cbuf_free(cb); + cbuf_free(json_simple_patch); + } + return ret; +} + +/*! YANG PATCH method + * @param[in] h Clixon handle + * @param[in] req Generic Www handle + * @param[in] api_path0 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 + * @param[in] pretty Set to 1 for pretty-printed xml/json output + * @param[in] media_out Output media + * Netconf: (nc:operation="merge") + * See RFC8072 + * YANG patch can be used to "create", "delete", "insert", "merge", "move", "replace", and/or + "remove" a resource within the target resource. + * Currently "move" not supported + */ +int +api_data_yang_patch(clicon_handle h, + void *req, + char *api_path0, + cvec *pcvec, + int pi, + cvec *qvec, + char *data, + int pretty, + restconf_media media_out, + ietf_ds_t ds) +{ + int retval = -1; + int i; + cxobj *xdata0 = NULL; /* Original -d data struct (including top symbol) */ + cbuf *cbx = NULL; + cxobj *xtop = NULL; /* top of api-path */ + cxobj *xbot = NULL; /* bottom of api-path */ + yang_stmt *ybot = NULL; /* yang of xbot */ + cxobj *xbot_tmp = NULL; + yang_stmt *yspec; + char *api_path; + cxobj *xret = NULL; + cxobj *xretcom = NULL; /* return from commit */ + cxobj *xretdis = NULL; /* return from discard-changes */ + cxobj *xerr = NULL; /* malloced must be freed */ + int ret; + cvec *nsc = NULL; + yang_bind yb; + char *xpath = NULL; + cbuf *path_orig_1 = NULL; + char yang_patch_path[] = "/ietf-yang-patch:yang-patch"; + int nrchildren0 = 0; + cxobj *x = NULL; + size_t veclen; + cxobj **vec = NULL; + + clicon_debug(1, "%s api_path:\"%s\"", __FUNCTION__, api_path0); + if ((yspec = clicon_dbspec_yang(h)) == NULL){ + clicon_err(OE_FATAL, 0, "No DB_SPEC"); + goto done; + } + api_path=api_path0; + /* strip /... from start */ + for (i=0; i $fexample -module clixon-example { - yang-version 1.1; - namespace "urn:example:clixon"; - prefix ex; - import ietf-interfaces { - /* is in yang/optional which means clixon must be installed using --opt-yang-installdir */ - prefix if; - } - import ietf-ip { - prefix ip; - } - import iana-if-type { - prefix ianaift; - } - import ietf-datastores { - prefix ds; - } - description - "Clixon example used as a part of the Clixon test suite. - It can be used as a basis for making new Clixon applications. - Note, may change without updating revision, just for testing current master. - "; - revision 2020-12-01 { - description "Added table/paramater/value as the primary data example"; - } - revision 2020-03-11 { - description "Added container around translation list. Released in Clixon 4.4.0"; - } - revision 2019-11-05 { - description "Augment interface. Released in Clixon 4.3.0"; - } - revision 2019-07-23 { - description "Extension e4. Released in Clixon 4.1.0"; - } - revision 2019-01-13 { - description "Released in Clixon 3.9"; - } - /* Example interface type for tests, local callbacks, etc */ - identity eth { - base if:interface-type; - } - identity loopback { - base if:interface-type; - } - /* Generic config data */ - container table{ - list parameter{ - key name; - leaf name{ - type string; - } - leaf value{ - type string; - } - leaf stat{ - description "Inline state data for example application"; - config false; - type int32; - } - } - } - /* State data (not config) for the example application*/ - container state { - config false; - description "state data for the example application (must be here for example get operation)"; - leaf-list op { - type string; - } - } - augment "/if:interfaces/if:interface" { - container my-status { - config false; - description "For testing augment+state"; - leaf int { - type int32; - } - leaf str { - type string; - } - } - } - /* yang extension implemented by the example backend code. */ - extension e4 { - description - "The first child of the ex:e4 (unknown) statement is inserted into - the module as a regular data statement. This means that 'uses bar;' - in the ex:e4 statement below is a valid data node"; - argument arg; - } - grouping bar { - leaf bar{ - type string; - } - } - ex:e4 arg1{ - uses bar; - } - /* Example notification as used in RFC 5277 and RFC 8040 */ - notification event { - description "Example notification event."; - leaf event-class { - type string; - description "Event class identifier."; - } - container reportingEntity { - description "Event specific information."; - leaf card { - type string; - description "Line card identifier."; - } - } - leaf severity { - type string; - description "Event severity description."; - } - } - rpc client-rpc { - description "Example local client-side RPC that is processed by the - the netconf/restconf and not sent to the backend. - This is a clixon implementation detail: some rpc:s - are better processed by the client for API or perf reasons"; - input { - leaf x { - type string; - } - } - output { - leaf x { - type string; - } - } - } - rpc empty { - description "Smallest possible RPC with no input or output sections"; - } - rpc optional { - description "Small RPC with optional input and output"; - input { - leaf x { - type string; - } - } - output { - leaf x { - type string; - } - } - } - rpc example { - description "Some example input/output for testing RFC7950 7.14. - RPC simply echoes the input for debugging."; - input { - leaf x { - description - "If a leaf in the input tree has a 'mandatory' statement with - the value 'true', the leaf MUST be present in an RPC invocation."; - type string; - mandatory true; - } - leaf y { - description - "If a leaf in the input tree has a 'mandatory' statement with the - value 'true', the leaf MUST be present in an RPC invocation."; - type string; - default "42"; - } - leaf-list z { - description - "If a leaf-list in the input tree has one or more default - values, the server MUST use these values (XXX not supported)"; - type string; - } - leaf w { - description - "If any node has a 'when' statement that would evaluate to - 'false',then this node MUST NOT be present in the input tree. - (XXX not supported)"; - type string; - } - list u0 { - description "list without key"; - leaf uk{ - type string; - } - } - list u1 { - description "list with key"; - key uk; - leaf uk{ - type string; - } - leaf val{ - type string; - } - } - } - output { - leaf x { - type string; - } - leaf y { - type string; - } - leaf z { - type string; - } - leaf w { - type string; - } - list u0 { - leaf uk{ - type string; - } - } - list u1 { - key uk; - leaf uk{ - type string; - } - leaf val{ - type string; - } - } - } - } -} -EOF2 - - diff --git a/test/interfaces.sh b/test/interfaces.sh deleted file mode 100755 index 107e2b99..00000000 --- a/test/interfaces.sh +++ /dev/null @@ -1,1130 +0,0 @@ -#!/usr/bin/env bash -# for rfc 8072 -# Assumes finterfaces is set to name of interfaces file - -cat < $finterfaces - -module ietf-interfaces { - yang-version 1.1; - namespace "urn:ietf:params:xml:ns:yang:ietf-interfaces"; - prefix if; - - import ietf-yang-types { - prefix yang; - } - - organization - "IETF NETMOD (Network Modeling) Working Group"; - - contact - "WG Web: - WG List: - - Editor: Martin Bjorklund - "; - - description - "This module contains a collection of YANG definitions for - managing network interfaces. - - Copyright (c) 2018 IETF Trust and the persons identified as - authors of the code. All rights reserved. - - Redistribution and use in source and binary forms, with or - without modification, is permitted pursuant to, and subject - to the license terms contained in, the Simplified BSD License - set forth in Section 4.c of the IETF Trust's Legal Provisions - Relating to IETF Documents - (https://trustee.ietf.org/license-info). - - This version of this YANG module is part of RFC 8343; see - the RFC itself for full legal notices."; - - revision 2018-02-20 { - description - "Updated to support NMDA."; - reference - "RFC 8343: A YANG Data Model for Interface Management"; - } - - revision 2014-05-08 { - description - "Initial revision."; - reference - "RFC 7223: A YANG Data Model for Interface Management"; - } - - /* - * Typedefs - */ - - typedef interface-ref { - type leafref { - path "/if:interfaces/if:interface/if:name"; - } - description - "This type is used by data models that need to reference - interfaces."; - } - - /* - * Identities - */ - - identity interface-type { - description - "Base identity from which specific interface types are - derived."; - } - - /* - * Features - */ - - feature arbitrary-names { - description - "This feature indicates that the device allows user-controlled - interfaces to be named arbitrarily."; - } - feature pre-provisioning { - description - "This feature indicates that the device supports - pre-provisioning of interface configuration, i.e., it is - possible to configure an interface whose physical interface - hardware is not present on the device."; - } - feature if-mib { - description - "This feature indicates that the device implements - the IF-MIB."; - reference - "RFC 2863: The Interfaces Group MIB"; - } - - /* - * Data nodes - */ - - container interfaces { - description - "Interface parameters."; - - list interface { - key "name"; - - description - "The list of interfaces on the device. - - The status of an interface is available in this list in the - operational state. If the configuration of a - system-controlled interface cannot be used by the system - (e.g., the interface hardware present does not match the - interface type), then the configuration is not applied to - the system-controlled interface shown in the operational - state. If the configuration of a user-controlled interface - cannot be used by the system, the configured interface is - not instantiated in the operational state. - - System-controlled interfaces created by the system are - always present in this list in the operational state, - whether or not they are configured."; - - leaf name { - type string; - description - "The name of the interface. - - A device MAY restrict the allowed values for this leaf, - possibly depending on the type of the interface. - For system-controlled interfaces, this leaf is the - device-specific name of the interface. - - If a client tries to create configuration for a - system-controlled interface that is not present in the - operational state, the server MAY reject the request if - the implementation does not support pre-provisioning of - interfaces or if the name refers to an interface that can - never exist in the system. A Network Configuration - Protocol (NETCONF) server MUST reply with an rpc-error - with the error-tag 'invalid-value' in this case. - - If the device supports pre-provisioning of interface - configuration, the 'pre-provisioning' feature is - advertised. - - If the device allows arbitrarily named user-controlled - interfaces, the 'arbitrary-names' feature is advertised. - - When a configured user-controlled interface is created by - the system, it is instantiated with the same name in the - operational state. - - A server implementation MAY map this leaf to the ifName - MIB object. Such an implementation needs to use some - mechanism to handle the differences in size and characters - allowed between this leaf and ifName. The definition of - such a mechanism is outside the scope of this document."; - reference - "RFC 2863: The Interfaces Group MIB - ifName"; - } - - leaf description { - type string; - description - "A textual description of the interface. - - A server implementation MAY map this leaf to the ifAlias - MIB object. Such an implementation needs to use some - mechanism to handle the differences in size and characters - allowed between this leaf and ifAlias. The definition of - such a mechanism is outside the scope of this document. - - Since ifAlias is defined to be stored in non-volatile - storage, the MIB implementation MUST map ifAlias to the - value of 'description' in the persistently stored - configuration."; - reference - "RFC 2863: The Interfaces Group MIB - ifAlias"; - } - - leaf type { - type identityref { - base interface-type; - } - mandatory true; - description - "The type of the interface. - - When an interface entry is created, a server MAY - initialize the type leaf with a valid value, e.g., if it - is possible to derive the type from the name of the - interface. - - If a client tries to set the type of an interface to a - value that can never be used by the system, e.g., if the - type is not supported or if the type does not match the - name of the interface, the server MUST reject the request. - A NETCONF server MUST reply with an rpc-error with the - error-tag 'invalid-value' in this case."; - reference - "RFC 2863: The Interfaces Group MIB - ifType"; - } - - leaf enabled { - type boolean; - default "true"; - description - "This leaf contains the configured, desired state of the - interface. - - Systems that implement the IF-MIB use the value of this - leaf in the intended configuration to set - IF-MIB.ifAdminStatus to 'up' or 'down' after an ifEntry - has been initialized, as described in RFC 2863. - - Changes in this leaf in the intended configuration are - reflected in ifAdminStatus."; - reference - "RFC 2863: The Interfaces Group MIB - ifAdminStatus"; - } - - leaf link-up-down-trap-enable { - if-feature if-mib; - type enumeration { - enum enabled { - value 1; - description - "The device will generate linkUp/linkDown SNMP - notifications for this interface."; - } - enum disabled { - value 2; - description - "The device will not generate linkUp/linkDown SNMP - notifications for this interface."; - } - } - description - "Controls whether linkUp/linkDown SNMP notifications - should be generated for this interface. - - If this node is not configured, the value 'enabled' is - operationally used by the server for interfaces that do - not operate on top of any other interface (i.e., there are - no 'lower-layer-if' entries), and 'disabled' otherwise."; - reference - "RFC 2863: The Interfaces Group MIB - - ifLinkUpDownTrapEnable"; - } - - leaf admin-status { - if-feature if-mib; - type enumeration { - enum up { - value 1; - description - "Ready to pass packets."; - } - enum down { - value 2; - description - "Not ready to pass packets and not in some test mode."; - } - enum testing { - value 3; - description - "In some test mode."; - } - } - config false; - mandatory true; - description - "The desired state of the interface. - - This leaf has the same read semantics as ifAdminStatus."; - reference - "RFC 2863: The Interfaces Group MIB - ifAdminStatus"; - } - - leaf oper-status { - type enumeration { - enum up { - value 1; - description - "Ready to pass packets."; - } - enum down { - value 2; - - description - "The interface does not pass any packets."; - } - enum testing { - value 3; - description - "In some test mode. No operational packets can - be passed."; - } - enum unknown { - value 4; - description - "Status cannot be determined for some reason."; - } - enum dormant { - value 5; - description - "Waiting for some external event."; - } - enum not-present { - value 6; - description - "Some component (typically hardware) is missing."; - } - enum lower-layer-down { - value 7; - description - "Down due to state of lower-layer interface(s)."; - } - } - config false; - mandatory true; - description - "The current operational state of the interface. - - This leaf has the same semantics as ifOperStatus."; - reference - "RFC 2863: The Interfaces Group MIB - ifOperStatus"; - } - - leaf last-change { - type yang:date-and-time; - config false; - description - "The time the interface entered its current operational - state. If the current state was entered prior to the - last re-initialization of the local network management - subsystem, then this node is not present."; - reference - "RFC 2863: The Interfaces Group MIB - ifLastChange"; - } - - leaf if-index { - if-feature if-mib; - type int32 { - range "1..2147483647"; - } - config false; - mandatory true; - description - "The ifIndex value for the ifEntry represented by this - interface."; - reference - "RFC 2863: The Interfaces Group MIB - ifIndex"; - } - - leaf phys-address { - type yang:phys-address; - config false; - description - "The interface's address at its protocol sub-layer. For - example, for an 802.x interface, this object normally - contains a Media Access Control (MAC) address. The - interface's media-specific modules must define the bit - and byte ordering and the format of the value of this - object. For interfaces that do not have such an address - (e.g., a serial line), this node is not present."; - reference - "RFC 2863: The Interfaces Group MIB - ifPhysAddress"; - } - - leaf-list higher-layer-if { - type interface-ref; - config false; - description - "A list of references to interfaces layered on top of this - interface."; - reference - "RFC 2863: The Interfaces Group MIB - ifStackTable"; - } - - leaf-list lower-layer-if { - type interface-ref; - config false; - - description - "A list of references to interfaces layered underneath this - interface."; - reference - "RFC 2863: The Interfaces Group MIB - ifStackTable"; - } - - leaf speed { - type yang:gauge64; - units "bits/second"; - config false; - description - "An estimate of the interface's current bandwidth in bits - per second. For interfaces that do not vary in - bandwidth or for those where no accurate estimation can - be made, this node should contain the nominal bandwidth. - For interfaces that have no concept of bandwidth, this - node is not present."; - reference - "RFC 2863: The Interfaces Group MIB - - ifSpeed, ifHighSpeed"; - } - - container statistics { - config false; - description - "A collection of interface-related statistics objects."; - - leaf discontinuity-time { - type yang:date-and-time; - mandatory true; - description - "The time on the most recent occasion at which any one or - more of this interface's counters suffered a - discontinuity. If no such discontinuities have occurred - since the last re-initialization of the local management - subsystem, then this node contains the time the local - management subsystem re-initialized itself."; - } - - leaf in-octets { - type yang:counter64; - description - "The total number of octets received on the interface, - including framing characters. - - Discontinuities in the value of this counter can occur - at re-initialization of the management system and at - other times as indicated by the value of - 'discontinuity-time'."; - reference - "RFC 2863: The Interfaces Group MIB - ifHCInOctets"; - } - - leaf in-unicast-pkts { - type yang:counter64; - description - "The number of packets, delivered by this sub-layer to a - higher (sub-)layer, that were not addressed to a - multicast or broadcast address at this sub-layer. - - Discontinuities in the value of this counter can occur - at re-initialization of the management system and at - other times as indicated by the value of - 'discontinuity-time'."; - reference - "RFC 2863: The Interfaces Group MIB - ifHCInUcastPkts"; - } - - leaf in-broadcast-pkts { - type yang:counter64; - description - "The number of packets, delivered by this sub-layer to a - higher (sub-)layer, that were addressed to a broadcast - address at this sub-layer. - - Discontinuities in the value of this counter can occur - at re-initialization of the management system and at - other times as indicated by the value of - 'discontinuity-time'."; - reference - "RFC 2863: The Interfaces Group MIB - - ifHCInBroadcastPkts"; - } - - leaf in-multicast-pkts { - type yang:counter64; - description - "The number of packets, delivered by this sub-layer to a - higher (sub-)layer, that were addressed to a multicast - address at this sub-layer. For a MAC-layer protocol, - this includes both Group and Functional addresses. - - Discontinuities in the value of this counter can occur - at re-initialization of the management system and at - other times as indicated by the value of - 'discontinuity-time'."; - reference - "RFC 2863: The Interfaces Group MIB - - ifHCInMulticastPkts"; - } - - leaf in-discards { - type yang:counter32; - description - "The number of inbound packets that were chosen to be - discarded even though no errors had been detected to - prevent their being deliverable to a higher-layer - protocol. One possible reason for discarding such a - packet could be to free up buffer space. - - Discontinuities in the value of this counter can occur - at re-initialization of the management system and at - other times as indicated by the value of - 'discontinuity-time'."; - reference - "RFC 2863: The Interfaces Group MIB - ifInDiscards"; - } - - leaf in-errors { - type yang:counter32; - description - "For packet-oriented interfaces, the number of inbound - packets that contained errors preventing them from being - deliverable to a higher-layer protocol. For character- - oriented or fixed-length interfaces, the number of - inbound transmission units that contained errors - preventing them from being deliverable to a higher-layer - protocol. - - Discontinuities in the value of this counter can occur - at re-initialization of the management system and at - other times as indicated by the value of - 'discontinuity-time'."; - reference - "RFC 2863: The Interfaces Group MIB - ifInErrors"; - } - - leaf in-unknown-protos { - type yang:counter32; - - description - "For packet-oriented interfaces, the number of packets - received via the interface that were discarded because - of an unknown or unsupported protocol. For - character-oriented or fixed-length interfaces that - support protocol multiplexing, the number of - transmission units received via the interface that were - discarded because of an unknown or unsupported protocol. - For any interface that does not support protocol - multiplexing, this counter is not present. - - Discontinuities in the value of this counter can occur - at re-initialization of the management system and at - other times as indicated by the value of - 'discontinuity-time'."; - reference - "RFC 2863: The Interfaces Group MIB - ifInUnknownProtos"; - } - - leaf out-octets { - type yang:counter64; - description - "The total number of octets transmitted out of the - interface, including framing characters. - - Discontinuities in the value of this counter can occur - at re-initialization of the management system and at - other times as indicated by the value of - 'discontinuity-time'."; - reference - "RFC 2863: The Interfaces Group MIB - ifHCOutOctets"; - } - - leaf out-unicast-pkts { - type yang:counter64; - description - "The total number of packets that higher-level protocols - requested be transmitted and that were not addressed - to a multicast or broadcast address at this sub-layer, - including those that were discarded or not sent. - - Discontinuities in the value of this counter can occur - at re-initialization of the management system and at - other times as indicated by the value of - 'discontinuity-time'."; - reference - "RFC 2863: The Interfaces Group MIB - ifHCOutUcastPkts"; - } - - leaf out-broadcast-pkts { - type yang:counter64; - description - "The total number of packets that higher-level protocols - requested be transmitted and that were addressed to a - broadcast address at this sub-layer, including those - that were discarded or not sent. - - Discontinuities in the value of this counter can occur - at re-initialization of the management system and at - other times as indicated by the value of - 'discontinuity-time'."; - reference - "RFC 2863: The Interfaces Group MIB - - ifHCOutBroadcastPkts"; - } - - leaf out-multicast-pkts { - type yang:counter64; - description - "The total number of packets that higher-level protocols - requested be transmitted and that were addressed to a - multicast address at this sub-layer, including those - that were discarded or not sent. For a MAC-layer - protocol, this includes both Group and Functional - addresses. - - Discontinuities in the value of this counter can occur - at re-initialization of the management system and at - other times as indicated by the value of - 'discontinuity-time'."; - reference - "RFC 2863: The Interfaces Group MIB - - ifHCOutMulticastPkts"; - } - - leaf out-discards { - type yang:counter32; - description - "The number of outbound packets that were chosen to be - discarded even though no errors had been detected to - prevent their being transmitted. One possible reason - for discarding such a packet could be to free up buffer - space. - - Discontinuities in the value of this counter can occur - at re-initialization of the management system and at - other times as indicated by the value of - 'discontinuity-time'."; - reference - "RFC 2863: The Interfaces Group MIB - ifOutDiscards"; - } - - leaf out-errors { - type yang:counter32; - description - "For packet-oriented interfaces, the number of outbound - packets that could not be transmitted because of errors. - For character-oriented or fixed-length interfaces, the - number of outbound transmission units that could not be - transmitted because of errors. - - Discontinuities in the value of this counter can occur - at re-initialization of the management system and at - other times as indicated by the value of - 'discontinuity-time'."; - reference - "RFC 2863: The Interfaces Group MIB - ifOutErrors"; - } - } - - } - } - - /* - * Legacy typedefs - */ - - typedef interface-state-ref { - type leafref { - path "/if:interfaces-state/if:interface/if:name"; - } - status deprecated; - description - "This type is used by data models that need to reference - the operationally present interfaces."; - } - - /* - * Legacy operational state data nodes - */ - - container interfaces-state { - config false; - status deprecated; - description - "Data nodes for the operational state of interfaces."; - - list interface { - key "name"; - status deprecated; - - description - "The list of interfaces on the device. - - System-controlled interfaces created by the system are - always present in this list, whether or not they are - configured."; - - leaf name { - type string; - status deprecated; - description - "The name of the interface. - - A server implementation MAY map this leaf to the ifName - MIB object. Such an implementation needs to use some - mechanism to handle the differences in size and characters - allowed between this leaf and ifName. The definition of - such a mechanism is outside the scope of this document."; - reference - "RFC 2863: The Interfaces Group MIB - ifName"; - } - - leaf type { - type identityref { - base interface-type; - } - mandatory true; - status deprecated; - description - "The type of the interface."; - reference - "RFC 2863: The Interfaces Group MIB - ifType"; - } - - leaf admin-status { - if-feature if-mib; - type enumeration { - enum up { - value 1; - description - "Ready to pass packets."; - } - enum down { - value 2; - description - "Not ready to pass packets and not in some test mode."; - } - enum testing { - value 3; - description - "In some test mode."; - } - } - mandatory true; - status deprecated; - description - "The desired state of the interface. - - This leaf has the same read semantics as ifAdminStatus."; - reference - "RFC 2863: The Interfaces Group MIB - ifAdminStatus"; - } - - leaf oper-status { - type enumeration { - enum up { - value 1; - description - "Ready to pass packets."; - } - enum down { - value 2; - description - "The interface does not pass any packets."; - } - enum testing { - value 3; - description - "In some test mode. No operational packets can - be passed."; - } - enum unknown { - value 4; - description - "Status cannot be determined for some reason."; - } - enum dormant { - value 5; - description - "Waiting for some external event."; - } - enum not-present { - value 6; - description - "Some component (typically hardware) is missing."; - } - enum lower-layer-down { - value 7; - description - "Down due to state of lower-layer interface(s)."; - } - } - mandatory true; - status deprecated; - description - "The current operational state of the interface. - - This leaf has the same semantics as ifOperStatus."; - reference - "RFC 2863: The Interfaces Group MIB - ifOperStatus"; - } - - leaf last-change { - type yang:date-and-time; - status deprecated; - description - "The time the interface entered its current operational - state. If the current state was entered prior to the - last re-initialization of the local network management - subsystem, then this node is not present."; - reference - "RFC 2863: The Interfaces Group MIB - ifLastChange"; - } - - leaf if-index { - if-feature if-mib; - type int32 { - range "1..2147483647"; - } - mandatory true; - status deprecated; - description - "The ifIndex value for the ifEntry represented by this - interface."; - - reference - "RFC 2863: The Interfaces Group MIB - ifIndex"; - } - - leaf phys-address { - type yang:phys-address; - status deprecated; - description - "The interface's address at its protocol sub-layer. For - example, for an 802.x interface, this object normally - contains a Media Access Control (MAC) address. The - interface's media-specific modules must define the bit - and byte ordering and the format of the value of this - object. For interfaces that do not have such an address - (e.g., a serial line), this node is not present."; - reference - "RFC 2863: The Interfaces Group MIB - ifPhysAddress"; - } - - leaf-list higher-layer-if { - type interface-state-ref; - status deprecated; - description - "A list of references to interfaces layered on top of this - interface."; - reference - "RFC 2863: The Interfaces Group MIB - ifStackTable"; - } - - leaf-list lower-layer-if { - type interface-state-ref; - status deprecated; - description - "A list of references to interfaces layered underneath this - interface."; - reference - "RFC 2863: The Interfaces Group MIB - ifStackTable"; - } - - leaf speed { - type yang:gauge64; - units "bits/second"; - status deprecated; - description - "An estimate of the interface's current bandwidth in bits - per second. For interfaces that do not vary in - bandwidth or for those where no accurate estimation can - - be made, this node should contain the nominal bandwidth. - For interfaces that have no concept of bandwidth, this - node is not present."; - reference - "RFC 2863: The Interfaces Group MIB - - ifSpeed, ifHighSpeed"; - } - - container statistics { - status deprecated; - description - "A collection of interface-related statistics objects."; - - leaf discontinuity-time { - type yang:date-and-time; - mandatory true; - status deprecated; - description - "The time on the most recent occasion at which any one or - more of this interface's counters suffered a - discontinuity. If no such discontinuities have occurred - since the last re-initialization of the local management - subsystem, then this node contains the time the local - management subsystem re-initialized itself."; - } - - leaf in-octets { - type yang:counter64; - status deprecated; - description - "The total number of octets received on the interface, - including framing characters. - - Discontinuities in the value of this counter can occur - at re-initialization of the management system and at - other times as indicated by the value of - 'discontinuity-time'."; - reference - "RFC 2863: The Interfaces Group MIB - ifHCInOctets"; - } - - leaf in-unicast-pkts { - type yang:counter64; - status deprecated; - description - "The number of packets, delivered by this sub-layer to a - higher (sub-)layer, that were not addressed to a - multicast or broadcast address at this sub-layer. - Discontinuities in the value of this counter can occur - at re-initialization of the management system and at - other times as indicated by the value of - 'discontinuity-time'."; - reference - "RFC 2863: The Interfaces Group MIB - ifHCInUcastPkts"; - } - - leaf in-broadcast-pkts { - type yang:counter64; - status deprecated; - description - "The number of packets, delivered by this sub-layer to a - higher (sub-)layer, that were addressed to a broadcast - address at this sub-layer. - - Discontinuities in the value of this counter can occur - at re-initialization of the management system and at - other times as indicated by the value of - 'discontinuity-time'."; - reference - "RFC 2863: The Interfaces Group MIB - - ifHCInBroadcastPkts"; - } - - leaf in-multicast-pkts { - type yang:counter64; - status deprecated; - description - "The number of packets, delivered by this sub-layer to a - higher (sub-)layer, that were addressed to a multicast - address at this sub-layer. For a MAC-layer protocol, - this includes both Group and Functional addresses. - - Discontinuities in the value of this counter can occur - at re-initialization of the management system and at - other times as indicated by the value of - 'discontinuity-time'."; - reference - "RFC 2863: The Interfaces Group MIB - - ifHCInMulticastPkts"; - } - - leaf in-discards { - type yang:counter32; - status deprecated; - - description - "The number of inbound packets that were chosen to be - discarded even though no errors had been detected to - prevent their being deliverable to a higher-layer - protocol. One possible reason for discarding such a - packet could be to free up buffer space. - - Discontinuities in the value of this counter can occur - at re-initialization of the management system and at - other times as indicated by the value of - 'discontinuity-time'."; - reference - "RFC 2863: The Interfaces Group MIB - ifInDiscards"; - } - - leaf in-errors { - type yang:counter32; - status deprecated; - description - "For packet-oriented interfaces, the number of inbound - packets that contained errors preventing them from being - deliverable to a higher-layer protocol. For character- - oriented or fixed-length interfaces, the number of - inbound transmission units that contained errors - preventing them from being deliverable to a higher-layer - protocol. - - Discontinuities in the value of this counter can occur - at re-initialization of the management system and at - other times as indicated by the value of - 'discontinuity-time'."; - reference - "RFC 2863: The Interfaces Group MIB - ifInErrors"; - } - - leaf in-unknown-protos { - type yang:counter32; - status deprecated; - description - "For packet-oriented interfaces, the number of packets - received via the interface that were discarded because - of an unknown or unsupported protocol. For - character-oriented or fixed-length interfaces that - support protocol multiplexing, the number of - transmission units received via the interface that were - discarded because of an unknown or unsupported protocol. - For any interface that does not support protocol - multiplexing, this counter is not present. - Discontinuities in the value of this counter can occur - at re-initialization of the management system and at - other times as indicated by the value of - 'discontinuity-time'."; - reference - "RFC 2863: The Interfaces Group MIB - ifInUnknownProtos"; - } - - leaf out-octets { - type yang:counter64; - status deprecated; - description - "The total number of octets transmitted out of the - interface, including framing characters. - - Discontinuities in the value of this counter can occur - at re-initialization of the management system and at - other times as indicated by the value of - 'discontinuity-time'."; - reference - "RFC 2863: The Interfaces Group MIB - ifHCOutOctets"; - } - - leaf out-unicast-pkts { - type yang:counter64; - status deprecated; - description - "The total number of packets that higher-level protocols - requested be transmitted and that were not addressed - to a multicast or broadcast address at this sub-layer, - including those that were discarded or not sent. - - Discontinuities in the value of this counter can occur - at re-initialization of the management system and at - other times as indicated by the value of - 'discontinuity-time'."; - reference - "RFC 2863: The Interfaces Group MIB - ifHCOutUcastPkts"; - } - - leaf out-broadcast-pkts { - type yang:counter64; - status deprecated; - - description - "The total number of packets that higher-level protocols - requested be transmitted and that were addressed to a - broadcast address at this sub-layer, including those - that were discarded or not sent. - - Discontinuities in the value of this counter can occur - at re-initialization of the management system and at - other times as indicated by the value of - 'discontinuity-time'."; - reference - "RFC 2863: The Interfaces Group MIB - - ifHCOutBroadcastPkts"; - } - - leaf out-multicast-pkts { - type yang:counter64; - status deprecated; - description - "The total number of packets that higher-level protocols - requested be transmitted and that were addressed to a - multicast address at this sub-layer, including those - that were discarded or not sent. For a MAC-layer - protocol, this includes both Group and Functional - addresses. - - Discontinuities in the value of this counter can occur - at re-initialization of the management system and at - other times as indicated by the value of - 'discontinuity-time'."; - reference - "RFC 2863: The Interfaces Group MIB - - ifHCOutMulticastPkts"; - } - - leaf out-discards { - type yang:counter32; - status deprecated; - description - "The number of outbound packets that were chosen to be - discarded even though no errors had been detected to - prevent their being transmitted. One possible reason - for discarding such a packet could be to free up buffer - space. - - Discontinuities in the value of this counter can occur - at re-initialization of the management system and at - other times as indicated by the value of - 'discontinuity-time'."; - reference - "RFC 2863: The Interfaces Group MIB - ifOutDiscards"; - } - - leaf out-errors { - type yang:counter32; - status deprecated; - description - "For packet-oriented interfaces, the number of outbound - packets that could not be transmitted because of errors. - For character-oriented or fixed-length interfaces, the - number of outbound transmission units that could not be - transmitted because of errors. - - Discontinuities in the value of this counter can occur - at re-initialization of the management system and at - other times as indicated by the value of - 'discontinuity-time'."; - reference - "RFC 2863: The Interfaces Group MIB - ifOutErrors"; - } - } - } - } -} -EOF2 diff --git a/test/test_restconf_patch.sh b/test/test_restconf_plain_patch.sh similarity index 99% rename from test/test_restconf_patch.sh rename to test/test_restconf_plain_patch.sh index 02cf7c88..6811b282 100755 --- a/test/test_restconf_patch.sh +++ b/test/test_restconf_plain_patch.sh @@ -218,8 +218,10 @@ expectpart "$(curl -u andy:bar $CURLOPTS -X PATCH -H 'Content-Type: application/ new "Check content (xml)" expectpart "$(curl -u andy:bar $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/example-jukebox:jukebox -H 'Accept: application/yang-data+xml')" 0 "HTTP/$HVER 200" 'ClashLondon Callingjazz1979' +if false; then # It is being implemented new "not implemented media type" expectpart "$(curl -u andy:bar $CURLOPTS -X PATCH -H 'Content-Type: application/yang-patch+xml' $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/library/artist=Clash/album=London%20Calling -d 'London Callingjazz')" 0 "HTTP/$HVER 501" +fi new "wrong media type" expectpart "$(curl -u andy:bar $CURLOPTS -X PATCH -H 'Content-Type: text/html' $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/library/artist=Clash/album=London%20Calling -d 'London Callingjazz')" 0 "HTTP/$HVER 415" diff --git a/test/test_restconf_yang_patch.sh b/test/test_restconf_yang_patch.sh index d472e6ee..79148d62 100755 --- a/test/test_restconf_yang_patch.sh +++ b/test/test_restconf_yang_patch.sh @@ -7,8 +7,9 @@ # Magic line must be first in script (see README.md) s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi -#echo "...skipped: YANG_PATCH JSON NYI" -#if [ "$s" = $0 ]; then exit 0; else return 0; fi +# Enable if YANG_PATCH +echo "...skipped: YANG_PATCH JSON NYI" +if [ "$s" = $0 ]; then exit 0; else return 0; fi APPNAME=example @@ -16,8 +17,6 @@ cfg=$dir/conf.xml startupdb=$dir/startup_db fjukebox=$dir/example-jukebox.yang fyangpatch=$dir/ietf-yang-patch.yang -finterfaces=$dir/ietf-interfaces.yang -fexample=$dir/clixon-example.yang # Define default restconfig config: RESTCONFIG RESTCONFIG=$(restconf_config user false) @@ -91,6 +90,13 @@ cat < $dir/example-system.yang module example-system { namespace "http://example.com/ns/example-system"; prefix "ex"; + import iana-if-type { + prefix ianaift; + } + import ietf-interfaces { + /* is in yang/optional which means clixon must be installed using --opt-yang-installdir */ + prefix if; + } import ietf-netconf-acm { prefix nacm; } @@ -108,12 +114,6 @@ EOF # Yang Patch spec (fyangpatch must be set) . ./yang-patch.sh -# Interfaces spec (finterfaces must be set) -. ./interfaces.sh - -# clixon example spec (fexample must be set) -. ./example.sh - # Common Jukebox spec (fjukebox must be set) . ./jukebox.sh @@ -157,7 +157,7 @@ REQ='{ "interface": [ { "name": "eth1", - "type": "clixon-example:eth", + "type": "iana-if-type:atm", "enabled": "false" } ] @@ -171,7 +171,7 @@ REQ='{ "interface": [ { "name": "eth2", - "type": "clixon-example:eth", + "type": "iana-if-type:atm", "enabled": "false" } ] @@ -185,7 +185,7 @@ REQ='{ "interface": [ { "name": "eth4", - "type": "clixon-example:eth", + "type": "iana-if-type:atm", "enabled": "false" } ] @@ -212,22 +212,22 @@ REQ='{ } }' new "RFC 8072 YANG Patch JSON: Error." -expectpart "$(curl -u andy:bar $CURLOPTS -X PATCH -H 'Content-Type: application/yang-patch+json' -H 'Accept: application/yang-patch+json' $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces -d "$REQ")" 0 "HTTP/$HVER 204 No Content" +expectpart "$(curl -u andy:bar $CURLOPTS -X PATCH -H 'Content-Type: application/yang-patch+json' -H 'Accept: application/yang-patch+json' $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces -d "$REQ")" 0 "HTTP/$HVER 204" # # Create artist in jukebox example REQ='{"example-jukebox:artist":[{"name":"Foo Fighters"}]}' new "RFC 8072 YANG Patch JSON jukebox example 1: Error." -expectpart "$(curl -u andy:bar $CURLOPTS -X POST -H 'Content-Type: application/yang-data+json' $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/library -d "$REQ")" 0 "HTTP/$HVER 201 Created" +expectpart "$(curl -u andy:bar $CURLOPTS -X POST -H 'Content-Type: application/yang-data+json' $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/library -d "$REQ")" 0 "HTTP/$HVER 201" # Create album in jukebox example REQ='Wasting Light2011' new "RFC 8072 YANG Patch JSON jukebox example 2: Error." -expectpart "$(curl -u andy:bar $CURLOPTS -X POST -H 'Content-Type: application/yang-data+xml' $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/library/artist=Foo%20Fighters -d "$REQ")" 0 "HTTP/$HVER 201 Created" +expectpart "$(curl -u andy:bar $CURLOPTS -X POST -H 'Content-Type: application/yang-data+xml' $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/library/artist=Foo%20Fighters -d "$REQ")" 0 "HTTP/$HVER 201" # Add fields to album in jukebox example REQ='{"example-jukebox:album":[{"name":"Wasting Light","genre":"example-jukebox:alternative","year":2011}]}' new "RFC 8072 YANG Patch JSON jukebox example 3: Error." -expectpart "$(curl -u andy:bar $CURLOPTS -X PUT -H 'Content-Type: application/yang-data+json' $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/library/artist=Foo%20Fighters/album=Wasting%20Light -d "$REQ")" 0 "HTTP/$HVER 204 No Content" +expectpart "$(curl -u andy:bar $CURLOPTS -X PUT -H 'Content-Type: application/yang-data+json' $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/library/artist=Foo%20Fighters/album=Wasting%20Light -d "$REQ")" 0 "HTTP/$HVER 204" # Uncomment to get info about album in jukebox example #new "RFC 8072 YANG Patch jukebox example get 2: Error." @@ -236,22 +236,22 @@ expectpart "$(curl -u andy:bar $CURLOPTS -X PUT -H 'Content-Type: application/ya # Add songs to playlist in jukebox example REQ="{\"example-jukebox:song\":[{\"index\":1,\"id\":\"/example-jukebox:jukebox/library/artist[name='Foo Fighters']/album[name='Wasting Light']/song[name='Rope']\"}]}" new "RFC 8072 YANG Patch JSON jukebox example 4: Error." -expectpart "$(curl -u andy:bar $CURLOPTS -X POST -H 'Content-Type: application/yang-data+json' $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/playlist=Foo-One?insert=first -d "$REQ")" 0 "HTTP/$HVER 201 Created" +expectpart "$(curl -u andy:bar $CURLOPTS -X POST -H 'Content-Type: application/yang-data+json' $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/playlist=Foo-One?insert=first -d "$REQ")" 0 "HTTP/$HVER 201" # Add song at end of playlist REQ="{\"example-jukebox:song\":[{\"index\":2,\"id\":\"/example-jukebox:jukebox/library/artist[name='Foo Fighters']/album[name='Wasting Light']/song[name='Bridge Burning']\"}]}" new "RFC 8072 YANG Patch JSON jukebox example 5: Error." -expectpart "$(curl -u andy:bar $CURLOPTS -X POST -H 'Content-Type: application/yang-data+json' $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/playlist=Foo-One?insert=last -d "$REQ")" 0 "HTTP/$HVER 201 Created" +expectpart "$(curl -u andy:bar $CURLOPTS -X POST -H 'Content-Type: application/yang-data+json' $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/playlist=Foo-One?insert=last -d "$REQ")" 0 "HTTP/$HVER 201" # Add song at end of playlist REQ="{\"example-jukebox:song\":[{\"index\":4,\"id\":\"/example-jukebox:jukebox/library/artist[name='Foo Fighters']/album[name='Wasting Light']/song[name='Still More Rope']\"}]}" new "RFC 8072 YANG Patch JSON jukebox example 6: Error." -expectpart "$(curl -u andy:bar $CURLOPTS -X POST -H 'Content-Type: application/yang-data+json' $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/playlist=Foo-One?insert=last -d "$REQ")" 0 "HTTP/$HVER 201 Created" +expectpart "$(curl -u andy:bar $CURLOPTS -X POST -H 'Content-Type: application/yang-data+json' $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/playlist=Foo-One?insert=last -d "$REQ")" 0 "HTTP/$HVER 201" # Add song at end of playlist REQ="{\"example-jukebox:song\":[{\"index\":3,\"id\":\"/example-jukebox:jukebox/library/artist[name='Foo Fighters']/album[name='Wasting Light']/song[name='More Rope']\"}]}" new "RFC 8072 YANG Patch JSON jukebox example 7: Error." -expectpart "$(curl -u andy:bar $CURLOPTS -X POST -H 'Content-Type: application/yang-data+json' $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/playlist=Foo-One?insert=last -d "$REQ")" 0 "HTTP/$HVER 201 Created" +expectpart "$(curl -u andy:bar $CURLOPTS -X POST -H 'Content-Type: application/yang-data+json' $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/playlist=Foo-One?insert=last -d "$REQ")" 0 "HTTP/$HVER 201" # Run YANG patch on the playlist, testing "insert after" and "insert before" REQ='{ @@ -307,7 +307,7 @@ REQ='{ } }' new "RFC 8072 YANG Patch JSON jukebox example: Error." -expectpart "$(curl -u andy:bar $CURLOPTS -X PATCH -H 'Content-Type: application/yang-patch+json' -H 'Accept: application/yang-patch+json' $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/playlist=Foo-One -d "$REQ")" 0 "HTTP/$HVER 201 Created" +expectpart "$(curl -u andy:bar $CURLOPTS -X PATCH -H 'Content-Type: application/yang-patch+json' -H 'Accept: application/yang-patch+json' $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/playlist=Foo-One -d "$REQ")" 0 "HTTP/$HVER 201" # Uncomment to get info about playlist in jukebox example #new "RFC 8072 YANG Patch jukebox example get : Error." diff --git a/test/test_restconf_yang_patch_xml.sh b/test/test_restconf_yang_patch_xml.sh index ffdd757e..93fa2727 100755 --- a/test/test_restconf_yang_patch_xml.sh +++ b/test/test_restconf_yang_patch_xml.sh @@ -7,8 +7,8 @@ # Magic line must be first in script (see README.md) s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi -#echo "...skipped: YANG_PATCH XML NYI" -#if [ "$s" = $0 ]; then exit 0; else return 0; fi +echo "...skipped: YANG_PATCH XML NYI" +if [ "$s" = $0 ]; then exit 0; else return 0; fi APPNAME=example