* YANG Leafref feature update

* Closer adherence to RFC 7950. Some of this is changed behavior, some is new feature.
  * Essentially instead of looking at the referring leaf, context is referred(target) node
  * Validation uses referred node
    * Validation changed to use type of referred node, instead of just "string"
  * Auto-cli
    * Changed to use type of referred node for typecheck
    * Completion uses referred node
  * Required instance / less strict validation
    * New: Leafrefs must refer to existing data leaf ONLY IF YANG `required-instance` is true
    * Previous: All leafrefs must refer to existing data leaf node
* Fixed: [Autocli does not offer completions for leafref to identityref #254](https://github.com/clicon/clixon/issues/254)
This commit is contained in:
Olof hagsand 2021-08-16 13:57:51 +02:00
parent 8db716ca07
commit 980718178a
18 changed files with 1151 additions and 115 deletions

View file

@ -73,6 +73,7 @@
#include "cli_common.h" /* internal functions */
/*! Given an xpath encoded in a cbuf, append a second xpath into the first
*
* The method reuses prefixes from xpath1 if they exist, otherwise the module prefix
* from y is used. Unless the element is .., .
* XXX: Predicates not handled
@ -87,10 +88,10 @@ and
traverse_canonical
*/
static int
xpath_myappend(cbuf *xpath0,
char *xpath1,
yang_stmt *y,
cvec *nsc)
xpath_append(cbuf *cb0,
char *xpath1,
yang_stmt *y,
cvec *nsc)
{
int retval = -1;
char **vec = NULL;
@ -100,27 +101,50 @@ xpath_myappend(cbuf *xpath0,
char *myprefix;
char *id = NULL;
char *prefix = NULL;
int initialups = 1; /* If starts with ../../.. */
char *xpath0;
if (xpath0 == NULL){
clicon_err(OE_XML, EINVAL, "xpath0 is NULL");
if (cb0 == NULL){
clicon_err(OE_XML, EINVAL, "cb0 is NULL");
goto done;
}
if (xpath1 == NULL || strlen(xpath1)==0)
goto ok;
if ((myprefix = yang_find_myprefix(y)) == NULL)
goto done;
if ((vec = clicon_strsep(xpath1, "/", &nvec)) == NULL)
goto done;
if (xpath1 && xpath1[0] == '/')
cbuf_reset(xpath0);
if (xpath1[0] == '/')
cbuf_reset(cb0);
xpath0 = cbuf_get(cb0);
for (i=0; i<nvec; i++){
v = vec[i];
if (strlen(v) == 0)
continue;
if (nodeid_split(v, &prefix, &id) < 0)
goto done;
if (strcmp(id, "..") == 0 || strcmp(id, ".") == 0)
cprintf(xpath0, "/%s", id);
else
cprintf(xpath0, "/%s:%s", prefix?prefix:myprefix, id);
if (strcmp(id, ".") == 0)
initialups = 0;
else if (strcmp(id, "..") == 0){
if (initialups){
/* Subtract from xpath0 */
int j;
for (j=cbuf_len(cb0); j >= 0; j--){
if (xpath0[j] != '/')
continue;
cbuf_trunc(cb0, j);
break;
}
}
else{
initialups = 0;
cprintf(cb0, "/%s", id);
}
}
else{
initialups = 0;
cprintf(cb0, "/%s:%s", prefix?prefix:myprefix, id);
}
if (prefix){
free(prefix);
prefix = NULL;
@ -130,6 +154,7 @@ xpath_myappend(cbuf *xpath0,
id = NULL;
}
}
ok:
retval = 0;
done:
if (prefix)
@ -182,13 +207,13 @@ expand_dbvar(void *h,
cxobj *xbot = NULL; /* xpath, NULL if datastore */
yang_stmt *y = NULL; /* yang spec of xpath */
yang_stmt *yp;
yang_stmt *ytype;
yang_stmt *ypath;
char *reason = NULL;
cvec *nsc = NULL;
int ret;
int cvvi = 0;
cbuf *cbxpath = NULL;
yang_stmt *ypath;
yang_stmt *ytype;
if (argv == NULL || cvec_len(argv) != 2){
clicon_err(OE_PLUGIN, EINVAL, "requires arguments: <db> <xmlkeyfmt>");
@ -238,7 +263,6 @@ expand_dbvar(void *h,
}
if (y==NULL)
goto ok;
/* Transform api-path to xpath for netconf */
if (api_path2xpath(api_path, yspec, &xpath, &nsc, NULL) < 0)
goto done;
@ -287,7 +311,7 @@ expand_dbvar(void *h,
/* */
/* Extend xpath with leafref path: Append yang_argument_get(ypath) to xpath
*/
if (xpath_myappend(cbxpath, yang_argument_get(ypath), y, nsc) < 0)
if (xpath_append(cbxpath, yang_argument_get(ypath), y, nsc) < 0)
goto done;
}
/* Get configuration based on cbxpath */
@ -297,7 +321,7 @@ expand_dbvar(void *h,
clixon_netconf_error(xe, "Get configuration", NULL);
goto ok;
}
if (xpath_vec(xt, nsc, "%s", &xvec, &xlen, xpath) < 0)
if (xpath_vec(xt, nsc, "%s", &xvec, &xlen, cbuf_get(cbxpath)) < 0)
goto done;
/* Loop for inserting into commands cvec.
* Detect duplicates: for ordered-by system assume list is ordered, so you need