Added support for YANG anyxml; Yang union CLI generation and validation; Removed yang string escaping

This commit is contained in:
Olof hagsand 2017-07-27 11:54:28 +02:00
parent 8fd59d4452
commit 5ae1aeb427
29 changed files with 753 additions and 499 deletions

View file

@ -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 */
}

View file

@ -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;

View file

@ -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 */

View file

@ -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:

View file

@ -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:

View file

@ -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;
}

View file

@ -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:

View file

@ -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;