Fixed: [Templates with nc:operation merge causes bad diffs to be shows](https://github.com/clicon/clixon-controller/issues/187)
This commit is contained in:
parent
b0cc1857c0
commit
ed226a990c
5 changed files with 117 additions and 22 deletions
|
|
@ -22,6 +22,10 @@ Planned: April 2025
|
|||
* New `clixon-restconf@2025-02-01.yang` revision
|
||||
* Added timeout parameter
|
||||
|
||||
### Corrected Bugs
|
||||
|
||||
* Fixed: [Templates with nc:operation "merge" causes bad diffs to be shows](https://github.com/clicon/clixon-controller/issues/187)
|
||||
|
||||
## 7.3.0
|
||||
30 January 2025
|
||||
|
||||
|
|
|
|||
|
|
@ -655,7 +655,8 @@ from_client_edit_config(clixon_handle h,
|
|||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
/* Must do before duplicate check */
|
||||
/* Must do before duplicate check,
|
||||
* should probably be done before minmax check above */
|
||||
if (xml_sort_recurse(xc) < 0)
|
||||
goto done;
|
||||
/* Disable duplicate check in NETCONF messages. */
|
||||
|
|
|
|||
|
|
@ -4,7 +4,5 @@ A collection of community links to usages of clixon. Please notify of changes or
|
|||
|
||||
Links:
|
||||
|
||||
* https://github.com/MontaVista-OpenSourceTechnology/clixon
|
||||
* https://github.com/MontaVista-OpenSourceTechnology/clixon-backend-helper
|
||||
* https://github.com/brunorijsman/yang-tutorial/tree/main/clixon
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -91,8 +91,8 @@
|
|||
*/
|
||||
struct vec_order {
|
||||
cxobj *vo_xml;
|
||||
char **vo_strvec;
|
||||
size_t vo_slen; /* length of vo_strvec (is actually global to vector) */
|
||||
char **vo_strvec; /* vector of keys, 1 element if leaf-list, NULL if non-list */
|
||||
size_t vo_slen; /* Length of vo_strvec (is actually global to vector) */
|
||||
};
|
||||
|
||||
/*! New element last in list, check if already exists if so return -1
|
||||
|
|
@ -877,9 +877,10 @@ remove_duplicates_list(yang_stmt *y,
|
|||
int *nr,
|
||||
cxobj **xret)
|
||||
{
|
||||
int retval = -1;
|
||||
int v;
|
||||
int i;
|
||||
int retval = -1;
|
||||
cvec *cvk;
|
||||
int v;
|
||||
int i;
|
||||
|
||||
if (nr)
|
||||
*nr = 0;
|
||||
|
|
@ -896,7 +897,7 @@ remove_duplicates_list(yang_stmt *y,
|
|||
(*nr)++;
|
||||
}
|
||||
else{
|
||||
cvec *cvk = NULL;
|
||||
cvk = NULL;
|
||||
if (yang_keyword_get(y) == Y_LEAF_LIST){
|
||||
if ((cvk = cvec_new(0)) == NULL){
|
||||
clixon_err(OE_UNIX, errno, "cvec_new");
|
||||
|
|
@ -922,6 +923,48 @@ remove_duplicates_list(yang_stmt *y,
|
|||
goto done;
|
||||
}
|
||||
|
||||
/*! Remove duplicates container or leaf
|
||||
*
|
||||
* @param[in] vec Ordered vector of string vectors
|
||||
* @param[in] vlen Length of vec
|
||||
* @param[in] rm 0: return 0 on first duplicate, 1: remove all duplicates
|
||||
* @param[in] cvv Vector of keys (for error)
|
||||
* @param[out] xret Error XML tree. Free with xml_free after use
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
remove_duplicates_single(yang_stmt *y,
|
||||
struct vec_order *vec,
|
||||
size_t vlen,
|
||||
int rm,
|
||||
int *nr,
|
||||
cxobj **xret)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *x;
|
||||
int v;
|
||||
|
||||
if (nr)
|
||||
*nr = 0;
|
||||
for (v=1; v<vlen; v++){
|
||||
x = vec[v-1].vo_xml;
|
||||
if (rm){
|
||||
if (xml_purge(x) < 0)
|
||||
goto done;
|
||||
if (nr)
|
||||
(*nr)++;
|
||||
}
|
||||
else{
|
||||
if (xret && netconf_minmax_elements_xml(xret, xml_parent(x), xml_name(x), 1) < 0)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Analyze sorted list: detect and potentially remove duplicates
|
||||
*
|
||||
* @param[in] y YANG node of list segment
|
||||
|
|
@ -946,12 +989,25 @@ vec_order_analyze(yang_stmt *y,
|
|||
int nr = 0;
|
||||
int ret;
|
||||
|
||||
if (yang_find(y, Y_ORDERED_BY, "user") != NULL)
|
||||
qsort(vec, vlen, sizeof(*vec), cmp_list_qsort);
|
||||
if ((ret = remove_duplicates_list(y, vec, vlen, rm, &nr, xret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0) {
|
||||
goto fail;
|
||||
switch (yang_keyword_get(y)){
|
||||
case Y_LIST:
|
||||
case Y_LEAF_LIST:
|
||||
if (yang_find(y, Y_ORDERED_BY, "user") != NULL)
|
||||
qsort(vec, vlen, sizeof(*vec), cmp_list_qsort);
|
||||
if ((ret = remove_duplicates_list(y, vec, vlen, rm, &nr, xret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
break;
|
||||
case Y_LEAF:
|
||||
case Y_CONTAINER:
|
||||
if (vlen > 1){
|
||||
if (remove_duplicates_single(y, vec, vlen, rm, &nr, xret) < 0)
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (x && nr)
|
||||
xml_vector_decrement(x, nr);
|
||||
|
|
@ -1016,12 +1072,28 @@ xml_duplicate_detect1(cxobj *xt,
|
|||
}
|
||||
keyw = yang_keyword_get(y);
|
||||
switch (keyw){
|
||||
case Y_CONTAINER:
|
||||
case Y_LEAF:
|
||||
if (vlen > 0 && slen0 != 0){ /* Sanity check */
|
||||
clixon_err(OE_YANG, 0, "Container vector mismatch %lu != 0", slen0);
|
||||
goto done;
|
||||
}
|
||||
if ((vec = realloc(vec, (vlen+1)*sizeof(*vec))) == NULL){
|
||||
clixon_err(OE_UNIX, errno, "cvec_new");
|
||||
goto done;
|
||||
}
|
||||
vec[vlen].vo_slen = 0;
|
||||
vec[vlen].vo_strvec = NULL;
|
||||
vec[vlen].vo_xml = x;
|
||||
vlen++;
|
||||
slen0 = 0;
|
||||
break;
|
||||
case Y_LIST:
|
||||
if ((cvk = yang_cvec_get(y)) == NULL)
|
||||
continue;
|
||||
if ((clen = cvec_len(cvk)) == 0)
|
||||
continue;
|
||||
if (vec>0 && slen0 != clen){ /* Sanity check */
|
||||
if (vlen > 0 && slen0 != clen){ /* Sanity check */
|
||||
clixon_err(OE_YANG, 0, "List key vector mismatch %lu != %lu", slen0, clen);
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -1063,7 +1135,7 @@ xml_duplicate_detect1(cxobj *xt,
|
|||
goto fail;
|
||||
break;
|
||||
case Y_LEAF_LIST:
|
||||
if (vec>0 && slen0 != 1){ /* Sanity check */
|
||||
if (vlen > 0 && slen0 != 1){ /* Sanity check */
|
||||
clixon_err(OE_YANG, 0, "Leaf-list key vector mismatch %lu != 1", slen0);
|
||||
goto done;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,9 +29,9 @@ EOF
|
|||
# Example (the list server part) from RFC7950 Sec 7.8.3.1 w changed types
|
||||
cat <<EOF > $fyang
|
||||
module unique{
|
||||
yang-version 1.1;
|
||||
namespace "urn:example:clixon";
|
||||
prefix un;
|
||||
yang-version 1.1;
|
||||
namespace "urn:example:clixon";
|
||||
prefix un;
|
||||
container c{
|
||||
presence "trigger"; // force presence container to trigger error
|
||||
list server {
|
||||
|
|
@ -63,6 +63,8 @@ module unique{
|
|||
type string;
|
||||
}
|
||||
}
|
||||
container d{
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
|
|
@ -79,7 +81,7 @@ if [ $BE -ne 0 ]; then
|
|||
start_backend -s init -f $cfg
|
||||
fi
|
||||
|
||||
new "wait backend"
|
||||
new "Wait backend 1"
|
||||
wait_backend
|
||||
|
||||
new "Add list entry"
|
||||
|
|
@ -326,6 +328,24 @@ expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS>
|
|||
new "Check mix w empty"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get-config><source><candidate/></source></get-config></rpc>" "" "<rpc-reply $DEFAULTNS><data><c xmlns=\"urn:example:clixon\"><user><name>aaa</name><value>foo</value></user><user><name/><value>foo</value></user><b/><b>bbb</b><b>ccc</b><buser>CCC</buser><buser>BBB</buser><buser>AAA</buser></c></data></rpc-reply>"
|
||||
|
||||
new "netconf discard-changes"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><discard-changes/></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||
|
||||
# Note both unordered and duplicate
|
||||
new "Container dups"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><default-operation>replace</default-operation><config>
|
||||
<c xmlns=\"urn:example:clixon\">
|
||||
<b>aaa</b>
|
||||
</c>
|
||||
<d xmlns=\"urn:example:clixon\"/>
|
||||
<c xmlns=\"urn:example:clixon\">
|
||||
<b>bbb</b>
|
||||
</c>
|
||||
</config></edit-config></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||
|
||||
new "Check no container duplicates"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get-config><source><candidate/></source></get-config></rpc>" "" "<rpc-reply $DEFAULTNS><data><c xmlns=\"urn:example:clixon\"><b>bbb</b></c></data></rpc-reply>"
|
||||
|
||||
if [ $BE -ne 0 ]; then
|
||||
new "Kill backend"
|
||||
# Check if premature kill
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue