From 97079b0a88514635df7dc77271a5ec6e556a3259 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Sat, 8 Jun 2019 10:17:56 +0200 Subject: [PATCH] Fixed side-effect of RESTCONF PUT key-match patch --- apps/restconf/restconf_methods.c | 73 +++++++++++++++++--------------- test/test_restconf2.sh | 6 +++ 2 files changed, 45 insertions(+), 34 deletions(-) diff --git a/apps/restconf/restconf_methods.c b/apps/restconf/restconf_methods.c index 756d2cce..edc194a5 100644 --- a/apps/restconf/restconf_methods.c +++ b/apps/restconf/restconf_methods.c @@ -636,11 +636,14 @@ api_data_post(clicon_handle h, /*! Check matching keys * + * Check that x1 and x2 (both of type list/leaf-list) share the same key statements + * I.e that if x1=b then x2 = b as + * well * @param[in] y Yang statement, should be list or leaf-list - * @param[in] xdata XML data tree - * @param[in] xapipath XML api-path tree + * @param[in] x1 First XML tree (eg data tree) + * @param[in] x2 Second XML tree (eg api-path tree) * @retval 0 Yes, keys match - * @retval -1 No keys do not match + * @retval -1 No keys do not match * If the target resource represents a YANG leaf-list, then the PUT * method MUST NOT change the value of the leaf-list instance. * @@ -651,17 +654,18 @@ api_data_post(clicon_handle h, */ static int match_list_keys(yang_stmt *y, - cxobj *xdata, - cxobj *xapipath) + cxobj *x1, + cxobj *x2) { int retval = -1; cvec *cvk = NULL; /* vector of index keys */ cg_var *cvi; char *keyname; - cxobj *xkeya; /* xml key object in api-path */ - cxobj *xkeyd; /* xml key object in data */ - char *keya; - char *keyd; + cxobj *xkey1; /* xml key object of x1 */ + cxobj *xkey2; /* xml key object of x2 */ + char *key1; + char *key2; + clicon_debug(1, "%s", __FUNCTION__); switch (yang_keyword_get(y)){ @@ -670,24 +674,24 @@ match_list_keys(yang_stmt *y, cvi = NULL; while ((cvi = cvec_each(cvk, cvi)) != NULL) { keyname = cv_string_get(cvi); - if ((xkeya = xml_find(xapipath, keyname)) == NULL) + if ((xkey2 = xml_find(x2, keyname)) == NULL) goto done; /* No key in api-path */ - if ((keya = xml_body(xkeya)) == NULL) + if ((key2 = xml_body(xkey2)) == NULL) goto done; - if ((xkeyd = xml_find(xdata, keyname)) == NULL) + if ((xkey1 = xml_find(x1, keyname)) == NULL) goto done; /* No key in data */ - if ((keyd = xml_body(xkeyd)) == NULL) + if ((key1 = xml_body(xkey1)) == NULL) goto done; - if (strcmp(keya, keyd) != 0) + if (strcmp(key2, key1) != 0) goto done; /* keys dont match */ } break; case Y_LEAF_LIST: - if ((keya = xml_body(xapipath)) == NULL) + if ((key2 = xml_body(x2)) == NULL) goto done; /* No key in api-path */ - if ((keyd = xml_body(xdata)) == NULL) + if ((key1 = xml_body(x1)) == NULL) goto done; /* No key in data */ - if (strcmp(keya, keyd) != 0) + if (strcmp(key2, key1) != 0) goto done; /* keys dont match */ break; default: @@ -884,26 +888,27 @@ api_data_put(clicon_handle h, * That is why the conditional is somewhat hairy */ xparent = xml_parent(xbot); -#if 1 - if (debug){ - cbuf *ccc=cbuf_new(); - if (clicon_xml2cbuf(ccc, xtop, 0, 0) < 0) - goto done; - clicon_debug(1, "%s AAA XPATH:%s", __FUNCTION__, cbuf_get(ccc)); - } - if (debug){ - cbuf *ccc=cbuf_new(); - if (clicon_xml2cbuf(ccc, xdata, 0, 0) < 0) - goto done; - clicon_debug(1, "%s DATA:%s", __FUNCTION__, cbuf_get(ccc)); - } -#endif - if (y){ yp = yang_parent_get(y); + /* Ensure list keys match between uri and data */ if (((yang_keyword_get(y) == Y_LIST || yang_keyword_get(y) == Y_LEAF_LIST) && - match_list_keys(y, x, xbot) < 0) || - (yp && yang_keyword_get(yp) == Y_LIST && + match_list_keys(y, x, xbot) < 0)){ + if (netconf_operation_failed_xml(&xerr, "protocol", "api-path keys do not match data keys") < 0) + goto done; + if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); + goto done; + } + if (api_return_err(h, r, xe, pretty, use_xml) < 0) + goto done; + goto ok; + + } + /* Ensure list keys match between uri and data of parents + * XXX: this may only be a special case of immediate parent + */ + if ((yp && yang_keyword_get(yp) == Y_LIST && + xml_parent(x) != xdata && match_list_keys(yp, xml_parent(x), xparent) < 0)){ if (netconf_operation_failed_xml(&xerr, "protocol", "api-path keys do not match data keys") < 0) goto done; diff --git a/test/test_restconf2.sh b/test/test_restconf2.sh index 52b6d2a5..740a8165 100755 --- a/test/test_restconf2.sh +++ b/test/test_restconf2.sh @@ -174,6 +174,12 @@ expectfn 'curl -s -X PUT -d {"interface":{"name":"TEST","type":"eth0"}} http://l new "restconf PUT change key error" expectfn 'curl -is -X PUT -d {"interface":{"name":"ALPHA","type":"eth0"}} http://localhost/restconf/data/example:cont1/interface=TEST' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "api-path keys do not match data keys"}}}' +new "restconf PUT change type to eth0 (non-key sub-element to list)" +expectfn 'curl -s -X PUT -d {"example:type":"eth0"} http://localhost/restconf/data/example:cont1/interface=local0/type' 0 "" + +new "restconf GET datastore eth" +expectfn "curl -s -X GET http://localhost/restconf/data/example:cont1/interface=local0" 0 '{"example:interface": \[{"name": "local0","type": "eth0"}\]}' + #--------------- json type tests new "restconf POST type x3" expectfn 'curl -s -X POST -d {"example:types":{"tint":42,"tdec64":42.123,"tbool":false,"tstr":"str"}} http://localhost/restconf/data' 0 ''