* Support for YANG conditionals "must" and "when" according to RFC 7950 Sec 7.5.3 and 7.21.5
* XPATH checked at validation time
This commit is contained in:
parent
ba7f84afee
commit
0eb9e6c8b2
14 changed files with 244 additions and 54 deletions
24
CHANGELOG.md
24
CHANGELOG.md
|
|
@ -3,20 +3,22 @@
|
||||||
## 3.7.0 (Upcoming)
|
## 3.7.0 (Upcoming)
|
||||||
### Major changes:
|
### Major changes:
|
||||||
|
|
||||||
* Much better support for XPATH 1.0 according to https://www.w3.org/TR/xpath-10 using yacc/lex
|
* Support for YANG conditionals "must" and "when" according to RFC 7950 Sec 7.5.3 and 7.21.5
|
||||||
* NOTE: Due to an error in the previous implementation, all XPATH calls on the form `x[a=str]` where `str` is a string (not a number or XML symbol), must be changed to: `x[a='str'] or x[a="str"]`
|
* XPATH checked at validation time
|
||||||
* This includes all calls to `xpath_vec, xpath_first`, etc.
|
* Support for YANG identity, identityref, must and when according to RFC 7950 Sec 7.189.
|
||||||
* All calls to cli_copy_config in CLI spec files must replace 2nd argument from `x[%s=%s]` to `x[%s='%s']`
|
|
||||||
* The old API is stillenabled. To define the new, define XPATH_USE_NEW in include/clixon_custom.h and recompile
|
|
||||||
* Conformance of restconf(RFC-8040) operations where prefix was used instead of module name.
|
|
||||||
* Proper specification for an operation is POST /restconf/operations/<module_name>:<rpc_procedure> HTTP/1.1
|
|
||||||
* See https://github.com/clicon/clixon/issues/31, https://github.com/clicon/clixon/pull/32 and https://github.com/clicon/clixon/issues/30
|
|
||||||
* Thanks David Cornejo and Dmitry Vakhrushev of Netgate for pointing this out.
|
|
||||||
* Support for YANG identity and identityref according to RFC 7950 Sec 7.18 and 9.10
|
|
||||||
* Previous support did no validation of values.
|
* Previous support did no validation of values.
|
||||||
* Validation of types and CLI expansion
|
* Validation of types and CLI expansion
|
||||||
* Example extended with inclusion of iana-if-type RFC 7224 interface identities
|
* Example extended with inclusion of iana-if-type RFC 7224 interface identities
|
||||||
* Applications which have not strictly enforced the identities may now have problems with validation and may need to be modified.
|
* Applications which have not strictly enforced the identities may now have problems with validation and may need to be modified.
|
||||||
|
* Much improved support for XPATH 1.0 according to https://www.w3.org/TR/xpath-10 using yacc/lex
|
||||||
|
* NOTE: Due to an error in the previous implementation, all XPATH calls on the form `x[a=str]` where `str` is a string (not a number or XML symbol), must be changed to: `x[a='str'] or x[a="str"]`
|
||||||
|
* This includes all calls to `xpath_vec, xpath_first`, etc.
|
||||||
|
* All calls to cli_copy_config in CLI spec files must replace 2nd argument from `x[%s=%s]` to `x[%s='%s']`
|
||||||
|
* The old API can be enabled by setting COMPAT_XSL in include/clixon_custom.h and recompile.
|
||||||
|
* Conformance of restconf(RFC-8040) operations where prefix was used instead of module name.
|
||||||
|
* Proper specification for an operation is POST /restconf/operations/<module_name>:<rpc_procedure> HTTP/1.1
|
||||||
|
* See https://github.com/clicon/clixon/issues/31, https://github.com/clicon/clixon/pull/32 and https://github.com/clicon/clixon/issues/30
|
||||||
|
* Thanks David Cornejo and Dmitry Vakhrushev of Netgate for pointing this out.
|
||||||
|
|
||||||
### Minor changes:
|
### Minor changes:
|
||||||
* Added systemd example files under example/systemd
|
* Added systemd example files under example/systemd
|
||||||
|
|
@ -33,7 +35,7 @@
|
||||||
* Added xmlns validation
|
* Added xmlns validation
|
||||||
* for eg <a xmlns:x="uri"><x:b/></a>
|
* for eg <a xmlns:x="uri"><x:b/></a>
|
||||||
* Added yang identityref runtime validation
|
* Added yang identityref runtime validation
|
||||||
* Removed cli callback vector functions. Set COMPAT_COMPAT_CLIV if you need to keep these functions in clixon_custom.h.
|
* Removed cli callback vector functions. Set COMPAT_CLIV if you need to keep these functions in include/clixon_custom.h.
|
||||||
* Replace functions as follows in CLI SPEC files:
|
* Replace functions as follows in CLI SPEC files:
|
||||||
* cli_setv --> cli_set
|
* cli_setv --> cli_set
|
||||||
* cli_mergev --> cli_merge
|
* cli_mergev --> cli_merge
|
||||||
|
|
|
||||||
13
README.md
13
README.md
|
|
@ -11,6 +11,7 @@ transaction support from a YANG specification.
|
||||||
* [Support](#support)
|
* [Support](#support)
|
||||||
* [Dependencies](#dependencies)
|
* [Dependencies](#dependencies)
|
||||||
* [Extending](#extending)
|
* [Extending](#extending)
|
||||||
|
* [XML and XPATH](#xml)
|
||||||
* [Yang](#yang)
|
* [Yang](#yang)
|
||||||
* [Netconf](#netconf)
|
* [Netconf](#netconf)
|
||||||
* [Restconf](#restconf)
|
* [Restconf](#restconf)
|
||||||
|
|
@ -89,9 +90,17 @@ are also available.
|
||||||
Plugins are written in C and easiest is to look at
|
Plugins are written in C and easiest is to look at
|
||||||
[example](example/README.md) or consulting the [FAQ](doc/FAQ.md).
|
[example](example/README.md) or consulting the [FAQ](doc/FAQ.md).
|
||||||
|
|
||||||
|
XML
|
||||||
|
===
|
||||||
|
Clixon has its own implementation of XML and XPATH implementation.
|
||||||
|
|
||||||
|
The standards covered include:
|
||||||
|
- [XML](https://www.w3.org/TR/2008/REC-xml-20081126)
|
||||||
|
- [Namespaces](https://www.w3.org/TR/2009/REC-xml-names-20091208)
|
||||||
|
- [XPATH](https://www.w3.org/TR/xpath-10)
|
||||||
|
|
||||||
Yang
|
Yang
|
||||||
====
|
====
|
||||||
|
|
||||||
YANG and XML is at the heart of Clixon. Yang modules are used as a
|
YANG and XML is at the heart of Clixon. Yang modules are used as a
|
||||||
specification for handling XML configuration data. The YANG spec is
|
specification for handling XML configuration data. The YANG spec is
|
||||||
used to generate an interactive CLI, netconf and restconf clients. It
|
used to generate an interactive CLI, netconf and restconf clients. It
|
||||||
|
|
@ -100,7 +109,7 @@ also manages an XML datastore.
|
||||||
Clixon mainly follows [YANG 1.0 RFC 6020](https://www.rfc-editor.org/rfc/rfc6020.txt) with some exceptions:
|
Clixon mainly follows [YANG 1.0 RFC 6020](https://www.rfc-editor.org/rfc/rfc6020.txt) with some exceptions:
|
||||||
- conformance: feature, if-feature, deviation
|
- conformance: feature, if-feature, deviation
|
||||||
- list features: min/max-elements, unique
|
- list features: min/max-elements, unique
|
||||||
- when, must, action statements
|
- action statements
|
||||||
- notifications
|
- notifications
|
||||||
|
|
||||||
The aim is also to cover new features in YANG 1.1 [YANG RFC 7950](https://www.rfc-editor.org/rfc/rfc7950.txt)
|
The aim is also to cover new features in YANG 1.1 [YANG RFC 7950](https://www.rfc-editor.org/rfc/rfc7950.txt)
|
||||||
|
|
|
||||||
|
|
@ -986,10 +986,10 @@ nacm_access(clicon_handle h,
|
||||||
goto step10;
|
goto step10;
|
||||||
/* User's group */
|
/* User's group */
|
||||||
if (xpath_vec(xacm,
|
if (xpath_vec(xacm,
|
||||||
#ifdef XPATH_USE_NEW
|
#ifdef COMPAT_XSL
|
||||||
"groups/group[user-name='%s']",
|
|
||||||
#else
|
|
||||||
"groups/group[user-name=%s]",
|
"groups/group[user-name=%s]",
|
||||||
|
#else
|
||||||
|
"groups/group[user-name='%s']",
|
||||||
#endif
|
#endif
|
||||||
&gvec, &glen, username) < 0)
|
&gvec, &glen, username) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -1009,10 +1009,10 @@ nacm_access(clicon_handle h,
|
||||||
char *gname;
|
char *gname;
|
||||||
gname = xml_find_body(gvec[j], "name");
|
gname = xml_find_body(gvec[j], "name");
|
||||||
if (xpath_first(xrlist,
|
if (xpath_first(xrlist,
|
||||||
#ifdef XPATH_USE_NEW
|
#ifdef COMPAT_XSL
|
||||||
".[group='%s']",
|
|
||||||
#else
|
|
||||||
".[group=%s]",
|
".[group=%s]",
|
||||||
|
#else
|
||||||
|
".[group='%s']",
|
||||||
#endif
|
#endif
|
||||||
gname)!=NULL)
|
gname)!=NULL)
|
||||||
break; /* found */
|
break; /* found */
|
||||||
|
|
|
||||||
|
|
@ -1249,7 +1249,7 @@ cli_copy_config(clicon_handle h,
|
||||||
for (i=0; i<strlen(xpath); i++){
|
for (i=0; i<strlen(xpath); i++){
|
||||||
if (xpath[i] == '%')
|
if (xpath[i] == '%')
|
||||||
j++;
|
j++;
|
||||||
#ifndef XPATH_USE_NEW
|
#ifdef COMPAT_XSL
|
||||||
/* This is a horrible kludge due to:
|
/* This is a horrible kludge due to:
|
||||||
* (1) old xpath implementation wrongly did: a[b=x] instead of a[b='x']
|
* (1) old xpath implementation wrongly did: a[b=x] instead of a[b='x']
|
||||||
* (2) cli_copy_config has as 2nd argument such an xpath provided by user.
|
* (2) cli_copy_config has as 2nd argument such an xpath provided by user.
|
||||||
|
|
|
||||||
|
|
@ -68,10 +68,10 @@ mycallback(clicon_handle h, cvec *cvv, cvec *argv)
|
||||||
|
|
||||||
/* Show eth0 interfaces config using XPATH */
|
/* Show eth0 interfaces config using XPATH */
|
||||||
if (clicon_rpc_get_config(h, "running",
|
if (clicon_rpc_get_config(h, "running",
|
||||||
#ifdef XPATH_USE_NEW
|
#ifdef COMPAT_XSL
|
||||||
"/interfaces/interface[name='eth0']",
|
|
||||||
#else
|
|
||||||
"/interfaces/interface[name=eth0]",
|
"/interfaces/interface[name=eth0]",
|
||||||
|
#else
|
||||||
|
"/interfaces/interface[name='eth0']",
|
||||||
#endif
|
#endif
|
||||||
&xret) < 0)
|
&xret) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,13 @@ int strverscmp (__const char *__s1, __const char *__s2);
|
||||||
*/
|
*/
|
||||||
#define XMLNS_YANG_ONLY 1
|
#define XMLNS_YANG_ONLY 1
|
||||||
|
|
||||||
/* Set if you want all old xpath functions in clixon_xsl.* to use the new
|
/* Set if you want to enable old xpath functions in clixon_xsl.* instead of the
|
||||||
* xpath functions in clixon_xpath.*
|
* the new xpath functions in clixon_xpath.*
|
||||||
|
* Note that when changing from old xpath code to new, calls on the form
|
||||||
|
* `x[a=str]` where `str` is a string (not a number or XML symbol),
|
||||||
|
* must be changed to: `x[a='str'] or x[a="str"]`
|
||||||
|
* Enabling COMPAT_XSL may make sense if you have written a lot of user code that
|
||||||
|
* relieson the error above. Or if a bug appears in the newimplementation.
|
||||||
|
* @see test/lib.sh
|
||||||
*/
|
*/
|
||||||
#undef XPATH_USE_NEW
|
#undef COMPAT_XSL
|
||||||
|
|
|
||||||
|
|
@ -101,14 +101,14 @@ int xpath_vec_bool(cxobj *xcur, char *format, ...);
|
||||||
int xpath_vec_ctx(cxobj *xcur, char *xpath, xp_ctx **xrp);
|
int xpath_vec_ctx(cxobj *xcur, char *xpath, xp_ctx **xrp);
|
||||||
|
|
||||||
/* backward compatible */
|
/* backward compatible */
|
||||||
#ifdef XPATH_USE_NEW
|
#ifdef COMPAT_XSL
|
||||||
#define xpath_first(cxtop, format, args...) xpath_first_nodeset(cxtop, format, ##args)
|
|
||||||
#define xpath_vec(cxtop, format, vec, veclen, args...) xpath_vec_nodeset(cxtop, format, vec, veclen, ##args)
|
|
||||||
#define xpath_vec_flag(cxtop, format, flags, vec, veclen, args...) xpath_vec_nodeset_flag(cxtop, format, flags, vec, veclen, ##args)
|
|
||||||
#else
|
|
||||||
#define xpath_first(cxtop, format, args...) xpath_first_xsl(cxtop, format, ##args)
|
#define xpath_first(cxtop, format, args...) xpath_first_xsl(cxtop, format, ##args)
|
||||||
#define xpath_vec(cxtop, format, vec, veclen, args...) xpath_vec_xsl(cxtop, format, vec, veclen, ##args)
|
#define xpath_vec(cxtop, format, vec, veclen, args...) xpath_vec_xsl(cxtop, format, vec, veclen, ##args)
|
||||||
#define xpath_vec_flag(cxtop, format, flags, vec, veclen, args...) xpath_vec_flag_xsl(cxtop, format, flags, vec, veclen, ##args)
|
#define xpath_vec_flag(cxtop, format, flags, vec, veclen, args...) xpath_vec_flag_xsl(cxtop, format, flags, vec, veclen, ##args)
|
||||||
|
#else
|
||||||
|
#define xpath_first(cxtop, format, args...) xpath_first_nodeset(cxtop, format, ##args)
|
||||||
|
#define xpath_vec(cxtop, format, vec, veclen, args...) xpath_vec_nodeset(cxtop, format, vec, veclen, ##args)
|
||||||
|
#define xpath_vec_flag(cxtop, format, flags, vec, veclen, args...) xpath_vec_nodeset_flag(cxtop, format, flags, vec, veclen, ##args)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* _CLIXON_XPATH_H */
|
#endif /* _CLIXON_XPATH_H */
|
||||||
|
|
|
||||||
|
|
@ -428,7 +428,9 @@ xml_yang_validate_all(cxobj *xt,
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
yang_stmt *ys; /* yang node */
|
yang_stmt *ys; /* yang node */
|
||||||
yang_stmt *yc; /* yang child */
|
yang_stmt *yc; /* yang child */
|
||||||
|
yang_stmt *ye; /* yang must error-message */
|
||||||
char *xpath;
|
char *xpath;
|
||||||
|
int b;
|
||||||
|
|
||||||
/* if not given by argument (overide) use default link
|
/* if not given by argument (overide) use default link
|
||||||
and !Node has a config sub-statement and it is false */
|
and !Node has a config sub-statement and it is false */
|
||||||
|
|
@ -453,17 +455,34 @@ xml_yang_validate_all(cxobj *xt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Y_MUST: /* RFC 7950 Sec 7.5.3 */
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* "when" sub-node RFC 7950 Sec 7.21.5 */
|
/* must sub-node RFC 7950 Sec 7.5.3. Can be several. */
|
||||||
|
yc = NULL;
|
||||||
|
while ((yc = yn_each((yang_node*)ys, yc)) != NULL) {
|
||||||
|
if (yc->ys_keyword != Y_MUST)
|
||||||
|
continue;
|
||||||
|
xpath = yc->ys_argument; /* "must" has xpath argument */
|
||||||
|
if ((b = xpath_vec_bool(xt, "%s", xpath)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (!b){
|
||||||
|
if ((ye = yang_find((yang_node*)yc, Y_ERROR_MESSAGE, NULL)) != NULL)
|
||||||
|
clicon_err(OE_DB, 0, "%s", ye->ys_argument);
|
||||||
|
else
|
||||||
|
clicon_err(OE_DB, 0, "xpath %s validation failed", xml_name(xt));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* "when" sub-node RFC 7950 Sec 7.21.5. Can only be one. */
|
||||||
if ((yc = yang_find((yang_node*)ys, Y_WHEN, NULL)) != NULL){
|
if ((yc = yang_find((yang_node*)ys, Y_WHEN, NULL)) != NULL){
|
||||||
xpath = yc->ys_argument; /* "when" has xpath argument */
|
xpath = yc->ys_argument; /* "when" has xpath argument */
|
||||||
if (xpath_first(xt, "%s", xpath))
|
if ((b = xpath_vec_bool(xt, "%s", xpath)) < 0)
|
||||||
;
|
goto done;
|
||||||
fprintf(stderr, "%s %s\n", __FUNCTION__, xpath);
|
if (!b){
|
||||||
|
clicon_err(OE_DB, 0, "xpath %s validation failed", xml_name(xt));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
@ -1041,10 +1060,10 @@ api_path_fmt2xpath(char *api_path_fmt,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
cprintf(cb,
|
cprintf(cb,
|
||||||
#ifdef XPATH_USE_NEW
|
#ifdef COMPAT_XSL
|
||||||
"[%s='%s']",
|
|
||||||
#else
|
|
||||||
"[%s=%s]",
|
"[%s=%s]",
|
||||||
|
#else
|
||||||
|
"[%s='%s']",
|
||||||
#endif
|
#endif
|
||||||
cv_name_get(cv), str);
|
cv_name_get(cv), str);
|
||||||
free(str);
|
free(str);
|
||||||
|
|
@ -1464,10 +1483,10 @@ api_path2xpath_cvv(yang_spec *yspec,
|
||||||
v = val;
|
v = val;
|
||||||
while ((cvi = cvec_each(cvk, cvi)) != NULL){
|
while ((cvi = cvec_each(cvk, cvi)) != NULL){
|
||||||
cprintf(xpath,
|
cprintf(xpath,
|
||||||
#ifdef XPATH_USE_NEW
|
#ifdef COMPAT_XSL
|
||||||
"[%s='%s']",
|
|
||||||
#else
|
|
||||||
"[%s=%s]",
|
"[%s=%s]",
|
||||||
|
#else
|
||||||
|
"[%s='%s']",
|
||||||
#endif
|
#endif
|
||||||
cv_string_get(cvi), v);
|
cv_string_get(cvi), v);
|
||||||
v += strlen(v)+1;
|
v += strlen(v)+1;
|
||||||
|
|
|
||||||
|
|
@ -776,6 +776,9 @@ xp_relop(xp_ctx *xc1,
|
||||||
} /* switch type */
|
} /* switch type */
|
||||||
}
|
}
|
||||||
ok:
|
ok:
|
||||||
|
/* Just ensure bool is 0 or 1 */
|
||||||
|
if (xr->xc_type == XT_BOOL && xr->xc_bool != 0)
|
||||||
|
xr->xc_bool = 1;
|
||||||
*xrp = xr;
|
*xrp = xr;
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
|
@ -849,7 +852,6 @@ xp_eval(xp_ctx *xc,
|
||||||
xp_ctx *xr2 = NULL;
|
xp_ctx *xr2 = NULL;
|
||||||
int use_xr0 = 0; /* In 2nd child use transitively result of 1st child */
|
int use_xr0 = 0; /* In 2nd child use transitively result of 1st child */
|
||||||
|
|
||||||
assert(xc->xc_initial);
|
|
||||||
if (debug){
|
if (debug){
|
||||||
cbuf *cb;
|
cbuf *cb;
|
||||||
if ((cb = cbuf_new()) == NULL){
|
if ((cb = cbuf_new()) == NULL){
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,9 @@
|
||||||
testnr=0
|
testnr=0
|
||||||
testname=
|
testname=
|
||||||
|
|
||||||
# Set to 1 if new xpath. Set to nothing, or comment if old
|
# Set to 1 to enable old XSL implementation. Set to nothing, or comment if new.
|
||||||
#XPATH_USE_NEW=1
|
# @see include/clixon_custom.h
|
||||||
|
#COMPAT_XSL=1
|
||||||
|
|
||||||
# For memcheck
|
# For memcheck
|
||||||
#clixon_cli="valgrind --leak-check=full --show-leak-kinds=all clixon_cli"
|
#clixon_cli="valgrind --leak-check=full --show-leak-kinds=all clixon_cli"
|
||||||
|
|
|
||||||
|
|
@ -94,11 +94,11 @@ new "Add subtree eth/0/0 using none and create which should add eth/0/0"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces><interface operation="create"><name>eth/0/0</name><type>ex:eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces><interface operation="create"><name>eth/0/0</name><type>ex:eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
# Too many quotes, (single inside double inside single) need to fool bash
|
# Too many quotes, (single inside double inside single) need to fool bash
|
||||||
if [ -n "$XPATH_USE_NEW" ]; then
|
if [ -z "$COMPAT_XSL" ]; then
|
||||||
cat <<EOF > $tmp # new
|
cat <<EOF > $tmp # new
|
||||||
<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name='eth/0/0']"/></get-config></rpc>]]>]]>
|
<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name='eth/0/0']"/></get-config></rpc>]]>]]>
|
||||||
EOF
|
EOF
|
||||||
else
|
else # old
|
||||||
cat <<EOF > $tmp
|
cat <<EOF > $tmp
|
||||||
<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name=eth/0/0]"/></get-config></rpc>]]>]]>
|
<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name=eth/0/0]"/></get-config></rpc>]]>]]>
|
||||||
EOF
|
EOF
|
||||||
|
|
@ -122,12 +122,12 @@ new "netconf edit config"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><interfaces><interface><name>eth/0/0</name></interface><interface><name>eth1</name><enabled>true</enabled><ipv4><address><ip>9.2.3.4</ip><prefix-length>24</prefix-length></address></ipv4></interface></interfaces></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><interfaces><interface><name>eth/0/0</name></interface><interface><name>eth1</name><enabled>true</enabled><ipv4><address><ip>9.2.3.4</ip><prefix-length>24</prefix-length></address></ipv4></interface></interfaces></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
# Too many quotes
|
# Too many quotes
|
||||||
if [ -n "$XPATH_USE_NEW" ]; then
|
if [ -z "$COMPAT_XSL" ]; then
|
||||||
cat <<EOF > $tmp # new
|
cat <<EOF > $tmp # new
|
||||||
<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name='eth1']/enabled"/></get-config></rpc>]]>]]>
|
<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name='eth1']/enabled"/></get-config></rpc>]]>]]>
|
||||||
EOF
|
EOF
|
||||||
else
|
else
|
||||||
cat <<EOF > $tmp # new
|
cat <<EOF > $tmp # old
|
||||||
<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name=eth1]/enabled"/></get-config></rpc>]]>]]>
|
<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name=eth1]/enabled"/></get-config></rpc>]]>]]>
|
||||||
EOF
|
EOF
|
||||||
fi
|
fi
|
||||||
|
|
@ -136,7 +136,7 @@ new "netconf get config xpath"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "$(cat $tmp)" "^<rpc-reply><data><interfaces><interface><name>eth1</name><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "$(cat $tmp)" "^<rpc-reply><data><interfaces><interface><name>eth1</name><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
# Too many quotes
|
# Too many quotes
|
||||||
if [ -n "$XPATH_USE_NEW" ]; then
|
if [ -z "$COMPAT_XSL" ]; then
|
||||||
cat <<EOF > $tmp # new
|
cat <<EOF > $tmp # new
|
||||||
<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name='eth1']/enabled/../.."/></get-config></rpc>]]>]]>
|
<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name='eth1']/enabled/../.."/></get-config></rpc>]]>]]>
|
||||||
EOF
|
EOF
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ fi
|
||||||
new "verify running from start, should be: l,c,y0,y1,y2,y3; y1 and y3 sorted. Note this fails if XML_SORT set to false"
|
new "verify running from start, should be: l,c,y0,y1,y2,y3; y1 and y3 sorted. Note this fails if XML_SORT set to false"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><running/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><c><d>hej</d></c><l>hopp</l><y0>d</y0><y0>b</y0><y0>c</y0><y0>a</y0><y1>a</y1><y1>b</y1><y1>c</y1><y1>d</y1><y2><k>d</k><a>bar</a></y2><y2><k>a</k><a>bar</a></y2><y2><k>c</k><a>bar</a></y2><y2><k>b</k><a>bar</a></y2><y3><k>a</k><a>bar</a></y3><y3><k>b</k><a>bar</a></y3><y3><k>c</k><a>bar</a></y3><y3><k>d</k><a>bar</a></y3></data></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><running/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><c><d>hej</d></c><l>hopp</l><y0>d</y0><y0>b</y0><y0>c</y0><y0>a</y0><y1>a</y1><y1>b</y1><y1>c</y1><y1>d</y1><y2><k>d</k><a>bar</a></y2><y2><k>a</k><a>bar</a></y2><y2><k>c</k><a>bar</a></y2><y2><k>b</k><a>bar</a></y2><y3><k>a</k><a>bar</a></y3><y3><k>b</k><a>bar</a></y3><y3><k>c</k><a>bar</a></y3><y3><k>d</k><a>bar</a></y3></data></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
if [ -n "$XPATH_USE_NEW" ]; then #new
|
if [ -z "$COMPAT_XSL" ]; then #new
|
||||||
|
|
||||||
new "get each ordered-by user leaf-list"
|
new "get each ordered-by user leaf-list"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y2[k='a']\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><y2><k>a</k><a>bar</a></y2></data></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y2[k='a']\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><y2><k>a</k><a>bar</a></y2></data></rpc-reply>]]>]]>$"
|
||||||
|
|
|
||||||
151
test/test_when_must.sh
Executable file
151
test/test_when_must.sh
Executable file
|
|
@ -0,0 +1,151 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Yang when and must conditional xpath specification
|
||||||
|
# Testing of validation phase.
|
||||||
|
|
||||||
|
APPNAME=example
|
||||||
|
# include err() and new() functions and creates $dir
|
||||||
|
. ./lib.sh
|
||||||
|
|
||||||
|
cfg=$dir/conf_yang.xml
|
||||||
|
fyang=$dir/test.yang
|
||||||
|
|
||||||
|
cat <<EOF > $cfg
|
||||||
|
<config>
|
||||||
|
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
|
||||||
|
<CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
|
||||||
|
<CLICON_YANG_MODULE_MAIN>$APPNAME</CLICON_YANG_MODULE_MAIN>
|
||||||
|
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
|
||||||
|
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
|
||||||
|
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
|
||||||
|
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
|
||||||
|
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
|
||||||
|
<CLICON_CLI_GENMODEL_COMPLETION>1</CLICON_CLI_GENMODEL_COMPLETION>
|
||||||
|
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
|
||||||
|
<CLICON_XMLDB_PLUGIN>/usr/local/lib/xmldb/text.so</CLICON_XMLDB_PLUGIN>
|
||||||
|
</config>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat <<EOF > $fyang
|
||||||
|
module $APPNAME{
|
||||||
|
prefix ex;
|
||||||
|
identity routing-protocol {
|
||||||
|
description
|
||||||
|
"Base identity from which routing protocol identities are
|
||||||
|
derived.";
|
||||||
|
}
|
||||||
|
identity direct {
|
||||||
|
base routing-protocol;
|
||||||
|
description
|
||||||
|
"Routing pseudo-protocol which provides routes to directly
|
||||||
|
connected networks.";
|
||||||
|
}
|
||||||
|
identity static {
|
||||||
|
base routing-protocol;
|
||||||
|
description
|
||||||
|
"Static routing pseudo-protocol.";
|
||||||
|
}
|
||||||
|
list whenex {
|
||||||
|
key "type name";
|
||||||
|
leaf type {
|
||||||
|
type identityref {
|
||||||
|
base routing-protocol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
leaf name {
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
leaf route-preference {
|
||||||
|
type uint32;
|
||||||
|
}
|
||||||
|
container static-routes {
|
||||||
|
when "../type='static'" {
|
||||||
|
description
|
||||||
|
"This container is only valid for the 'static'
|
||||||
|
routing protocol.";
|
||||||
|
}
|
||||||
|
presence true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
container interface {
|
||||||
|
leaf ifType {
|
||||||
|
type enumeration {
|
||||||
|
enum ethernet;
|
||||||
|
enum atm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
leaf ifMTU {
|
||||||
|
type uint32;
|
||||||
|
}
|
||||||
|
must 'ifType != "ethernet" or ifMTU = 1500' {
|
||||||
|
error-message "An Ethernet MTU must be 1500";
|
||||||
|
}
|
||||||
|
must 'ifType != "atm" or'
|
||||||
|
+ ' (ifMTU <= 17966 and ifMTU >= 64)' {
|
||||||
|
error-message "An ATM MTU must be 64 .. 17966";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# kill old backend (if any)
|
||||||
|
new "kill old backend"
|
||||||
|
sudo clixon_backend -zf $cfg -y $fyang
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
err
|
||||||
|
fi
|
||||||
|
|
||||||
|
new "start backend -s init -f $cfg -y $fyang"
|
||||||
|
# start new backend
|
||||||
|
sudo clixon_backend -s init -f $cfg -y $fyang
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
err
|
||||||
|
fi
|
||||||
|
|
||||||
|
new "when: add static route"
|
||||||
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><whenex><type>static</type><name>r1</name><static-routes/></whenex></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "when: validate ok"
|
||||||
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "when: add direct route"
|
||||||
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><whenex><type>direct</type><name>r2</name><static-routes/></whenex></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "when get config"
|
||||||
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><whenex><type>direct</type><name>r2</name><static-routes/></whenex><whenex><type>static</type><name>r1</name><static-routes/></whenex></data></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "when: validate fail"
|
||||||
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-tag>operation-failed</error-tag><error-type>application</error-type><error-severity>error</error-severity><error-message>xpath static-routes validation failed</error-message></rpc-error></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "when: discard-changes"
|
||||||
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "must: add interface"
|
||||||
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><interface><ifType>ethernet</ifType><ifMTU>1500</ifMTU></interface></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "must: validate ok"
|
||||||
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "must: add atm interface"
|
||||||
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><interface><ifType>atm</ifType><ifMTU>32</ifMTU></interface></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "must: atm validate fail"
|
||||||
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-tag>operation-failed</error-tag><error-type>application</error-type><error-severity>error</error-severity><error-message>An ATM MTU must be 64 .. 17966</error-message></rpc-error></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "must: add eth interface"
|
||||||
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><interface><ifType>ethernet</ifType><ifMTU>989</ifMTU></interface></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "must: eth validate fail"
|
||||||
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-tag>operation-failed</error-tag><error-type>application</error-type><error-severity>error</error-severity><error-message>An Ethernet MTU must be 1500</error-message></rpc-error></rpc-reply>]]>]]>"
|
||||||
|
|
||||||
|
# Check if still alive
|
||||||
|
pid=`pgrep clixon_backend`
|
||||||
|
if [ -z "$pid" ]; then
|
||||||
|
err "backend already dead"
|
||||||
|
fi
|
||||||
|
# kill backend
|
||||||
|
sudo clixon_backend -zf $cfg
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
err "kill backend"
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -rf $dir
|
||||||
|
|
@ -136,7 +136,7 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><can
|
||||||
new "netconf get leaf-list"
|
new "netconf get leaf-list"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<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 $cfg -y $fyang" 0 "<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>]]>]]>$"
|
||||||
|
|
||||||
if [ -n "$XPATH_USE_NEW" ]; then # new
|
if [ -z "$COMPAT_XSL" ]; then # new
|
||||||
new "netconf get leaf-list path"
|
new "netconf get leaf-list path"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<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 $cfg -y $fyang" 0 "<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>]]>]]>$"
|
||||||
else # old
|
else # old
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue