- Yang deviation [deviation statement not yet support #211](https://github.com/clicon/clixon/issues/211)
- Added "depth" parameter to yang_apply - Added extra API function to yang_cardinality to check individual relation
This commit is contained in:
parent
6e5e53e02e
commit
5a72626aa4
7 changed files with 311 additions and 92 deletions
|
|
@ -36,7 +36,8 @@ Expected: June 2021
|
||||||
|
|
||||||
* Yang Deviation/deviate [deviation statement not yet support #211](https://github.com/clicon/clixon/issues/211)
|
* Yang Deviation/deviate [deviation statement not yet support #211](https://github.com/clicon/clixon/issues/211)
|
||||||
* See RFC7950 Sec 5.6.3
|
* See RFC7950 Sec 5.6.3
|
||||||
* Work-in-progress
|
* Implemented: "not-supported" and "add"
|
||||||
|
* Not yet: "replace" and "delete"
|
||||||
|
|
||||||
### Minor features
|
### Minor features
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -238,12 +238,12 @@ int yang_order(yang_stmt *y);
|
||||||
int yang_print_cb(FILE *f, yang_stmt *yn, clicon_output_cb *fn);
|
int yang_print_cb(FILE *f, yang_stmt *yn, clicon_output_cb *fn);
|
||||||
int yang_print(FILE *f, yang_stmt *yn);
|
int yang_print(FILE *f, yang_stmt *yn);
|
||||||
int yang_print_cbuf(cbuf *cb, yang_stmt *yn, int marginal);
|
int yang_print_cbuf(cbuf *cb, yang_stmt *yn, int marginal);
|
||||||
|
int yang_deviation(yang_stmt *ys, void *arg);
|
||||||
int yang_spec_dump(yang_stmt *yspec, int debuglevel);
|
int yang_spec_dump(yang_stmt *yspec, int debuglevel);
|
||||||
int if_feature(yang_stmt *yspec, char *module, char *feature);
|
int if_feature(yang_stmt *yspec, char *module, char *feature);
|
||||||
int ys_populate(yang_stmt *ys, void *arg);
|
int ys_populate(yang_stmt *ys, void *arg);
|
||||||
int ys_populate2(yang_stmt *ys, void *arg);
|
int ys_populate2(yang_stmt *ys, void *arg);
|
||||||
int yang_apply(yang_stmt *yn, enum rfc_6020 key, yang_applyfn_t fn,
|
int yang_apply(yang_stmt *yn, enum rfc_6020 key, yang_applyfn_t fn, int from, void *arg);
|
||||||
void *arg);
|
|
||||||
int yang_datanode(yang_stmt *ys);
|
int yang_datanode(yang_stmt *ys);
|
||||||
int yang_abs_schema_nodeid(yang_stmt *ys, char *schema_nodeid, yang_stmt **yres);
|
int yang_abs_schema_nodeid(yang_stmt *ys, char *schema_nodeid, yang_stmt **yres);
|
||||||
int yang_desc_schema_nodeid(yang_stmt *yn, char *schema_nodeid, yang_stmt **yres);
|
int yang_desc_schema_nodeid(yang_stmt *yn, char *schema_nodeid, yang_stmt **yres);
|
||||||
|
|
|
||||||
|
|
@ -513,6 +513,40 @@ ys_prune(yang_stmt *yp,
|
||||||
return yc;
|
return yc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Remove yang node from parent (dont free
|
||||||
|
* @param[in] ys Yang node to remove
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
|
* @see ys_prune if parent and position is known
|
||||||
|
* @note Do not call this in a loop of yang children (unless you know what you are doing)
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
ys_prune_self(yang_stmt *ys)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
yang_stmt *yp;
|
||||||
|
yang_stmt *yc;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if ((yp = yang_parent_get(ys)) != NULL){
|
||||||
|
yc = NULL;
|
||||||
|
i = 0;
|
||||||
|
/* Find order of ys in child-list */
|
||||||
|
while ((yc = yn_each(yp, yc)) != NULL) {
|
||||||
|
if (ys == yc)
|
||||||
|
break;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (yc != NULL){
|
||||||
|
assert(yc == ys);
|
||||||
|
ys_prune(yp, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
retval = 0;
|
||||||
|
// done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Free a yang statement tree recursively
|
/*! Free a yang statement tree recursively
|
||||||
* @param[in] ys Yang node to remove and all its children recursively
|
* @param[in] ys Yang node to remove and all its children recursively
|
||||||
* @note does not remove yang node from tree
|
* @note does not remove yang node from tree
|
||||||
|
|
@ -1555,6 +1589,105 @@ yang_print_cbuf(cbuf *cb,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Yang deviation/deviate
|
||||||
|
*
|
||||||
|
* Identify deviation target node, and go through all its deviate statements.
|
||||||
|
* Features/if-feature must have run before
|
||||||
|
* @param[in] ys The yang deviation to populate.
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @see RFC 7950 5.6.3 and 7.20.3
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
yang_deviation(yang_stmt *ys,
|
||||||
|
void *arg)
|
||||||
|
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
char *nodeid;
|
||||||
|
yang_stmt *ytarget = NULL;
|
||||||
|
yang_stmt *yd;
|
||||||
|
yang_stmt *yc;
|
||||||
|
yang_stmt *yc1;
|
||||||
|
char *devop;
|
||||||
|
clicon_handle h = (clicon_handle)arg;
|
||||||
|
enum rfc_6020 kw;
|
||||||
|
int min;
|
||||||
|
int max;
|
||||||
|
|
||||||
|
if (yang_keyword_get(ys) != Y_DEVIATION)
|
||||||
|
goto ok;
|
||||||
|
/* Absolute schema node identifier identifying target node */
|
||||||
|
if ((nodeid = yang_argument_get(ys)) == NULL){
|
||||||
|
clicon_err(OE_YANG, EINVAL, "No argument to deviation");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
/* Get target node */
|
||||||
|
if (yang_abs_schema_nodeid(ys, nodeid, &ytarget) < 0)
|
||||||
|
goto done;
|
||||||
|
if (ytarget == NULL){
|
||||||
|
goto ok;
|
||||||
|
/* The RFC does not explicitly say the target node MUST exist
|
||||||
|
clicon_err(OE_YANG, 0, "schemanode sanity check of %s", nodeid);
|
||||||
|
goto done;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
/* Go through deviates of deviation */
|
||||||
|
yd = NULL;
|
||||||
|
while ((yd = yn_each(ys, yd)) != NULL) {
|
||||||
|
/* description / if-feature / reference */
|
||||||
|
if (yang_keyword_get(yd) != Y_DEVIATE)
|
||||||
|
continue;
|
||||||
|
devop = yang_argument_get(yd);
|
||||||
|
if (strcmp(devop, "not-supported") == 0){
|
||||||
|
if (ys_prune_self(ytarget) < 0)
|
||||||
|
goto done;
|
||||||
|
if (ys_free(ytarget) < 0)
|
||||||
|
goto done;
|
||||||
|
goto ok; /* Target node removed, no other deviates possible */
|
||||||
|
}
|
||||||
|
else if (strcmp(devop, "add") == 0){
|
||||||
|
yc = NULL;
|
||||||
|
while ((yc = yn_each(yd, yc)) != NULL) {
|
||||||
|
/* If a property can only appear once, the property MUST NOT
|
||||||
|
exist in the target node. */
|
||||||
|
kw = yang_keyword_get(yc);
|
||||||
|
if (yang_find(ytarget, kw, NULL) != NULL){
|
||||||
|
if (yang_cardinality_interval(h,
|
||||||
|
yang_keyword_get(ytarget),
|
||||||
|
kw,
|
||||||
|
&min,
|
||||||
|
&max) < 0)
|
||||||
|
goto done;
|
||||||
|
if (max == 1){
|
||||||
|
clicon_err(OE_YANG, 0, "deviation %s: \"%s %s\" added but node already exist in target %s",
|
||||||
|
nodeid,
|
||||||
|
yang_key2str(kw), yang_argument_get(yc),
|
||||||
|
yang_argument_get(ytarget));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Make a copy of deviate child and insert. */
|
||||||
|
if ((yc1 = ys_dup(yc)) == NULL)
|
||||||
|
goto done;
|
||||||
|
if (yn_insert(ytarget, yc1) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(devop, "replace") == 0){
|
||||||
|
}
|
||||||
|
else if (strcmp(devop, "delete") == 0){
|
||||||
|
}
|
||||||
|
else{ /* Shouldnt happen, lex/yacc takes it */
|
||||||
|
clicon_err(OE_YANG, EINVAL, "%s: invalid deviate operator", devop);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ok:
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Populate yang leafs after parsing. Create cv and fill it in.
|
/*! Populate yang leafs after parsing. Create cv and fill it in.
|
||||||
*
|
*
|
||||||
* Populate leaf in 2nd round of yang parsing, now that context is complete:
|
* Populate leaf in 2nd round of yang parsing, now that context is complete:
|
||||||
|
|
@ -2507,6 +2640,7 @@ yang_features(clicon_handle h,
|
||||||
* @param[in] yn yang node
|
* @param[in] yn yang node
|
||||||
* @param[in] key yang keyword to use as filer or -1 for all
|
* @param[in] key yang keyword to use as filer or -1 for all
|
||||||
* @param[in] fn Callback
|
* @param[in] fn Callback
|
||||||
|
* @param[in] depth Depth argument: where to start. If <=0 call the calling node yn, if 1 start with its children, etc
|
||||||
* @param[in] arg Argument
|
* @param[in] arg Argument
|
||||||
* @retval -1 Error, aborted at first error encounter
|
* @retval -1 Error, aborted at first error encounter
|
||||||
* @retval 0 OK, all nodes traversed
|
* @retval 0 OK, all nodes traversed
|
||||||
|
|
@ -2516,7 +2650,7 @@ yang_features(clicon_handle h,
|
||||||
* {
|
* {
|
||||||
* return 0;
|
* return 0;
|
||||||
* }
|
* }
|
||||||
* yang_apply(ys, Y_TYPE, ys_fn, NULL);
|
* yang_apply(ys, Y_TYPE, ys_fn, 1, NULL); // Call all yn:s children recursively
|
||||||
* @endcode
|
* @endcode
|
||||||
* @note do not delete or move around any children during this function
|
* @note do not delete or move around any children during this function
|
||||||
*/
|
*/
|
||||||
|
|
@ -2524,6 +2658,7 @@ int
|
||||||
yang_apply(yang_stmt *yn,
|
yang_apply(yang_stmt *yn,
|
||||||
enum rfc_6020 keyword,
|
enum rfc_6020 keyword,
|
||||||
yang_applyfn_t fn,
|
yang_applyfn_t fn,
|
||||||
|
int depth,
|
||||||
void *arg)
|
void *arg)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
@ -2531,17 +2666,19 @@ yang_apply(yang_stmt *yn,
|
||||||
int i;
|
int i;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
for (i=0; i<yn->ys_len; i++){
|
if (depth <= 0){
|
||||||
ys = yn->ys_stmt[i];
|
if ((int)keyword == -1 || keyword == yn->ys_keyword){
|
||||||
if ((int)keyword == -1 || keyword == ys->ys_keyword){
|
if ((ret = fn(yn, arg)) < 0)
|
||||||
if ((ret = fn(ys, arg)) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
if (ret > 0){
|
if (ret > 0){
|
||||||
retval = ret;
|
retval = ret;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((ret = yang_apply(ys, keyword, fn, arg)) < 0)
|
}
|
||||||
|
for (i=0; i<yn->ys_len; i++){
|
||||||
|
ys = yn->ys_stmt[i];
|
||||||
|
if ((ret = yang_apply(ys, keyword, fn, depth-1, arg)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret > 0){
|
if (ret > 0){
|
||||||
retval = ret;
|
retval = ret;
|
||||||
|
|
@ -2551,7 +2688,7 @@ yang_apply(yang_stmt *yn,
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Check if a node is a yang "data node"
|
/*! Check if a node is a yang "data node"
|
||||||
* @param[in] ys Yang statement node
|
* @param[in] ys Yang statement node
|
||||||
|
|
|
||||||
|
|
@ -459,7 +459,6 @@ ycard_find(enum rfc_6020 parent,
|
||||||
enum rfc_6020 child,
|
enum rfc_6020 child,
|
||||||
const struct ycard *yclist,
|
const struct ycard *yclist,
|
||||||
int p)
|
int p)
|
||||||
|
|
||||||
{
|
{
|
||||||
const struct ycard *yc;
|
const struct ycard *yc;
|
||||||
|
|
||||||
|
|
@ -490,12 +489,12 @@ yang_cardinality(clicon_handle h,
|
||||||
yang_stmt *yt,
|
yang_stmt *yt,
|
||||||
char *modname)
|
char *modname)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
yang_stmt *ys = NULL;
|
yang_stmt *ys = NULL;
|
||||||
int pk;
|
int pk;
|
||||||
int ck;
|
int ck;
|
||||||
int i;
|
int i;
|
||||||
int nr;
|
int nr;
|
||||||
const struct ycard *ycplist; /* ycard parent table*/
|
const struct ycard *ycplist; /* ycard parent table*/
|
||||||
const struct ycard *yc;
|
const struct ycard *yc;
|
||||||
|
|
||||||
|
|
@ -556,3 +555,32 @@ yang_cardinality(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Return cardinality interval [min,max] given yang parent and child keyword.
|
||||||
|
*
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] parent_key
|
||||||
|
* @param[in] child_key
|
||||||
|
* @param[out] minp 0 or 1
|
||||||
|
* @param[out] maxp 1 or NMAX (large number)
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
yang_cardinality_interval(clicon_handle h,
|
||||||
|
enum rfc_6020 parent_key,
|
||||||
|
enum rfc_6020 child_key,
|
||||||
|
int *min,
|
||||||
|
int *max)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
const struct ycard *ycplist; /* ycard parent table*/
|
||||||
|
|
||||||
|
if ((ycplist = ycard_find(parent_key, child_key, yclist, 0)) == NULL){
|
||||||
|
clicon_err(OE_YANG, EINVAL, "keys %d %d do not have cardinality",
|
||||||
|
parent_key, child_key);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
*min = ycplist->yc_min;
|
||||||
|
*max = ycplist->yc_max;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,4 +40,6 @@
|
||||||
*/
|
*/
|
||||||
int yang_cardinality(clicon_handle h, yang_stmt *yt, char *modname);
|
int yang_cardinality(clicon_handle h, yang_stmt *yt, char *modname);
|
||||||
|
|
||||||
|
int yang_cardinality_interval(clicon_handle h, enum rfc_6020 parent_key, enum rfc_6020 child_key, int *min, int *max);
|
||||||
|
|
||||||
#endif /* _CLIXON_YANG_CARDINALITY_H_ */
|
#endif /* _CLIXON_YANG_CARDINALITY_H_ */
|
||||||
|
|
|
||||||
|
|
@ -1074,14 +1074,6 @@ ys_schemanode_check(yang_stmt *ys,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Y_DEVIATION:
|
|
||||||
if (yang_abs_schema_nodeid(ys, arg, &yres) < 0)
|
|
||||||
goto done;
|
|
||||||
if (yres == NULL){
|
|
||||||
clicon_err(OE_YANG, 0, "schemanode sanity check of %s", arg);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -1330,21 +1322,27 @@ yang_parse_post(clicon_handle h,
|
||||||
for (i=modmin; i<modmax; i++)
|
for (i=modmin; i<modmax; i++)
|
||||||
if (yang_features(h, yang_child_i(yspec, i)) < 0)
|
if (yang_features(h, yang_child_i(yspec, i)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* 4: Go through parse tree and populate it with cv types */
|
/* 4: Check deviations: not-supported add/delete/replace statements
|
||||||
for (i=modmin; i<modmax; i++){
|
* done after if-features since they may affect deviations but before populate since target yang statements
|
||||||
if (ys_populate(yang_child_i(yspec, i), h) < 0) /* Alt: make a yang_apply0 */
|
* may be removed or changed
|
||||||
|
*/
|
||||||
|
for (i=modmin; i<modmax; i++) /* Really only under (sub)modules no need to traverse whole tree */
|
||||||
|
if (yang_apply(yang_child_i(yspec, i), -1, yang_deviation, 1, (void*)h) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (yang_apply(yang_child_i(yspec, i), -1, ys_populate, (void*)h) < 0)
|
|
||||||
|
/* 5: Go through parse tree and populate it with cv types */
|
||||||
|
for (i=modmin; i<modmax; i++){
|
||||||
|
if (yang_apply(yang_child_i(yspec, i), -1, ys_populate, 0, (void*)h) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 5: Resolve all types: populate type caches. Requires eg length/range cvecs
|
/* 6: Resolve all types: populate type caches. Requires eg length/range cvecs
|
||||||
* from ys_populate step.
|
* from ys_populate step.
|
||||||
* Must be done using static binding.
|
* Must be done using static binding.
|
||||||
*/
|
*/
|
||||||
for (i=modmin; i<modmax; i++)
|
for (i=modmin; i<modmax; i++)
|
||||||
if (yang_apply(yang_child_i(yspec, i), Y_TYPE, ys_resolve_type, h) < 0)
|
if (yang_apply(yang_child_i(yspec, i), Y_TYPE, ys_resolve_type, 1, h) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* Up to here resolving is made in the context they are defined, rather
|
/* Up to here resolving is made in the context they are defined, rather
|
||||||
|
|
@ -1354,14 +1352,14 @@ yang_parse_post(clicon_handle h,
|
||||||
* single tree as they are used.
|
* single tree as they are used.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* 6: Macro expansion of all grouping/uses pairs. Expansion needs marking */
|
/* 7: Macro expansion of all grouping/uses pairs. Expansion needs marking */
|
||||||
for (i=0; i<ylen; i++){
|
for (i=0; i<ylen; i++){
|
||||||
if (yang_expand_grouping(ylist[i]) < 0)
|
if (yang_expand_grouping(ylist[i]) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
yang_apply(ylist[i], -1, (yang_applyfn_t*)yang_flag_reset, (void*)YANG_FLAG_MARK);
|
yang_apply(ylist[i], -1, (yang_applyfn_t*)yang_flag_reset, 1, (void*)YANG_FLAG_MARK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 7: Top-level augmentation of all modules.
|
/* 8: Top-level augmentation of all modules.
|
||||||
* Note: Clixon does not implement augment in USES
|
* Note: Clixon does not implement augment in USES
|
||||||
* Note: There is an ordering problem, where an augment in one module depends on an augment in
|
* Note: There is an ordering problem, where an augment in one module depends on an augment in
|
||||||
* another module not yet augmented.
|
* another module not yet augmented.
|
||||||
|
|
@ -1370,21 +1368,21 @@ yang_parse_post(clicon_handle h,
|
||||||
if (yang_augment_module(ylist[i]) < 0)
|
if (yang_augment_module(ylist[i]) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* 4: Go through parse tree and do 2nd step populate (eg default) */
|
/* 9: Go through parse tree and do 2nd step populate (eg default) */
|
||||||
for (i=0; i<ylen; i++)
|
for (i=0; i<ylen; i++)
|
||||||
if (yang_apply(ylist[i], -1, ys_populate2, (void*)h) < 0)
|
if (yang_apply(ylist[i], -1, ys_populate2, 1, (void*)h) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* 8: sanity checks of expanded yangs need more here */
|
/* 10: sanity checks of expanded yangs need more here */
|
||||||
for (i=0; i<ylen; i++){
|
for (i=0; i<ylen; i++){
|
||||||
/* Check schemanode references */
|
/* Check schemanode references */
|
||||||
if (yang_apply(ylist[i], -1, ys_schemanode_check, NULL) < 0)
|
if (yang_apply(ylist[i], -1, ys_schemanode_check, 1, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Check list key values */
|
/* Check list key values */
|
||||||
if (ys_list_check(h, ylist[i]) < 0)
|
if (ys_list_check(h, ylist[i]) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* 9. Check cardinality a second time after grouping/augment etc */
|
/* 11. Check cardinality a second time after grouping/augment etc */
|
||||||
for (i=0; i<ylen; i++)
|
for (i=0; i<ylen; i++)
|
||||||
if (yang_cardinality(h, ylist[i], yang_argument_get(ylist[i])) < 0)
|
if (yang_cardinality(h, ylist[i], yang_argument_get(ylist[i])) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -35,84 +35,137 @@ module example-base{
|
||||||
prefix base;
|
prefix base;
|
||||||
namespace "urn:example:base";
|
namespace "urn:example:base";
|
||||||
container system {
|
container system {
|
||||||
must "daytime or time";
|
must "daytime or time";
|
||||||
leaf daytime{
|
leaf daytime{ /* not supported removes this */
|
||||||
type string;
|
type string;
|
||||||
}
|
}
|
||||||
list name-server {
|
list name-server {
|
||||||
key name;
|
key name;
|
||||||
leaf name {
|
leaf name {
|
||||||
type string;
|
type string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
list user {
|
list user {
|
||||||
key name;
|
key name;
|
||||||
leaf name {
|
leaf name {
|
||||||
type string;
|
type string;
|
||||||
}
|
}
|
||||||
leaf type {
|
leaf type {
|
||||||
type string;
|
type string;
|
||||||
|
/* add rule adds default here */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
# Args:
|
||||||
|
# 0: daytime implemented: true/false
|
||||||
|
# 1: admin type default: true/false
|
||||||
|
function testrun()
|
||||||
|
{
|
||||||
|
daytime=$1
|
||||||
|
admindefault=$2
|
||||||
|
|
||||||
|
new "test params: -f $cfg"
|
||||||
|
|
||||||
|
if [ "$BE" -ne 0 ]; then
|
||||||
|
new "kill old backend"
|
||||||
|
sudo clixon_backend -zf "$cfg"
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
err
|
||||||
|
fi
|
||||||
|
new "start backend -s init -f $cfg"
|
||||||
|
start_backend -s init -f "$cfg"
|
||||||
|
fi
|
||||||
|
|
||||||
|
new "wait backend"
|
||||||
|
wait_backend
|
||||||
|
|
||||||
|
if ! $daytime; then # Not supported - dont continue
|
||||||
|
new "Add example-base daytime - should not be supported"
|
||||||
|
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><system xmlns=\"urn:example:base\"><daytime>Sept17</daytime></system></config></edit-config></rpc>]]>]]>" "<rpc-reply $DEFAULTNS><rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>daytime</bad-element></error-info><error-severity>error</error-severity><error-message>Failed to find YANG spec of XML node: daytime with parent: system in namespace: urn:example:base</error-message></rpc-error></rpc-reply>]]>]]"
|
||||||
|
else
|
||||||
|
new "Add example-base daytime - supported"
|
||||||
|
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><system xmlns=\"urn:example:base\"><daytime>Sept17</daytime></system></config></edit-config></rpc>]]>]]>" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]"
|
||||||
|
|
||||||
|
new "Add user bob"
|
||||||
|
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><system xmlns=\"urn:example:base\"><user><name>bob</name></user></system></config></edit-config></rpc>]]>]]>" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]"
|
||||||
|
|
||||||
|
new "netconf commit"
|
||||||
|
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
if $admindefault; then
|
||||||
|
new "Get type admin expected"
|
||||||
|
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><get-config><source><running/></source><filter type=\"xpath\" select=\"/base:system/base:user[base:name='bob']\" xmlns:base=\"urn:example:base\"/></get-config></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><data><system xmlns=\"urn:example:base\"><user><name>bob</name><type>admin</type></user></system></data></rpc-reply>]]>]]>$"
|
||||||
|
# XXX Cannot select a default value??
|
||||||
|
# expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><get-config><source><running/></source><filter type=\"xpath\" select=\"/base:system/base:user[base:name='bob']/base:type\" xmlns:base=\"urn:example:base\"/></get-config></rpc>]]>]]>" foo
|
||||||
|
else
|
||||||
|
new "Get type none expected"
|
||||||
|
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><get-config><source><running/></source><filter type=\"xpath\" select=\"/base:system/base:user[base:name='bob']/base:type\" xmlns:base=\"urn:example:base\"/></get-config></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><data/></rpc-reply>]]>]]>$"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [ "$BE" -ne 0 ]; then
|
||||||
|
new "Kill backend"
|
||||||
|
# Check if premature kill
|
||||||
|
pid=$(pgrep -u root -f clixon_backend)
|
||||||
|
if [ -z "$pid" ]; then
|
||||||
|
err "backend already dead"
|
||||||
|
fi
|
||||||
|
# kill backend
|
||||||
|
stop_backend -f "$cfg"
|
||||||
|
fi
|
||||||
|
} # testrun
|
||||||
|
|
||||||
# Example from RFC 7950 Sec 7.20.3.3
|
# Example from RFC 7950 Sec 7.20.3.3
|
||||||
cat <<EOF > $fyangdev
|
cat <<EOF > $fyangdev
|
||||||
module $APPNAME{
|
module example-deviations{
|
||||||
yang-version 1.1;
|
yang-version 1.1;
|
||||||
prefix md;
|
prefix md;
|
||||||
namespace "urn:example:deviations";
|
namespace "urn:example:deviations";
|
||||||
|
|
||||||
import example-base {
|
import example-base {
|
||||||
prefix base;
|
prefix base;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
new "daytime supported"
|
||||||
|
testrun true false
|
||||||
|
|
||||||
|
# Example from RFC 7950 Sec 7.20.3.3
|
||||||
|
cat <<EOF > $fyangdev
|
||||||
|
module example-deviations{
|
||||||
|
yang-version 1.1;
|
||||||
|
prefix md;
|
||||||
|
namespace "urn:example:deviations";
|
||||||
|
import example-base {
|
||||||
|
prefix base;
|
||||||
|
}
|
||||||
deviation /base:system/base:daytime {
|
deviation /base:system/base:daytime {
|
||||||
deviate not-supported;
|
deviate not-supported;
|
||||||
}
|
|
||||||
deviation /base:system/base:user/base:type {
|
|
||||||
deviate add {
|
|
||||||
default "admin"; // new users are 'admin' by default
|
|
||||||
}
|
|
||||||
}
|
|
||||||
deviation /base:system {
|
|
||||||
deviate delete {
|
|
||||||
must "daytime or time";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
new "daytime not supported"
|
||||||
|
testrun false false
|
||||||
|
|
||||||
new "test params: -f $cfg"
|
# Example from RFC 7950 Sec 7.20.3.3
|
||||||
|
cat <<EOF > $fyangdev
|
||||||
if [ "$BE" -ne 0 ]; then
|
module example-deviations{
|
||||||
new "kill old backend"
|
yang-version 1.1;
|
||||||
sudo clixon_backend -zf "$cfg"
|
prefix md;
|
||||||
if [ $? -ne 0 ]; then
|
namespace "urn:example:deviations";
|
||||||
err
|
import example-base {
|
||||||
fi
|
prefix base;
|
||||||
new "start backend -s init -f $cfg"
|
}
|
||||||
start_backend -s init -f "$cfg"
|
deviation /base:system/base:user/base:type {
|
||||||
|
deviate add {
|
||||||
new "waiting"
|
default "admin"; // new users are 'admin' by default
|
||||||
wait_backend
|
}
|
||||||
fi
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
if [ "$BE" -eq 0 ]; then
|
new "deviate add, check admin default"
|
||||||
exit # BE
|
testrun true true
|
||||||
fi
|
|
||||||
|
|
||||||
new "Kill backend"
|
|
||||||
# Check if premature kill
|
|
||||||
pid=$(pgrep -u root -f clixon_backend)
|
|
||||||
if [ -z "$pid" ]; then
|
|
||||||
err "backend already dead"
|
|
||||||
fi
|
|
||||||
# kill backend
|
|
||||||
stop_backend -f "$cfg"
|
|
||||||
|
|
||||||
rm -rf "$dir"
|
rm -rf "$dir"
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue