Added support for YANG anyxml; Yang union CLI generation and validation; Removed yang string escaping
This commit is contained in:
parent
8fd59d4452
commit
5ae1aeb427
29 changed files with 753 additions and 499 deletions
|
|
@ -1028,6 +1028,10 @@ from_client_msg(clicon_handle h,
|
|||
xml_free(xt);
|
||||
if (cbret)
|
||||
cbuf_free(cbret);
|
||||
/* Sanity: log if clicon_err() is not called ! */
|
||||
if (retval < 0 && clicon_errno < 0)
|
||||
clicon_log(LOG_NOTICE, "%s: Internal error: No clicon_err call on error (message: %s)",
|
||||
__FUNCTION__, name?name:"");
|
||||
return retval;// -1 here terminates backend
|
||||
}
|
||||
|
||||
|
|
@ -1060,5 +1064,5 @@ from_client(int s,
|
|||
done:
|
||||
if (msg)
|
||||
free(msg);
|
||||
return retval;
|
||||
return retval; /* -1 here terminates backend */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ generic_validate(yang_spec *yspec,
|
|||
for (i=0; i<td->td_dlen; i++){
|
||||
x1 = td->td_dvec[i];
|
||||
ys = xml_spec(x1);
|
||||
if (yang_mandatory(ys)){
|
||||
if (ys && yang_mandatory(ys)){
|
||||
clicon_err(OE_CFG, 0,"Removed mandatory variable: %s",
|
||||
xml_name(x1));
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -431,13 +431,8 @@ main(int argc, char **argv)
|
|||
case 'p' : /* Print spec */
|
||||
printspec++;
|
||||
break;
|
||||
case 'y' :{ /* yang module */
|
||||
/* Set revision to NULL, extract dir and module */
|
||||
char *str = strdup(optarg);
|
||||
char *dir = dirname(str);
|
||||
hash_del(clicon_options(h), (char*)"CLICON_YANG_MODULE_REVISION");
|
||||
clicon_option_str_set(h, "CLICON_YANG_MODULE_MAIN", basename(optarg));
|
||||
clicon_option_str_set(h, "CLICON_YANG_DIR", strdup(dir));
|
||||
case 'y' :{ /* Override yang module or absolute filename */
|
||||
clicon_option_str_set(h, "CLICON_YANG_MODULE_MAIN", optarg);
|
||||
break;
|
||||
}
|
||||
case 'x' :{ /* xmldb plugin */
|
||||
|
|
|
|||
|
|
@ -189,44 +189,15 @@ yang2cli_var_sub(clicon_handle h,
|
|||
yang_stmt *yi = NULL;
|
||||
int i = 0;
|
||||
char *cvtypestr;
|
||||
int completion;
|
||||
|
||||
/* enumeration already gives completion */
|
||||
if (cvtype == CGV_VOID){
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
type = ytype?ytype->ys_argument:NULL;
|
||||
if (type)
|
||||
completion = clicon_cli_genmodel_completion(h) &&
|
||||
strcmp(type, "enumeration") != 0 &&
|
||||
strcmp(type, "bits") != 0;
|
||||
else
|
||||
completion = clicon_cli_genmodel_completion(h);
|
||||
|
||||
if (completion)
|
||||
cprintf(cb0, "(");
|
||||
cvtypestr = cv_type2str(cvtype);
|
||||
cprintf(cb0, "<%s:%s", ys->ys_argument, cvtypestr);
|
||||
#if 0
|
||||
if (type && (strcmp(type, "identityref") == 0)){
|
||||
yang_stmt *ybase;
|
||||
if ((ybase = yang_find((yang_node*)ytype, Y_BASE, NULL)) != NULL){
|
||||
cprintf(cb0, " choice:");
|
||||
i = 0;
|
||||
/* for every found identity derived from base-type , do: */
|
||||
{
|
||||
if (yi->ys_keyword != Y_ENUM && yi->ys_keyword != Y_BIT)
|
||||
continue;
|
||||
if (i)
|
||||
cprintf(cb0, "|");
|
||||
cprintf(cb0, "%s", yi->ys_argument);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
/* enumeration special case completion */
|
||||
if (type && (strcmp(type, "enumeration") == 0 || strcmp(type, "bits") == 0)){
|
||||
cprintf(cb0, " choice:");
|
||||
i = 0;
|
||||
|
|
@ -242,6 +213,7 @@ yang2cli_var_sub(clicon_handle h,
|
|||
if (options & YANG_OPTIONS_FRACTION_DIGITS)
|
||||
cprintf(cb0, " fraction-digits:%u", fraction_digits);
|
||||
if (options & (YANG_OPTIONS_RANGE|YANG_OPTIONS_LENGTH)){
|
||||
assert(mincv || maxcv);
|
||||
cprintf(cb0, " %s[", (options&YANG_OPTIONS_RANGE)?"range":"length");
|
||||
if (mincv){
|
||||
if ((r = cv2str_dup(mincv)) == NULL){
|
||||
|
|
@ -250,13 +222,13 @@ yang2cli_var_sub(clicon_handle h,
|
|||
}
|
||||
cprintf(cb0, "%s:", r);
|
||||
free(r);
|
||||
r = NULL;
|
||||
}
|
||||
if (maxcv != NULL){
|
||||
if ((r = cv2str_dup(maxcv)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cv2str_dup");
|
||||
goto done;
|
||||
}
|
||||
|
||||
}
|
||||
else{ /* Cligen does not have 'max' keyword in range so need to find actual
|
||||
max value of type if yang range expression is 0..max */
|
||||
|
|
@ -267,6 +239,7 @@ yang2cli_var_sub(clicon_handle h,
|
|||
}
|
||||
cprintf(cb0, "%s]", r);
|
||||
free(r);
|
||||
r = NULL;
|
||||
}
|
||||
if (options & YANG_OPTIONS_PATTERN)
|
||||
cprintf(cb0, " regexp:\"%s\"", pattern);
|
||||
|
|
@ -274,30 +247,74 @@ yang2cli_var_sub(clicon_handle h,
|
|||
cprintf(cb0, ">");
|
||||
if (helptext)
|
||||
cprintf(cb0, "(\"%s\")", helptext);
|
||||
if (completion){
|
||||
#if 0
|
||||
if (type && (strcmp(type, "leafref") == 0)){
|
||||
yang_stmt *ypath;
|
||||
/* XXX only for absolute xpath */
|
||||
if ((ypath = yang_find((yang_node*)ytype, Y_PATH, NULL)) == NULL){
|
||||
clicon_err(OE_XML, 0, "leafref should have path sub");
|
||||
goto done;
|
||||
}
|
||||
clicon_debug(1, "%s ypath:%s\n", __FUNCTION__, ypath->ys_argument);
|
||||
cprintf(cb0, "|<%s:%s", ys->ys_argument,
|
||||
cv_type2str(cvtype));
|
||||
cprintf(cb0, " %s(\"candidate\",\"%s\")>",
|
||||
GENERATE_EXPAND_XMLDB,
|
||||
ypath->ys_argument);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (cli_expand_var_generate(h, ys, cvtype, cb0,
|
||||
options, fraction_digits) < 0)
|
||||
goto done;
|
||||
if (helptext)
|
||||
cprintf(cb0, "(\"%s\")", helptext);
|
||||
cprintf(cb0, ")");
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* forward */
|
||||
static int yang2cli_var_union(clicon_handle h, yang_stmt *ys, cbuf *cb0,
|
||||
char *helptext, yang_stmt *yrestype, char *type);
|
||||
|
||||
static int
|
||||
yang2cli_var_union_one(clicon_handle h,
|
||||
yang_stmt *ys,
|
||||
cbuf *cb0,
|
||||
char *helptext,
|
||||
char *type,
|
||||
yang_stmt *yt)
|
||||
{
|
||||
int retval = -1;
|
||||
int options = 0;
|
||||
cg_var *mincv = NULL;
|
||||
cg_var *maxcv = NULL;
|
||||
char *pattern = NULL;
|
||||
uint8_t fraction_digits = 0;
|
||||
enum cv_type cvtype;
|
||||
yang_stmt *yrestype;
|
||||
char *restype;
|
||||
|
||||
if (yang_type_resolve(ys, yt, &yrestype,
|
||||
&options, &mincv, &maxcv, &pattern, &fraction_digits) < 0)
|
||||
goto done;
|
||||
restype = yrestype?yrestype->ys_argument:NULL;
|
||||
|
||||
if (restype && strcmp(restype, "union") == 0){ /* recursive union */
|
||||
if (yang2cli_var_union(h, ys, cb0, helptext, yrestype, type) < 0)
|
||||
goto done;
|
||||
}
|
||||
else {
|
||||
if (clicon_type2cv(type, restype, &cvtype) < 0)
|
||||
goto done;
|
||||
if ((retval = yang2cli_var_sub(h, ys, cb0, helptext, cvtype, yrestype,
|
||||
options, mincv, maxcv, pattern, fraction_digits)) < 0)
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
yang2cli_var_union(clicon_handle h,
|
||||
yang_stmt *ys,
|
||||
cbuf *cb0,
|
||||
char *helptext,
|
||||
yang_stmt *yrestype,
|
||||
char *type)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt *yt = NULL;
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
while ((yt = yn_each((yang_node*)yrestype, yt)) != NULL){
|
||||
if (yt->ys_keyword != Y_TYPE)
|
||||
continue;
|
||||
if (i++)
|
||||
cprintf(cb0, "|");
|
||||
if (yang2cli_var_union_one(h, ys, cb0, helptext, type, yt) < 0)
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
@ -322,12 +339,10 @@ yang2cli_var(clicon_handle h,
|
|||
cg_var *mincv = NULL;
|
||||
cg_var *maxcv = NULL;
|
||||
char *pattern = NULL;
|
||||
yang_stmt *yt = NULL;
|
||||
yang_stmt *yrt;
|
||||
uint8_t fraction_digits = 0;
|
||||
enum cv_type cvtype;
|
||||
int options = 0;
|
||||
int i;
|
||||
int completionp;
|
||||
|
||||
if (yang_type_get(ys, &type, &yrestype,
|
||||
&options, &mincv, &maxcv, &pattern, &fraction_digits) < 0)
|
||||
|
|
@ -335,35 +350,45 @@ yang2cli_var(clicon_handle h,
|
|||
restype = yrestype?yrestype->ys_argument:NULL;
|
||||
if (clicon_type2cv(type, restype, &cvtype) < 0)
|
||||
goto done;
|
||||
|
||||
/* Note restype can be NULL here for example with unresolved hardcoded uuid */
|
||||
if (restype && strcmp(restype, "union") == 0){
|
||||
/* Union: loop over resolved type's sub-types */
|
||||
/* Union: loop over resolved type's sub-types (can also be recursive unions) */
|
||||
cprintf(cb0, "(");
|
||||
yt = NULL;
|
||||
i = 0;
|
||||
while ((yt = yn_each((yang_node*)yrestype, yt)) != NULL){
|
||||
if (yt->ys_keyword != Y_TYPE)
|
||||
continue;
|
||||
if (i++)
|
||||
cprintf(cb0, "|");
|
||||
if (yang_type_resolve(ys, yt, &yrt,
|
||||
&options, &mincv, &maxcv, &pattern, &fraction_digits) < 0)
|
||||
if (yang2cli_var_union(h, ys, cb0, helptext, yrestype, type) < 0)
|
||||
goto done;
|
||||
if (clicon_cli_genmodel_completion(h)){
|
||||
if (cli_expand_var_generate(h, ys, cvtype, cb0,
|
||||
options, fraction_digits) < 0)
|
||||
goto done;
|
||||
restype = yrt?yrt->ys_argument:NULL;
|
||||
if (clicon_type2cv(type, restype, &cvtype) < 0)
|
||||
goto done;
|
||||
if ((retval = yang2cli_var_sub(h, ys, cb0, helptext, cvtype, yrt,
|
||||
options, mincv, maxcv, pattern, fraction_digits)) < 0)
|
||||
|
||||
goto done;
|
||||
|
||||
if (helptext)
|
||||
cprintf(cb0, "(\"%s\")", helptext);
|
||||
}
|
||||
cprintf(cb0, ")");
|
||||
}
|
||||
else
|
||||
else{
|
||||
char *type;
|
||||
type = yrestype?yrestype->ys_argument:NULL;
|
||||
if (type)
|
||||
completionp = clicon_cli_genmodel_completion(h) &&
|
||||
strcmp(type, "enumeration") != 0 &&
|
||||
strcmp(type, "bits") != 0;
|
||||
else
|
||||
completionp = clicon_cli_genmodel_completion(h);
|
||||
if (completionp)
|
||||
cprintf(cb0, "(");
|
||||
if ((retval = yang2cli_var_sub(h, ys, cb0, helptext, cvtype, yrestype,
|
||||
options, mincv, maxcv, pattern, fraction_digits)) < 0)
|
||||
goto done;
|
||||
if (completionp){
|
||||
if (cli_expand_var_generate(h, ys, cvtype, cb0,
|
||||
options, fraction_digits) < 0)
|
||||
goto done;
|
||||
if (helptext)
|
||||
cprintf(cb0, "(\"%s\")", helptext);
|
||||
cprintf(cb0, ")");
|
||||
}
|
||||
}
|
||||
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
|
|||
|
|
@ -291,14 +291,8 @@ main(int argc, char **argv)
|
|||
case 'L' : /* Debug print dynamic CLI syntax */
|
||||
logclisyntax++;
|
||||
break;
|
||||
case 'y' :{ /* yang module */
|
||||
/* Set revision to NULL, extract dir and module */
|
||||
char *str = strdup(optarg);
|
||||
char *dir = dirname(str);
|
||||
hash_del(clicon_options(h), (char*)"CLICON_YANG_MODULE_REVISION");
|
||||
clicon_option_str_set(h, "CLICON_YANG_MODULE_MAIN", basename(optarg));
|
||||
clicon_option_str_set(h, "CLICON_YANG_DIR", dir);
|
||||
free(str);
|
||||
case 'y' :{ /* Overwrite yang module or absolute filename */
|
||||
clicon_option_str_set(h, "CLICON_YANG_MODULE_MAIN", optarg);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -628,7 +628,12 @@ clicon_parse(clicon_handle h,
|
|||
parse_tree *pt; /* Orig */
|
||||
cg_obj *match_obj;
|
||||
cvec *cvv = NULL;
|
||||
FILE *f;
|
||||
|
||||
if (clicon_get_logflags()&CLICON_LOG_STDOUT)
|
||||
f = stdout;
|
||||
else
|
||||
f = stderr;
|
||||
stx = cli_syntax(h);
|
||||
m = *mode;
|
||||
if (m == NULL) {
|
||||
|
|
@ -637,7 +642,7 @@ clicon_parse(clicon_handle h,
|
|||
}
|
||||
else {
|
||||
if ((smode = syntax_mode_find(stx, m, 0)) == NULL) {
|
||||
cli_output(stderr, "Can't find syntax mode '%s'\n", m);
|
||||
cli_output(f, "Can't find syntax mode '%s'\n", m);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
@ -663,10 +668,11 @@ clicon_parse(clicon_handle h,
|
|||
free(msav);
|
||||
}
|
||||
msav = NULL;
|
||||
|
||||
switch (res) {
|
||||
case CG_EOF: /* eof */
|
||||
case CG_ERROR:
|
||||
cli_output(stderr, "CLI parse error: %s\n", cmd);
|
||||
cli_output(f, "CLI parse error: %s\n", cmd);
|
||||
goto done;
|
||||
case CG_NOMATCH: /* no match */
|
||||
smode = NULL;
|
||||
|
|
@ -676,10 +682,12 @@ clicon_parse(clicon_handle h,
|
|||
if ((smode = syntax_mode_find(stx, m, 0)) != NULL)
|
||||
continue;
|
||||
else
|
||||
cli_output(stderr, "Can't find syntax mode '%s'\n", m);
|
||||
cli_output(f, "Can't find syntax mode '%s'\n", m);
|
||||
}
|
||||
}
|
||||
cli_output(stderr, "CLI syntax error: \"%s\": %s\n",
|
||||
/* clicon_err(OE_CFG, 0, "CLI syntax error: \"%s\": %s",
|
||||
cmd, cli_nomatch(h));*/
|
||||
cli_output(f, "CLI syntax error: \"%s\": %s\n",
|
||||
cmd, cli_nomatch(h));
|
||||
break;
|
||||
case CG_MATCH:
|
||||
|
|
@ -695,7 +703,7 @@ clicon_parse(clicon_handle h,
|
|||
goto done;
|
||||
break;
|
||||
default:
|
||||
cli_output(stderr, "CLI syntax error: \"%s\" is ambiguous\n", cmd);
|
||||
cli_output(f, "CLI syntax error: \"%s\" is ambiguous\n", cmd);
|
||||
goto done;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -359,13 +359,8 @@ main(int argc, char **argv)
|
|||
usage(h, argv[0]);
|
||||
clicon_option_str_set(h, "CLICON_NETCONF_DIR", optarg);
|
||||
break;
|
||||
case 'y' :{ /* yang module */
|
||||
/* Set revision to NULL, extract dir and module */
|
||||
char *str = strdup(optarg);
|
||||
char *dir = dirname(str);
|
||||
hash_del(clicon_options(h), (char*)"CLICON_YANG_MODULE_REVISION");
|
||||
clicon_option_str_set(h, "CLICON_YANG_MODULE_MAIN", basename(optarg));
|
||||
clicon_option_str_set(h, "CLICON_YANG_DIR", strdup(dir));
|
||||
case 'y' :{ /* Overwrite yang module or absolute filename */
|
||||
clicon_option_str_set(h, "CLICON_YANG_MODULE_MAIN", optarg);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -320,14 +320,9 @@ main(int argc,
|
|||
goto done;
|
||||
|
||||
/* Overwrite yang module with -y option */
|
||||
if (yangspec){
|
||||
/* Set revision to NULL, extract dir and module */
|
||||
char *str = strdup(yangspec);
|
||||
char *dir = dirname(str);
|
||||
hash_del(clicon_options(h), (char*)"CLICON_YANG_MODULE_REVISION");
|
||||
clicon_option_str_set(h, "CLICON_YANG_MODULE_MAIN", basename(yangspec));
|
||||
clicon_option_str_set(h, "CLICON_YANG_DIR", strdup(dir));
|
||||
}
|
||||
if (yangspec)
|
||||
clicon_option_str_set(h, "CLICON_YANG_MODULE_MAIN", yangspec);
|
||||
|
||||
/* Initialize plugins group */
|
||||
if (restconf_plugin_load(h) < 0)
|
||||
return -1;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue