Documented bug [Yang identityref XML encoding is not general #90](https://github.com/clicon/clixon/issues/90)
This commit is contained in:
parent
e44685a100
commit
6d46087109
6 changed files with 84 additions and 46 deletions
|
|
@ -217,6 +217,7 @@
|
||||||
|
|
||||||
### Minor changes
|
### Minor changes
|
||||||
|
|
||||||
|
* Documented bug [Yang identityref XML encoding is not general #90](https://github.com/clicon/clixon/issues/90)
|
||||||
* Added new API function `xpath_parse()` to split parsing and xml evaluation.
|
* Added new API function `xpath_parse()` to split parsing and xml evaluation.
|
||||||
* Rewrote `api_path2xpath` to handle namespaces.
|
* Rewrote `api_path2xpath` to handle namespaces.
|
||||||
* `api_path2xml_vec` strict mode check added if list key length mismatch
|
* `api_path2xml_vec` strict mode check added if list key length mismatch
|
||||||
|
|
|
||||||
|
|
@ -181,33 +181,56 @@ yang2cli_var_identityref(yang_stmt *ys,
|
||||||
yang_stmt *ybaseref;
|
yang_stmt *ybaseref;
|
||||||
yang_stmt *ybaseid;
|
yang_stmt *ybaseid;
|
||||||
cg_var *cv = NULL;
|
cg_var *cv = NULL;
|
||||||
char *name;
|
char *prefix = NULL;
|
||||||
char *id;
|
char *id = NULL;
|
||||||
int i;
|
int i;
|
||||||
|
cvec *idrefvec;
|
||||||
|
yang_stmt *ymod;
|
||||||
|
yang_stmt *yprefix;
|
||||||
|
yang_stmt *yspec;
|
||||||
|
|
||||||
if ((ybaseref = yang_find(ytype, Y_BASE, NULL)) != NULL &&
|
if ((ybaseref = yang_find(ytype, Y_BASE, NULL)) != NULL &&
|
||||||
(ybaseid = yang_find_identity(ys, yang_argument_get(ybaseref))) != NULL){
|
(ybaseid = yang_find_identity(ys, yang_argument_get(ybaseref))) != NULL){
|
||||||
if (cvec_len(yang_cvec_get(ybaseid)) > 0){
|
idrefvec = yang_cvec_get(ybaseid);
|
||||||
|
if (cvec_len(idrefvec) > 0){
|
||||||
/* Add a wildchar string first -let validate take it for default prefix */
|
/* Add a wildchar string first -let validate take it for default prefix */
|
||||||
cprintf(cb, ">");
|
cprintf(cb, ">");
|
||||||
if (helptext)
|
if (helptext)
|
||||||
cprintf(cb, "(\"%s\")", helptext);
|
cprintf(cb, "(\"%s\")", helptext);
|
||||||
cprintf(cb, "|<%s:%s choice:", yang_argument_get(ys), cvtypestr);
|
cprintf(cb, "|<%s:%s choice:", yang_argument_get(ys), cvtypestr);
|
||||||
|
yspec = ys_spec(ys);
|
||||||
i = 0;
|
i = 0;
|
||||||
while ((cv = cvec_each(yang_cvec_get(ybaseid), cv)) != NULL){
|
while ((cv = cvec_each(idrefvec, cv)) != NULL){
|
||||||
|
if (nodeid_split(cv_name_get(cv), &prefix, &id) < 0)
|
||||||
|
goto done;
|
||||||
|
/* Translate from module-name(prefix) to global prefix
|
||||||
|
* This is really a kludge for true identityref prefix handling
|
||||||
|
* IDENTITYREF_KLUDGE
|
||||||
|
* This is actually quite complicated: the cli needs to generate
|
||||||
|
* a netconf statement with correct xmlns binding
|
||||||
|
*/
|
||||||
|
if ((ymod = yang_find_module_by_name(yspec, prefix)) != NULL &&
|
||||||
|
(yprefix = yang_find(ymod, Y_PREFIX, NULL)) != NULL)
|
||||||
if (i++)
|
if (i++)
|
||||||
cprintf(cb, "|");
|
cprintf(cb, "|");
|
||||||
name = strdup(cv_name_get(cv));
|
cprintf(cb, "%s:%s", yang_argument_get(yprefix), id);
|
||||||
if ((id=strchr(name, ':')) != NULL)
|
}
|
||||||
*id = '\0';
|
if (prefix){
|
||||||
cprintf(cb, "%s:%s", name, id+1);
|
free(prefix);
|
||||||
if (name)
|
prefix = NULL;
|
||||||
free(name);
|
}
|
||||||
|
if (id){
|
||||||
|
free(id);
|
||||||
|
id = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
// done:
|
done:
|
||||||
|
if (prefix)
|
||||||
|
free(prefix);
|
||||||
|
if (id)
|
||||||
|
free(id);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,9 +48,13 @@
|
||||||
*/
|
*/
|
||||||
#define USE_NETCONF_NS_AS_DEFAULT
|
#define USE_NETCONF_NS_AS_DEFAULT
|
||||||
|
|
||||||
/* Use modulename:id instead of prefix:id in derived identityref list
|
/*! Tag for wrong handling of identityref prefixes (XML encoding)
|
||||||
* Modulenames are global/canonical but prefixes are not.
|
* See https://github.com/clicon/clixon/issues/90
|
||||||
* Experimental since there is some mapping between prefixes and module names
|
* Instead of using generic xmlns prefix bindings, the module's own prefix
|
||||||
* that needs to be done
|
* is used.
|
||||||
|
* In the CLI generation case, this is actually quite complicated: the cli
|
||||||
|
* needs to generate a netconf statement with correct xmlns binding.
|
||||||
|
* The easy way to do this is to always generate all prefix/namespace bindings
|
||||||
|
* on the top-level for the modules involved in the netconf operation.
|
||||||
*/
|
*/
|
||||||
#undef USE_IDREF_LIST_MODULE
|
#undef IDENTITYREF_KLUDGE
|
||||||
|
|
|
||||||
|
|
@ -330,6 +330,25 @@ validate_leafref(cxobj *xt,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get module from its own prefix
|
||||||
|
* This is really not a valid usecase, a kludge for the identityref derived
|
||||||
|
* list workaround (IDENTITYREF_KLUDGE)
|
||||||
|
*/
|
||||||
|
static yang_stmt *
|
||||||
|
yang_find_module_by_prefix_yspec(yang_stmt *yspec,
|
||||||
|
char *prefix)
|
||||||
|
{
|
||||||
|
yang_stmt *ymod = NULL;
|
||||||
|
yang_stmt *yprefix;
|
||||||
|
|
||||||
|
while ((ymod = yn_each(yspec, ymod)) != NULL)
|
||||||
|
if (ymod->ys_keyword == Y_MODULE &&
|
||||||
|
(yprefix = yang_find(ymod, Y_PREFIX, NULL)) != NULL &&
|
||||||
|
strcmp(yang_argument_get(yprefix), prefix) == 0)
|
||||||
|
return ymod;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Validate xml node of type identityref, ensure value is a defined identity
|
/*! Validate xml node of type identityref, ensure value is a defined identity
|
||||||
* Check if a given node has value derived from base identity. This is
|
* Check if a given node has value derived from base identity. This is
|
||||||
* a run-time check necessary when validating eg netconf.
|
* a run-time check necessary when validating eg netconf.
|
||||||
|
|
@ -367,6 +386,7 @@ validate_identityref(cxobj *xt,
|
||||||
char *id = NULL;
|
char *id = NULL;
|
||||||
cbuf *cberr = NULL;
|
cbuf *cberr = NULL;
|
||||||
cbuf *cb = NULL;
|
cbuf *cb = NULL;
|
||||||
|
cvec *idrefvec; /* Derived identityref list: (module:id)**/
|
||||||
|
|
||||||
if ((cb = cbuf_new()) == NULL){
|
if ((cb = cbuf_new()) == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||||
|
|
@ -395,13 +415,15 @@ validate_identityref(cxobj *xt,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0 /* Assume proper namespace, otherwise we assume module prefixes */
|
#if 0 /* Assume proper namespace, otherwise we assume module prefixes,
|
||||||
|
* see IDENTITYREF_KLUDGE
|
||||||
|
*/
|
||||||
{
|
{
|
||||||
char *namespace;
|
char *namespace;
|
||||||
yang_stmt *ymod;
|
yang_stmt *ymod;
|
||||||
yang_stmt *yspec;
|
yang_stmt *yspec;
|
||||||
|
|
||||||
/* Create an idref as <module>:<id> which is the format of the derived
|
/* Create an idref as <bbmodule>:<id> which is the format of the derived
|
||||||
* identityref list associated with the base identities.
|
* identityref list associated with the base identities.
|
||||||
*/
|
*/
|
||||||
/* Get namespace (of idref) from xml */
|
/* Get namespace (of idref) from xml */
|
||||||
|
|
@ -416,14 +438,16 @@ validate_identityref(cxobj *xt,
|
||||||
cprintf(cb, "%s:%s", yang_argument_get(ymod), id);
|
cprintf(cb, "%s:%s", yang_argument_get(ymod), id);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#ifdef USE_IDREF_LIST_MODULE
|
|
||||||
{
|
{
|
||||||
yang_stmt *ymod;
|
yang_stmt *ymod;
|
||||||
/* idref from prefix:id to module:id */
|
/* idref from prefix:id to module:id */
|
||||||
if (prefix == NULL)
|
if (prefix == NULL)
|
||||||
ymod = ys_module(ys);
|
ymod = ys_module(ys);
|
||||||
else /* from prefix to name */
|
else{ /* from prefix to name */
|
||||||
ymod = yang_find_module_by_prefix(ys, prefix);
|
#if 1 /* IDENTITYREF_KLUDGE */
|
||||||
|
ymod = yang_find_module_by_prefix_yspec(ys_spec(ys), prefix);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
if (ymod == NULL){
|
if (ymod == NULL){
|
||||||
cprintf(cberr, "Identityref validation failed, %s not derived from %s",
|
cprintf(cberr, "Identityref validation failed, %s not derived from %s",
|
||||||
node, yang_argument_get(ybaseid));
|
node, yang_argument_get(ybaseid));
|
||||||
|
|
@ -433,18 +457,13 @@ validate_identityref(cxobj *xt,
|
||||||
}
|
}
|
||||||
cprintf(cb, "%s:%s", yang_argument_get(ymod), id);
|
cprintf(cb, "%s:%s", yang_argument_get(ymod), id);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
if (prefix == NULL)
|
|
||||||
cprintf(cb, "%s:%s", yang_find_myprefix(ys), id);
|
|
||||||
else
|
|
||||||
cprintf(cb, "%s:%s", prefix, id);
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
idref = cbuf_get(cb);
|
idref = cbuf_get(cb);
|
||||||
/* Here check if node is in the derived node list of the base identity
|
/* Here check if node is in the derived node list of the base identity
|
||||||
* The derived node list is a cvec computed XXX
|
* The derived node list is a cvec computed XXX
|
||||||
*/
|
*/
|
||||||
if (cvec_find(yang_cvec_get(ybaseid), idref) == NULL){
|
idrefvec = yang_cvec_get(ybaseid);
|
||||||
|
if (cvec_find(idrefvec, idref) == NULL){
|
||||||
cprintf(cberr, "Identityref validation failed, %s not derived from %s",
|
cprintf(cberr, "Identityref validation failed, %s not derived from %s",
|
||||||
node, yang_argument_get(ybaseid));
|
node, yang_argument_get(ybaseid));
|
||||||
if (netconf_operation_failed_xml(xret, "application", cbuf_get(cberr)) < 0)
|
if (netconf_operation_failed_xml(xret, "application", cbuf_get(cberr)) < 0)
|
||||||
|
|
|
||||||
|
|
@ -1616,12 +1616,13 @@ ys_populate_identity(clicon_handle h,
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
yang_stmt *yc = NULL;
|
yang_stmt *yc = NULL;
|
||||||
yang_stmt *ybaseid;
|
yang_stmt *ybaseid;
|
||||||
// yang_stmt *ymod;
|
|
||||||
cg_var *cv;
|
cg_var *cv;
|
||||||
char *baseid;
|
char *baseid;
|
||||||
char *prefix = NULL;
|
char *prefix = NULL;
|
||||||
char *id = NULL;
|
char *id = NULL;
|
||||||
cbuf *cb = NULL;
|
cbuf *cb = NULL;
|
||||||
|
yang_stmt *ymod;
|
||||||
|
cvec *idrefvec; /* Derived identityref list: (module:id)**/
|
||||||
|
|
||||||
/* Top-call (no recursion) create idref
|
/* Top-call (no recursion) create idref
|
||||||
* The idref is (here) in "canonical form": <module>:<id>
|
* The idref is (here) in "canonical form": <module>:<id>
|
||||||
|
|
@ -1632,7 +1633,6 @@ ys_populate_identity(clicon_handle h,
|
||||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
#if 0 /* Use module:id instead of prefix:id in derived list */
|
|
||||||
if (nodeid_split(yang_argument_get(ys), &prefix, &id) < 0)
|
if (nodeid_split(yang_argument_get(ys), &prefix, &id) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((ymod = ys_module(ys)) == NULL){
|
if ((ymod = ys_module(ys)) == NULL){
|
||||||
|
|
@ -1640,16 +1640,6 @@ ys_populate_identity(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
cprintf(cb, "%s:%s", yang_argument_get(ymod), id);
|
cprintf(cb, "%s:%s", yang_argument_get(ymod), id);
|
||||||
#else
|
|
||||||
{
|
|
||||||
if (nodeid_split(yang_argument_get(ys), &prefix, &id) < 0)
|
|
||||||
goto done;
|
|
||||||
if (prefix)
|
|
||||||
cprintf(cb, "%s:%s", prefix, id);
|
|
||||||
else
|
|
||||||
cprintf(cb, "%s:%s", yang_find_myprefix(ys), id);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
idref = cbuf_get(cb);
|
idref = cbuf_get(cb);
|
||||||
}
|
}
|
||||||
/* Iterate through all base statements and check the base identity exists
|
/* Iterate through all base statements and check the base identity exists
|
||||||
|
|
@ -1666,7 +1656,8 @@ ys_populate_identity(clicon_handle h,
|
||||||
}
|
}
|
||||||
// continue; /* root identity */
|
// continue; /* root identity */
|
||||||
/* Check if derived id is already in base identifier */
|
/* Check if derived id is already in base identifier */
|
||||||
if (cvec_find(ybaseid->ys_cvec, idref) != NULL)
|
idrefvec = yang_cvec_get(ybaseid);
|
||||||
|
if (cvec_find(idrefvec, idref) != NULL)
|
||||||
continue;
|
continue;
|
||||||
/* Add derived id to ybaseid */
|
/* Add derived id to ybaseid */
|
||||||
if ((cv = cv_new(CGV_STRING)) == NULL){
|
if ((cv = cv_new(CGV_STRING)) == NULL){
|
||||||
|
|
@ -1675,7 +1666,7 @@ ys_populate_identity(clicon_handle h,
|
||||||
}
|
}
|
||||||
/* add prefix */
|
/* add prefix */
|
||||||
cv_name_set(cv, idref);
|
cv_name_set(cv, idref);
|
||||||
cvec_append_var(ybaseid->ys_cvec, cv); /* cv copied */
|
cvec_append_var(idrefvec, cv); /* cv copied */
|
||||||
if (cv){
|
if (cv){
|
||||||
cv_free(cv);
|
cv_free(cv);
|
||||||
cv = NULL;
|
cv = NULL;
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ struct yang_stmt{
|
||||||
Y_RANGE: range_min, range_max
|
Y_RANGE: range_min, range_max
|
||||||
Y_LIST: vector of keys
|
Y_LIST: vector of keys
|
||||||
Y_TYPE & identity: store all derived
|
Y_TYPE & identity: store all derived
|
||||||
types as <prefix>:<id> list
|
types as <module>:<id> list
|
||||||
*/
|
*/
|
||||||
yang_type_cache *ys_typecache; /* If ys_keyword==Y_TYPE, cache all typedef data except unions */
|
yang_type_cache *ys_typecache; /* If ys_keyword==Y_TYPE, cache all typedef data except unions */
|
||||||
int _ys_vector_i; /* internal use: yn_each */
|
int _ys_vector_i; /* internal use: yn_each */
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue