Fixed side-effect of RESTCONF PUT key-match patch

This commit is contained in:
Olof hagsand 2019-06-08 10:17:56 +02:00
parent 519fac186c
commit 97079b0a88
2 changed files with 45 additions and 34 deletions

View file

@ -636,11 +636,14 @@ api_data_post(clicon_handle h,
/*! Check matching keys /*! Check matching keys
* *
* Check that x1 and x2 (both of type list/leaf-list) share the same key statements
* I.e that if x1=<list><key>b</key></list> then x2 = <list><key>b</key></list> as
* well
* @param[in] y Yang statement, should be list or leaf-list * @param[in] y Yang statement, should be list or leaf-list
* @param[in] xdata XML data tree * @param[in] x1 First XML tree (eg data tree)
* @param[in] xapipath XML api-path tree * @param[in] x2 Second XML tree (eg api-path tree)
* @retval 0 Yes, keys match * @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 * If the target resource represents a YANG leaf-list, then the PUT
* method MUST NOT change the value of the leaf-list instance. * method MUST NOT change the value of the leaf-list instance.
* *
@ -651,17 +654,18 @@ api_data_post(clicon_handle h,
*/ */
static int static int
match_list_keys(yang_stmt *y, match_list_keys(yang_stmt *y,
cxobj *xdata, cxobj *x1,
cxobj *xapipath) cxobj *x2)
{ {
int retval = -1; int retval = -1;
cvec *cvk = NULL; /* vector of index keys */ cvec *cvk = NULL; /* vector of index keys */
cg_var *cvi; cg_var *cvi;
char *keyname; char *keyname;
cxobj *xkeya; /* xml key object in api-path */ cxobj *xkey1; /* xml key object of x1 */
cxobj *xkeyd; /* xml key object in data */ cxobj *xkey2; /* xml key object of x2 */
char *keya; char *key1;
char *keyd; char *key2;
clicon_debug(1, "%s", __FUNCTION__); clicon_debug(1, "%s", __FUNCTION__);
switch (yang_keyword_get(y)){ switch (yang_keyword_get(y)){
@ -670,24 +674,24 @@ match_list_keys(yang_stmt *y,
cvi = NULL; cvi = NULL;
while ((cvi = cvec_each(cvk, cvi)) != NULL) { while ((cvi = cvec_each(cvk, cvi)) != NULL) {
keyname = cv_string_get(cvi); 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 */ goto done; /* No key in api-path */
if ((keya = xml_body(xkeya)) == NULL) if ((key2 = xml_body(xkey2)) == NULL)
goto done; goto done;
if ((xkeyd = xml_find(xdata, keyname)) == NULL) if ((xkey1 = xml_find(x1, keyname)) == NULL)
goto done; /* No key in data */ goto done; /* No key in data */
if ((keyd = xml_body(xkeyd)) == NULL) if ((key1 = xml_body(xkey1)) == NULL)
goto done; goto done;
if (strcmp(keya, keyd) != 0) if (strcmp(key2, key1) != 0)
goto done; /* keys dont match */ goto done; /* keys dont match */
} }
break; break;
case Y_LEAF_LIST: case Y_LEAF_LIST:
if ((keya = xml_body(xapipath)) == NULL) if ((key2 = xml_body(x2)) == NULL)
goto done; /* No key in api-path */ 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 */ goto done; /* No key in data */
if (strcmp(keya, keyd) != 0) if (strcmp(key2, key1) != 0)
goto done; /* keys dont match */ goto done; /* keys dont match */
break; break;
default: default:
@ -884,26 +888,27 @@ api_data_put(clicon_handle h,
* That is why the conditional is somewhat hairy * That is why the conditional is somewhat hairy
*/ */
xparent = xml_parent(xbot); 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){ if (y){
yp = yang_parent_get(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) && if (((yang_keyword_get(y) == Y_LIST || yang_keyword_get(y) == Y_LEAF_LIST) &&
match_list_keys(y, x, xbot) < 0) || match_list_keys(y, x, xbot) < 0)){
(yp && yang_keyword_get(yp) == Y_LIST && 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)){ 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) if (netconf_operation_failed_xml(&xerr, "protocol", "api-path keys do not match data keys") < 0)
goto done; goto done;

View file

@ -174,6 +174,12 @@ expectfn 'curl -s -X PUT -d {"interface":{"name":"TEST","type":"eth0"}} http://l
new "restconf PUT change key error" 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"}}}' 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 #--------------- json type tests
new "restconf POST type x3" 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 '' expectfn 'curl -s -X POST -d {"example:types":{"tint":42,"tdec64":42.123,"tbool":false,"tstr":"str"}} http://localhost/restconf/data' 0 ''