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
|
|
@ -2,7 +2,12 @@
|
||||||
|
|
||||||
## Upcoming 3.3.2
|
## Upcoming 3.3.2
|
||||||
|
|
||||||
|
### Known issues
|
||||||
|
* Error in CLI generated code for Yang empty types
|
||||||
|
|
||||||
### Major changes:
|
### Major changes:
|
||||||
|
* Added support for YANG anyxml.
|
||||||
|
|
||||||
* Changed top-level netconf get-config and get to return `<data>` instead of `<data><config>` to comply to the RFC.
|
* Changed top-level netconf get-config and get to return `<data>` instead of `<data><config>` to comply to the RFC.
|
||||||
* If you use direct netconf get or get-config calls, you may need to handle the return XML differently.
|
* If you use direct netconf get or get-config calls, you may need to handle the return XML differently.
|
||||||
* RESTCONF and CLI is not affected.
|
* RESTCONF and CLI is not affected.
|
||||||
|
|
@ -82,6 +87,10 @@ If you submit "nopresence" without a leaf, it will automatically be removed:
|
||||||
* You need to define state data in a backend callback. See the example and documentation for more details.
|
* You need to define state data in a backend callback. See the example and documentation for more details.
|
||||||
|
|
||||||
### Minor changes:
|
### Minor changes:
|
||||||
|
* Corrected Yang union CLI generation and type validation. Recursive unions did not work.
|
||||||
|
* Corrected Yang pattern type escaping problem, ie '\.' did not work properly. This requires update of cligen as well.
|
||||||
|
* Compliance with RFC: Rename yang xpath to schema_nodeid and syntaxnode to datanode.
|
||||||
|
* Main yang module (CLICON_YANG_MODULE_MAIN or -y) can be an absolute file name.
|
||||||
* Removed 'margin' parameter of yang_print().
|
* Removed 'margin' parameter of yang_print().
|
||||||
* Extended example with ietf-routing (not only ietf-ip) for rpc operations.
|
* Extended example with ietf-routing (not only ietf-ip) for rpc operations.
|
||||||
* Added yang dir with ietf-netconf and clixon-config yang specs for internal usage.
|
* Added yang dir with ietf-netconf and clixon-config yang specs for internal usage.
|
||||||
|
|
|
||||||
|
|
@ -1028,6 +1028,10 @@ from_client_msg(clicon_handle h,
|
||||||
xml_free(xt);
|
xml_free(xt);
|
||||||
if (cbret)
|
if (cbret)
|
||||||
cbuf_free(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
|
return retval;// -1 here terminates backend
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1060,5 +1064,5 @@ from_client(int s,
|
||||||
done:
|
done:
|
||||||
if (msg)
|
if (msg)
|
||||||
free(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++){
|
for (i=0; i<td->td_dlen; i++){
|
||||||
x1 = td->td_dvec[i];
|
x1 = td->td_dvec[i];
|
||||||
ys = xml_spec(x1);
|
ys = xml_spec(x1);
|
||||||
if (yang_mandatory(ys)){
|
if (ys && yang_mandatory(ys)){
|
||||||
clicon_err(OE_CFG, 0,"Removed mandatory variable: %s",
|
clicon_err(OE_CFG, 0,"Removed mandatory variable: %s",
|
||||||
xml_name(x1));
|
xml_name(x1));
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -431,13 +431,8 @@ main(int argc, char **argv)
|
||||||
case 'p' : /* Print spec */
|
case 'p' : /* Print spec */
|
||||||
printspec++;
|
printspec++;
|
||||||
break;
|
break;
|
||||||
case 'y' :{ /* yang module */
|
case 'y' :{ /* Override yang module or absolute filename */
|
||||||
/* Set revision to NULL, extract dir and module */
|
clicon_option_str_set(h, "CLICON_YANG_MODULE_MAIN", optarg);
|
||||||
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));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'x' :{ /* xmldb plugin */
|
case 'x' :{ /* xmldb plugin */
|
||||||
|
|
|
||||||
|
|
@ -189,44 +189,15 @@ yang2cli_var_sub(clicon_handle h,
|
||||||
yang_stmt *yi = NULL;
|
yang_stmt *yi = NULL;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
char *cvtypestr;
|
char *cvtypestr;
|
||||||
int completion;
|
|
||||||
|
|
||||||
/* enumeration already gives completion */
|
|
||||||
if (cvtype == CGV_VOID){
|
if (cvtype == CGV_VOID){
|
||||||
retval = 0;
|
retval = 0;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
type = ytype?ytype->ys_argument:NULL;
|
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);
|
cvtypestr = cv_type2str(cvtype);
|
||||||
cprintf(cb0, "<%s:%s", ys->ys_argument, cvtypestr);
|
cprintf(cb0, "<%s:%s", ys->ys_argument, cvtypestr);
|
||||||
#if 0
|
/* enumeration special case completion */
|
||||||
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
|
|
||||||
if (type && (strcmp(type, "enumeration") == 0 || strcmp(type, "bits") == 0)){
|
if (type && (strcmp(type, "enumeration") == 0 || strcmp(type, "bits") == 0)){
|
||||||
cprintf(cb0, " choice:");
|
cprintf(cb0, " choice:");
|
||||||
i = 0;
|
i = 0;
|
||||||
|
|
@ -242,6 +213,7 @@ yang2cli_var_sub(clicon_handle h,
|
||||||
if (options & YANG_OPTIONS_FRACTION_DIGITS)
|
if (options & YANG_OPTIONS_FRACTION_DIGITS)
|
||||||
cprintf(cb0, " fraction-digits:%u", fraction_digits);
|
cprintf(cb0, " fraction-digits:%u", fraction_digits);
|
||||||
if (options & (YANG_OPTIONS_RANGE|YANG_OPTIONS_LENGTH)){
|
if (options & (YANG_OPTIONS_RANGE|YANG_OPTIONS_LENGTH)){
|
||||||
|
assert(mincv || maxcv);
|
||||||
cprintf(cb0, " %s[", (options&YANG_OPTIONS_RANGE)?"range":"length");
|
cprintf(cb0, " %s[", (options&YANG_OPTIONS_RANGE)?"range":"length");
|
||||||
if (mincv){
|
if (mincv){
|
||||||
if ((r = cv2str_dup(mincv)) == NULL){
|
if ((r = cv2str_dup(mincv)) == NULL){
|
||||||
|
|
@ -250,13 +222,13 @@ yang2cli_var_sub(clicon_handle h,
|
||||||
}
|
}
|
||||||
cprintf(cb0, "%s:", r);
|
cprintf(cb0, "%s:", r);
|
||||||
free(r);
|
free(r);
|
||||||
|
r = NULL;
|
||||||
}
|
}
|
||||||
if (maxcv != NULL){
|
if (maxcv != NULL){
|
||||||
if ((r = cv2str_dup(maxcv)) == NULL){
|
if ((r = cv2str_dup(maxcv)) == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "cv2str_dup");
|
clicon_err(OE_UNIX, errno, "cv2str_dup");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else{ /* Cligen does not have 'max' keyword in range so need to find actual
|
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 */
|
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);
|
cprintf(cb0, "%s]", r);
|
||||||
free(r);
|
free(r);
|
||||||
|
r = NULL;
|
||||||
}
|
}
|
||||||
if (options & YANG_OPTIONS_PATTERN)
|
if (options & YANG_OPTIONS_PATTERN)
|
||||||
cprintf(cb0, " regexp:\"%s\"", pattern);
|
cprintf(cb0, " regexp:\"%s\"", pattern);
|
||||||
|
|
@ -274,30 +247,74 @@ yang2cli_var_sub(clicon_handle h,
|
||||||
cprintf(cb0, ">");
|
cprintf(cb0, ">");
|
||||||
if (helptext)
|
if (helptext)
|
||||||
cprintf(cb0, "(\"%s\")", helptext);
|
cprintf(cb0, "(\"%s\")", helptext);
|
||||||
if (completion){
|
retval = 0;
|
||||||
#if 0
|
done:
|
||||||
if (type && (strcmp(type, "leafref") == 0)){
|
return retval;
|
||||||
yang_stmt *ypath;
|
}
|
||||||
/* XXX only for absolute xpath */
|
|
||||||
if ((ypath = yang_find((yang_node*)ytype, Y_PATH, NULL)) == NULL){
|
/* forward */
|
||||||
clicon_err(OE_XML, 0, "leafref should have path sub");
|
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;
|
goto done;
|
||||||
}
|
}
|
||||||
clicon_debug(1, "%s ypath:%s\n", __FUNCTION__, ypath->ys_argument);
|
else {
|
||||||
cprintf(cb0, "|<%s:%s", ys->ys_argument,
|
if (clicon_type2cv(type, restype, &cvtype) < 0)
|
||||||
cv_type2str(cvtype));
|
goto done;
|
||||||
cprintf(cb0, " %s(\"candidate\",\"%s\")>",
|
if ((retval = yang2cli_var_sub(h, ys, cb0, helptext, cvtype, yrestype,
|
||||||
GENERATE_EXPAND_XMLDB,
|
options, mincv, maxcv, pattern, fraction_digits)) < 0)
|
||||||
ypath->ys_argument);
|
goto done;
|
||||||
}
|
}
|
||||||
else
|
retval = 0;
|
||||||
#endif
|
done:
|
||||||
if (cli_expand_var_generate(h, ys, cvtype, cb0,
|
return retval;
|
||||||
options, fraction_digits) < 0)
|
}
|
||||||
|
|
||||||
|
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;
|
goto done;
|
||||||
if (helptext)
|
|
||||||
cprintf(cb0, "(\"%s\")", helptext);
|
|
||||||
cprintf(cb0, ")");
|
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
|
@ -322,12 +339,10 @@ yang2cli_var(clicon_handle h,
|
||||||
cg_var *mincv = NULL;
|
cg_var *mincv = NULL;
|
||||||
cg_var *maxcv = NULL;
|
cg_var *maxcv = NULL;
|
||||||
char *pattern = NULL;
|
char *pattern = NULL;
|
||||||
yang_stmt *yt = NULL;
|
|
||||||
yang_stmt *yrt;
|
|
||||||
uint8_t fraction_digits = 0;
|
uint8_t fraction_digits = 0;
|
||||||
enum cv_type cvtype;
|
enum cv_type cvtype;
|
||||||
int options = 0;
|
int options = 0;
|
||||||
int i;
|
int completionp;
|
||||||
|
|
||||||
if (yang_type_get(ys, &type, &yrestype,
|
if (yang_type_get(ys, &type, &yrestype,
|
||||||
&options, &mincv, &maxcv, &pattern, &fraction_digits) < 0)
|
&options, &mincv, &maxcv, &pattern, &fraction_digits) < 0)
|
||||||
|
|
@ -335,35 +350,45 @@ yang2cli_var(clicon_handle h,
|
||||||
restype = yrestype?yrestype->ys_argument:NULL;
|
restype = yrestype?yrestype->ys_argument:NULL;
|
||||||
if (clicon_type2cv(type, restype, &cvtype) < 0)
|
if (clicon_type2cv(type, restype, &cvtype) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* Note restype can be NULL here for example with unresolved hardcoded uuid */
|
/* Note restype can be NULL here for example with unresolved hardcoded uuid */
|
||||||
if (restype && strcmp(restype, "union") == 0){
|
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, "(");
|
cprintf(cb0, "(");
|
||||||
yt = NULL;
|
if (yang2cli_var_union(h, ys, cb0, helptext, yrestype, type) < 0)
|
||||||
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)
|
|
||||||
goto done;
|
goto done;
|
||||||
restype = yrt?yrt->ys_argument:NULL;
|
if (clicon_cli_genmodel_completion(h)){
|
||||||
if (clicon_type2cv(type, restype, &cvtype) < 0)
|
if (cli_expand_var_generate(h, ys, cvtype, cb0,
|
||||||
|
options, fraction_digits) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((retval = yang2cli_var_sub(h, ys, cb0, helptext, cvtype, yrt,
|
if (helptext)
|
||||||
options, mincv, maxcv, pattern, fraction_digits)) < 0)
|
cprintf(cb0, "(\"%s\")", helptext);
|
||||||
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
cprintf(cb0, ")");
|
cprintf(cb0, ")");
|
||||||
}
|
}
|
||||||
|
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
|
else
|
||||||
|
completionp = clicon_cli_genmodel_completion(h);
|
||||||
|
if (completionp)
|
||||||
|
cprintf(cb0, "(");
|
||||||
if ((retval = yang2cli_var_sub(h, ys, cb0, helptext, cvtype, yrestype,
|
if ((retval = yang2cli_var_sub(h, ys, cb0, helptext, cvtype, yrestype,
|
||||||
options, mincv, maxcv, pattern, fraction_digits)) < 0)
|
options, mincv, maxcv, pattern, fraction_digits)) < 0)
|
||||||
goto done;
|
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;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
|
|
||||||
|
|
@ -291,14 +291,8 @@ main(int argc, char **argv)
|
||||||
case 'L' : /* Debug print dynamic CLI syntax */
|
case 'L' : /* Debug print dynamic CLI syntax */
|
||||||
logclisyntax++;
|
logclisyntax++;
|
||||||
break;
|
break;
|
||||||
case 'y' :{ /* yang module */
|
case 'y' :{ /* Overwrite yang module or absolute filename */
|
||||||
/* Set revision to NULL, extract dir and module */
|
clicon_option_str_set(h, "CLICON_YANG_MODULE_MAIN", optarg);
|
||||||
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);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -628,7 +628,12 @@ clicon_parse(clicon_handle h,
|
||||||
parse_tree *pt; /* Orig */
|
parse_tree *pt; /* Orig */
|
||||||
cg_obj *match_obj;
|
cg_obj *match_obj;
|
||||||
cvec *cvv = NULL;
|
cvec *cvv = NULL;
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
if (clicon_get_logflags()&CLICON_LOG_STDOUT)
|
||||||
|
f = stdout;
|
||||||
|
else
|
||||||
|
f = stderr;
|
||||||
stx = cli_syntax(h);
|
stx = cli_syntax(h);
|
||||||
m = *mode;
|
m = *mode;
|
||||||
if (m == NULL) {
|
if (m == NULL) {
|
||||||
|
|
@ -637,7 +642,7 @@ clicon_parse(clicon_handle h,
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ((smode = syntax_mode_find(stx, m, 0)) == NULL) {
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -663,10 +668,11 @@ clicon_parse(clicon_handle h,
|
||||||
free(msav);
|
free(msav);
|
||||||
}
|
}
|
||||||
msav = NULL;
|
msav = NULL;
|
||||||
|
|
||||||
switch (res) {
|
switch (res) {
|
||||||
case CG_EOF: /* eof */
|
case CG_EOF: /* eof */
|
||||||
case CG_ERROR:
|
case CG_ERROR:
|
||||||
cli_output(stderr, "CLI parse error: %s\n", cmd);
|
cli_output(f, "CLI parse error: %s\n", cmd);
|
||||||
goto done;
|
goto done;
|
||||||
case CG_NOMATCH: /* no match */
|
case CG_NOMATCH: /* no match */
|
||||||
smode = NULL;
|
smode = NULL;
|
||||||
|
|
@ -676,10 +682,12 @@ clicon_parse(clicon_handle h,
|
||||||
if ((smode = syntax_mode_find(stx, m, 0)) != NULL)
|
if ((smode = syntax_mode_find(stx, m, 0)) != NULL)
|
||||||
continue;
|
continue;
|
||||||
else
|
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));
|
cmd, cli_nomatch(h));
|
||||||
break;
|
break;
|
||||||
case CG_MATCH:
|
case CG_MATCH:
|
||||||
|
|
@ -695,7 +703,7 @@ clicon_parse(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
break;
|
||||||
default:
|
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;
|
goto done;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -359,13 +359,8 @@ main(int argc, char **argv)
|
||||||
usage(h, argv[0]);
|
usage(h, argv[0]);
|
||||||
clicon_option_str_set(h, "CLICON_NETCONF_DIR", optarg);
|
clicon_option_str_set(h, "CLICON_NETCONF_DIR", optarg);
|
||||||
break;
|
break;
|
||||||
case 'y' :{ /* yang module */
|
case 'y' :{ /* Overwrite yang module or absolute filename */
|
||||||
/* Set revision to NULL, extract dir and module */
|
clicon_option_str_set(h, "CLICON_YANG_MODULE_MAIN", optarg);
|
||||||
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));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -320,14 +320,9 @@ main(int argc,
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* Overwrite yang module with -y option */
|
/* Overwrite yang module with -y option */
|
||||||
if (yangspec){
|
if (yangspec)
|
||||||
/* Set revision to NULL, extract dir and module */
|
clicon_option_str_set(h, "CLICON_YANG_MODULE_MAIN", yangspec);
|
||||||
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));
|
|
||||||
}
|
|
||||||
/* Initialize plugins group */
|
/* Initialize plugins group */
|
||||||
if (restconf_plugin_load(h) < 0)
|
if (restconf_plugin_load(h) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
||||||
|
|
@ -45,17 +45,15 @@
|
||||||
# Location of configuration-file for default values (this file)
|
# Location of configuration-file for default values (this file)
|
||||||
CLICON_CONFIGFILE sysconfdir/APPNAME.conf
|
CLICON_CONFIGFILE sysconfdir/APPNAME.conf
|
||||||
|
|
||||||
# Location of YANG module and submodule files. Only if CLICON_DBSPEC_TYPE is YANG
|
# Location of YANG module and submodule files.
|
||||||
CLICON_YANG_DIR prefix/share/APPNAME/yang
|
CLICON_YANG_DIR prefix/share/APPNAME/yang
|
||||||
|
|
||||||
# Option used to construct initial yang file:
|
# Main yang module or absolute filename. If module then search as follows:
|
||||||
# <module>[@<revision>]
|
# <yangdir>/<module>[@<revision>]
|
||||||
# This option is only relevant if CLICON_DBSPEC_TYPE is YANG
|
|
||||||
# CLICON_YANG_MODULE_MAIN clicon
|
# CLICON_YANG_MODULE_MAIN clicon
|
||||||
|
|
||||||
# Option used to construct initial yang file:
|
# Option used to construct initial yang file:
|
||||||
# <module>[@<revision>]
|
# <module>[@<revision>]
|
||||||
# This option is only relevant if CLICON_DBSPEC_TYPE is YANG
|
|
||||||
CLICON_YANG_MODULE_REVISION
|
CLICON_YANG_MODULE_REVISION
|
||||||
|
|
||||||
# Location of backend .so plugins
|
# Location of backend .so plugins
|
||||||
|
|
|
||||||
|
|
@ -327,7 +327,7 @@ get(char *dbname,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if ((y = yang_find_syntax((yang_node*)y, name)) == NULL){
|
if ((y = yang_find_datanode((yang_node*)y, name)) == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "No yang node found: %s", name);
|
clicon_err(OE_UNIX, errno, "No yang node found: %s", name);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -760,7 +760,7 @@ put(char *dbfile,
|
||||||
}
|
}
|
||||||
/* For every node, create a key with values */
|
/* For every node, create a key with values */
|
||||||
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL){
|
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL){
|
||||||
if ((y = yang_find_syntax((yang_node*)ys, xml_name(x))) == NULL){
|
if ((y = yang_find_datanode((yang_node*)ys, xml_name(x))) == NULL){
|
||||||
clicon_err(OE_UNIX, 0, "No yang node found: %s", xml_name(x));
|
clicon_err(OE_UNIX, 0, "No yang node found: %s", xml_name(x));
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -543,7 +543,7 @@ text_modify(cxobj *x0,
|
||||||
break;
|
break;
|
||||||
} /* switch op */
|
} /* switch op */
|
||||||
} /* if LEAF|LEAF_LIST */
|
} /* if LEAF|LEAF_LIST */
|
||||||
else { /* eg Y_CONTAINER, Y_LIST */
|
else { /* eg Y_CONTAINER, Y_LIST, Y_ANYXML */
|
||||||
switch(op){
|
switch(op){
|
||||||
case OP_CREATE:
|
case OP_CREATE:
|
||||||
if (x0){
|
if (x0){
|
||||||
|
|
@ -555,8 +555,21 @@ text_modify(cxobj *x0,
|
||||||
xml_purge(x0);
|
xml_purge(x0);
|
||||||
x0 = NULL;
|
x0 = NULL;
|
||||||
}
|
}
|
||||||
case OP_NONE: /* fall thru */
|
case OP_MERGE: /* fall thru */
|
||||||
case OP_MERGE:
|
case OP_NONE:
|
||||||
|
/* Special case: anyxml, just replace tree,
|
||||||
|
See 7.10.3 of RFC6020bis */
|
||||||
|
if (y0->yn_keyword == Y_ANYXML){
|
||||||
|
if (op == OP_NONE)
|
||||||
|
break;
|
||||||
|
if (x0)
|
||||||
|
xml_purge(x0);
|
||||||
|
if ((x0 = xml_new_spec(x1name, x0p, y0)) == NULL)
|
||||||
|
goto done;
|
||||||
|
if (xml_copy(x1, x0) < 0)
|
||||||
|
goto done;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (x0==NULL){
|
if (x0==NULL){
|
||||||
if ((x0 = xml_new_spec(x1name, x0p, y0)) == NULL)
|
if ((x0 = xml_new_spec(x1name, x0p, y0)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -568,7 +581,7 @@ text_modify(cxobj *x0,
|
||||||
while ((x1c = xml_child_each(x1, x1c, CX_ELMNT)) != NULL) {
|
while ((x1c = xml_child_each(x1, x1c, CX_ELMNT)) != NULL) {
|
||||||
x1cname = xml_name(x1c);
|
x1cname = xml_name(x1c);
|
||||||
/* Get yang spec of the child */
|
/* Get yang spec of the child */
|
||||||
if ((yc = yang_find_syntax(y0, x1cname)) == NULL){
|
if ((yc = yang_find_datanode(y0, x1cname)) == NULL){
|
||||||
clicon_err(OE_YANG, errno, "No yang node found: %s", x1cname);
|
clicon_err(OE_YANG, errno, "No yang node found: %s", x1cname);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -690,12 +703,9 @@ xml_container_presence(cxobj *x,
|
||||||
void *arg)
|
void *arg)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *name;
|
|
||||||
yang_stmt *y; /* yang node */
|
yang_stmt *y; /* yang node */
|
||||||
|
|
||||||
name = xml_name(x);
|
|
||||||
if ((y = (yang_stmt*)xml_spec(x)) == NULL){
|
if ((y = (yang_stmt*)xml_spec(x)) == NULL){
|
||||||
clicon_log(LOG_WARNING, "%s: no xml_spec(%s)", __FUNCTION__, name);
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ extern int debug;
|
||||||
* Prototypes
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
int clicon_log_init(char *ident, int upto, int flags);
|
int clicon_log_init(char *ident, int upto, int flags);
|
||||||
|
int clicon_get_logflags(void);
|
||||||
int clicon_log_str(int level, char *msg);
|
int clicon_log_str(int level, char *msg);
|
||||||
int clicon_log(int level, char *format, ...);
|
int clicon_log(int level, char *format, ...);
|
||||||
clicon_log_notify_t *clicon_log_register_callback(clicon_log_notify_t *cb, void *arg);
|
clicon_log_notify_t *clicon_log_register_callback(clicon_log_notify_t *cb, void *arg);
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,7 @@ cg_var *xml_cv_get(cxobj *xn);
|
||||||
int xml_cv_set(cxobj *xn, cg_var *cv);
|
int xml_cv_set(cxobj *xn, cg_var *cv);
|
||||||
|
|
||||||
int xml_child_nr(cxobj *xn);
|
int xml_child_nr(cxobj *xn);
|
||||||
|
int xml_child_nr_type(cxobj *xn, enum cxobj_type type);
|
||||||
cxobj *xml_child_i(cxobj *xn, int i);
|
cxobj *xml_child_i(cxobj *xn, int i);
|
||||||
cxobj *xml_child_i_set(cxobj *xt, int i, cxobj *xc);
|
cxobj *xml_child_i_set(cxobj *xt, int i, cxobj *xc);
|
||||||
cxobj *xml_child_each(cxobj *xparent, cxobj *xprev, enum cxobj_type type);
|
cxobj *xml_child_each(cxobj *xparent, cxobj *xprev, enum cxobj_type type);
|
||||||
|
|
|
||||||
|
|
@ -124,8 +124,11 @@ enum rfc_6020{
|
||||||
|
|
||||||
#define YANG_FLAG_MARK 0x01 /* Marker for dynamic algorithms, eg expand */
|
#define YANG_FLAG_MARK 0x01 /* Marker for dynamic algorithms, eg expand */
|
||||||
|
|
||||||
/* Yang syntz nodes */
|
/* Yang data node */
|
||||||
#define yang_is_syntax(y) ((y)->ys_keyword == Y_CONTAINER || (y)->ys_keyword == Y_LEAF || (y)->ys_keyword == Y_LIST || (y)->ys_keyword == Y_LEAF_LIST)
|
#define yang_datanode(y) ((y)->ys_keyword == Y_CONTAINER || (y)->ys_keyword == Y_LEAF || (y)->ys_keyword == Y_LIST || (y)->ys_keyword == Y_LEAF_LIST || (y)->ys_keyword == Y_ANYXML)
|
||||||
|
|
||||||
|
/* Yang schema node */
|
||||||
|
#define yang_schemanode(y) (yang_datanode(y) || (y)->ys_keyword == Y_RPC || (y)->ys_keyword == Y_CHOICE || (y)->ys_keyword == Y_CASE || (y)->ys_keyword == Y_INPUT || (y)->ys_keyword == Y_OUTPUT || (y)->ys_keyword == Y_NOTIFICATION)
|
||||||
|
|
||||||
typedef struct yang_stmt yang_stmt; /* forward */
|
typedef struct yang_stmt yang_stmt; /* forward */
|
||||||
|
|
||||||
|
|
@ -201,7 +204,7 @@ yang_stmt *ys_module(yang_stmt *ys);
|
||||||
yang_spec *ys_spec(yang_stmt *ys);
|
yang_spec *ys_spec(yang_stmt *ys);
|
||||||
yang_stmt *yang_find_module_by_prefix(yang_stmt *ys, char *prefix);
|
yang_stmt *yang_find_module_by_prefix(yang_stmt *ys, char *prefix);
|
||||||
yang_stmt *yang_find(yang_node *yn, int keyword, char *argument);
|
yang_stmt *yang_find(yang_node *yn, int keyword, char *argument);
|
||||||
yang_stmt *yang_find_syntax(yang_node *yn, char *argument);
|
yang_stmt *yang_find_datanode(yang_node *yn, char *argument);
|
||||||
yang_stmt *yang_find_topnode(yang_spec *ysp, char *name);
|
yang_stmt *yang_find_topnode(yang_spec *ysp, char *name);
|
||||||
|
|
||||||
int yang_print(FILE *f, yang_node *yn);
|
int yang_print(FILE *f, yang_node *yn);
|
||||||
|
|
@ -210,8 +213,9 @@ int yang_parse(clicon_handle h, const char *yang_dir,
|
||||||
const char *module, const char *revision, yang_spec *ysp);
|
const char *module, const char *revision, yang_spec *ysp);
|
||||||
int yang_apply(yang_node *yn, enum rfc_6020 key, yang_applyfn_t fn,
|
int yang_apply(yang_node *yn, enum rfc_6020 key, yang_applyfn_t fn,
|
||||||
void *arg);
|
void *arg);
|
||||||
yang_node *yang_xpath_abs(yang_node *yn, char *xpath);
|
yang_node *yang_abs_schema_nodeid(yang_node *yn, char *schema_nodeid);
|
||||||
yang_node *yang_xpath(yang_node *yn, char *xpath);
|
yang_node *yang_desc_schema_nodeid(yang_node *yn, char *schema_nodeid);
|
||||||
|
yang_node *yang_schema_nodeid(yang_node *yn, char *xpath);
|
||||||
cg_var *ys_parse(yang_stmt *ys, enum cv_type cvtype);
|
cg_var *ys_parse(yang_stmt *ys, enum cv_type cvtype);
|
||||||
int ys_parse_sub(yang_stmt *ys);
|
int ys_parse_sub(yang_stmt *ys);
|
||||||
int yang_mandatory(yang_stmt *ys);
|
int yang_mandatory(yang_stmt *ys);
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,12 @@ clicon_log_init(char *ident,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
clicon_get_logflags(void)
|
||||||
|
{
|
||||||
|
return _logflags;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Register log callback, return old setting
|
/*! Register log callback, return old setting
|
||||||
*/
|
*/
|
||||||
clicon_log_notify_t *
|
clicon_log_notify_t *
|
||||||
|
|
@ -153,7 +159,7 @@ slogtime(void)
|
||||||
/*! Make a logging call to syslog (or stderr).
|
/*! Make a logging call to syslog (or stderr).
|
||||||
*
|
*
|
||||||
* This is the _only_ place the actual syslog (or stderr) logging is made in clicon,..
|
* This is the _only_ place the actual syslog (or stderr) logging is made in clicon,..
|
||||||
* @note yslog makes itw own filtering, but if log to stderr we do it here
|
* @note syslog makes itw own filtering, but if log to stderr we do it here
|
||||||
* @see clicon_debug()
|
* @see clicon_debug()
|
||||||
*
|
*
|
||||||
* @param[in] level log level, eg LOG_DEBUG,LOG_INFO,...,LOG_EMERG. Thisis OR:d with facility == LOG_USER
|
* @param[in] level log level, eg LOG_DEBUG,LOG_INFO,...,LOG_EMERG. Thisis OR:d with facility == LOG_USER
|
||||||
|
|
|
||||||
|
|
@ -392,7 +392,6 @@ clicon_configfile(clicon_handle h)
|
||||||
return clicon_option_str(h, "CLICON_CONFIGFILE");
|
return clicon_option_str(h, "CLICON_CONFIGFILE");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! YANG database specification directory */
|
/*! YANG database specification directory */
|
||||||
char *
|
char *
|
||||||
clicon_yang_dir(clicon_handle h)
|
clicon_yang_dir(clicon_handle h)
|
||||||
|
|
@ -400,7 +399,7 @@ clicon_yang_dir(clicon_handle h)
|
||||||
return clicon_option_str(h, "CLICON_YANG_DIR");
|
return clicon_option_str(h, "CLICON_YANG_DIR");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! YANG main module */
|
/*! YANG main module or absolute file name */
|
||||||
char *
|
char *
|
||||||
clicon_yang_module_main(clicon_handle h)
|
clicon_yang_module_main(clicon_handle h)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -492,7 +492,7 @@ clicon_rpc(int s,
|
||||||
char **ret)
|
char **ret)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
struct clicon_msg *reply;
|
struct clicon_msg *reply = NULL;
|
||||||
int eof;
|
int eof;
|
||||||
char *data = NULL;
|
char *data = NULL;
|
||||||
cxobj *cx = NULL;
|
cxobj *cx = NULL;
|
||||||
|
|
|
||||||
|
|
@ -351,6 +351,23 @@ xml_child_nr(cxobj *xn)
|
||||||
return xn->x_childvec_len;
|
return xn->x_childvec_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Get number of children of specific type
|
||||||
|
* @param[in] xn xml node
|
||||||
|
* @param[in] type XML type or -1 for all
|
||||||
|
* @retval number of typed children in XML tree
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml_child_nr_type(cxobj *xn,
|
||||||
|
enum cxobj_type type)
|
||||||
|
{
|
||||||
|
cxobj *x = NULL;
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
while ((x = xml_child_each(xn, x, type)) != NULL)
|
||||||
|
len++;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Get a specific child
|
/*! Get a specific child
|
||||||
* @param[in] xn xml node
|
* @param[in] xn xml node
|
||||||
* @param[in] i the number of the child, eg order in children vector
|
* @param[in] i the number of the child, eg order in children vector
|
||||||
|
|
@ -516,6 +533,9 @@ xml_new_spec(char *name,
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Return yang spec of node.
|
||||||
|
* Not necessarily set. Either has not been set yet (by xml_spec_set( or anyxml.
|
||||||
|
*/
|
||||||
void *
|
void *
|
||||||
xml_spec(cxobj *x)
|
xml_spec(cxobj *x)
|
||||||
{
|
{
|
||||||
|
|
@ -939,7 +959,7 @@ clicon_xml2cbuf(cbuf *cb,
|
||||||
while ((xc = xml_child_each(x, xc, CX_ATTR)) != NULL)
|
while ((xc = xml_child_each(x, xc, CX_ATTR)) != NULL)
|
||||||
clicon_xml2cbuf(cb, xc, level+1, prettyprint);
|
clicon_xml2cbuf(cb, xc, level+1, prettyprint);
|
||||||
/* Check for special case <a/> instead of <a></a> */
|
/* Check for special case <a/> instead of <a></a> */
|
||||||
if (xml_body(x)==NULL && xml_child_nr(x)==0)
|
if (xml_body(x)==NULL && xml_child_nr_type(x, CX_ELMNT)==0)
|
||||||
cprintf(cb, "/>");
|
cprintf(cb, "/>");
|
||||||
else{
|
else{
|
||||||
cprintf(cb, ">");
|
cprintf(cb, ">");
|
||||||
|
|
|
||||||
|
|
@ -340,7 +340,7 @@ xml_yang_validate_add(cxobj *xt,
|
||||||
char *body;
|
char *body;
|
||||||
|
|
||||||
/* if not given by argument (overide) use default link */
|
/* if not given by argument (overide) use default link */
|
||||||
ys = xml_spec(xt);
|
if ((ys = xml_spec(xt)) != NULL){
|
||||||
switch (ys->ys_keyword){
|
switch (ys->ys_keyword){
|
||||||
case Y_LIST:
|
case Y_LIST:
|
||||||
/* fall thru */
|
/* fall thru */
|
||||||
|
|
@ -385,6 +385,7 @@ xml_yang_validate_add(cxobj *xt,
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (cv)
|
if (cv)
|
||||||
|
|
@ -408,7 +409,7 @@ xml_yang_validate_all(cxobj *xt,
|
||||||
yang_stmt *ytype;
|
yang_stmt *ytype;
|
||||||
|
|
||||||
/* if not given by argument (overide) use default link */
|
/* if not given by argument (overide) use default link */
|
||||||
ys = xml_spec(xt);
|
if ((ys = xml_spec(xt)) != NULL){
|
||||||
switch (ys->ys_keyword){
|
switch (ys->ys_keyword){
|
||||||
case Y_LEAF:
|
case Y_LEAF:
|
||||||
/* fall thru */
|
/* fall thru */
|
||||||
|
|
@ -424,6 +425,7 @@ xml_yang_validate_all(cxobj *xt,
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
|
|
@ -477,7 +479,7 @@ xml2cvec(cxobj *xt,
|
||||||
/* Go through all children of the xml tree */
|
/* Go through all children of the xml tree */
|
||||||
while ((xc = xml_child_each(xt, xc, CX_ELMNT)) != NULL){
|
while ((xc = xml_child_each(xt, xc, CX_ELMNT)) != NULL){
|
||||||
name = xml_name(xc);
|
name = xml_name(xc);
|
||||||
if ((ys = yang_find_syntax((yang_node*)yt, name)) == NULL){
|
if ((ys = yang_find_datanode((yang_node*)yt, name)) == NULL){
|
||||||
clicon_debug(0, "%s: yang sanity problem: %s in xml but not present in yang under %s",
|
clicon_debug(0, "%s: yang sanity problem: %s in xml but not present in yang under %s",
|
||||||
__FUNCTION__, name, yt->ys_argument);
|
__FUNCTION__, name, yt->ys_argument);
|
||||||
if ((body = xml_body(xc)) != NULL){
|
if ((body = xml_body(xc)) != NULL){
|
||||||
|
|
@ -592,11 +594,14 @@ xml_is_body(cxobj *xt,
|
||||||
char *val)
|
char *val)
|
||||||
{
|
{
|
||||||
cxobj *x;
|
cxobj *x;
|
||||||
|
char *bx;
|
||||||
|
|
||||||
x = NULL;
|
x = NULL;
|
||||||
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
|
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
|
||||||
if (strcmp(name, xml_name(x)))
|
if (strcmp(name, xml_name(x)))
|
||||||
continue;
|
continue;
|
||||||
|
if ((bx = xml_body(x)) == NULL)
|
||||||
|
continue;
|
||||||
if (strcmp(xml_body(x), val) == 0)
|
if (strcmp(xml_body(x), val) == 0)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -641,7 +646,7 @@ xml_diff1(yang_stmt *ys,
|
||||||
if (ys->ys_keyword == Y_SPEC)
|
if (ys->ys_keyword == Y_SPEC)
|
||||||
y = yang_find_topnode((yang_spec*)ys, name);
|
y = yang_find_topnode((yang_spec*)ys, name);
|
||||||
else
|
else
|
||||||
y = yang_find_syntax((yang_node*)ys, name);
|
y = yang_find_datanode((yang_node*)ys, name);
|
||||||
if (y == NULL){
|
if (y == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "No yang node found: %s", name);
|
clicon_err(OE_UNIX, errno, "No yang node found: %s", name);
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -719,6 +724,10 @@ xml_diff1(yang_stmt *ys,
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
body1 = xml_body(x1);
|
||||||
|
body2 = xml_body(x2);
|
||||||
|
if (body1 == NULL || body2 == NULL) /* empty type */
|
||||||
|
break;
|
||||||
if (strcmp(xml_body(x1), xml_body(x2))){
|
if (strcmp(xml_body(x1), xml_body(x2))){
|
||||||
if (cxvec_append(x1, changed1, changedlen) < 0)
|
if (cxvec_append(x1, changed1, changedlen) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -728,7 +737,8 @@ xml_diff1(yang_stmt *ys,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Y_LEAF_LIST:
|
case Y_LEAF_LIST:
|
||||||
body1 = xml_body(x1);
|
if ((body1 = xml_body(x1)) == NULL)
|
||||||
|
continue;
|
||||||
if (!xml_is_body(xt2, name, body1)) /* where body is */
|
if (!xml_is_body(xt2, name, body1)) /* where body is */
|
||||||
if (cxvec_append(x1, first, firstlen) < 0)
|
if (cxvec_append(x1, first, firstlen) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -746,7 +756,7 @@ xml_diff1(yang_stmt *ys,
|
||||||
if (ys->ys_keyword == Y_SPEC)
|
if (ys->ys_keyword == Y_SPEC)
|
||||||
y = yang_find_topnode((yang_spec*)ys, name);
|
y = yang_find_topnode((yang_spec*)ys, name);
|
||||||
else
|
else
|
||||||
y = yang_find_syntax((yang_node*)ys, name);
|
y = yang_find_datanode((yang_node*)ys, name);
|
||||||
if (y == NULL){
|
if (y == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "No yang node found: %s", name);
|
clicon_err(OE_UNIX, errno, "No yang node found: %s", name);
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -1197,7 +1207,7 @@ xml_tree_prune_flagged_sub(cxobj *xt,
|
||||||
yang_node *yt;
|
yang_node *yt;
|
||||||
|
|
||||||
mark = 0;
|
mark = 0;
|
||||||
yt = xml_spec(xt);
|
yt = xml_spec(xt); /* xan be null */
|
||||||
x = NULL;
|
x = NULL;
|
||||||
xprev = x = NULL;
|
xprev = x = NULL;
|
||||||
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
|
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
|
||||||
|
|
@ -1306,7 +1316,6 @@ xml_default(cxobj *xt,
|
||||||
char *str;
|
char *str;
|
||||||
|
|
||||||
if ((ys = (yang_stmt*)xml_spec(xt)) == NULL){
|
if ((ys = (yang_stmt*)xml_spec(xt)) == NULL){
|
||||||
clicon_log(LOG_WARNING, "%s: no xml_spec(%s)", __FUNCTION__, xml_name(xt));
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -1359,7 +1368,6 @@ xml_order(cxobj *xt,
|
||||||
char *xname; /* xml child name */
|
char *xname; /* xml child name */
|
||||||
|
|
||||||
if ((y = (yang_stmt*)xml_spec(xt)) == NULL){
|
if ((y = (yang_stmt*)xml_spec(xt)) == NULL){
|
||||||
clicon_log(LOG_WARNING, "%s: no xml_spec(%s)", __FUNCTION__, xml_name(xt));
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -1367,7 +1375,7 @@ xml_order(cxobj *xt,
|
||||||
/* Go through xml children and ensure they are same order as yspec children */
|
/* Go through xml children and ensure they are same order as yspec children */
|
||||||
for (i=0; i<y->ys_len; i++){
|
for (i=0; i<y->ys_len; i++){
|
||||||
yc = y->ys_stmt[i];
|
yc = y->ys_stmt[i];
|
||||||
if (!yang_is_syntax(yc))
|
if (!yang_datanode(yc))
|
||||||
continue;
|
continue;
|
||||||
yname = yc->ys_argument;
|
yname = yc->ys_argument;
|
||||||
/* First go thru xml children with same name */
|
/* First go thru xml children with same name */
|
||||||
|
|
@ -1411,7 +1419,6 @@ xml_sanity(cxobj *xt,
|
||||||
char *name;
|
char *name;
|
||||||
|
|
||||||
if ((ys = (yang_stmt*)xml_spec(xt)) == NULL){
|
if ((ys = (yang_stmt*)xml_spec(xt)) == NULL){
|
||||||
clicon_log(LOG_WARNING, "%s: no xml_spec(%s)", __FUNCTION__, xml_name(xt));
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -1438,7 +1445,6 @@ xml_non_config_data(cxobj *xt,
|
||||||
yang_stmt *ys;
|
yang_stmt *ys;
|
||||||
|
|
||||||
if ((ys = (yang_stmt*)xml_spec(xt)) == NULL){
|
if ((ys = (yang_stmt*)xml_spec(xt)) == NULL){
|
||||||
clicon_log(LOG_WARNING, "%s: no xml_spec(%s)", __FUNCTION__, xml_name(xt));
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -1455,6 +1461,7 @@ xml_non_config_data(cxobj *xt,
|
||||||
/*! Add yang specification backpoint to XML node
|
/*! Add yang specification backpoint to XML node
|
||||||
* @param[in] xt XML tree node
|
* @param[in] xt XML tree node
|
||||||
* @note This should really be unnecessary since yspec should be set on creation
|
* @note This should really be unnecessary since yspec should be set on creation
|
||||||
|
* @note For subs to anyxml nodes will not have spec set
|
||||||
* @code
|
* @code
|
||||||
* xml_apply(xc, CX_ELMNT, xml_spec_populate, yspec)
|
* xml_apply(xc, CX_ELMNT, xml_spec_populate, yspec)
|
||||||
* @endcode
|
* @endcode
|
||||||
|
|
@ -1466,25 +1473,28 @@ xml_spec_populate(cxobj *x,
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
yang_spec *yspec = (yang_spec*)arg;
|
yang_spec *yspec = (yang_spec*)arg;
|
||||||
char *name;
|
char *name;
|
||||||
yang_stmt *y; /* yang node */
|
yang_stmt *y=NULL; /* yang node */
|
||||||
cxobj *xp; /* xml parent */
|
cxobj *xp; /* xml parent */
|
||||||
yang_stmt *yp; /* parent yang */
|
yang_stmt *yp; /* parent yang */
|
||||||
|
|
||||||
name = xml_name(x);
|
name = xml_name(x);
|
||||||
if ((xp = xml_parent(x)) != NULL &&
|
if ((xp = xml_parent(x)) != NULL &&
|
||||||
(yp = xml_spec(xp)) != NULL)
|
(yp = xml_spec(xp)) != NULL)
|
||||||
y = yang_find_syntax((yang_node*)yp, xml_name(x));
|
y = yang_find_datanode((yang_node*)yp, xml_name(x));
|
||||||
else
|
else
|
||||||
y = yang_find_topnode(yspec, name); /* still NULL for config */
|
y = yang_find_topnode(yspec, name); /* still NULL for config */
|
||||||
|
#ifdef XXX_OBSOLETE /* Add validate elsewhere */
|
||||||
if (y==NULL){
|
if (y==NULL){
|
||||||
clicon_err(OE_XML, EBADF, "yang spec not found for xml node '%s' xml parent name: '%s' yangspec:'%s']",
|
clicon_err(OE_XML, EBADF, "yang spec not found for xml node '%s' xml parent name: '%s' yangspec:'%s']",
|
||||||
name,
|
name,
|
||||||
xp?xml_name(xp):"", yp?yp->ys_argument:"");
|
xp?xml_name(xp):"", yp?yp->ys_argument:"");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
if (y)
|
||||||
xml_spec_set(x, y);
|
xml_spec_set(x, y);
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
// done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1541,7 +1551,7 @@ api_path2xpath_cvv(yang_spec *yspec,
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
assert(y!=NULL);
|
assert(y!=NULL);
|
||||||
if ((y = yang_find_syntax((yang_node*)y, name)) == NULL){
|
if ((y = yang_find_datanode((yang_node*)y, name)) == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "No yang node found: %s", name);
|
clicon_err(OE_UNIX, errno, "No yang node found: %s", name);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -1671,7 +1681,7 @@ api_path2xml_vec(char **vec,
|
||||||
if (y0->yn_keyword == Y_SPEC) /* top-node */
|
if (y0->yn_keyword == Y_SPEC) /* top-node */
|
||||||
y = yang_find_topnode((yang_spec*)y0, name);
|
y = yang_find_topnode((yang_spec*)y0, name);
|
||||||
else
|
else
|
||||||
y = yang_find_syntax((yang_node*)y0, name);
|
y = yang_find_datanode((yang_node*)y0, name);
|
||||||
if (y == NULL){
|
if (y == NULL){
|
||||||
clicon_err(OE_YANG, errno, "No yang node found: %s", name);
|
clicon_err(OE_YANG, errno, "No yang node found: %s", name);
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -1936,7 +1946,7 @@ xml_merge1(cxobj *x0,
|
||||||
while ((x1c = xml_child_each(x1, x1c, CX_ELMNT)) != NULL) {
|
while ((x1c = xml_child_each(x1, x1c, CX_ELMNT)) != NULL) {
|
||||||
x1cname = xml_name(x1c);
|
x1cname = xml_name(x1c);
|
||||||
/* Get yang spec of the child */
|
/* Get yang spec of the child */
|
||||||
if ((yc = yang_find_syntax(y0, x1cname)) == NULL){
|
if ((yc = yang_find_datanode(y0, x1cname)) == NULL){
|
||||||
clicon_err(OE_YANG, errno, "No yang node found: %s", x1cname);
|
clicon_err(OE_YANG, errno, "No yang node found: %s", x1cname);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -376,7 +376,7 @@ yn_each(yang_node *yn,
|
||||||
* @param[in] argument String compare w wrgument. if NULL, match any.
|
* @param[in] argument String compare w wrgument. if NULL, match any.
|
||||||
* This however means that if you actually want to match only a yang-stmt with
|
* This however means that if you actually want to match only a yang-stmt with
|
||||||
* argument==NULL you cannot, but I have not seen any such examples.
|
* argument==NULL you cannot, but I have not seen any such examples.
|
||||||
* @see yang_find_syntax
|
* @see yang_find_datanode
|
||||||
*/
|
*/
|
||||||
yang_stmt *
|
yang_stmt *
|
||||||
yang_find(yang_node *yn,
|
yang_find(yang_node *yn,
|
||||||
|
|
@ -402,19 +402,16 @@ yang_find(yang_node *yn,
|
||||||
return match ? ys : NULL;
|
return match ? ys : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Find a child syntax-node yang_stmt with matching argument (container, leaf, etc)
|
/*! Find child data node with matching argument (container, leaf, etc)
|
||||||
*
|
*
|
||||||
* @param[in] yn Yang node, current context node.
|
* @param[in] yn Yang node, current context node.
|
||||||
* @param[in] argument if NULL, match any(first) argument.
|
* @param[in] argument if NULL, match any(first) argument. XXX is that really a case?
|
||||||
*
|
*
|
||||||
* @see yang_find But this looks only for the yang specification nodes with
|
* @see yang_find Looks for any node
|
||||||
* the following keyword: container, leaf, list, leaf-list
|
* @note May deviate from RFC since it explores choice/case not just return it.
|
||||||
* That is, basic syntax nodes.
|
|
||||||
* @note check if argument==NULL really required?
|
|
||||||
* Is this yang-stmt a container, list, leaf or leaf-list?
|
|
||||||
*/
|
*/
|
||||||
yang_stmt *
|
yang_stmt *
|
||||||
yang_find_syntax(yang_node *yn,
|
yang_find_datanode(yang_node *yn,
|
||||||
char *argument)
|
char *argument)
|
||||||
{
|
{
|
||||||
yang_stmt *ys = NULL;
|
yang_stmt *ys = NULL;
|
||||||
|
|
@ -428,9 +425,9 @@ yang_find_syntax(yang_node *yn,
|
||||||
for (j=0; j<ys->ys_len; j++){
|
for (j=0; j<ys->ys_len; j++){
|
||||||
yc = ys->ys_stmt[j];
|
yc = ys->ys_stmt[j];
|
||||||
if (yc->ys_keyword == Y_CASE) /* Look for its children */
|
if (yc->ys_keyword == Y_CASE) /* Look for its children */
|
||||||
ysmatch = yang_find_syntax((yang_node*)yc, argument);
|
ysmatch = yang_find_datanode((yang_node*)yc, argument);
|
||||||
else
|
else
|
||||||
if (yang_is_syntax(yc)){
|
if (yang_datanode(yc)){
|
||||||
if (argument == NULL)
|
if (argument == NULL)
|
||||||
ysmatch = yc;
|
ysmatch = yc;
|
||||||
else
|
else
|
||||||
|
|
@ -440,9 +437,9 @@ yang_find_syntax(yang_node *yn,
|
||||||
if (ysmatch)
|
if (ysmatch)
|
||||||
goto match;
|
goto match;
|
||||||
}
|
}
|
||||||
}
|
} /* Y_CHOICE */
|
||||||
else
|
else
|
||||||
if (yang_is_syntax(ys)){
|
if (yang_datanode(ys)){
|
||||||
if (argument == NULL)
|
if (argument == NULL)
|
||||||
ysmatch = ys;
|
ysmatch = ys;
|
||||||
else
|
else
|
||||||
|
|
@ -456,7 +453,10 @@ yang_find_syntax(yang_node *yn,
|
||||||
return ysmatch;
|
return ysmatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Help function to check find 'top-node', eg first 'syntax' node in a spec
|
/*! Find 'top-node', eg first data node in all (sub)modules in a yang spec
|
||||||
|
*
|
||||||
|
* @param[in] ysp Yang specification
|
||||||
|
* @param[in] name if NULL, match any(first) argument. XXX is that really a case?
|
||||||
* A yang specification has modules as children which in turn can have
|
* A yang specification has modules as children which in turn can have
|
||||||
* syntax-nodes as children. This function goes through all the modules to
|
* syntax-nodes as children. This function goes through all the modules to
|
||||||
* look for syntax-nodes. Note that if a child to a module is a choice,
|
* look for syntax-nodes. Note that if a child to a module is a choice,
|
||||||
|
|
@ -472,23 +472,22 @@ yang_find_topnode(yang_spec *ysp,
|
||||||
|
|
||||||
for (i=0; i<ysp->yp_len; i++){
|
for (i=0; i<ysp->yp_len; i++){
|
||||||
ys = ysp->yp_stmt[i];
|
ys = ysp->yp_stmt[i];
|
||||||
if ((yc = yang_find_syntax((yang_node*)ys, name)) != NULL)
|
if ((yc = yang_find_datanode((yang_node*)ys, name)) != NULL)
|
||||||
return yc;
|
return yc;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Find a child spec-node yang_stmt with matching argument for xpath
|
/*! Find a child spec-node yang_stmt with matching argument for schema-nodid
|
||||||
*
|
*
|
||||||
* See also yang_find() but this looks only for the yang specification nodes with
|
* See also yang_find() but this looks only for the yang specification nodes with
|
||||||
* the following keyword: container, leaf, list, leaf-list
|
* the following keyword: container, leaf, list, leaf-list
|
||||||
* That is, basic syntax nodes.
|
* That is, basic syntax nodes.
|
||||||
* @see yang_find_syntax # Maybe this is the same as specnode?
|
* @see yang_find_datanode
|
||||||
* @see clicon_dbget_xpath
|
* @see clicon_dbget_xpath
|
||||||
* @see xpath_vec
|
|
||||||
*/
|
*/
|
||||||
static yang_stmt *
|
static yang_stmt *
|
||||||
yang_find_xpath_stmt(yang_node *yn,
|
schema_nodeid_stmt(yang_node *yn,
|
||||||
char *argument)
|
char *argument)
|
||||||
{
|
{
|
||||||
yang_stmt *ys = NULL;
|
yang_stmt *ys = NULL;
|
||||||
|
|
@ -497,24 +496,20 @@ yang_find_xpath_stmt(yang_node *yn,
|
||||||
|
|
||||||
for (i=0; i<yn->yn_len; i++){
|
for (i=0; i<yn->yn_len; i++){
|
||||||
ys = yn->yn_stmt[i];
|
ys = yn->yn_stmt[i];
|
||||||
|
if (!yang_schemanode(ys))
|
||||||
|
continue;
|
||||||
/* some keys dont have arguments, match on key */
|
/* some keys dont have arguments, match on key */
|
||||||
if (ys->ys_keyword == Y_INPUT || ys->ys_keyword == Y_OUTPUT){
|
if (ys->ys_keyword == Y_INPUT || ys->ys_keyword == Y_OUTPUT){
|
||||||
if (strcmp(argument, yang_key2str(ys->ys_keyword)) == 0)
|
if (strcmp(argument, yang_key2str(ys->ys_keyword)) == 0){
|
||||||
match++;
|
match++;
|
||||||
}
|
|
||||||
else
|
|
||||||
if (ys->ys_keyword == Y_CONTAINER || ys->ys_keyword == Y_LEAF ||
|
|
||||||
ys->ys_keyword == Y_LIST || ys->ys_keyword == Y_LEAF_LIST ||
|
|
||||||
ys->ys_keyword == Y_MODULE || ys->ys_keyword == Y_SUBMODULE ||
|
|
||||||
ys->ys_keyword == Y_RPC || ys->ys_keyword == Y_CHOICE ||
|
|
||||||
ys->ys_keyword == Y_CASE
|
|
||||||
){
|
|
||||||
if (ys->ys_argument && strcmp(argument, ys->ys_argument) == 0)
|
|
||||||
match++;
|
|
||||||
}
|
|
||||||
if (match)
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} else
|
||||||
|
if (ys->ys_argument && strcmp(argument, ys->ys_argument) == 0){
|
||||||
|
match++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
return match ? ys : NULL;
|
return match ? ys : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -966,21 +961,6 @@ ys_populate_type(yang_stmt *ys,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
if (strcmp(ys->ys_argument, "leafref") == 0){
|
|
||||||
#ifdef notyet /* XXX: Do augment first */
|
|
||||||
yang_stmt *ypath;
|
|
||||||
if ((ypath = yang_find((yang_node*)ys, Y_PATH, NULL)) == NULL){
|
|
||||||
clicon_err(OE_YANG, 0, "leafref type requires path sub-statement");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (yang_xpath((yang_node*)ys, ypath->ys_argument) == NULL){
|
|
||||||
clicon_err(OE_YANG, 0, "Leafref path %s not found",
|
|
||||||
ypath->ys_argument);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
|
|
@ -1101,17 +1081,17 @@ yang_augment_node(yang_stmt *ys,
|
||||||
yang_spec *ysp)
|
yang_spec *ysp)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *path;
|
char *schema_nodeid;
|
||||||
yang_node *yn;
|
yang_node *yn;
|
||||||
yang_stmt *yc;
|
yang_stmt *yc;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
path = ys->ys_argument;
|
schema_nodeid = ys->ys_argument;
|
||||||
clicon_debug(1, "%s %s", __FUNCTION__, path);
|
clicon_debug(1, "%s %s", __FUNCTION__, schema_nodeid);
|
||||||
|
|
||||||
/* Find the target */
|
/* Find the target */
|
||||||
if ((yn = yang_xpath_abs((yang_node*)ys, path)) == NULL){
|
if ((yn = yang_abs_schema_nodeid((yang_node*)ys, schema_nodeid)) == NULL){
|
||||||
clicon_err(OE_YANG, 0, "Augment path %s not found", path);
|
clicon_err(OE_YANG, 0, "Augment schema_nodeid %s not found", schema_nodeid);
|
||||||
// retval = 0; /* Ignore, continue */
|
// retval = 0; /* Ignore, continue */
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -1269,8 +1249,7 @@ yang_expand(yang_node *yn)
|
||||||
* @retval NULL Error encountered
|
* @retval NULL Error encountered
|
||||||
* Calling order:
|
* Calling order:
|
||||||
* yang_parse # Parse top-level yang module. Expand and populate yang tree
|
* yang_parse # Parse top-level yang module. Expand and populate yang tree
|
||||||
* yang_parse1 # Parse one yang module, go through its (sub)modules and parse them
|
* yang_parse_recurse # Parse one yang module, go through its (sub)modules, parse them and then recursively parse them
|
||||||
* yang_parse2 # Find file from yang (sub)module
|
|
||||||
* yang_parse_file # Read yang file into a string
|
* yang_parse_file # Read yang file into a string
|
||||||
* yang_parse_str # Set up yacc parser and call it given a string
|
* yang_parse_str # Set up yacc parser and call it given a string
|
||||||
* clixon_yang_parseparse # Actual yang parsing using yacc
|
* clixon_yang_parseparse # Actual yang parsing using yacc
|
||||||
|
|
@ -1322,8 +1301,7 @@ yang_parse_str(clicon_handle h,
|
||||||
* Similar to clicon_yang_str(), just read a file first
|
* Similar to clicon_yang_str(), just read a file first
|
||||||
* (cloned from cligen)
|
* (cloned from cligen)
|
||||||
* @param h CLICON handle
|
* @param h CLICON handle
|
||||||
* @param f Open file handle
|
* @param filename Name of file
|
||||||
* @param name Log string, typically filename
|
|
||||||
* @param ysp Yang specification. Should ave been created by caller using yspec_new
|
* @param ysp Yang specification. Should ave been created by caller using yspec_new
|
||||||
* @retval ymod Top-level yang (sub)module
|
* @retval ymod Top-level yang (sub)module
|
||||||
* @retval NULL Error encountered
|
* @retval NULL Error encountered
|
||||||
|
|
@ -1331,26 +1309,35 @@ yang_parse_str(clicon_handle h,
|
||||||
* The database symbols are inserted in alphabetical order.
|
* The database symbols are inserted in alphabetical order.
|
||||||
* Calling order:
|
* Calling order:
|
||||||
* yang_parse # Parse top-level yang module. Expand and populate yang tree
|
* yang_parse # Parse top-level yang module. Expand and populate yang tree
|
||||||
* yang_parse1 # Parse one yang module, go through its (sub)modules and parse them
|
* yang_parse_recurse # Parse one yang module, go through its (sub)modules, parse them and then recursively parse them
|
||||||
* yang_parse2 # Find file from yang (sub)module
|
|
||||||
* yang_parse_file # Read yang file into a string
|
* yang_parse_file # Read yang file into a string
|
||||||
* yang_parse_str # Set up yacc parser and call it given a string
|
* yang_parse_str # Set up yacc parser and call it given a string
|
||||||
* clixon_yang_parseparse # Actual yang parsing using yacc
|
* clixon_yang_parseparse # Actual yang parsing using yacc
|
||||||
*/
|
*/
|
||||||
static yang_stmt *
|
static yang_stmt *
|
||||||
yang_parse_file(clicon_handle h,
|
yang_parse_file(clicon_handle h,
|
||||||
FILE *f,
|
const char *filename,
|
||||||
const char *name, /* just for errs */
|
|
||||||
yang_spec *ysp
|
yang_spec *ysp
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
char *buf;
|
char *buf = NULL;
|
||||||
int i;
|
int i;
|
||||||
int c;
|
int c;
|
||||||
int len;
|
int len;
|
||||||
yang_stmt *ymod = NULL;
|
yang_stmt *ymod = NULL;
|
||||||
|
FILE *f = NULL;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
clicon_debug(1, "Yang parse file: %s", filename);
|
||||||
|
if (stat(filename, &st) < 0){
|
||||||
|
clicon_err(OE_YANG, errno, "%s not found", filename);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if ((f = fopen(filename, "r")) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "fopen(%s)", filename);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
clicon_debug(1, "Yang parse file: %s", name);
|
|
||||||
len = 1024; /* any number is fine */
|
len = 1024; /* any number is fine */
|
||||||
if ((buf = malloc(len)) == NULL){
|
if ((buf = malloc(len)) == NULL){
|
||||||
perror("pt_file malloc");
|
perror("pt_file malloc");
|
||||||
|
|
@ -1372,9 +1359,11 @@ yang_parse_file(clicon_handle h,
|
||||||
}
|
}
|
||||||
buf[i++] = (char)(c&0xff);
|
buf[i++] = (char)(c&0xff);
|
||||||
} /* read a line */
|
} /* read a line */
|
||||||
if ((ymod = yang_parse_str(h, buf, name, ysp)) < 0)
|
if ((ymod = yang_parse_str(h, buf, filename, ysp)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
done:
|
done:
|
||||||
|
if (f)
|
||||||
|
fclose(f);
|
||||||
if (buf)
|
if (buf)
|
||||||
free(buf);
|
free(buf);
|
||||||
return ymod; /* top-level (sub)module */
|
return ymod; /* top-level (sub)module */
|
||||||
|
|
@ -1431,38 +1420,43 @@ yang_parse_find_match(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Find and open yang file and then parse it
|
/*! Parse one yang module then go through (sub)modules and parse them recursively
|
||||||
*
|
*
|
||||||
* @param h CLICON handle
|
* @param[in] h CLICON handle
|
||||||
* @param yang_dir Directory where all YANG module files reside
|
* @param[in] yang_dir Directory where all YANG module files reside
|
||||||
* @param module Name of main YANG module. More modules may be parsed if imported
|
* @param[in] module Name of main YANG module. Or absolute file name.
|
||||||
* @param revision Optional module revision date
|
* @param[in] revision Optional module revision date
|
||||||
* @param ysp Yang specification. Should ave been created by caller using yspec_new
|
* @param[in] ysp Yang specification. Should have been created by caller using yspec_new
|
||||||
* @retval ymod Top-level yang (sub)module
|
* @retval ymod Top-level yang (sub)module
|
||||||
* @retval NULL Error encountered
|
* @retval NULL Error encountered
|
||||||
* module-or-submodule-name ['@' revision-date] ( '.yang' / '.yin' )
|
* Find a yang module file, and then recursively parse all its imported modules.
|
||||||
* Calling order:
|
* Calling order:
|
||||||
* yang_parse # Parse top-level yang module. Expand and populate yang tree
|
* yang_parse # Parse top-level yang module. Expand and populate yang tree
|
||||||
* yang_parse1 # Parse one yang module, go through its (sub)modules and parse them
|
* yang_parse_recurse # Parse one yang module, go through its (sub)modules, parse them and then recursively parse them
|
||||||
* yang_parse2 # Find file from yang (sub)module
|
|
||||||
* yang_parse_file # Read yang file into a string
|
* yang_parse_file # Read yang file into a string
|
||||||
* yang_parse_str # Set up yacc parser and call it given a string
|
* yang_parse_str # Set up yacc parser and call it given a string
|
||||||
* clixon_yang_parseparse # Actual yang parsing using yacc
|
* clixon_yang_parseparse # Actual yang parsing using yacc
|
||||||
*/
|
*/
|
||||||
static yang_stmt *
|
static yang_stmt *
|
||||||
yang_parse2(clicon_handle h,
|
yang_parse_recurse(clicon_handle h,
|
||||||
const char *yang_dir,
|
const char *yang_dir,
|
||||||
const char *module,
|
const char *module,
|
||||||
const char *revision,
|
const char *revision,
|
||||||
yang_spec *ysp)
|
yang_spec *ysp)
|
||||||
{
|
{
|
||||||
FILE *f = NULL;
|
yang_stmt *yi = NULL; /* import */
|
||||||
|
yang_stmt *ymod;
|
||||||
|
yang_stmt *yrev;
|
||||||
|
char *modname;
|
||||||
|
char *subrevision;
|
||||||
cbuf *fbuf = NULL;
|
cbuf *fbuf = NULL;
|
||||||
char *filename;
|
|
||||||
yang_stmt *ymod = NULL;
|
|
||||||
struct stat st;
|
|
||||||
int nr;
|
int nr;
|
||||||
|
|
||||||
|
if (module[0] == '/'){
|
||||||
|
if ((ymod = yang_parse_file(h, module, ysp)) == NULL)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
else {
|
||||||
if ((fbuf = cbuf_new()) == NULL){
|
if ((fbuf = cbuf_new()) == NULL){
|
||||||
clicon_err(OE_YANG, errno, "%s: cbuf_new", __FUNCTION__);
|
clicon_err(OE_YANG, errno, "%s: cbuf_new", __FUNCTION__);
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -1478,58 +1472,10 @@ yang_parse2(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
filename = cbuf_get(fbuf);
|
if ((ymod = yang_parse_file(h, cbuf_get(fbuf), ysp)) == NULL)
|
||||||
if (stat(filename, &st) < 0){
|
|
||||||
clicon_err(OE_YANG, errno, "%s not found", filename);
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((f = fopen(filename, "r")) == NULL){
|
|
||||||
clicon_err(OE_UNIX, errno, "fopen(%s)", filename);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if ((ymod = yang_parse_file(h, f, filename, ysp)) == NULL)
|
|
||||||
goto done;
|
|
||||||
done:
|
|
||||||
if (fbuf)
|
|
||||||
cbuf_free(fbuf);
|
|
||||||
if (f)
|
|
||||||
fclose(f);
|
|
||||||
return ymod; /* top-level (sub)module */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Parse one yang module then go through (sub)modules and parse them recursively
|
|
||||||
*
|
|
||||||
* @param h CLICON handle
|
|
||||||
* @param yang_dir Directory where all YANG module files reside
|
|
||||||
* @param module Name of main YANG module. More modules may be parsed if imported
|
|
||||||
* @param revision Optional module revision date
|
|
||||||
* @param ysp Yang specification. Should have been created by caller using yspec_new
|
|
||||||
* @retval ymod Top-level yang (sub)module
|
|
||||||
* @retval NULL Error encountered
|
|
||||||
* Find a yang module file, and then recursively parse all its imported modules.
|
|
||||||
* Calling order:
|
|
||||||
* yang_parse # Parse top-level yang module. Expand and populate yang tree
|
|
||||||
* yang_parse1 # Parse one yang module, go through its (sub)modules and parse them
|
|
||||||
* yang_parse2 # Find file from yang (sub)module
|
|
||||||
* yang_parse_file # Read yang file into a string
|
|
||||||
* yang_parse_str # Set up yacc parser and call it given a string
|
|
||||||
* clixon_yang_parseparse # Actual yang parsing using yacc
|
|
||||||
*/
|
|
||||||
static yang_stmt *
|
|
||||||
yang_parse1(clicon_handle h,
|
|
||||||
const char *yang_dir,
|
|
||||||
const char *module,
|
|
||||||
const char *revision,
|
|
||||||
yang_spec *ysp)
|
|
||||||
{
|
|
||||||
yang_stmt *yi = NULL; /* import */
|
|
||||||
yang_stmt *ymod;
|
|
||||||
yang_stmt *yrev;
|
|
||||||
char *modname;
|
|
||||||
char *subrevision;
|
|
||||||
|
|
||||||
if ((ymod = yang_parse2(h, yang_dir, module, revision, ysp)) == NULL)
|
|
||||||
goto done;
|
|
||||||
/* go through all import statements of ysp (or its module) */
|
/* go through all import statements of ysp (or its module) */
|
||||||
while ((yi = yn_each((yang_node*)ymod, yi)) != NULL){
|
while ((yi = yn_each((yang_node*)ymod, yi)) != NULL){
|
||||||
if (yi->ys_keyword != Y_IMPORT)
|
if (yi->ys_keyword != Y_IMPORT)
|
||||||
|
|
@ -1540,30 +1486,33 @@ yang_parse1(clicon_handle h,
|
||||||
else
|
else
|
||||||
subrevision = NULL;
|
subrevision = NULL;
|
||||||
if (yang_find((yang_node*)ysp, Y_MODULE, modname) == NULL)
|
if (yang_find((yang_node*)ysp, Y_MODULE, modname) == NULL)
|
||||||
if (yang_parse1(h, yang_dir, modname, subrevision, ysp) == NULL){
|
/* recursive call */
|
||||||
|
if (yang_parse_recurse(h, yang_dir, modname, subrevision, ysp) == NULL){
|
||||||
ymod = NULL;
|
ymod = NULL;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
|
if (fbuf)
|
||||||
|
cbuf_free(fbuf);
|
||||||
return ymod; /* top-level (sub)module */
|
return ymod; /* top-level (sub)module */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Parse top yang module including all its sub-modules. Expand and populate yang tree
|
/*! Parse top yang module including all its sub-modules. Expand and populate yang tree
|
||||||
*
|
*
|
||||||
* @param[in] h CLICON handle
|
* @param[in] h CLICON handle
|
||||||
* @param[in] yang_dir Directory where all YANG module files reside
|
* @param[in] yang_dir Directory where all YANG module files reside (except mainfile)
|
||||||
* @param[in] module Name of main YANG module. More modules may be parsed if imported
|
* @param[in] mainmod Name of main YANG module. Or absolute file name.
|
||||||
* @param[in] revision Optional module revision date
|
* @param[in] revision Optional main module revision date.
|
||||||
* @param[out] ysp Yang specification. Should ave been created by caller using yspec_new
|
* @param[out] ysp Yang specification. Should ave been created by caller using yspec_new
|
||||||
* @retval 0 Everything OK
|
* @retval 0 Everything OK
|
||||||
* @retval -1 Error encountered
|
* @retval -1 Error encountered
|
||||||
* The database symbols are inserted in alphabetical order.
|
* The database symbols are inserted in alphabetical order.
|
||||||
* Find a yang module file, and then recursively parse all its imported modules.
|
* Find a yang module file, and then recursively parse all its imported modules.
|
||||||
|
* @note if mainmod is filename, revision is not considered.
|
||||||
* Calling order:
|
* Calling order:
|
||||||
* yang_parse # Parse top-level yang module. Expand and populate yang tree
|
* yang_parse # Parse top-level yang module. Expand and populate yang tree
|
||||||
* yang_parse1 # Parse one yang module, go through its (sub)modules and parse them
|
* yang_parse_recurse # Parse one yang module, go through its (sub)modules, parse them and then recursively parse them
|
||||||
* yang_parse2 # Find file from yang (sub)module
|
|
||||||
* yang_parse_file # Read yang file into a string
|
* yang_parse_file # Read yang file into a string
|
||||||
* yang_parse_str # Set up yacc parser and call it given a string
|
* yang_parse_str # Set up yacc parser and call it given a string
|
||||||
* clixon_yang_parseparse # Actual yang parsing using yacc
|
* clixon_yang_parseparse # Actual yang parsing using yacc
|
||||||
|
|
@ -1571,7 +1520,7 @@ yang_parse1(clicon_handle h,
|
||||||
int
|
int
|
||||||
yang_parse(clicon_handle h,
|
yang_parse(clicon_handle h,
|
||||||
const char *yang_dir,
|
const char *yang_dir,
|
||||||
const char *module,
|
const char *mainmodule,
|
||||||
const char *revision,
|
const char *revision,
|
||||||
yang_spec *ysp)
|
yang_spec *ysp)
|
||||||
{
|
{
|
||||||
|
|
@ -1579,7 +1528,7 @@ yang_parse(clicon_handle h,
|
||||||
yang_stmt *ymod; /* Top-level yang (sub)module */
|
yang_stmt *ymod; /* Top-level yang (sub)module */
|
||||||
|
|
||||||
/* Step 1: parse from text to yang parse-tree. */
|
/* Step 1: parse from text to yang parse-tree. */
|
||||||
if ((ymod = yang_parse1(h, yang_dir, module, revision, ysp)) == NULL)
|
if ((ymod = yang_parse_recurse(h, yang_dir, mainmodule, revision, ysp)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
/* Add top module name as dbspec-name */
|
/* Add top module name as dbspec-name */
|
||||||
clicon_dbspec_name_set(h, ymod->ys_argument);
|
clicon_dbspec_name_set(h, ymod->ys_argument);
|
||||||
|
|
@ -1661,16 +1610,22 @@ yang_apply(yang_node *yn,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! All the work for yang_xpath.
|
/*! All the work for schema_nodeid functions both absolute and descendant
|
||||||
Ignore prefixes, see _abs */
|
* Ignore prefixes, see _abs
|
||||||
|
* @param[in] yn Yang node
|
||||||
|
* @param[in] vec Vector of nodeid's in a schema node identifier, eg a/b
|
||||||
|
* @param[in] nvec Length of vec
|
||||||
|
* @retval NULL Error, with clicon_err called
|
||||||
|
* @retval yres First yang node matching schema nodeid
|
||||||
|
*/
|
||||||
static yang_node *
|
static yang_node *
|
||||||
yang_xpath_vec(yang_node *yn,
|
schema_nodeid_vec(yang_node *yn,
|
||||||
char **vec,
|
char **vec,
|
||||||
int nvec)
|
int nvec)
|
||||||
{
|
{
|
||||||
char *arg;
|
char *arg;
|
||||||
yang_stmt *ys;
|
yang_stmt *ys;
|
||||||
yang_node *yret = NULL;
|
yang_node *yres = NULL;
|
||||||
char *id;
|
char *id;
|
||||||
|
|
||||||
if (nvec <= 0)
|
if (nvec <= 0)
|
||||||
|
|
@ -1687,44 +1642,46 @@ yang_xpath_vec(yang_node *yn,
|
||||||
id = arg;
|
id = arg;
|
||||||
else
|
else
|
||||||
id++;
|
id++;
|
||||||
if ((ys = yang_find_xpath_stmt(yn, id)) == NULL){
|
if ((ys = schema_nodeid_stmt(yn, id)) == NULL){
|
||||||
clicon_debug(1, "%s %s not found", __FUNCTION__, id);
|
clicon_debug(1, "%s %s not found", __FUNCTION__, id);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nvec == 1){
|
if (nvec == 1){
|
||||||
yret = (yang_node*)ys;
|
yres = (yang_node*)ys;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
yret = yang_xpath_vec((yang_node*)ys, vec+1, nvec-1);
|
yres = schema_nodeid_vec((yang_node*)ys, vec+1, nvec-1);
|
||||||
done:
|
done:
|
||||||
return yret;
|
return yres;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Given an absolute schema-nodeid (eg /a/b/c) find matching yang spec
|
||||||
/*! Given an absolute xpath (eg /a/b/c) find matching yang specification
|
|
||||||
* @param[in] yn Yang node
|
* @param[in] yn Yang node
|
||||||
* @param[in] xpath Absolute xpath, ie /a/b
|
* @param[in] schema_nodeid Absolute schema-node-id, ie /a/b
|
||||||
|
* @retval NULL Error, with clicon_err called
|
||||||
|
* @retval yres First yang node matching schema nodeid
|
||||||
|
* @see yang_schema_nodeid
|
||||||
*/
|
*/
|
||||||
yang_node *
|
yang_node *
|
||||||
yang_xpath_abs(yang_node *yn,
|
yang_abs_schema_nodeid(yang_node *yn,
|
||||||
char *xpath)
|
char *schema_nodeid)
|
||||||
{
|
{
|
||||||
char **vec = NULL;
|
char **vec = NULL;
|
||||||
int nvec;
|
int nvec;
|
||||||
yang_node *ys = NULL;
|
yang_node *yres = NULL;
|
||||||
yang_stmt *ymod;
|
yang_stmt *ymod;
|
||||||
char *id;
|
char *id;
|
||||||
char *prefix = NULL;
|
char *prefix = NULL;
|
||||||
|
|
||||||
if ((vec = clicon_strsep(xpath, "/", &nvec)) == NULL){
|
if ((vec = clicon_strsep(schema_nodeid, "/", &nvec)) == NULL){
|
||||||
clicon_err(OE_YANG, errno, "%s: strsep", __FUNCTION__);
|
clicon_err(OE_YANG, errno, "%s: strsep", __FUNCTION__);
|
||||||
return NULL;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Assume path looks like: "/prefix:id[/prefix:id]*" */
|
/* Assume schame nodeid looks like: "/prefix:id[/prefix:id]*" */
|
||||||
if (nvec < 2){
|
if (nvec < 2){
|
||||||
clicon_err(OE_YANG, 0, "%s: NULL or truncated path: %s",
|
clicon_err(OE_YANG, 0, "%s: NULL or truncated path: %s",
|
||||||
__FUNCTION__, xpath);
|
__FUNCTION__, schema_nodeid);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1753,53 +1710,77 @@ yang_xpath_abs(yang_node *yn,
|
||||||
if ((ymod = yang_find_module_by_prefix((yang_stmt*)yn, prefix)) == NULL)
|
if ((ymod = yang_find_module_by_prefix((yang_stmt*)yn, prefix)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
ys = yang_xpath_vec((yang_node*)ymod, vec+1, nvec-1);
|
yres = schema_nodeid_vec((yang_node*)ymod, vec+1, nvec-1);
|
||||||
done:
|
done:
|
||||||
if (vec)
|
if (vec)
|
||||||
free(vec);
|
free(vec);
|
||||||
if (prefix)
|
if (prefix)
|
||||||
free(prefix);
|
free(prefix);
|
||||||
return ys;
|
return yres;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Given an xpath (eg /a/b/c or a/b/c) find matching yang specification
|
/*! Given a descendant schema-nodeid (eg a/b/c) find matching yang spec
|
||||||
* Note that xpath is defined for xml, and for instances of data, this is
|
* @param[in] yn Yang node
|
||||||
* for specifications, sp expect some differences.
|
* @param[in] schema_nodeid Descendant schema-node-id, ie a/b
|
||||||
* @param[in] yn Yang node tree
|
|
||||||
* @param[in] xpath A limited xpath expression on the type a/b/c
|
|
||||||
* @retval NULL Error, with clicon_err called
|
* @retval NULL Error, with clicon_err called
|
||||||
* @retval ys First yang node matching xpath
|
* @retval yres First yang node matching schema nodeid
|
||||||
|
* @see yang_schema_nodeid
|
||||||
|
*/
|
||||||
|
yang_node *
|
||||||
|
yang_desc_schema_nodeid(yang_node *yn,
|
||||||
|
char *schema_nodeid)
|
||||||
|
{
|
||||||
|
yang_node *yres = NULL;
|
||||||
|
char **vec = NULL;
|
||||||
|
int nvec;
|
||||||
|
|
||||||
|
if (strlen(schema_nodeid) == 0)
|
||||||
|
goto done;
|
||||||
|
/* check absolute schema_nodeid */
|
||||||
|
if (schema_nodeid[0] == '/'){
|
||||||
|
clicon_err(OE_YANG, EINVAL, "descenadant schema nodeid should not start with /");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if ((vec = clicon_strsep(schema_nodeid, "/", &nvec)) == NULL)
|
||||||
|
goto done;
|
||||||
|
yres = schema_nodeid_vec((yang_node*)yn, vec, nvec);
|
||||||
|
done:
|
||||||
|
if (vec)
|
||||||
|
free(vec);
|
||||||
|
return yres;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Given a schema-node-id (eg /a/b/c or a/b/c) find matching yang specification
|
||||||
|
*
|
||||||
|
* They are either absolute (start with /) or descendant (no /)
|
||||||
|
* Compare with XPATH for XML, this is for YANG spec
|
||||||
|
* @param[in] yn Yang node tree
|
||||||
|
* @param[in] schema_nodeid schema-node-id, ie a/b or /a/b
|
||||||
|
* @retval NULL Error, with clicon_err called
|
||||||
|
* @retval yres First yang node matching schema nodeid
|
||||||
* @note: the identifiers in the xpath (eg a, b in a/b) can match the nodes
|
* @note: the identifiers in the xpath (eg a, b in a/b) can match the nodes
|
||||||
* defined in yang_xpath: container, leaf,list,leaf-list, modules, sub-modules
|
* defined in yang_xpath: container, leaf,list,leaf-list, modules, sub-modules
|
||||||
* Example:
|
* Example:
|
||||||
* yn : module m { prefix b; container b { list c { key d; leaf d; }} }
|
* yn : module m { prefix b; container b { list c { key d; leaf d; }} }
|
||||||
* xpath = m/b/c, returns the list 'c'.
|
* schema-node-id = m/b/c, returns the list 'c'.
|
||||||
* @see xpath_vec
|
|
||||||
* @see clicon_dbget_xpath
|
|
||||||
*/
|
*/
|
||||||
yang_node *
|
yang_node *
|
||||||
yang_xpath(yang_node *yn,
|
yang_schema_nodeid(yang_node *yn,
|
||||||
char *xpath)
|
char *schema_nodeid)
|
||||||
{
|
{
|
||||||
char **vec = NULL;
|
yang_node *yres = NULL;
|
||||||
yang_node *ys = NULL;
|
|
||||||
int nvec;
|
|
||||||
|
|
||||||
if (strlen(xpath) == 0)
|
if (strlen(schema_nodeid) == 0)
|
||||||
return NULL;
|
goto done;
|
||||||
/* check absolute path */
|
/* check absolute schema_nodeid */
|
||||||
if (xpath[0] == '/')
|
if (schema_nodeid[0] == '/')
|
||||||
return yang_xpath_abs(yn, xpath);
|
yres = yang_abs_schema_nodeid(yn, schema_nodeid);
|
||||||
if ((vec = clicon_strsep(xpath, "/", &nvec)) == NULL)
|
else
|
||||||
goto err;
|
yres = yang_desc_schema_nodeid(yn, schema_nodeid);
|
||||||
ys = yang_xpath_vec((yang_node*)yn, vec, nvec);
|
done:
|
||||||
err:
|
return yres;
|
||||||
if (vec)
|
|
||||||
free(vec);
|
|
||||||
return ys;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Parse argument as CV and save result in yang cv variable
|
/*! Parse argument as CV and save result in yang cv variable
|
||||||
*
|
*
|
||||||
* Note that some CV:s are parsed directly (eg fraction-digits) while others are parsed
|
* Note that some CV:s are parsed directly (eg fraction-digits) while others are parsed
|
||||||
|
|
@ -1933,6 +1914,7 @@ yang_spec_main(clicon_handle h,
|
||||||
clicon_err(OE_FATAL, 0, "CLICON_YANG_DIR option not set");
|
clicon_err(OE_FATAL, 0, "CLICON_YANG_DIR option not set");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
/* Yang module is either specific absolute filename, or main module */
|
||||||
if ((yang_module = clicon_yang_module_main(h)) == NULL){
|
if ((yang_module = clicon_yang_module_main(h)) == NULL){
|
||||||
clicon_err(OE_FATAL, 0, "CLICON_YANG_MODULE_MAIN option not set");
|
clicon_err(OE_FATAL, 0, "CLICON_YANG_MODULE_MAIN option not set");
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -202,14 +202,12 @@ clixon_yang_parsewrap(void)
|
||||||
<STRING0>. { clixon_yang_parselval.string = strdup(yytext);
|
<STRING0>. { clixon_yang_parselval.string = strdup(yytext);
|
||||||
return CHAR;}
|
return CHAR;}
|
||||||
|
|
||||||
|
|
||||||
<STRING1>\\ { _YY->yy_lex_state = STRING1; BEGIN(ESCAPE); }
|
<STRING1>\\ { _YY->yy_lex_state = STRING1; BEGIN(ESCAPE); }
|
||||||
<STRING1>\" { BEGIN(_YY->yy_lex_string_state); return DQ; }
|
<STRING1>\" { BEGIN(_YY->yy_lex_string_state); return DQ; }
|
||||||
<STRING1>\n { _YY->yy_linenum++; clixon_yang_parselval.string = strdup(yytext); return CHAR;}
|
<STRING1>\n { _YY->yy_linenum++; clixon_yang_parselval.string = strdup(yytext); return CHAR;}
|
||||||
<STRING1>. { clixon_yang_parselval.string = strdup(yytext);
|
<STRING1>. { clixon_yang_parselval.string = strdup(yytext);
|
||||||
return CHAR;}
|
return CHAR;}
|
||||||
|
|
||||||
<STRING2>\\ { _YY->yy_lex_state = STRING2; BEGIN(ESCAPE); }
|
|
||||||
<STRING2>\' { BEGIN(_YY->yy_lex_string_state); return DQ; }
|
<STRING2>\' { BEGIN(_YY->yy_lex_string_state); return DQ; }
|
||||||
<STRING2>\n { _YY->yy_linenum++; clixon_yang_parselval.string = strdup(yytext); return CHAR;}
|
<STRING2>\n { _YY->yy_linenum++; clixon_yang_parselval.string = strdup(yytext); return CHAR;}
|
||||||
<STRING2>. { clixon_yang_parselval.string = strdup(yytext);
|
<STRING2>. { clixon_yang_parselval.string = strdup(yytext);
|
||||||
|
|
|
||||||
|
|
@ -221,6 +221,10 @@ ys_resolve_type(yang_stmt *ys,
|
||||||
if (yang_type_resolve((yang_stmt*)ys->ys_parent, ys, &resolved,
|
if (yang_type_resolve((yang_stmt*)ys->ys_parent, ys, &resolved,
|
||||||
&options, &mincv, &maxcv, &pattern, &fraction) < 0)
|
&options, &mincv, &maxcv, &pattern, &fraction) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
/* skip unions since they may have different sets of options, mincv, etc */
|
||||||
|
if (resolved && strcmp(resolved->ys_argument, "union")==0)
|
||||||
|
;
|
||||||
|
else
|
||||||
if (yang_type_cache_set(&ys->ys_typecache,
|
if (yang_type_cache_set(&ys->ys_typecache,
|
||||||
resolved, options, mincv, maxcv, pattern, fraction) < 0)
|
resolved, options, mincv, maxcv, pattern, fraction) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -561,6 +565,91 @@ cv_validate1(cg_var *cv,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Forward */
|
||||||
|
static int ys_cv_validate_union(yang_stmt *ys, char **reason, yang_stmt *yrestype,
|
||||||
|
char *type, char *val);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @retval -1 Error (fatal), with errno set to indicate error
|
||||||
|
* @retval 0 Validation not OK, malloced reason is returned. Free reason with free()
|
||||||
|
* @retval 1 Validation OK
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
ys_cv_validate_union_one(yang_stmt *ys,
|
||||||
|
char **reason,
|
||||||
|
yang_stmt *yt,
|
||||||
|
char *type, /* orig type */
|
||||||
|
char *val)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
yang_stmt *yrt; /* union subtype */
|
||||||
|
int options = 0;
|
||||||
|
cg_var *range_min = NULL;
|
||||||
|
cg_var *range_max = NULL;
|
||||||
|
char *pattern = NULL;
|
||||||
|
uint8_t fraction = 0;
|
||||||
|
char *restype;
|
||||||
|
enum cv_type cvtype;
|
||||||
|
cg_var *cvt=NULL;
|
||||||
|
|
||||||
|
if (yang_type_resolve(ys, yt, &yrt,
|
||||||
|
&options, &range_min, &range_max, &pattern,
|
||||||
|
&fraction) < 0)
|
||||||
|
goto done;
|
||||||
|
restype = yrt?yrt->ys_argument:NULL;
|
||||||
|
if (restype && strcmp(restype, "union") == 0){ /* recursive union */
|
||||||
|
if ((retval = ys_cv_validate_union(ys, reason, yrt, type, val)) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (clicon_type2cv(type, restype, &cvtype) < 0)
|
||||||
|
goto done;
|
||||||
|
/* reparse value with the new type */
|
||||||
|
if ((cvt = cv_new(cvtype)) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "cv_new");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (cv_parse(val, cvt) <0){
|
||||||
|
clicon_err(OE_UNIX, errno, "cv_parse");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if ((retval = cv_validate1(cvt, cvtype, options, range_min, range_max,
|
||||||
|
pattern, yrt, restype, reason)) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
if (cvt)
|
||||||
|
cv_free(cvt);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @retval -1 Error (fatal), with errno set to indicate error
|
||||||
|
* @retval 0 Validation not OK, malloced reason is returned. Free reason with free()
|
||||||
|
* @retval 1 Validation OK
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
ys_cv_validate_union(yang_stmt *ys,
|
||||||
|
char **reason,
|
||||||
|
yang_stmt *yrestype,
|
||||||
|
char *type, /* orig type */
|
||||||
|
char *val)
|
||||||
|
{
|
||||||
|
int retval = 1; /* valid */
|
||||||
|
yang_stmt *yt = NULL;
|
||||||
|
|
||||||
|
while ((yt = yn_each((yang_node*)yrestype, yt)) != NULL){
|
||||||
|
if (yt->ys_keyword != Y_TYPE)
|
||||||
|
continue;
|
||||||
|
if ((retval = ys_cv_validate_union_one(ys, reason, yt, type, val)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (retval == 1) /* Enough that one type validates value */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Validate cligen variable cv using yang statement as spec
|
/*! Validate cligen variable cv using yang statement as spec
|
||||||
*
|
*
|
||||||
* @param[in] cv A cligen variable to validate. This is a correctly parsed cv.
|
* @param[in] cv A cligen variable to validate. This is a correctly parsed cv.
|
||||||
|
|
@ -579,17 +668,15 @@ ys_cv_validate(cg_var *cv,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cg_var *ycv; /* cv of yang-statement */
|
cg_var *ycv; /* cv of yang-statement */
|
||||||
int options;
|
int options = 0;
|
||||||
cg_var *range_min;
|
cg_var *range_min = NULL;
|
||||||
cg_var *range_max;
|
cg_var *range_max = NULL;
|
||||||
char *pattern;
|
char *pattern = NULL;
|
||||||
enum cv_type cvtype;
|
enum cv_type cvtype;
|
||||||
char *type; /* orig type */
|
char *type; /* orig type */
|
||||||
yang_stmt *yrestype; /* resolved type */
|
yang_stmt *yrestype; /* resolved type */
|
||||||
yang_stmt *yrt; /* union subtype */
|
|
||||||
char *restype;
|
char *restype;
|
||||||
uint8_t fraction;
|
uint8_t fraction = 0;
|
||||||
yang_stmt *yt = NULL;
|
|
||||||
int retval2;
|
int retval2;
|
||||||
char *val;
|
char *val;
|
||||||
cg_var *cvt=NULL;
|
cg_var *cvt=NULL;
|
||||||
|
|
@ -621,38 +708,10 @@ ys_cv_validate(cg_var *cv,
|
||||||
}
|
}
|
||||||
/* Note restype can be NULL here for example with unresolved hardcoded uuid */
|
/* Note restype can be NULL here for example with unresolved hardcoded uuid */
|
||||||
if (restype && strcmp(restype, "union") == 0){
|
if (restype && strcmp(restype, "union") == 0){
|
||||||
yt = NULL;
|
|
||||||
retval2 = 1; /* valid */
|
|
||||||
assert(cvtype == CGV_REST);
|
assert(cvtype == CGV_REST);
|
||||||
val = cv_string_get(cv);
|
val = cv_string_get(cv);
|
||||||
while ((yt = yn_each((yang_node*)yrestype, yt)) != NULL){
|
if ((retval2 = ys_cv_validate_union(ys, reason, yrestype, type, val)) < 0)
|
||||||
if (yt->ys_keyword != Y_TYPE)
|
|
||||||
continue;
|
|
||||||
if (yang_type_resolve(ys, yt, &yrt,
|
|
||||||
&options, &range_min, &range_max, &pattern,
|
|
||||||
&fraction) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
restype = yrestype?yrt->ys_argument:NULL;
|
|
||||||
if (clicon_type2cv(type, restype, &cvtype) < 0)
|
|
||||||
goto done;
|
|
||||||
/* reparse value with the new type */
|
|
||||||
if ((cvt = cv_new(cvtype)) == NULL){
|
|
||||||
clicon_err(OE_UNIX, errno, "cv_new");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (cv_parse(val, cvt) <0){
|
|
||||||
clicon_err(OE_UNIX, errno, "cv_parse");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if ((retval2 = cv_validate1(cvt, cvtype, options, range_min, range_max,
|
|
||||||
pattern, yrt, restype, reason)) < 0)
|
|
||||||
goto done;
|
|
||||||
if (retval2 == 1) /* done */
|
|
||||||
break;
|
|
||||||
/* Here retval == 0, validation failed */
|
|
||||||
cv_free(cvt);
|
|
||||||
cvt=NULL;
|
|
||||||
}
|
|
||||||
retval = retval2; /* invalid (0) with latest reason or valid 1 */
|
retval = retval2; /* invalid (0) with latest reason or valid 1 */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -860,7 +919,7 @@ yang_type_resolve(yang_stmt *ys,
|
||||||
/* Not basic type. Now check if prefix which means we look in other module */
|
/* Not basic type. Now check if prefix which means we look in other module */
|
||||||
if (prefix){ /* Go to top and find import that matches */
|
if (prefix){ /* Go to top and find import that matches */
|
||||||
if ((ymod = yang_find_module_by_prefix(ys, prefix)) == NULL){
|
if ((ymod = yang_find_module_by_prefix(ys, prefix)) == NULL){
|
||||||
clicon_err(OE_DB, 0, "Module not resolved: %s", prefix);
|
clicon_err(OE_DB, 0, "Type not resolved: %s:%s", prefix, type);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((rytypedef = yang_find((yang_node*)ymod, Y_TYPEDEF, type)) == NULL)
|
if ((rytypedef = yang_find((yang_node*)ymod, Y_TYPEDEF, type)) == NULL)
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,9 @@ expectfn(){
|
||||||
if [ -z "$ret" -a -z "$expect" ]; then
|
if [ -z "$ret" -a -z "$expect" ]; then
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
if [ -z "$ret" -a "$expect" = "^$" ]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
# grep extended grep
|
# grep extended grep
|
||||||
match=`echo "$ret" | grep -EZo "$expect"`
|
match=`echo "$ret" | grep -EZo "$expect"`
|
||||||
# echo "ret:\"$ret\""
|
# echo "ret:\"$ret\""
|
||||||
|
|
|
||||||
|
|
@ -29,19 +29,19 @@ fi
|
||||||
new "cli tests"
|
new "cli tests"
|
||||||
|
|
||||||
new "cli configure top"
|
new "cli configure top"
|
||||||
expectfn "$clixon_cli -1f $clixon_cf set interfaces" ""
|
expectfn "$clixon_cli -1f $clixon_cf set interfaces" "^$"
|
||||||
|
|
||||||
new "cli show configuration top (no presence)"
|
new "cli show configuration top (no presence)"
|
||||||
expectfn "$clixon_cli -1f $clixon_cf show conf cli" ""
|
expectfn "$clixon_cli -1f $clixon_cf show conf cli" "^$"
|
||||||
|
|
||||||
new "cli configure delete top"
|
new "cli configure delete top"
|
||||||
expectfn "$clixon_cli -1f $clixon_cf delete interfaces" ""
|
expectfn "$clixon_cli -1f $clixon_cf delete interfaces" "^$"
|
||||||
|
|
||||||
new "cli show configuration delete top"
|
new "cli show configuration delete top"
|
||||||
expectfn "$clixon_cli -1f $clixon_cf show conf cli" ""
|
expectfn "$clixon_cli -1f $clixon_cf show conf cli" "^$"
|
||||||
|
|
||||||
new "cli configure"
|
new "cli configure"
|
||||||
expectfn "$clixon_cli -1f $clixon_cf set interfaces interface eth/0/0" ""
|
expectfn "$clixon_cli -1f $clixon_cf set interfaces interface eth/0/0" "^$"
|
||||||
|
|
||||||
new "cli show configuration"
|
new "cli show configuration"
|
||||||
expectfn "$clixon_cli -1f $clixon_cf show conf cli" "^interfaces interface name eth/0/0" "interfaces interface enabled true$"
|
expectfn "$clixon_cli -1f $clixon_cf show conf cli" "^interfaces interface name eth/0/0" "interfaces interface enabled true$"
|
||||||
|
|
@ -50,9 +50,9 @@ new "cli failed validate"
|
||||||
expectfn "$clixon_cli -1f $clixon_cf -l o validate" "Missing mandatory variable"
|
expectfn "$clixon_cli -1f $clixon_cf -l o validate" "Missing mandatory variable"
|
||||||
|
|
||||||
new "cli configure more"
|
new "cli configure more"
|
||||||
expectfn "$clixon_cli -1f $clixon_cf set interfaces interface eth/0/0 ipv4 address 1.2.3.4 prefix-length 24" ""
|
expectfn "$clixon_cli -1f $clixon_cf set interfaces interface eth/0/0 ipv4 address 1.2.3.4 prefix-length 24" "^$"
|
||||||
expectfn "$clixon_cli -1f $clixon_cf set interfaces interface eth/0/0 description mydesc" ""
|
expectfn "$clixon_cli -1f $clixon_cf set interfaces interface eth/0/0 description mydesc" "^$"
|
||||||
expectfn "$clixon_cli -1f $clixon_cf set interfaces interface eth/0/0 type bgp" ""
|
expectfn "$clixon_cli -1f $clixon_cf set interfaces interface eth/0/0 type bgp" "^$"
|
||||||
|
|
||||||
new "cli show xpath description"
|
new "cli show xpath description"
|
||||||
expectfn "$clixon_cli -1f $clixon_cf -l o show xpath /interfaces/interface/description" "<description>mydesc</description>"
|
expectfn "$clixon_cli -1f $clixon_cf -l o show xpath /interfaces/interface/description" "<description>mydesc</description>"
|
||||||
|
|
@ -61,32 +61,32 @@ new "cli delete description"
|
||||||
expectfn "$clixon_cli -1f $clixon_cf -l o delete interfaces interface eth/0/0 description mydesc"
|
expectfn "$clixon_cli -1f $clixon_cf -l o delete interfaces interface eth/0/0 description mydesc"
|
||||||
|
|
||||||
new "cli show xpath no description"
|
new "cli show xpath no description"
|
||||||
expectfn "$clixon_cli -1f $clixon_cf -l o show xpath /interfaces/interface/description" ""
|
expectfn "$clixon_cli -1f $clixon_cf -l o show xpath /interfaces/interface/description" "^$"
|
||||||
|
|
||||||
new "cli success validate"
|
new "cli success validate"
|
||||||
expectfn "$clixon_cli -1f $clixon_cf -l o validate" ""
|
expectfn "$clixon_cli -1f $clixon_cf -l o validate" "^$"
|
||||||
|
|
||||||
new "cli commit"
|
new "cli commit"
|
||||||
expectfn "$clixon_cli -1f $clixon_cf -l o commit" ""
|
expectfn "$clixon_cli -1f $clixon_cf -l o commit" "^$"
|
||||||
|
|
||||||
new "cli save"
|
new "cli save"
|
||||||
expectfn "$clixon_cli -1f $clixon_cf -l o save /tmp/foo" ""
|
expectfn "$clixon_cli -1f $clixon_cf -l o save /tmp/foo" "^$"
|
||||||
|
|
||||||
new "cli delete all"
|
new "cli delete all"
|
||||||
expectfn "$clixon_cli -1f $clixon_cf -l o delete all" ""
|
expectfn "$clixon_cli -1f $clixon_cf -l o delete all" "^$"
|
||||||
|
|
||||||
new "cli load"
|
new "cli load"
|
||||||
expectfn "$clixon_cli -1f $clixon_cf -l o load /tmp/foo" ""
|
expectfn "$clixon_cli -1f $clixon_cf -l o load /tmp/foo" "^$"
|
||||||
|
|
||||||
new "cli check load"
|
new "cli check load"
|
||||||
expectfn "$clixon_cli -1f $clixon_cf -l o show conf cli" "^interfaces interface name eth/0/0" "interfaces interface enabled true$"
|
expectfn "$clixon_cli -1f $clixon_cf -l o show conf cli" "^interfaces interface name eth/0/0" "interfaces interface enabled true$"
|
||||||
|
|
||||||
new "cli debug"
|
new "cli debug"
|
||||||
expectfn "$clixon_cli -1f $clixon_cf -l o debug level 1" ""
|
expectfn "$clixon_cli -1f $clixon_cf -l o debug level 1" "^$"
|
||||||
# How to test this?
|
# How to test this?
|
||||||
expectfn "$clixon_cli -1f $clixon_cf -l o debug level 0" ""
|
expectfn "$clixon_cli -1f $clixon_cf -l o debug level 0" "^$"
|
||||||
|
|
||||||
new "cli downcall"
|
new "cli rpc"
|
||||||
expectfn "$clixon_cli -1f $clixon_cf -l o rpc ipv4" "^<rpc-reply>"
|
expectfn "$clixon_cli -1f $clixon_cf -l o rpc ipv4" "^<rpc-reply>"
|
||||||
|
|
||||||
new "Kill backend"
|
new "Kill backend"
|
||||||
|
|
|
||||||
|
|
@ -48,47 +48,47 @@ EOF
|
||||||
|
|
||||||
# kill old backend (if any)
|
# kill old backend (if any)
|
||||||
new "kill old backend"
|
new "kill old backend"
|
||||||
sudo clixon_backend -zf $clixon_cf -y /tmp/leafref
|
sudo clixon_backend -zf $clixon_cf -y /tmp/leafref.yang
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
err
|
err
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new "start backend"
|
new "start backend"
|
||||||
# start new backend
|
# start new backend
|
||||||
sudo clixon_backend -If $clixon_cf -y /tmp/leafref
|
sudo clixon_backend -If $clixon_cf -y /tmp/leafref.yang
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
err
|
err
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new "leafref base config"
|
new "leafref base config"
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref" "<rpc><edit-config><target><candidate/></target><config><interface><name>eth0</name><admin-status>up</admin-status><address><ip>192.0.2.1</ip></address><address><ip>192.0.2.2</ip></address></interface><interface><name>lo</name><admin-status>up</admin-status><address><ip>127.0.0.1</ip></address></interface></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref.yang" "<rpc><edit-config><target><candidate/></target><config><interface><name>eth0</name><admin-status>up</admin-status><address><ip>192.0.2.1</ip></address><address><ip>192.0.2.2</ip></address></interface><interface><name>lo</name><admin-status>up</admin-status><address><ip>127.0.0.1</ip></address></interface></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "leafref get config"
|
new "leafref get config"
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf" '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply><data><interface><name>eth0</name>'
|
expecteof "$clixon_netconf -qf $clixon_cf" '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply><data><interface><name>eth0</name>'
|
||||||
|
|
||||||
new "leafref base commit"
|
new "leafref base commit"
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref" "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref.yang" "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "leafref add wrong ref"
|
new "leafref add wrong ref"
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref" "<rpc><edit-config><target><candidate/></target><config><default-address><ifname>eth3</ifname><address>10.0.4.6</address></default-address></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref.yang" "<rpc><edit-config><target><candidate/></target><config><default-address><ifname>eth3</ifname><address>10.0.4.6</address></default-address></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "leafref validate"
|
new "leafref validate"
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-tag>missing-attribute</error-tag>"
|
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref.yang" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-tag>missing-attribute</error-tag>"
|
||||||
|
|
||||||
new "leafref discard-changes"
|
new "leafref discard-changes"
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "leafref add correct ref"
|
new "leafref add correct ref"
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref" "<rpc><edit-config><target><candidate/></target><config><default-address><ifname>eth0</ifname><address>192.0.2.2</address></default-address></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref.yang" "<rpc><edit-config><target><candidate/></target><config><default-address><ifname>eth0</ifname><address>192.0.2.2</address></default-address></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "leafref validate (ok)"
|
new "leafref validate (ok)"
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>"
|
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref.yang" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>"
|
||||||
|
|
||||||
new "leafref delete leaf"
|
new "leafref delete leaf"
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref" "<rpc><edit-config><target><candidate/></target><config><interface operation=\"delete\"><name>eth0</name></interface></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>"
|
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref.yang" "<rpc><edit-config><target><candidate/></target><config><interface operation=\"delete\"><name>eth0</name></interface></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>"
|
||||||
|
|
||||||
new "leafref validate (should fail)"
|
new "leafref validate (should fail)"
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-tag>missing-attribute</error-tag>"
|
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/leafref.yang" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-tag>missing-attribute</error-tag>"
|
||||||
|
|
||||||
|
|
||||||
new "Kill backend"
|
new "Kill backend"
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,12 @@ expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><discard-changes/></rpc>]]>]]>"
|
||||||
new "netconf get empty config2"
|
new "netconf get empty config2"
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "netconf edit extra xml"
|
||||||
|
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><edit-config><target><candidate/></target><config><interfaces><extra/></interfaces></config></edit-config></rpc>]]>]]>" "^<rpc-reply><rpc-error>"
|
||||||
|
|
||||||
|
new "netconf discard-changes"
|
||||||
|
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf edit config eth1"
|
new "netconf edit config eth1"
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><edit-config><target><candidate/></target><config><interfaces><interface><name>eth1</name><type>eth</type></interface></interfaces></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><edit-config><target><candidate/></target><config><interfaces><interface><name>eth1</name><type>eth</type></interface></interfaces></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
|
|
||||||
114
test/test_type.sh
Executable file
114
test/test_type.sh
Executable file
|
|
@ -0,0 +1,114 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Advanced union types and generated code
|
||||||
|
|
||||||
|
# include err() and new() functions
|
||||||
|
. ./lib.sh
|
||||||
|
|
||||||
|
# For memcheck
|
||||||
|
#clixon_cli="valgrind --leak-check=full --show-leak-kinds=all clixon_cli"
|
||||||
|
clixon_cli=clixon_cli
|
||||||
|
clixon_netconf=clixon_netconf
|
||||||
|
|
||||||
|
cat <<EOF > /tmp/type.yang
|
||||||
|
module example{
|
||||||
|
typedef ab {
|
||||||
|
type string {
|
||||||
|
pattern
|
||||||
|
'(([a-b])\.){3}[a-b]';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
typedef cd {
|
||||||
|
type string {
|
||||||
|
pattern
|
||||||
|
'(([c-d])\.){3}[c-d]';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
typedef ef {
|
||||||
|
type string {
|
||||||
|
pattern
|
||||||
|
'(([e-f])\.){3}[e-f]';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
typedef ad {
|
||||||
|
type union {
|
||||||
|
type ab;
|
||||||
|
type cd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
typedef af {
|
||||||
|
type union {
|
||||||
|
type ad;
|
||||||
|
type ef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list list {
|
||||||
|
key k;
|
||||||
|
leaf k {
|
||||||
|
type af;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
|
||||||
|
# kill old backend (if any)
|
||||||
|
new "kill old backend"
|
||||||
|
sudo clixon_backend -zf $clixon_cf
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
err
|
||||||
|
fi
|
||||||
|
new "start backend"
|
||||||
|
# start new backend
|
||||||
|
sudo clixon_backend -If $clixon_cf -y /tmp/type.yang
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
err
|
||||||
|
fi
|
||||||
|
|
||||||
|
new "cli set ab"
|
||||||
|
expectfn "$clixon_cli -1f $clixon_cf -l o -y /tmp/type.yang set list a.b.a.b" "^$"
|
||||||
|
|
||||||
|
new "cli set cd"
|
||||||
|
expectfn "$clixon_cli -1f $clixon_cf -l o -y /tmp/type.yang set list c.d.c.d" "^$"
|
||||||
|
|
||||||
|
new "cli set ef"
|
||||||
|
expectfn "$clixon_cli -1f $clixon_cf -l o -y /tmp/type.yang set list e.f.e.f" "^$"
|
||||||
|
|
||||||
|
new "cli set ab fail"
|
||||||
|
expectfn "$clixon_cli -1f $clixon_cf -l o -y /tmp/type.yang set list a&b&a&b" "^CLI syntax error"
|
||||||
|
|
||||||
|
new "cli set ad fail"
|
||||||
|
expectfn "$clixon_cli -1f $clixon_cf -l o -y /tmp/type.yang set list a.b.c.d" "^CLI syntax error"
|
||||||
|
|
||||||
|
new "cli validate"
|
||||||
|
expectfn "$clixon_cli -1f $clixon_cf -l o -y /tmp/type.yang -l o validate" "^$"
|
||||||
|
|
||||||
|
new "cli commit"
|
||||||
|
expectfn "$clixon_cli -1f $clixon_cf -l o -y /tmp/type.yang -l o commit" "^$"
|
||||||
|
|
||||||
|
new "netconf validate ok"
|
||||||
|
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "netconf set ab fail"
|
||||||
|
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><edit-config><target><candidate/></target><config><list><k>a.b&c.d</k></list></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "netconf validate"
|
||||||
|
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error>"
|
||||||
|
|
||||||
|
new "netconf discard-changes"
|
||||||
|
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "netconf commit"
|
||||||
|
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "Kill backend"
|
||||||
|
# Check if still alive
|
||||||
|
pid=`pgrep clixon_backend`
|
||||||
|
if [ -z "$pid" ]; then
|
||||||
|
err "backend already dead"
|
||||||
|
fi
|
||||||
|
# kill backend
|
||||||
|
sudo clixon_backend -zf $clixon_cf
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
err "kill backend"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
@ -48,6 +48,9 @@ module example{
|
||||||
type string;
|
type string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
anyxml any{
|
||||||
|
description "testing of anyxml";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
container state {
|
container state {
|
||||||
config false;
|
config false;
|
||||||
|
|
@ -60,51 +63,66 @@ EOF
|
||||||
|
|
||||||
# kill old backend (if any)
|
# kill old backend (if any)
|
||||||
new "kill old backend"
|
new "kill old backend"
|
||||||
sudo clixon_backend -zf $clixon_cf -y /tmp/test
|
sudo clixon_backend -zf $clixon_cf -y /tmp/test.yang
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
err
|
err
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new "start backend"
|
new "start backend"
|
||||||
# start new backend
|
# start new backend
|
||||||
sudo clixon_backend -If $clixon_cf -y /tmp/test
|
sudo clixon_backend -If $clixon_cf -y /tmp/test.yang
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
err
|
err
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new "netconf edit config"
|
new "netconf edit config"
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test" "<rpc><edit-config><target><candidate/></target><config><x><y><a>1</a><b>2</b><c>5</c></y><d/></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test.yang" "<rpc><edit-config><target><candidate/></target><config><x><y><a>1</a><b>2</b><c>5</c></y><d/></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf commit"
|
new "netconf commit"
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test" "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test.yang" "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
# text empty type in running
|
||||||
|
new "netconf commit 2nd"
|
||||||
|
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test.yang" "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf get config xpath"
|
new "netconf get config xpath"
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test" "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/x/y[a=1][b=2]\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><x><y><a>1</a><b>2</b><c>5</c></y></x></data></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test.yang" "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/x/y[a=1][b=2]\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><x><y><a>1</a><b>2</b><c>5</c></y></x></data></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf edit leaf-list"
|
new "netconf edit leaf-list"
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test" "<rpc><edit-config><target><candidate/></target><config><x><f><e>hej</e><e>hopp</e></f></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test.yang" "<rpc><edit-config><target><candidate/></target><config><x><f><e>hej</e><e>hopp</e></f></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf get leaf-list"
|
new "netconf get leaf-list"
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test" "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/x/f/e\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><x><f><e>hej</e><e>hopp</e></f></x></data></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test.yang" "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/x/f/e\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><x><f><e>hej</e><e>hopp</e></f></x></data></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf get leaf-list path"
|
new "netconf get leaf-list path"
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test" "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/x/f[e=hej]\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><x><f><e>hej</e><e>hopp</e></f></x></data></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test.yang" "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/x/f[e=hej]\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><x><f><e>hej</e><e>hopp</e></f></x></data></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf get (should be some)"
|
new "netconf get (should be some)"
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test" "<rpc><get><filter type=\"xpath\" select=\"/\"/></get></rpc>]]>]]>" "^<rpc-reply><data><x><y><a>1</a><b>2</b><c>5</c></y><d/></x></data></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test.yang" "<rpc><get><filter type=\"xpath\" select=\"/\"/></get></rpc>]]>]]>" "^<rpc-reply><data><x><y><a>1</a><b>2</b><c>5</c></y><d/></x></data></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "cli set leaf-list"
|
new "cli set leaf-list"
|
||||||
expectfn "$clixon_cli -1f $clixon_cf -y /tmp/test set x f e foo" ""
|
expectfn "$clixon_cli -D 1 -1f $clixon_cf -y /tmp/test.yang set x f e foo" ""
|
||||||
|
|
||||||
new "cli show leaf-list"
|
new "cli show leaf-list"
|
||||||
expectfn "$clixon_cli -1f $clixon_cf -y /tmp/test show xpath /x/f/e" "<e>foo</e>"
|
expectfn "$clixon_cli -1f $clixon_cf -y /tmp/test.yang show xpath /x/f/e" "<e>foo</e>"
|
||||||
new "netconf set state data (not allowed)"
|
new "netconf set state data (not allowed)"
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test" "<rpc><edit-config><target><candidate/></target><config><state><op>42</op></state></config></edit-config></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-tag>invalid-value"
|
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test.yang" "<rpc><edit-config><target><candidate/></target><config><state><op>42</op></state></config></edit-config></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-tag>invalid-value"
|
||||||
|
|
||||||
new "netconf set presence and not present"
|
new "netconf set presence and not present"
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test" "<rpc><edit-config><target><candidate/></target><config><x><nopresence/><presence/></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test.yang" "<rpc><edit-config><target><candidate/></target><config><x><nopresence/><presence/></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf get"
|
new "netconf get"
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test" "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/x/*presence\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><x><presence/></x></data></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test.yang" "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/x/*presence\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><x><presence/></x></data></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "netconf discard-changes"
|
||||||
|
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
|
||||||
|
new "netconf anyxml"
|
||||||
|
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test.yang" "<rpc><edit-config><target><candidate/></target><config><x><any><foo><bar a=\"nisse\"/></foo></any></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "netconf validate anyxml"
|
||||||
|
expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test.yang" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "Kill backend"
|
new "Kill backend"
|
||||||
# Check if still alive
|
# Check if still alive
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue