Resolved conflict.
This commit is contained in:
commit
9ce20ea449
17 changed files with 310 additions and 40 deletions
|
|
@ -82,6 +82,7 @@ Developers may need to change their code
|
||||||
|
|
||||||
### Corrected Bugs
|
### Corrected Bugs
|
||||||
|
|
||||||
|
* [cl:autocli-op hide has no effect in yang submodule](https://github.com/clicon/clixon/issues/282)
|
||||||
* [Doxygen - Typo in Input #275](https://github.com/clicon/clixon/issues/275)
|
* [Doxygen - Typo in Input #275](https://github.com/clicon/clixon/issues/275)
|
||||||
|
|
||||||
## 5.3.0
|
## 5.3.0
|
||||||
|
|
@ -105,7 +106,7 @@ The 5.3 release has pagination support, Linkref changes in validation and auto-c
|
||||||
* Updated state callback signature containing parameters for pagination
|
* Updated state callback signature containing parameters for pagination
|
||||||
* See API changes below
|
* See API changes below
|
||||||
* Work-in-progress
|
* Work-in-progress
|
||||||
* Enable remaining attriute with LIST_PAGINATION_REMAINING compile-time option
|
* Enable remaining attribute with LIST_PAGINATION_REMAINING compile-time option
|
||||||
* sort/direction/where etc not supported
|
* sort/direction/where etc not supported
|
||||||
* For documentation: [User manual pagination](https://clixon-docs.readthedocs.io/en/latest/misc.html#pagination)
|
* For documentation: [User manual pagination](https://clixon-docs.readthedocs.io/en/latest/misc.html#pagination)
|
||||||
* YANG Leafref feature update
|
* YANG Leafref feature update
|
||||||
|
|
|
||||||
|
|
@ -353,7 +353,7 @@ cli_xml2cli(cxobj *xn,
|
||||||
yang_keyword_get(ys) == Y_LEAF_LIST){
|
yang_keyword_get(ys) == Y_LEAF_LIST){
|
||||||
if (prepend)
|
if (prepend)
|
||||||
(*fn)(stdout, "%s", prepend);
|
(*fn)(stdout, "%s", prepend);
|
||||||
if (gt == GT_ALL || gt == GT_VARS || gt == GT_HIDE)
|
if (gt == GT_ALL || gt == GT_VARS || gt == GT_HIDE || gt == GT_OC_COMPRESS)
|
||||||
(*fn)(stdout, "%s ", xml_name(xn));
|
(*fn)(stdout, "%s ", xml_name(xn));
|
||||||
if ((body = xml_body(xn)) != NULL){
|
if ((body = xml_body(xn)) != NULL){
|
||||||
if (index(body, ' '))
|
if (index(body, ' '))
|
||||||
|
|
|
||||||
|
|
@ -764,7 +764,7 @@ yang2cli_leaf(clicon_handle h,
|
||||||
/* Look for autocli-op defined in clixon-lib.yang */
|
/* Look for autocli-op defined in clixon-lib.yang */
|
||||||
if (yang_extension_value(ys, "autocli-op", CLIXON_LIB_NS, NULL, &opext) < 0)
|
if (yang_extension_value(ys, "autocli-op", CLIXON_LIB_NS, NULL, &opext) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (gt == GT_VARS|| gt == GT_ALL || gt == GT_HIDE){
|
if (gt == GT_VARS || gt == GT_ALL || gt == GT_HIDE || gt == GT_OC_COMPRESS){
|
||||||
cprintf(cb, "%s", yang_argument_get(ys));
|
cprintf(cb, "%s", yang_argument_get(ys));
|
||||||
yang2cli_helptext(cb, helptext);
|
yang2cli_helptext(cb, helptext);
|
||||||
cprintf(cb, " ");
|
cprintf(cb, " ");
|
||||||
|
|
@ -833,13 +833,27 @@ yang2cli_container(clicon_handle h,
|
||||||
char *helptext = NULL;
|
char *helptext = NULL;
|
||||||
char *s;
|
char *s;
|
||||||
int hide = 0;
|
int hide = 0;
|
||||||
|
int hide_oc = 0;
|
||||||
|
int exist = 0;
|
||||||
char *opext = NULL;
|
char *opext = NULL;
|
||||||
|
yang_stmt *ymod = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
if (ys_real_module(ys, &ymod) < 0)
|
||||||
|
goto done;
|
||||||
|
if (yang_extension_value(ymod, "openconfig-version", "http://openconfig.net/yang/openconfig-ext", &exist, NULL) < 0)
|
||||||
|
goto done;
|
||||||
|
if (exist) {
|
||||||
|
if (strcmp(yang_argument_get(ys), "config") == 0){
|
||||||
|
hide_oc = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If non-presence container && HIDE mode && only child is
|
/* If non-presence container && HIDE mode && only child is
|
||||||
* a list, then skip container keyword
|
* a list, then skip container keyword
|
||||||
* See also xml2cli
|
* See also xml2cli
|
||||||
*/
|
*/
|
||||||
if ((hide = yang_container_cli_hide(ys, gt)) == 0){
|
if ((hide = yang_container_cli_hide(ys, gt)) == 0 && hide_oc == 0){
|
||||||
cprintf(cb, "%*s%s", level*3, "", yang_argument_get(ys));
|
cprintf(cb, "%*s%s", level*3, "", yang_argument_get(ys));
|
||||||
if ((yd = yang_find(ys, Y_DESCRIPTION, NULL)) != NULL){
|
if ((yd = yang_find(ys, Y_DESCRIPTION, NULL)) != NULL){
|
||||||
if ((helptext = strdup(yang_argument_get(yd))) == NULL){
|
if ((helptext = strdup(yang_argument_get(yd))) == NULL){
|
||||||
|
|
@ -868,10 +882,10 @@ yang2cli_container(clicon_handle h,
|
||||||
yc = NULL;
|
yc = NULL;
|
||||||
while ((yc = yn_each(ys, yc)) != NULL)
|
while ((yc = yn_each(ys, yc)) != NULL)
|
||||||
if (yang2cli_stmt(h, yc, gt, level+1, state, show_tree, cb) < 0)
|
if (yang2cli_stmt(h, yc, gt, level+1, state, show_tree, cb) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (hide == 0)
|
if (hide == 0 && hide_oc == 0)
|
||||||
cprintf(cb, "%*s}\n", level*3, "");
|
cprintf(cb, "%*s}\n", level*3, "");
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (helptext)
|
if (helptext)
|
||||||
free(helptext);
|
free(helptext);
|
||||||
|
|
@ -956,7 +970,7 @@ yang2cli_list(clicon_handle h,
|
||||||
cprintf(cb, "{\n");
|
cprintf(cb, "{\n");
|
||||||
}
|
}
|
||||||
if (yang2cli_leaf(h, yleaf,
|
if (yang2cli_leaf(h, yleaf,
|
||||||
(gt==GT_VARS||gt==GT_HIDE)?GT_NONE:gt, level+1,
|
(gt==GT_VARS||gt==GT_HIDE||gt==GT_OC_COMPRESS)?GT_NONE:gt, level+1,
|
||||||
last_key, show_tree, 1,
|
last_key, show_tree, 1,
|
||||||
cb) < 0)
|
cb) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -620,7 +620,7 @@ main(int argc,
|
||||||
Should be 0 but default is 1 since all legacy apps use 1
|
Should be 0 but default is 1 since all legacy apps use 1
|
||||||
Test legacy before shifting default to 0
|
Test legacy before shifting default to 0
|
||||||
*/
|
*/
|
||||||
cv_exclude_keys(clicon_cli_varonly(h));
|
cligen_exclude_keys_set(cli_cligen(h), clicon_cli_varonly(h));
|
||||||
|
|
||||||
/* Initialize plugin module by creating a handle holding plugin and callback lists */
|
/* Initialize plugin module by creating a handle holding plugin and callback lists */
|
||||||
if (clixon_plugin_module_init(h) < 0)
|
if (clixon_plugin_module_init(h) < 0)
|
||||||
|
|
|
||||||
|
|
@ -525,34 +525,50 @@ cli_handler_err(FILE *f)
|
||||||
/*! Variant of eval for context checking
|
/*! Variant of eval for context checking
|
||||||
* @see cligen_eval
|
* @see cligen_eval
|
||||||
*/
|
*/
|
||||||
int
|
static int
|
||||||
cligen_clixon_eval(cligen_handle h,
|
clixon_cligen_eval(cligen_handle h,
|
||||||
cg_obj *co,
|
cg_obj *co,
|
||||||
cvec *cvv)
|
cvec *cvv)
|
||||||
{
|
{
|
||||||
struct cg_callback *cc;
|
struct cg_callback *cc;
|
||||||
int retval = 0;
|
int retval = -1;
|
||||||
cvec *argv;
|
cvec *argv;
|
||||||
plugin_context_t *pc = NULL;
|
cvec *cvv1 = NULL; /* Modified */
|
||||||
|
plugin_context_t *pc = NULL; /* Clixon-specific */
|
||||||
|
|
||||||
|
|
||||||
|
/* Save matched object for plugin use */
|
||||||
if (h)
|
if (h)
|
||||||
cligen_co_match_set(h, co);
|
cligen_co_match_set(h, co);
|
||||||
|
/* Make a copy of var argument for modifications */
|
||||||
|
if ((cvv1 = cvec_dup(cvv)) == NULL)
|
||||||
|
goto done;
|
||||||
|
/* Make modifications to cvv */
|
||||||
|
if (cligen_expand_first_get(h) &&
|
||||||
|
cvec_expand_first(cvv1) < 0)
|
||||||
|
goto done;
|
||||||
|
if (cligen_exclude_keys_get(h) &&
|
||||||
|
cvec_exclude_keys(cvv1) < 0)
|
||||||
|
goto done;
|
||||||
|
/* Traverse callbacks */
|
||||||
for (cc = co->co_callbacks; cc; cc=cc->cc_next){
|
for (cc = co->co_callbacks; cc; cc=cc->cc_next){
|
||||||
/* Vector cvec argument to callback */
|
/* Vector cvec argument to callback */
|
||||||
if (cc->cc_fn_vec){
|
if (cc->cc_fn_vec){
|
||||||
argv = cc->cc_cvec ? cvec_dup(cc->cc_cvec) : NULL;
|
argv = cc->cc_cvec ? cvec_dup(cc->cc_cvec) : NULL;
|
||||||
cligen_fn_str_set(h, cc->cc_fn_str);
|
cligen_fn_str_set(h, cc->cc_fn_str);
|
||||||
if ((pc = plugin_context_get()) == NULL)
|
/* Clixon-specific */
|
||||||
|
if ((pc = plugin_context_get()) == NULL)
|
||||||
break;
|
break;
|
||||||
if ((retval = (*cc->cc_fn_vec)(
|
if ((retval = (*cc->cc_fn_vec)(
|
||||||
cligen_userhandle(h)?cligen_userhandle(h):h,
|
cligen_userhandle(h)?cligen_userhandle(h):h,
|
||||||
cvv,
|
cvv1,
|
||||||
argv)) < 0){
|
argv)) < 0){
|
||||||
if (argv != NULL)
|
if (argv != NULL)
|
||||||
cvec_free(argv);
|
cvec_free(argv);
|
||||||
cligen_fn_str_set(h, NULL);
|
cligen_fn_str_set(h, NULL);
|
||||||
break;
|
goto done;
|
||||||
}
|
}
|
||||||
|
/* Clixon-specific */
|
||||||
if (plugin_context_check(pc, "CLIgen", cc->cc_fn_str) < 0)
|
if (plugin_context_check(pc, "CLIgen", cc->cc_fn_str) < 0)
|
||||||
break;
|
break;
|
||||||
if (pc){
|
if (pc){
|
||||||
|
|
@ -564,8 +580,12 @@ cligen_clixon_eval(cligen_handle h,
|
||||||
cligen_fn_str_set(h, NULL);
|
cligen_fn_str_set(h, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pc)
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (pc) /* Clixon-specific */
|
||||||
free(pc);
|
free(pc);
|
||||||
|
if (cvv1)
|
||||||
|
cvec_free(cvv1);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -589,7 +609,7 @@ clicon_eval(clicon_handle h,
|
||||||
if (!cligen_exiting(cli_cligen(h))) {
|
if (!cligen_exiting(cli_cligen(h))) {
|
||||||
clicon_err_reset();
|
clicon_err_reset();
|
||||||
|
|
||||||
if ((retval = cligen_clixon_eval(cli_cligen(h), match_obj, cvv)) < 0) {
|
if ((retval = clixon_cligen_eval(cli_cligen(h), match_obj, cvv)) < 0) {
|
||||||
#if 0 /* This is removed since we get two error messages on failure.
|
#if 0 /* This is removed since we get two error messages on failure.
|
||||||
But maybe only sometime?
|
But maybe only sometime?
|
||||||
Both a real log when clicon_err is called, and the here again.
|
Both a real log when clicon_err is called, and the here again.
|
||||||
|
|
@ -631,7 +651,7 @@ clicon_parse(clicon_handle h,
|
||||||
cli_syntax_t *stx = NULL;
|
cli_syntax_t *stx = NULL;
|
||||||
cli_syntaxmode_t *csm;
|
cli_syntaxmode_t *csm;
|
||||||
parse_tree *pt; /* Orig */
|
parse_tree *pt; /* Orig */
|
||||||
cg_obj *match_obj;
|
cg_obj *match_obj = NULL;
|
||||||
cvec *cvv = NULL;
|
cvec *cvv = NULL;
|
||||||
FILE *f;
|
FILE *f;
|
||||||
char *reason = NULL;
|
char *reason = NULL;
|
||||||
|
|
@ -663,12 +683,15 @@ clicon_parse(clicon_handle h,
|
||||||
fprintf(stderr, "No such parse-tree registered: %s\n", modename);
|
fprintf(stderr, "No such parse-tree registered: %s\n", modename);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((cvv = cvec_new(0)) == NULL){
|
#if 0 // switch after 5.4
|
||||||
clicon_err(OE_UNIX, errno, "cvec_new");
|
if (cliread_parse2(cli_cligen(h), cmd, pt, &match_obj, &cvv, result, &reason) < 0)
|
||||||
|
goto done;
|
||||||
|
#else
|
||||||
|
if ((cvv = cvec_new(0)) == NULL)
|
||||||
goto done;;
|
goto done;;
|
||||||
}
|
|
||||||
if (cliread_parse(cli_cligen(h), cmd, pt, &match_obj, cvv, result, &reason) < 0)
|
if (cliread_parse(cli_cligen(h), cmd, pt, &match_obj, cvv, result, &reason) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
#endif
|
||||||
/* Debug command and result code */
|
/* Debug command and result code */
|
||||||
clicon_debug(1, "%s result:%d command: \"%s\"", __FUNCTION__, *result, cmd);
|
clicon_debug(1, "%s result:%d command: \"%s\"", __FUNCTION__, *result, cmd);
|
||||||
if (*result != CG_MATCH)
|
if (*result != CG_MATCH)
|
||||||
|
|
@ -708,6 +731,8 @@ done:
|
||||||
free(reason);
|
free(reason);
|
||||||
if (cvv)
|
if (cvv)
|
||||||
cvec_free(cvv);
|
cvec_free(cvv);
|
||||||
|
if (match_obj)
|
||||||
|
co_free(match_obj, 0);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,7 @@ enum genmodel_type{
|
||||||
GT_VARS, /* Keywords on non-key variables */
|
GT_VARS, /* Keywords on non-key variables */
|
||||||
GT_ALL, /* Keywords on all variables */
|
GT_ALL, /* Keywords on all variables */
|
||||||
GT_HIDE, /* Keywords on all variables and hide container around lists */
|
GT_HIDE, /* Keywords on all variables and hide container around lists */
|
||||||
|
GT_OC_COMPRESS, /* OpenConfig */
|
||||||
};
|
};
|
||||||
typedef enum genmodel_type genmodel_type;
|
typedef enum genmodel_type genmodel_type;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -223,12 +223,27 @@ json_current_clone(clixon_json_yacc *jy)
|
||||||
|
|
||||||
clicon_debug(2, "%s", __FUNCTION__);
|
clicon_debug(2, "%s", __FUNCTION__);
|
||||||
if (jy->jy_current == NULL){
|
if (jy->jy_current == NULL){
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
xn = jy->jy_current;
|
xn = jy->jy_current;
|
||||||
json_current_pop(jy);
|
json_current_pop(jy);
|
||||||
if (jy->jy_current)
|
|
||||||
json_current_new(jy, xml_name(xn));
|
if (jy->jy_current) {
|
||||||
|
char* name = xml_name(xn);
|
||||||
|
char* prefix = xml_prefix(xn);
|
||||||
|
char* maybe_prefixed_name = NULL;
|
||||||
|
|
||||||
|
if (prefix) {
|
||||||
|
char* name_parts[] = {prefix, name};
|
||||||
|
maybe_prefixed_name = clicon_strjoin(2, name_parts, ":");
|
||||||
|
} else {
|
||||||
|
maybe_prefixed_name = strdup(name);
|
||||||
|
}
|
||||||
|
json_current_new(jy, maybe_prefixed_name);
|
||||||
|
|
||||||
|
if (maybe_prefixed_name)
|
||||||
|
free(maybe_prefixed_name);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,7 @@ static const map_str2int cli_genmodel_map[] = {
|
||||||
{"VARS", GT_VARS},
|
{"VARS", GT_VARS},
|
||||||
{"ALL", GT_ALL},
|
{"ALL", GT_ALL},
|
||||||
{"HIDE", GT_HIDE},
|
{"HIDE", GT_HIDE},
|
||||||
|
{"OC_COMPRESS", GT_OC_COMPRESS},
|
||||||
{NULL, -1}
|
{NULL, -1}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -156,7 +156,7 @@ clixon_signal_restore(sigset_t *sigset,
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (sigprocmask(0, sigset, NULL) < 0){
|
if (sigprocmask(SIG_SETMASK, sigset, NULL) < 0){
|
||||||
clicon_err(OE_UNIX, errno, "sigprocmask");
|
clicon_err(OE_UNIX, errno, "sigprocmask");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -581,10 +581,11 @@ xml_parent(cxobj *xn)
|
||||||
return xn->x_up;
|
return xn->x_up;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Set parent of xnode, parent is copied.
|
/*! Set parent of xml node.
|
||||||
* @param[in] xn xml node
|
* @param[in] xn xml node
|
||||||
* @param[in] parent pointer to new parent xml node
|
* @param[in] parent pointer to new parent xml node
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
|
* @see xml_child_rm remove child from parent
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xml_parent_set(cxobj *xn,
|
xml_parent_set(cxobj *xn,
|
||||||
|
|
@ -1986,8 +1987,6 @@ xml_copy(cxobj *x0,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*! Create and return a copy of xml tree.
|
/*! Create and return a copy of xml tree.
|
||||||
*
|
*
|
||||||
* @code
|
* @code
|
||||||
|
|
|
||||||
|
|
@ -286,7 +286,7 @@ xml2cli_recurse(FILE *f,
|
||||||
/* If presence container, then print as leaf (but continue to children) */
|
/* If presence container, then print as leaf (but continue to children) */
|
||||||
if (prepend)
|
if (prepend)
|
||||||
(*fn)(f, "%s", prepend);
|
(*fn)(f, "%s", prepend);
|
||||||
if (gt == GT_ALL || gt == GT_VARS || gt == GT_HIDE)
|
if (gt == GT_ALL || gt == GT_VARS || gt == GT_HIDE || gt == GT_OC_COMPRESS)
|
||||||
(*fn)(f, "%s ", xml_name(x));
|
(*fn)(f, "%s ", xml_name(x));
|
||||||
if ((body = xml_body(x)) != NULL){
|
if ((body = xml_body(x)) != NULL){
|
||||||
if (index(body, ' '))
|
if (index(body, ' '))
|
||||||
|
|
|
||||||
|
|
@ -2355,6 +2355,14 @@ ys_populate_unique(clicon_handle h,
|
||||||
* RFC 7950 Sec 7.19:
|
* RFC 7950 Sec 7.19:
|
||||||
* If no "argument" statement is present, the keyword expects no argument when
|
* If no "argument" statement is present, the keyword expects no argument when
|
||||||
* it is used.
|
* it is used.
|
||||||
|
* Note there is some complexity in different yang modules with unknown-statements.
|
||||||
|
* y0) The location of the extension definition. E.g. extension autocli-op
|
||||||
|
* y1) The location of the unknown-statement (ys). This is for example: cl:autocli-op hide.
|
||||||
|
* Lookup of "cl" is lexically scoped in this context (to find (y0)).
|
||||||
|
* y2) The unknown statement may be used by uses/grouping of (y1). But "cl" is declared
|
||||||
|
* in y1 context. This is fixed by setting ys_mymodule to y1 which is then used in
|
||||||
|
* lookups such as in yang_extension_value().
|
||||||
|
* @see yang_extension_value Called on expanded YANG, eg in context of (y2)
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
ys_populate_unknown(clicon_handle h,
|
ys_populate_unknown(clicon_handle h,
|
||||||
|
|
@ -2376,6 +2384,8 @@ ys_populate_unknown(clicon_handle h,
|
||||||
clicon_err(OE_YANG, ENOENT, "Extension \"%s:%s\", module not found", prefix, id);
|
clicon_err(OE_YANG, ENOENT, "Extension \"%s:%s\", module not found", prefix, id);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
/* To find right binding eg after grouping/uses */
|
||||||
|
ys->ys_mymodule = ys_module(ys);
|
||||||
if ((yext = yang_find(ymod, Y_EXTENSION, id)) == NULL){
|
if ((yext = yang_find(ymod, Y_EXTENSION, id)) == NULL){
|
||||||
clicon_err(OE_YANG, ENOENT, "Extension \"%s:%s\" not found", prefix, id);
|
clicon_err(OE_YANG, ENOENT, "Extension \"%s:%s\" not found", prefix, id);
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -3255,7 +3265,7 @@ yang_container_cli_hide(yang_stmt *ys,
|
||||||
|
|
||||||
keyw = yang_keyword_get(ys);
|
keyw = yang_keyword_get(ys);
|
||||||
/* HIDE mode */
|
/* HIDE mode */
|
||||||
if (gt != GT_HIDE)
|
if (gt != GT_HIDE && gt != GT_OC_COMPRESS)
|
||||||
return 0;
|
return 0;
|
||||||
/* A container */
|
/* A container */
|
||||||
if (yang_keyword_get(ys) != Y_CONTAINER)
|
if (yang_keyword_get(ys) != Y_CONTAINER)
|
||||||
|
|
@ -3572,6 +3582,7 @@ yang_anydata_add(yang_stmt *yp,
|
||||||
* // use extension value
|
* // use extension value
|
||||||
* }
|
* }
|
||||||
* @endcode
|
* @endcode
|
||||||
|
* @see ys_populate_unknown Called when parsing YANGo
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
yang_extension_value(yang_stmt *ys,
|
yang_extension_value(yang_stmt *ys,
|
||||||
|
|
|
||||||
|
|
@ -71,9 +71,13 @@ struct yang_stmt{
|
||||||
|
|
||||||
char *ys_argument; /* String / argument depending on keyword */
|
char *ys_argument; /* String / argument depending on keyword */
|
||||||
uint16_t ys_flags; /* Flags according to YANG_FLAG_MARK and others */
|
uint16_t ys_flags; /* Flags according to YANG_FLAG_MARK and others */
|
||||||
yang_stmt *ys_mymodule; /* Shortcut to "my" module. Augmented
|
yang_stmt *ys_mymodule; /* Shortcut to "my" module. Used by:
|
||||||
nodes can belong to other
|
1) Augmented nodes "belong" to the module where the
|
||||||
modules than the ancestor module */
|
augment is declared, which may be differnt from
|
||||||
|
the direct ancestor module
|
||||||
|
2) Unknown nodes "belong" to where the extension is
|
||||||
|
declared
|
||||||
|
*/
|
||||||
cg_var *ys_cv; /* cligen variable. See ys_populate()
|
cg_var *ys_cv; /* cligen variable. See ys_populate()
|
||||||
Following stmts have cv:s:
|
Following stmts have cv:s:
|
||||||
leaf: for default value
|
leaf: for default value
|
||||||
|
|
|
||||||
|
|
@ -185,6 +185,18 @@ module example-augment {
|
||||||
type string;
|
type string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* augment a list */
|
||||||
|
augment "/if:interfaces" {
|
||||||
|
list ports{
|
||||||
|
key id;
|
||||||
|
leaf id {
|
||||||
|
type int32;
|
||||||
|
}
|
||||||
|
leaf str {
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
|
|
@ -291,6 +303,30 @@ expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/ietf-inte
|
||||||
new "restconf GET augment multi-namespace cross level 2"
|
new "restconf GET augment multi-namespace cross level 2"
|
||||||
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces/interface=e1/example-augment:ospf/reference-bandwidth)" 0 "HTTP/$HVER 200" '{"example-augment:reference-bandwidth":23}'
|
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces/interface=e1/example-augment:ospf/reference-bandwidth)" 0 "HTTP/$HVER 200" '{"example-augment:reference-bandwidth":23}'
|
||||||
|
|
||||||
|
new "delete interfaces"
|
||||||
|
expectpart "$(curl $CURLOPTS -X DELETE $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces)" 0 "HTTP/$HVER 204"
|
||||||
|
|
||||||
|
# augmented lists
|
||||||
|
XML="<interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\"><mymod:ports xmlns:mymod=\"urn:example:augment\"><mymod:id>22</mymod:id><mymod:str>nisse</mymod:str></mymod:ports><mymod:ports xmlns:mymod=\"urn:example:augment\"><mymod:id>44</mymod:id><mymod:str>kalle</mymod:str></mymod:ports></interfaces>"
|
||||||
|
new "netconf PUT augmented list"
|
||||||
|
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><edit-config><default-operation>merge</default-operation><target><candidate/></target><config>$XML</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>]]>]]>$"
|
||||||
|
|
||||||
|
new "netconf get config"
|
||||||
|
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><get-config><source><running/></source></get-config></rpc>]]>]]>" "<rpc-reply $DEFAULTNS><data>$XML</data></rpc-reply>]]>]]>"
|
||||||
|
|
||||||
|
JSON='{"ietf-interfaces:interfaces":{"example-augment:ports":[{"id":22,"str":"foo"},{"id":44,"str":"bar"}]}}'
|
||||||
|
|
||||||
|
new "restconf PUT augmented list"
|
||||||
|
expectpart "$(curl $CURLOPTS -X PUT -H 'Content-Type: application/yang-data+json' $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces -d "$JSON")" 0 "HTTP/$HVER 204"
|
||||||
|
|
||||||
|
# Escaped [] why?
|
||||||
|
JSON1='{"ietf-interfaces:interfaces":{"example-augment:ports":\[{"id":22,"str":"foo"},{"id":44,"str":"bar"}\]}}'
|
||||||
|
new "restconf GET augmented list"
|
||||||
|
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+json' $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces)" 0 "HTTP/$HVER 200" "$JSON1"
|
||||||
|
|
||||||
if [ $RC -ne 0 ]; then
|
if [ $RC -ne 0 ]; then
|
||||||
new "Kill restconf daemon"
|
new "Kill restconf daemon"
|
||||||
stop_restconf
|
stop_restconf
|
||||||
|
|
|
||||||
|
|
@ -136,7 +136,6 @@ wait_backend
|
||||||
|
|
||||||
function testparam()
|
function testparam()
|
||||||
{
|
{
|
||||||
|
|
||||||
# Try hidden parameter list
|
# Try hidden parameter list
|
||||||
new "query table parameter hidden"
|
new "query table parameter hidden"
|
||||||
expectpart "$(echo "set table ?" | $clixon_cli -f $cfg 2>&1)" 0 "set table" "<cr>" --not-- "parameter"
|
expectpart "$(echo "set table ?" | $clixon_cli -f $cfg 2>&1)" 0 "set table" "<cr>" --not-- "parameter"
|
||||||
|
|
@ -282,6 +281,60 @@ EOF
|
||||||
new "Test hidden parameter in table/param/value augment"
|
new "Test hidden parameter in table/param/value augment"
|
||||||
testvalue
|
testvalue
|
||||||
|
|
||||||
|
# Example using imported module where clixon-lib is NOT declared in main module
|
||||||
|
# see discussion in ys_populate_unknown (y1 vs y2) and
|
||||||
|
# https://github.com/clicon/clixon/issues/282
|
||||||
|
cat <<EOF > $fyang
|
||||||
|
module example {
|
||||||
|
yang-version 1.1;
|
||||||
|
namespace "urn:example:clixon";
|
||||||
|
prefix ex;
|
||||||
|
import example-augment{
|
||||||
|
prefix aug;
|
||||||
|
}
|
||||||
|
|
||||||
|
container table{
|
||||||
|
list parameter{
|
||||||
|
key name;
|
||||||
|
leaf name{
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
uses aug:pg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Use this as grouping (not annotate)
|
||||||
|
cat <<EOF > $fyang2
|
||||||
|
module example-augment {
|
||||||
|
namespace "urn:example:augment";
|
||||||
|
prefix aug;
|
||||||
|
import clixon-lib{
|
||||||
|
prefix cl;
|
||||||
|
}
|
||||||
|
grouping pg {
|
||||||
|
cl:autocli-op hide; /* This is the extension */
|
||||||
|
leaf value{
|
||||||
|
description "a value";
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
list index{
|
||||||
|
key i;
|
||||||
|
leaf i{
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
leaf iv{
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
new "Test hidden parameter in imported module"
|
||||||
|
testparam
|
||||||
|
|
||||||
new "Kill backend"
|
new "Kill backend"
|
||||||
# Check if premature kill
|
# Check if premature kill
|
||||||
pid=$(pgrep -u root -f clixon_backend)
|
pid=$(pgrep -u root -f clixon_backend)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
|
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Tests for using the auto cli.
|
# Tests for using the auto cli.
|
||||||
# In particular setting a config, displaying as cli commands and reconfigure it
|
# In particular setting a config, displaying as cli commands and reconfigure it
|
||||||
# Tests:
|
# Tests:
|
||||||
# Make a config in CLI. Show output as CLI, save it and ensure it is the same
|
# Make a config in CLI. Show output as CLI, save it and ensure it is the same
|
||||||
# Try the different GENMODEL settings
|
# Try the different GENMODEL settings
|
||||||
|
|
@ -15,6 +16,7 @@ APPNAME=example
|
||||||
|
|
||||||
cfg=$dir/conf_yang.xml
|
cfg=$dir/conf_yang.xml
|
||||||
fyang=$dir/$APPNAME.yang
|
fyang=$dir/$APPNAME.yang
|
||||||
|
fyang2=$dir/${APPNAME}2.yang
|
||||||
fstate=$dir/state.xml
|
fstate=$dir/state.xml
|
||||||
clidir=$dir/cli
|
clidir=$dir/cli
|
||||||
if [ -d $clidir ]; then
|
if [ -d $clidir ]; then
|
||||||
|
|
@ -25,12 +27,19 @@ fi
|
||||||
|
|
||||||
# Use yang in example
|
# Use yang in example
|
||||||
|
|
||||||
|
if [ ! -d "$OPENCONFIG" ]; then
|
||||||
|
# err "Hmm Openconfig dir does not seem to exist, try git clone https://github.com/openconfig/public?"
|
||||||
|
echo "...skipped: OPENCONFIG not set"
|
||||||
|
if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||||
|
fi
|
||||||
|
|
||||||
cat <<EOF > $cfg
|
cat <<EOF > $cfg
|
||||||
<clixon-config xmlns="http://clicon.org/config">
|
<clixon-config xmlns="http://clicon.org/config">
|
||||||
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
|
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
|
||||||
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
|
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
|
||||||
<CLICON_YANG_DIR>$dir_tmp</CLICON_YANG_DIR>
|
<CLICON_YANG_DIR>$dir_tmp</CLICON_YANG_DIR>
|
||||||
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
|
<CLICON_YANG_DIR>$OPENCONFIG/</CLICON_YANG_DIR>
|
||||||
|
<CLICON_YANG_MAIN_DIR>$dir</CLICON_YANG_MAIN_DIR>
|
||||||
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
|
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
|
||||||
<CLICON_CLISPEC_DIR>$clidir</CLICON_CLISPEC_DIR>
|
<CLICON_CLISPEC_DIR>$clidir</CLICON_CLISPEC_DIR>
|
||||||
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
|
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
|
||||||
|
|
@ -49,6 +58,9 @@ cat <<EOF > $fyang
|
||||||
module $APPNAME {
|
module $APPNAME {
|
||||||
namespace "urn:example:clixon";
|
namespace "urn:example:clixon";
|
||||||
prefix ex;
|
prefix ex;
|
||||||
|
import openconfig-extensions { prefix oc-ext; }
|
||||||
|
/* Set openconfig version to "fake" an openconfig YANG */
|
||||||
|
oc-ext:openconfig-version;
|
||||||
container table{
|
container table{
|
||||||
list parameter{
|
list parameter{
|
||||||
key name;
|
key name;
|
||||||
|
|
@ -69,6 +81,85 @@ module $APPNAME {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
container interfaces {
|
||||||
|
list interface {
|
||||||
|
key name;
|
||||||
|
leaf name {
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
container config {
|
||||||
|
leaf enabled {
|
||||||
|
type boolean;
|
||||||
|
default false;
|
||||||
|
description "Whether the interface is enabled or not.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
container state {
|
||||||
|
config false;
|
||||||
|
leaf oper-status {
|
||||||
|
type enumeration {
|
||||||
|
enum UP {
|
||||||
|
value 1;
|
||||||
|
description "Ready to pass packets.";
|
||||||
|
}
|
||||||
|
enum DOWN {
|
||||||
|
value 2;
|
||||||
|
description "The interface does not pass any packets.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
leaf enabled {
|
||||||
|
type boolean;
|
||||||
|
default false;
|
||||||
|
description "Whether the interface is enabled or not.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# For openconfig but NO openconfig extension
|
||||||
|
cat <<EOF > $fyang2
|
||||||
|
module ${APPNAME}2 {
|
||||||
|
namespace "urn:example:clixon2";
|
||||||
|
prefix ex2;
|
||||||
|
import openconfig-extensions { prefix oc-ext; }
|
||||||
|
container interfaces2 {
|
||||||
|
list interface {
|
||||||
|
key name;
|
||||||
|
leaf name {
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
container config {
|
||||||
|
leaf enabled {
|
||||||
|
type boolean;
|
||||||
|
default false;
|
||||||
|
description "Whether the interface is enabled or not.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
container state {
|
||||||
|
config false;
|
||||||
|
leaf oper-status {
|
||||||
|
type enumeration {
|
||||||
|
enum UP {
|
||||||
|
value 1;
|
||||||
|
description "Ready to pass packets.";
|
||||||
|
}
|
||||||
|
enum DOWN {
|
||||||
|
value 2;
|
||||||
|
description "The interface does not pass any packets.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
leaf enabled {
|
||||||
|
type boolean;
|
||||||
|
default false;
|
||||||
|
description "Whether the interface is enabled or not.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
|
@ -127,6 +218,9 @@ function testrun()
|
||||||
elif [ $mode = HIDE ]; then
|
elif [ $mode = HIDE ]; then
|
||||||
table=
|
table=
|
||||||
name=
|
name=
|
||||||
|
elif [ $mode = OC_COMPRESS ]; then
|
||||||
|
table=
|
||||||
|
name=
|
||||||
else
|
else
|
||||||
table=" table"
|
table=" table"
|
||||||
name=
|
name=
|
||||||
|
|
@ -159,7 +253,7 @@ SAVED=$($clixon_cli -1 -o CLICON_CLI_GENMODEL_TYPE=$mode -f $cfg show config)
|
||||||
new "delete a x"
|
new "delete a x"
|
||||||
expectpart "$($clixon_cli -1 -o CLICON_CLI_GENMODEL_TYPE=$mode -f $cfg delete$table parameter$name a value x)" 0 ""
|
expectpart "$($clixon_cli -1 -o CLICON_CLI_GENMODEL_TYPE=$mode -f $cfg delete$table parameter$name a value x)" 0 ""
|
||||||
|
|
||||||
new "show match a & b xml"
|
new "show match a & b xml"
|
||||||
expectpart "$($clixon_cli -1 -o CLICON_CLI_GENMODEL_TYPE=$mode -f $cfg show xml)" 0 "<table xmlns=\"urn:example:clixon\">" "<parameter>" "<name>a</name>" "</parameter>" "<parameter>" "<name>b</name>" "<value>z</value>" "</parameter>" "</table>" --not-- "<value>x</value>"
|
expectpart "$($clixon_cli -1 -o CLICON_CLI_GENMODEL_TYPE=$mode -f $cfg show xml)" 0 "<table xmlns=\"urn:example:clixon\">" "<parameter>" "<name>a</name>" "</parameter>" "<parameter>" "<name>b</name>" "<value>z</value>" "</parameter>" "</table>" --not-- "<value>x</value>"
|
||||||
|
|
||||||
new "delete a"
|
new "delete a"
|
||||||
|
|
@ -190,6 +284,9 @@ testrun HIDE
|
||||||
new "keywords=ALL"
|
new "keywords=ALL"
|
||||||
testrun ALL
|
testrun ALL
|
||||||
|
|
||||||
|
new "keywords=OC_COMPRESS"
|
||||||
|
testrun OC_COMPRESS
|
||||||
|
|
||||||
new "keywords=VARS"
|
new "keywords=VARS"
|
||||||
testrun VARS
|
testrun VARS
|
||||||
|
|
||||||
|
|
@ -201,11 +298,20 @@ new "commit"
|
||||||
expectpart "$($clixon_cli -1 -f $cfg commit)" 0 ""
|
expectpart "$($clixon_cli -1 -f $cfg commit)" 0 ""
|
||||||
|
|
||||||
new "show state"
|
new "show state"
|
||||||
expectpart "$($clixon_cli -1 -f $cfg show state)" 0 "exstate sender x" "table parameter a" "table parameter a value x"
|
expectpart "$($clixon_cli -1 -f $cfg show state)" 0 "exstate sender x" "table parameter a" "table parameter a value x"
|
||||||
|
|
||||||
new "show state exstate"
|
new "show state exstate"
|
||||||
expectpart "$($clixon_cli -1 -f $cfg show state exstate)" 0 "state sender x" --not-- "table parameter a" "table parameter a value x"
|
expectpart "$($clixon_cli -1 -f $cfg show state exstate)" 0 "state sender x" --not-- "table parameter a" "table parameter a value x"
|
||||||
|
|
||||||
|
#---- openconfig path compression
|
||||||
|
|
||||||
|
new "Openconfig: check no config path"
|
||||||
|
expectpart "$($clixon_cli -1 -f $cfg set interfaces interface e config enabled true 2>&1)" 255 "Unknown command"
|
||||||
|
|
||||||
|
# negative test
|
||||||
|
new "Openconfig: check exist config path"
|
||||||
|
expectpart "$($clixon_cli -1 -f $cfg set interfaces2 interface e config enabled true 2>&1)" 0 "^$"
|
||||||
|
|
||||||
new "Kill backend"
|
new "Kill backend"
|
||||||
# Check if premature kill
|
# Check if premature kill
|
||||||
pid=$(pgrep -u root -f clixon_backend)
|
pid=$(pgrep -u root -f clixon_backend)
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
module clixon-config {
|
module clixon-config {
|
||||||
yang-version 1.1;
|
yang-version 1.1;
|
||||||
namespace "http://clicon.org/config";
|
namespace "http://clicon.org/config";
|
||||||
|
|
@ -247,6 +248,9 @@ module clixon-config {
|
||||||
enum HIDE{
|
enum HIDE{
|
||||||
description "Keywords on non-key variables and hide container around lists: a <x> y <y>";
|
description "Keywords on non-key variables and hide container around lists: a <x> y <y>";
|
||||||
}
|
}
|
||||||
|
enum OC_COMPRESS{
|
||||||
|
description "See: https://github.com/openconfig/ygot/blob/master/docs/design.md#openconfig-path-compression";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
typedef nacm_mode{
|
typedef nacm_mode{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue