* Strict namespace setting can be a problem when upgrading existing database files, such as startup-db or persistent running-db, or any other saved XML file.
* For backward compatibility, load of startup and running set CLICON_XML_NS_STRICT to false temporarily. * Added three-valued return values for several validate functions where -1 is fatal error, 0 is validation failed and 1 is validation OK. * This includes: `xmldb_put`, `xml_yang_validate_all`, `xml_yang_validate_add`, `xml_yang_validate_rpc`, `api_path2xml`, `api_path2xpath` * Added new xml functions for specific types: `xml_child_nr_notype`, `xml_child_nr_notype`, `xml_child_i_type`, `xml_find_type`.
This commit is contained in:
parent
861300d6c0
commit
0baebc93fd
71 changed files with 2679 additions and 1573 deletions
75
CHANGELOG.md
75
CHANGELOG.md
|
|
@ -1,11 +1,61 @@
|
||||||
# Clixon Changelog
|
# Clixon Changelog
|
||||||
|
|
||||||
## 3.9.0 (Preliminary Target: 31 December 2018)
|
## 3.9.0 (Preliminary Target: Mid-January 2019)
|
||||||
|
|
||||||
### Planned new features
|
### Planned new features
|
||||||
* [Roadmap](ROADMAP.md) (Uncommitted and unprioritized)
|
* [Roadmap](ROADMAP.md) (Uncommitted and unprioritized)
|
||||||
|
|
||||||
### Major New features
|
### Major New features
|
||||||
|
* Correct XML namespace handling
|
||||||
|
* XML multiple modules was based on non-strict semantics so that yang modules were found by iterating thorugh namespaces until a match was made. This did not adhere to proper [XML namespace handling](https://www.w3.org/TR/2009/REC-xml-names-20091208) as well as strict Netconf and Restconf namespace handling, which causes problems with overlapping names and false positives, and most importantly, with standard conformance.
|
||||||
|
* There are still the following non-strict namespace handling:
|
||||||
|
* Everything in ietf-netconf base syntax with namespace `urn:ietf:params:xml:ns:netconf:base:1.0` is default and need not be explicitly given
|
||||||
|
* edit-config xpath select statement does not support namespaces
|
||||||
|
* notifications do not support namespaces.
|
||||||
|
* Below see netconf old (but wrong) netconf RPC:
|
||||||
|
```
|
||||||
|
<rpc>
|
||||||
|
<my-own-method/>
|
||||||
|
</rpc>
|
||||||
|
<rpc-reply>
|
||||||
|
<route>
|
||||||
|
<address-family>ipv4</address-family>
|
||||||
|
</route>
|
||||||
|
</rpc-reply>
|
||||||
|
```
|
||||||
|
This is the currently correct Netconf RPC:
|
||||||
|
```
|
||||||
|
<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> # xmlns may be ommitted
|
||||||
|
<my-own-method xmlns="urn:example:my-own">
|
||||||
|
</rpc>
|
||||||
|
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
|
||||||
|
<route xmlns="urn:ietf:params:xml:ns:yang:ietf-routing">
|
||||||
|
<address-family>ipv4</address-family>
|
||||||
|
</route>
|
||||||
|
</rpc-reply>
|
||||||
|
```
|
||||||
|
* Another example for restconf rpc with new correct syntax. Note that while Netconf uses xmlns attribute syntax, Restconf uses module name prefix. First the request:
|
||||||
|
```
|
||||||
|
POST http://localhost/restconf/operations/example:example)
|
||||||
|
Content-Type: application/yang-data+json
|
||||||
|
{
|
||||||
|
"example:input":{
|
||||||
|
"x":0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
then the reply:
|
||||||
|
```
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
{
|
||||||
|
"example:output": {
|
||||||
|
"x": "0",
|
||||||
|
"y": "42"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
* To keep previous non-strict namespace handling (backwards compatible), set CLICON_XML_NS_STRICT to false.
|
||||||
|
* See https://github.com/clicon/clixon/issues/49
|
||||||
* NACM extension (RFC8341)
|
* NACM extension (RFC8341)
|
||||||
* NACM module support (RFC8341 A1+A2)
|
* NACM module support (RFC8341 A1+A2)
|
||||||
* Recovery user "_nacm_recovery" added.
|
* Recovery user "_nacm_recovery" added.
|
||||||
|
|
@ -27,25 +77,15 @@
|
||||||
* Note CLIXON_DATADIR (=/usr/local/share/clixon) need to be in the list
|
* Note CLIXON_DATADIR (=/usr/local/share/clixon) need to be in the list
|
||||||
* CLICON_YANG_MAIN_FILE Provides a filename with a single module filename.
|
* CLICON_YANG_MAIN_FILE Provides a filename with a single module filename.
|
||||||
* CLICON_YANG_MAIN_DIR Provides a directory where all yang modules should be loaded.
|
* CLICON_YANG_MAIN_DIR Provides a directory where all yang modules should be loaded.
|
||||||
* Correct XML namespace handling
|
|
||||||
* XML multiple modules was based on "loose" semantics so that yang modules were found by iterating thorugh namespaces until a match was made. This did not adhere to proper [XML namespace handling](https://www.w3.org/TR/2009/REC-xml-names-20091208), and causes problems with overlapping names and false positives. Below see XML accepted (but wrong), and correct namespace declaration:
|
|
||||||
```
|
|
||||||
<rpc><my-own-method></rpc> # Wrong but accepted
|
|
||||||
<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> # Correct
|
|
||||||
<my-own-method xmlns="http://example.net/me/my-own/1.0">
|
|
||||||
</rpc>
|
|
||||||
```
|
|
||||||
* To keep old loose semantics set config option CLICON_XML_NS_ITERATE (true by default)
|
|
||||||
* XML to JSON translator support for mapping xmlns attribute to module name prefix.
|
|
||||||
* Default namespace is still "urn:ietf:params:xml:ns:netconf:base:1.0"
|
|
||||||
* See https://github.com/clicon/clixon/issues/49
|
|
||||||
|
|
||||||
### API changes on existing features (you may need to change your code)
|
### API changes on existing features (you may need to change your code)
|
||||||
* Removed delete-config support for candidate db since it is not supported in RFC6241.
|
* Strict namespace setting can be a problem when upgrading existing database files, such as startup-db or persistent running-db, or any other saved XML file.
|
||||||
|
* For backward compatibility, load of startup and running set CLICON_XML_NS_STRICT to false temporarily.
|
||||||
|
* Removed `delete-config` support for candidate db since it is not supported in RFC6241.
|
||||||
* Switched the order of `error-type` and `error-tag` in all netconf and restconf error messages to comply to RFC order.
|
* Switched the order of `error-type` and `error-tag` in all netconf and restconf error messages to comply to RFC order.
|
||||||
* Yang parser is stricter (see above) which may break parsing of existing yang specs.
|
* Yang parser is stricter (see above) which may break parsing of existing yang specs.
|
||||||
* XML namespace handling is corrected (see above)
|
* XML namespace handling is corrected (see above)
|
||||||
* For backward compatibility set config option CLICON_XML_NS_ITERATE
|
* For backward compatibility set config option CLICON_XML_NS_LOOSE
|
||||||
* Yang parser functions have changed signatures. Please check the source if you call these functions.
|
* Yang parser functions have changed signatures. Please check the source if you call these functions.
|
||||||
* Add `<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>` to your configuration file, or corresponding CLICON_DATADIR directory for Clixon system yang files.
|
* Add `<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>` to your configuration file, or corresponding CLICON_DATADIR directory for Clixon system yang files.
|
||||||
* Change all @datamodel:tree to @datamodel in all CLI specification files
|
* Change all @datamodel:tree to @datamodel in all CLI specification files
|
||||||
|
|
@ -53,6 +93,9 @@
|
||||||
* For backward compatibility, define CLICON_CLI_MODEL_TREENAME_PATCH in clixon_custom.h
|
* For backward compatibility, define CLICON_CLI_MODEL_TREENAME_PATCH in clixon_custom.h
|
||||||
|
|
||||||
### Minor changes
|
### Minor changes
|
||||||
|
* Added three-valued return values for several validate functions where -1 is fatal error, 0 is validation failed and 1 is validation OK.
|
||||||
|
* This includes: `xmldb_put`, `xml_yang_validate_all`, `xml_yang_validate_add`, `xml_yang_validate_rpc`, `api_path2xml`, `api_path2xpath`
|
||||||
|
* Added new xml functions for specific types: `xml_child_nr_notype`, `xml_child_nr_notype`, `xml_child_i_type`, `xml_find_type`.
|
||||||
* Added example_rpc RPC to example backend
|
* Added example_rpc RPC to example backend
|
||||||
* Renamed xml_namespace[_set]() to xml_prefix[_set]()
|
* Renamed xml_namespace[_set]() to xml_prefix[_set]()
|
||||||
* Changed all make tags --> make TAGS
|
* Changed all make tags --> make TAGS
|
||||||
|
|
@ -273,7 +316,7 @@ translate {
|
||||||
|
|
||||||
### Known issues
|
### Known issues
|
||||||
* Namespace name relabeling is not supported.
|
* Namespace name relabeling is not supported.
|
||||||
* Eg: if "des" is defined as prefix for an imported module, then a relabeling using xmlfns is not supported, such as:
|
* Eg: if "des" is defined as prefix for an imported module, then a relabeling using xmlns is not supported, such as:
|
||||||
```
|
```
|
||||||
<crypto xmlns:x="urn:example:des">x:des3</crypto>
|
<crypto xmlns:x="urn:example:des">x:des3</crypto>
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,9 @@ EOF
|
||||||
|
|
||||||
## New release
|
## New release
|
||||||
What to think about when doing a new release.
|
What to think about when doing a new release.
|
||||||
|
* valgrind for memory leaks
|
||||||
|
* New clixon-config.yang revision?
|
||||||
|
Tagging:
|
||||||
* git merge --no-ff develop
|
* git merge --no-ff develop
|
||||||
* change CLIXON_VERSION in configure.ac
|
* change CLIXON_VERSION in configure.ac
|
||||||
* git tag -a <version"
|
* git tag -a <version"
|
||||||
|
|
|
||||||
20
README.md
20
README.md
|
|
@ -105,6 +105,23 @@ The standards covered include:
|
||||||
Not supported:
|
Not supported:
|
||||||
- !DOCTYPE (ie DTD)
|
- !DOCTYPE (ie DTD)
|
||||||
|
|
||||||
|
Historically, Clixon has not until 3.9 made strict namespace
|
||||||
|
enforcing. For example, the following non-strict netconf was
|
||||||
|
previously accepted:
|
||||||
|
```
|
||||||
|
<rpc><my-own-method/></rpc>
|
||||||
|
```
|
||||||
|
In 3.9, the same statement should be, for example:
|
||||||
|
```
|
||||||
|
<rpc><my-own-method xmlns="urn:example:my-own"/></rpc>
|
||||||
|
```
|
||||||
|
Note that base netconf syntax is still not enforced but recommended:
|
||||||
|
```
|
||||||
|
<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
|
||||||
|
<my-own-method xmlns="urn:example:my-own"/>
|
||||||
|
</rpc>
|
||||||
|
```
|
||||||
|
|
||||||
Yang
|
Yang
|
||||||
====
|
====
|
||||||
YANG and XML is the heart of Clixon. Yang modules are used as a
|
YANG and XML is the heart of Clixon. Yang modules are used as a
|
||||||
|
|
@ -153,6 +170,9 @@ Clixon does not support the following netconf features:
|
||||||
- edit-config config-text
|
- edit-config config-text
|
||||||
- edit-config operation
|
- edit-config operation
|
||||||
|
|
||||||
|
Some other deviations from the RFC:
|
||||||
|
- edit-config xpath select statement does not support namespaces
|
||||||
|
|
||||||
Restconf
|
Restconf
|
||||||
========
|
========
|
||||||
Clixon Restconf is a daemon based on FastCGI C-API. Instructions are available to
|
Clixon Restconf is a daemon based on FastCGI C-API. Instructions are available to
|
||||||
|
|
|
||||||
|
|
@ -292,7 +292,7 @@ client_get_streams(clicon_handle h,
|
||||||
* @param[in,out] xret Existing XML tree, merge x into this
|
* @param[in,out] xret Existing XML tree, merge x into this
|
||||||
* @retval -1 Error (fatal)
|
* @retval -1 Error (fatal)
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
* @retval 1 Statedata callback failed
|
* @retval 1 Statedata callback failed (clicon_err called)
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
client_statedata(clicon_handle h,
|
client_statedata(clicon_handle h,
|
||||||
|
|
@ -309,15 +309,15 @@ client_statedata(clicon_handle h,
|
||||||
clicon_err(OE_YANG, ENOENT, "No yang spec");
|
clicon_err(OE_YANG, ENOENT, "No yang spec");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC5277") &&
|
if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC5277"))
|
||||||
(retval = client_get_streams(h, yspec, xpath, "ietf-netconf-notification", "netconf", xret)) != 0)
|
if ((retval = client_get_streams(h, yspec, xpath, "ietf-netconf-notification", "netconf", xret)) != 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC8040") &&
|
if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC8040"))
|
||||||
(retval = client_get_streams(h, yspec, xpath, "ietf-restconf-monitoring", "restconf-state", xret)) != 0)
|
if ((retval = client_get_streams(h, yspec, xpath, "ietf-restconf-monitoring", "restconf-state", xret)) != 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_option_bool(h, "CLICON_MODULE_LIBRARY_RFC7895") &&
|
if (clicon_option_bool(h, "CLICON_MODULE_LIBRARY_RFC7895"))
|
||||||
(retval = yang_modules_state_get(h, yspec, xret)) != 0)
|
if ((retval = yang_modules_state_get(h, yspec, xret)) != 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((retval = clixon_plugin_statedata(h, yspec, xpath, xret)) != 0)
|
if ((retval = clixon_plugin_statedata(h, yspec, xpath, xret)) != 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Code complex to filter out anything that is outside of xpath */
|
/* Code complex to filter out anything that is outside of xpath */
|
||||||
|
|
@ -339,7 +339,7 @@ client_statedata(clicon_handle h,
|
||||||
/* reset flag */
|
/* reset flag */
|
||||||
if (xml_apply(*xret, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, (void*)XML_FLAG_MARK) < 0)
|
if (xml_apply(*xret, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, (void*)XML_FLAG_MARK) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
retval = 0;
|
retval = 0; /* OK */
|
||||||
done:
|
done:
|
||||||
if (xvec)
|
if (xvec)
|
||||||
free(xvec);
|
free(xvec);
|
||||||
|
|
@ -363,7 +363,6 @@ from_client_get(clicon_handle h,
|
||||||
char *xpath = "/";
|
char *xpath = "/";
|
||||||
cxobj *xret = NULL;
|
cxobj *xret = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
cbuf *cbx = NULL; /* Assist cbuf */
|
|
||||||
|
|
||||||
if ((xfilter = xml_find(xe, "filter")) != NULL)
|
if ((xfilter = xml_find(xe, "filter")) != NULL)
|
||||||
if ((xpath = xml_find_value(xfilter, "select"))==NULL)
|
if ((xpath = xml_find_value(xfilter, "select"))==NULL)
|
||||||
|
|
@ -379,33 +378,24 @@ from_client_get(clicon_handle h,
|
||||||
clicon_err_reset();
|
clicon_err_reset();
|
||||||
if ((ret = client_statedata(h, xpath, &xret)) < 0)
|
if ((ret = client_statedata(h, xpath, &xret)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0){ /* OK */
|
if (ret == 1){ /* Error from callback (error in xret) */
|
||||||
cprintf(cbret, "<rpc-reply>");
|
if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
|
||||||
if (xret==NULL)
|
|
||||||
cprintf(cbret, "<data/>");
|
|
||||||
else{
|
|
||||||
if (xml_name_set(xret, "data") < 0)
|
|
||||||
goto done;
|
|
||||||
if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
cprintf(cbret, "</rpc-reply>");
|
|
||||||
}
|
|
||||||
else { /* 1 Error from callback */
|
|
||||||
if ((cbx = cbuf_new()) == NULL){
|
|
||||||
clicon_err(OE_XML, errno, "cbuf_new");
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
goto ok;
|
||||||
cprintf(cbx, "Internal error:%s", clicon_err_reason);
|
|
||||||
if (netconf_operation_failed(cbret, "rpc", cbuf_get(cbx))< 0)
|
|
||||||
goto done;
|
|
||||||
clicon_log(LOG_NOTICE, "%s Error in backend_statedata_call:%s", __FUNCTION__, xml_name(xe));
|
|
||||||
}
|
}
|
||||||
|
cprintf(cbret, "<rpc-reply>"); /* OK */
|
||||||
|
if (xret==NULL)
|
||||||
|
cprintf(cbret, "<data/>");
|
||||||
|
else{
|
||||||
|
if (xml_name_set(xret, "data") < 0)
|
||||||
|
goto done;
|
||||||
|
if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
cprintf(cbret, "</rpc-reply>");
|
||||||
ok:
|
ok:
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (cbx)
|
|
||||||
cbuf_free(cbx);
|
|
||||||
if (xret)
|
if (xret)
|
||||||
xml_free(xret);
|
xml_free(xret);
|
||||||
return retval;
|
return retval;
|
||||||
|
|
@ -433,6 +423,7 @@ from_client_edit_config(clicon_handle h,
|
||||||
int non_config = 0;
|
int non_config = 0;
|
||||||
yang_spec *yspec;
|
yang_spec *yspec;
|
||||||
cbuf *cbx = NULL; /* Assist cbuf */
|
cbuf *cbx = NULL; /* Assist cbuf */
|
||||||
|
int ret;
|
||||||
|
|
||||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||||
clicon_err(OE_YANG, ENOENT, "No yang spec9");
|
clicon_err(OE_YANG, ENOENT, "No yang spec9");
|
||||||
|
|
@ -491,24 +482,27 @@ from_client_edit_config(clicon_handle h,
|
||||||
/* Cant do this earlier since we dont have a yang spec to
|
/* Cant do this earlier since we dont have a yang spec to
|
||||||
* the upper part of the tree, until we get the "config" tree.
|
* the upper part of the tree, until we get the "config" tree.
|
||||||
*/
|
*/
|
||||||
if (xml_child_sort && xml_apply0(xc, CX_ELMNT, xml_sort, NULL) < 0)
|
if (clicon_xml_sort(h) && xml_apply0(xc, CX_ELMNT, xml_sort, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (xmldb_put(h, target, operation, xc, cbret) < 0){
|
if ((ret = xmldb_put(h, target, operation, xc, cbret)) < 0){
|
||||||
clicon_debug(1, "%s ERROR PUT", __FUNCTION__);
|
clicon_debug(1, "%s ERROR PUT", __FUNCTION__);
|
||||||
if (netconf_operation_failed(cbret, "protocol", clicon_err_reason)< 0)
|
if (netconf_operation_failed(cbret, "protocol", clicon_err_reason)< 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
|
if (ret == 0)
|
||||||
|
goto ok;
|
||||||
}
|
}
|
||||||
|
assert(cbuf_len(cbret) == 0);
|
||||||
|
cprintf(cbret, "<rpc-reply><ok/></rpc-reply>");
|
||||||
ok:
|
ok:
|
||||||
if (!cbuf_len(cbret))
|
|
||||||
cprintf(cbret, "<rpc-reply><ok/></rpc-reply>");
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (cbx)
|
if (cbx)
|
||||||
cbuf_free(cbx);
|
cbuf_free(cbx);
|
||||||
clicon_debug(1, "%s done cbret:%s", __FUNCTION__, cbuf_get(cbret));
|
clicon_debug(1, "%s done cbret:%s", __FUNCTION__, cbuf_get(cbret));
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
} /* from_client_edit_config */
|
} /* from_client_edit_config */
|
||||||
|
|
||||||
/*! Internal message: Lock database
|
/*! Internal message: Lock database
|
||||||
|
|
|
||||||
|
|
@ -165,12 +165,24 @@ validate_common(clicon_handle h,
|
||||||
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* 2. Parse xml trees */
|
/* 2. Parse xml trees
|
||||||
|
* This is the state we are going from */
|
||||||
if (xmldb_get(h, "running", "/", 1, &td->td_src) < 0)
|
if (xmldb_get(h, "running", "/", 1, &td->td_src) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
/* This is the state we are going to */
|
||||||
if (xmldb_get(h, candidate, "/", 1, &td->td_target) < 0)
|
if (xmldb_get(h, candidate, "/", 1, &td->td_target) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
/* Validate the target state. It is not completely clear this should be done
|
||||||
|
* here. It is being made in generic_validate below.
|
||||||
|
* But xml_diff requires some basic validation, at least check that yang-specs
|
||||||
|
* have been assigned
|
||||||
|
*/
|
||||||
|
if ((ret = xml_yang_validate_all_top(td->td_target, cbret)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (ret == 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
/* 3. Compute differences */
|
/* 3. Compute differences */
|
||||||
if (xml_diff(yspec,
|
if (xml_diff(yspec,
|
||||||
td->td_src,
|
td->td_src,
|
||||||
|
|
@ -240,7 +252,7 @@ validate_common(clicon_handle h,
|
||||||
* do something more drastic?
|
* do something more drastic?
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] candidate A candidate database, not necessarily "candidate"
|
* @param[in] candidate A candidate database, not necessarily "candidate"
|
||||||
* @retval -1 Error - or validation failed (but cbret not set)
|
* @retval -1 Error - or validation failed
|
||||||
* @retval 0 Validation failed (with cbret set)
|
* @retval 0 Validation failed (with cbret set)
|
||||||
* @retval 1 Validation OK
|
* @retval 1 Validation OK
|
||||||
* @note Need to differentiate between error and validation fail
|
* @note Need to differentiate between error and validation fail
|
||||||
|
|
@ -259,7 +271,9 @@ candidate_commit(clicon_handle h,
|
||||||
if ((td = transaction_new()) == NULL)
|
if ((td = transaction_new()) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* Common steps (with validate). Note this is only call that uses 3-values */
|
/* Common steps (with validate). Load candidate and running and compute diffs
|
||||||
|
* Note this is only call that uses 3-values
|
||||||
|
*/
|
||||||
if ((ret = validate_common(h, candidate, td, cbret)) < 0)
|
if ((ret = validate_common(h, candidate, td, cbret)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
|
|
@ -270,12 +284,14 @@ candidate_commit(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* Optionally write (potentially modified) tree back to candidate */
|
/* Optionally write (potentially modified) tree back to candidate */
|
||||||
if (clicon_option_bool(h, "CLICON_TRANSACTION_MOD"))
|
if (clicon_option_bool(h, "CLICON_TRANSACTION_MOD")){
|
||||||
if (xmldb_put(h, candidate, OP_REPLACE, td->td_target, NULL) < 0)
|
if ((ret = xmldb_put(h, candidate, OP_REPLACE, td->td_target, NULL)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
if (ret == 0)
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
/* 8. Success: Copy candidate to running
|
/* 8. Success: Copy candidate to running
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (xmldb_copy(h, candidate, "running") < 0)
|
if (xmldb_copy(h, candidate, "running") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
|
@ -423,9 +439,11 @@ from_client_validate(clicon_handle h,
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
/* Optionally write (potentially modified) tree back to candidate */
|
/* Optionally write (potentially modified) tree back to candidate */
|
||||||
if (clicon_option_bool(h, "CLICON_TRANSACTION_MOD"))
|
if (clicon_option_bool(h, "CLICON_TRANSACTION_MOD")){
|
||||||
if (xmldb_put(h, "candidate", OP_REPLACE, td->td_target, NULL) < 0)
|
if ((ret = xmldb_put(h, "candidate", OP_REPLACE, td->td_target, cbret)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
goto ok;
|
||||||
|
}
|
||||||
cprintf(cbret, "<rpc-reply><ok/></rpc-reply>");
|
cprintf(cbret, "<rpc-reply><ok/></rpc-reply>");
|
||||||
ok:
|
ok:
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
|
||||||
|
|
@ -176,22 +176,24 @@ db_reset(clicon_handle h,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Merge db1 into db2 without commit
|
/*! Merge db1 into db2 without commit
|
||||||
|
* @retval -1 Error
|
||||||
|
* @retval 0 Validation failed (with cbret set)
|
||||||
|
* @retval 1 Validation OK
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
db_merge(clicon_handle h,
|
db_merge(clicon_handle h,
|
||||||
const char *db1,
|
const char *db1,
|
||||||
const char *db2)
|
const char *db2,
|
||||||
|
cbuf *cbret)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *xt = NULL;
|
cxobj *xt = NULL;
|
||||||
|
|
||||||
/* Get data as xml from db1 */
|
/* Get data as xml from db1 */
|
||||||
if (xmldb_get(h, (char*)db1, NULL, 1, &xt) < 0)
|
if (xmldb_get(h, (char*)db1, NULL, 1, &xt) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Merge xml into db2. Without commit */
|
/* Merge xml into db2. Without commit */
|
||||||
if (xmldb_put(h, (char*)db2, OP_MERGE, xt, NULL) < 0)
|
retval = xmldb_put(h, (char*)db2, OP_MERGE, xt, cbret);
|
||||||
goto done;
|
|
||||||
retval = 0;
|
|
||||||
done:
|
done:
|
||||||
if (xt)
|
if (xt)
|
||||||
xml_free(xt);
|
xml_free(xt);
|
||||||
|
|
@ -288,18 +290,22 @@ nacm_load_external(clicon_handle h)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Merge xml in filename into database
|
/*! Merge xml in filename into database
|
||||||
|
* @retval -1 Error
|
||||||
|
* @retval 0 Validation failed (with cbret set)
|
||||||
|
* @retval 1 Validation OK
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
load_extraxml(clicon_handle h,
|
load_extraxml(clicon_handle h,
|
||||||
char *filename,
|
char *filename,
|
||||||
const char *db)
|
const char *db,
|
||||||
|
cbuf *cbret)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *xt = NULL;
|
cxobj *xt = NULL;
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
|
|
||||||
if (filename == NULL)
|
if (filename == NULL)
|
||||||
return 0;
|
return 1;
|
||||||
if ((fd = open(filename, O_RDONLY)) < 0){
|
if ((fd = open(filename, O_RDONLY)) < 0){
|
||||||
clicon_err(OE_UNIX, errno, "open(%s)", filename);
|
clicon_err(OE_UNIX, errno, "open(%s)", filename);
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -310,9 +316,7 @@ load_extraxml(clicon_handle h,
|
||||||
if (xml_rootchild(xt, 0, &xt) < 0)
|
if (xml_rootchild(xt, 0, &xt) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Merge user reset state */
|
/* Merge user reset state */
|
||||||
if (xmldb_put(h, (char*)db, OP_MERGE, xt, NULL) < 0)
|
retval = xmldb_put(h, (char*)db, OP_MERGE, xt, cbret);
|
||||||
goto done;
|
|
||||||
retval = 0;
|
|
||||||
done:
|
done:
|
||||||
if (fd != -1)
|
if (fd != -1)
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
@ -385,9 +389,13 @@ static int
|
||||||
startup_mode_running(clicon_handle h,
|
startup_mode_running(clicon_handle h,
|
||||||
char *extraxml_file)
|
char *extraxml_file)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cbuf *cbret = NULL;
|
cbuf *cbret = NULL;
|
||||||
|
|
||||||
|
if ((cbret = cbuf_new()) == NULL){
|
||||||
|
clicon_err(OE_XML, errno, "cbuf_new");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
/* Stash original running to candidate for later commit */
|
/* Stash original running to candidate for later commit */
|
||||||
if (xmldb_copy(h, "running", "candidate") < 0)
|
if (xmldb_copy(h, "running", "candidate") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -400,41 +408,46 @@ startup_mode_running(clicon_handle h,
|
||||||
/* Application may define extra xml in its reset function*/
|
/* Application may define extra xml in its reset function*/
|
||||||
if (clixon_plugin_reset(h, "tmp") < 0)
|
if (clixon_plugin_reset(h, "tmp") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
/* XXX Kludge to low-level functions to search for xml in all yang modules */
|
||||||
|
_CLICON_XML_NS_STRICT = 0;
|
||||||
/* Get application extra xml from file */
|
/* Get application extra xml from file */
|
||||||
if (load_extraxml(h, extraxml_file, "tmp") < 0)
|
if (load_extraxml(h, extraxml_file, "tmp", cbret) < 1)
|
||||||
goto done;
|
goto fail;
|
||||||
/* Clear running db */
|
/* Clear running db */
|
||||||
if (db_reset(h, "running") < 0)
|
if (db_reset(h, "running") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((cbret = cbuf_new()) == NULL){
|
|
||||||
clicon_err(OE_XML, errno, "cbuf_new");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* Commit original running. Assume -1 is validate fail */
|
/* Commit original running. Assume -1 is validate fail */
|
||||||
if (candidate_commit(h, "candidate", cbret) < 1){
|
if (candidate_commit(h, "candidate", cbret) < 1)
|
||||||
/* (1) We cannot differentiate between fatal errors and validation
|
goto fail;
|
||||||
* failures
|
|
||||||
* (2) If fatal error, we should exit
|
|
||||||
* (3) If validation fails we cannot continue. How could we?
|
|
||||||
* (4) Need to restore the running db since we destroyed it above
|
|
||||||
*/
|
|
||||||
clicon_log(LOG_NOTICE, "%s: Commit of saved running failed, exiting: %s.",
|
|
||||||
__FUNCTION__, cbuf_get(cbret));
|
|
||||||
/* Reinstate original */
|
|
||||||
if (xmldb_copy(h, "candidate", "running") < 0)
|
|
||||||
goto done;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* Merge user reset state and extra xml file (no commit) */
|
/* Merge user reset state and extra xml file (no commit) */
|
||||||
if (db_merge(h, "tmp", "running") < 0)
|
if (db_merge(h, "tmp", "running", cbret) < 1)
|
||||||
goto done;
|
goto fail;
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
/* XXX Kludge to low-level functions to search for xml in all yang modules */
|
||||||
|
_CLICON_XML_NS_STRICT = clicon_option_bool(h, "CLICON_XML_NS_STRICT");
|
||||||
if (cbret)
|
if (cbret)
|
||||||
cbuf_free(cbret);
|
cbuf_free(cbret);
|
||||||
if (xmldb_delete(h, "tmp") < 0)
|
if (xmldb_delete(h, "tmp") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
return retval;
|
return retval;
|
||||||
|
fail:
|
||||||
|
/* (1) We cannot differentiate between fatal errors and validation
|
||||||
|
* failures
|
||||||
|
* (2) If fatal error, we should exit
|
||||||
|
* (3) If validation fails we cannot continue. How could we?
|
||||||
|
* (4) Need to restore the running db since we destroyed it above
|
||||||
|
*/
|
||||||
|
if (strlen(cbuf_get(cbret)))
|
||||||
|
clicon_log(LOG_NOTICE, "%s: Commit of running failed, exiting: %s.",
|
||||||
|
__FUNCTION__, cbuf_get(cbret));
|
||||||
|
else
|
||||||
|
clicon_log(LOG_NOTICE, "%s: Commit of running failed, exiting: %s.",
|
||||||
|
__FUNCTION__, clicon_err_reason);
|
||||||
|
/* Reinstate original */
|
||||||
|
if (xmldb_copy(h, "candidate", "running") < 0)
|
||||||
|
goto done;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Clixon startup startup mode: Commit startup configuration into running state
|
/*! Clixon startup startup mode: Commit startup configuration into running state
|
||||||
|
|
@ -460,11 +473,16 @@ startup -------------------------+--|
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
startup_mode_startup(clicon_handle h,
|
startup_mode_startup(clicon_handle h,
|
||||||
char *extraxml_file)
|
char *extraxml_file)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cbuf *cbret = NULL;
|
cbuf *cbret = NULL;
|
||||||
|
|
||||||
|
/* Create return buffer for netconf xml errors */
|
||||||
|
if ((cbret = cbuf_new()) == NULL){
|
||||||
|
clicon_err(OE_XML, errno, "cbuf_new");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
/* Stash original running to backup */
|
/* Stash original running to backup */
|
||||||
if (xmldb_copy(h, "running", "backup") < 0)
|
if (xmldb_copy(h, "running", "backup") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -481,34 +499,25 @@ startup_mode_startup(clicon_handle h,
|
||||||
/* Application may define extra xml in its reset function*/
|
/* Application may define extra xml in its reset function*/
|
||||||
if (clixon_plugin_reset(h, "tmp") < 0)
|
if (clixon_plugin_reset(h, "tmp") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
/* XXX Kludge to low-level functions to search for xml in all yang modules */
|
||||||
|
_CLICON_XML_NS_STRICT = 0;
|
||||||
/* Get application extra xml from file */
|
/* Get application extra xml from file */
|
||||||
if (load_extraxml(h, extraxml_file, "tmp") < 0)
|
if (load_extraxml(h, extraxml_file, "tmp", cbret) < 1)
|
||||||
goto done;
|
goto fail;
|
||||||
/* Clear running db */
|
/* Clear running db */
|
||||||
if (db_reset(h, "running") < 0)
|
if (db_reset(h, "running") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Create return buffer (not used) */
|
|
||||||
if ((cbret = cbuf_new()) == NULL){
|
|
||||||
clicon_err(OE_XML, errno, "cbuf_new");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* Commit startup */
|
/* Commit startup */
|
||||||
if (candidate_commit(h, "startup", cbret) < 1){ /* diff */
|
if (candidate_commit(h, "startup", cbret) < 1) /* diff */
|
||||||
/* We cannot differentiate between fatal errors and validation
|
goto fail;
|
||||||
* failures
|
|
||||||
* In both cases we copy back the original running and quit
|
|
||||||
*/
|
|
||||||
clicon_log(LOG_NOTICE, "%s: Commit of startup failed, exiting: %s.",
|
|
||||||
__FUNCTION__, cbuf_get(cbret));
|
|
||||||
if (xmldb_copy(h, "backup", "running") < 0)
|
|
||||||
goto done;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* Merge user reset state and extra xml file (no commit) */
|
/* Merge user reset state and extra xml file (no commit) */
|
||||||
if (db_merge(h, "tmp", "running") < 0)
|
if (db_merge(h, "tmp", "running", cbret) < 1)
|
||||||
goto done;
|
goto fail;
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
/* XXX Kludge to low-level functions to search for xml in all yang modules */
|
||||||
|
_CLICON_XML_NS_STRICT = clicon_option_bool(h, "CLICON_XML_NS_STRICT");
|
||||||
if (cbret)
|
if (cbret)
|
||||||
cbuf_free(cbret);
|
cbuf_free(cbret);
|
||||||
if (xmldb_delete(h, "backup") < 0)
|
if (xmldb_delete(h, "backup") < 0)
|
||||||
|
|
@ -516,6 +525,20 @@ startup_mode_startup(clicon_handle h,
|
||||||
if (xmldb_delete(h, "tmp") < 0)
|
if (xmldb_delete(h, "tmp") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
return retval;
|
return retval;
|
||||||
|
fail:
|
||||||
|
/* We cannot differentiate between fatal errors and validation
|
||||||
|
* failures
|
||||||
|
* In both cases we copy back the original running and quit
|
||||||
|
*/
|
||||||
|
if (strlen(cbuf_get(cbret)))
|
||||||
|
clicon_log(LOG_NOTICE, "%s: Commit of startup failed, exiting: %s.",
|
||||||
|
__FUNCTION__, cbuf_get(cbret));
|
||||||
|
else
|
||||||
|
clicon_log(LOG_NOTICE, "%s: Commit of startup failed, exiting: %s.",
|
||||||
|
__FUNCTION__, clicon_err_reason);
|
||||||
|
if (xmldb_copy(h, "backup", "running") < 0)
|
||||||
|
goto done;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
@ -540,7 +563,6 @@ main(int argc,
|
||||||
int sockfamily;
|
int sockfamily;
|
||||||
char *xmldb_plugin;
|
char *xmldb_plugin;
|
||||||
int xml_cache;
|
int xml_cache;
|
||||||
int xml_pretty;
|
|
||||||
char *xml_format;
|
char *xml_format;
|
||||||
char *nacm_mode;
|
char *nacm_mode;
|
||||||
int logdst = CLICON_LOG_SYSLOG|CLICON_LOG_STDERR;
|
int logdst = CLICON_LOG_SYSLOG|CLICON_LOG_STDERR;
|
||||||
|
|
@ -808,9 +830,10 @@ main(int argc,
|
||||||
if ((xml_format = clicon_option_str(h, "CLICON_XMLDB_FORMAT")) >= 0)
|
if ((xml_format = clicon_option_str(h, "CLICON_XMLDB_FORMAT")) >= 0)
|
||||||
if (xmldb_setopt(h, "format", (void*)xml_format) < 0)
|
if (xmldb_setopt(h, "format", (void*)xml_format) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xml_pretty = clicon_option_bool(h, "CLICON_XMLDB_PRETTY")) >= 0)
|
if (xmldb_setopt(h, "pretty", (void*)(intptr_t)clicon_option_bool(h, "CLICON_XMLDB_PRETTY")) < 0)
|
||||||
if (xmldb_setopt(h, "pretty", (void*)(intptr_t)xml_pretty) < 0)
|
goto done;
|
||||||
goto done;
|
if (xmldb_setopt(h, "sort", (void*)(intptr_t)clicon_option_bool(h, "CLICON_XML_SORT")) < 0)
|
||||||
|
goto done;
|
||||||
/* Startup mode needs to be defined, */
|
/* Startup mode needs to be defined, */
|
||||||
startup_mode = clicon_startup_mode(h);
|
startup_mode = clicon_startup_mode(h);
|
||||||
if (startup_mode == -1){
|
if (startup_mode == -1){
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,7 @@ clixon_plugin_reset(clicon_handle h,
|
||||||
* @param[in,out] xtop State XML tree is merged with existing tree.
|
* @param[in,out] xtop State XML tree is merged with existing tree.
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
* @retval 1 Statedata callback failed
|
* @retval 1 Statedata callback failed (xret set with netconf-error)
|
||||||
* @note xtop can be replaced
|
* @note xtop can be replaced
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
|
|
|
||||||
|
|
@ -236,7 +236,7 @@ cli_dbxml(clicon_handle h,
|
||||||
if ((xtop = xml_new("config", NULL, NULL)) == NULL)
|
if ((xtop = xml_new("config", NULL, NULL)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
xbot = xtop;
|
xbot = xtop;
|
||||||
if (api_path && api_path2xml(api_path, yspec, xtop, YC_DATANODE, &xbot, &y) < 0)
|
if (api_path && api_path2xml(api_path, yspec, xtop, YC_DATANODE, &xbot, &y) < 1)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xa = xml_new("operation", xbot, NULL)) == NULL)
|
if ((xa = xml_new("operation", xbot, NULL)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -293,7 +293,7 @@ cli_set(clicon_handle h,
|
||||||
cvec *cvv,
|
cvec *cvv,
|
||||||
cvec *argv)
|
cvec *argv)
|
||||||
{
|
{
|
||||||
int retval = 1;
|
int retval = -1;
|
||||||
|
|
||||||
if (cli_dbxml(h, cvv, argv, OP_REPLACE) < 0)
|
if (cli_dbxml(h, cvv, argv, OP_REPLACE) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -501,53 +501,54 @@ cli_start_shell(clicon_handle h,
|
||||||
cvec *vars,
|
cvec *vars,
|
||||||
cvec *argv)
|
cvec *argv)
|
||||||
{
|
{
|
||||||
char *cmd;
|
char *cmd;
|
||||||
struct passwd *pw;
|
struct passwd *pw;
|
||||||
int retval;
|
int retval = -1;
|
||||||
char bcmd[128];
|
char bcmd[128];
|
||||||
cg_var *cv1 = cvec_i(vars, 1);
|
cg_var *cv1 = cvec_i(vars, 1);
|
||||||
|
|
||||||
cmd = (cvec_len(vars)>1 ? cv_string_get(cv1) : NULL);
|
cmd = (cvec_len(vars)>1 ? cv_string_get(cv1) : NULL);
|
||||||
|
|
||||||
if ((pw = getpwuid(getuid())) == NULL){
|
if ((pw = getpwuid(getuid())) == NULL){
|
||||||
fprintf(stderr, "%s: getpwuid: %s\n",
|
fprintf(stderr, "%s: getpwuid: %s\n",
|
||||||
__FUNCTION__, strerror(errno));
|
__FUNCTION__, strerror(errno));
|
||||||
return -1;
|
goto done;
|
||||||
}
|
}
|
||||||
if (chdir(pw->pw_dir) < 0){
|
if (chdir(pw->pw_dir) < 0){
|
||||||
fprintf(stderr, "%s: chdir(%s): %s\n",
|
fprintf(stderr, "%s: chdir(%s): %s\n",
|
||||||
__FUNCTION__, pw->pw_dir, strerror(errno));
|
__FUNCTION__, pw->pw_dir, strerror(errno));
|
||||||
endpwent();
|
endpwent();
|
||||||
return -1;
|
goto done;
|
||||||
}
|
}
|
||||||
endpwent();
|
endpwent();
|
||||||
cli_signal_flush(h);
|
cli_signal_flush(h);
|
||||||
cli_signal_unblock(h);
|
cli_signal_unblock(h);
|
||||||
if (cmd){
|
if (cmd){
|
||||||
snprintf(bcmd, 128, "bash -l -c \"%s\"", cmd);
|
snprintf(bcmd, 128, "bash -l -c \"%s\"", cmd);
|
||||||
if ((retval = system(bcmd)) < 0){
|
if (system(bcmd) < 0){
|
||||||
cli_signal_block(h);
|
cli_signal_block(h);
|
||||||
fprintf(stderr, "%s: system(bash -c): %s\n",
|
fprintf(stderr, "%s: system(bash -c): %s\n",
|
||||||
__FUNCTION__, strerror(errno));
|
__FUNCTION__, strerror(errno));
|
||||||
return -1;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if ((retval = system("bash -l")) < 0){
|
if (system("bash -l") < 0){
|
||||||
cli_signal_block(h);
|
cli_signal_block(h);
|
||||||
fprintf(stderr, "%s: system(bash): %s\n",
|
fprintf(stderr, "%s: system(bash): %s\n",
|
||||||
__FUNCTION__, strerror(errno));
|
__FUNCTION__, strerror(errno));
|
||||||
return -1;
|
goto done;
|
||||||
}
|
}
|
||||||
cli_signal_block(h);
|
cli_signal_block(h);
|
||||||
#if 0 /* Allow errcodes from bash */
|
#if 0 /* Allow errcodes from bash */
|
||||||
if (retval != 0){
|
if (retval != 0){
|
||||||
fprintf(stderr, "%s: system(%s) code=%d\n", __FUNCTION__, cmd, retval);
|
fprintf(stderr, "%s: system(%s) code=%d\n", __FUNCTION__, cmd, retval);
|
||||||
return -1;
|
goto done;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
retval = 0;
|
||||||
return 0;
|
done:
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Generic quit callback
|
/*! Generic quit callback
|
||||||
|
|
|
||||||
|
|
@ -171,7 +171,7 @@ expand_dbvar(void *h,
|
||||||
/* This is primarily to get "y",
|
/* This is primarily to get "y",
|
||||||
* xpath2xml would have worked!!
|
* xpath2xml would have worked!!
|
||||||
*/
|
*/
|
||||||
if (api_path && api_path2xml(api_path, yspec, xtop, YC_DATANODE, &xbot, &y) < 0)
|
if (api_path && api_path2xml(api_path, yspec, xtop, YC_DATANODE, &xbot, &y) < 1)
|
||||||
goto done;
|
goto done;
|
||||||
if (y==NULL)
|
if (y==NULL)
|
||||||
goto ok;
|
goto ok;
|
||||||
|
|
@ -443,6 +443,7 @@ cli_show_config(clicon_handle h,
|
||||||
cxobj *xc;
|
cxobj *xc;
|
||||||
cxobj *xerr;
|
cxobj *xerr;
|
||||||
enum genmodel_type gt;
|
enum genmodel_type gt;
|
||||||
|
yang_spec *yspec;
|
||||||
|
|
||||||
if (cvec_len(argv) != 3 && cvec_len(argv) != 4){
|
if (cvec_len(argv) != 3 && cvec_len(argv) != 4){
|
||||||
clicon_err(OE_PLUGIN, 0, "Got %d arguments. Expected: <dbname>,<format>,<xpath>[,<attr>]", cvec_len(argv));
|
clicon_err(OE_PLUGIN, 0, "Got %d arguments. Expected: <dbname>,<format>,<xpath>[,<attr>]", cvec_len(argv));
|
||||||
|
|
@ -496,6 +497,13 @@ cli_show_config(clicon_handle h,
|
||||||
clicon_rpc_generate_error("Get configuration", xerr);
|
clicon_rpc_generate_error("Get configuration", xerr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||||
|
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
/* Some formats (eg cli) require yang */
|
||||||
|
if (xml_apply(xt, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
||||||
|
goto done;
|
||||||
/* Print configuration according to format */
|
/* Print configuration according to format */
|
||||||
switch (format){
|
switch (format){
|
||||||
case FORMAT_XML:
|
case FORMAT_XML:
|
||||||
|
|
@ -516,7 +524,7 @@ cli_show_config(clicon_handle h,
|
||||||
if ((gt = clicon_cli_genmodel_type(h)) == GT_ERR)
|
if ((gt = clicon_cli_genmodel_type(h)) == GT_ERR)
|
||||||
goto done;
|
goto done;
|
||||||
xc = NULL; /* Dont print xt itself */
|
xc = NULL; /* Dont print xt itself */
|
||||||
while ((xc = xml_child_each(xt, xc, -1)) != NULL)
|
while ((xc = xml_child_each(xt, xc, CX_ELMNT)) != NULL)
|
||||||
xml2cli(stdout, xc, NULL, gt); /* cli syntax */
|
xml2cli(stdout, xc, NULL, gt); /* cli syntax */
|
||||||
break;
|
break;
|
||||||
case FORMAT_NETCONF:
|
case FORMAT_NETCONF:
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,8 @@ process_incoming_packet(clicon_handle h,
|
||||||
free(str0);
|
free(str0);
|
||||||
if ((xrpc=xpath_first(xreq, "//rpc")) != NULL){
|
if ((xrpc=xpath_first(xreq, "//rpc")) != NULL){
|
||||||
isrpc++;
|
isrpc++;
|
||||||
|
if (xml_spec_populate_rpc(h, xrpc, yspec) < 0)
|
||||||
|
goto done;
|
||||||
if ((ret = xml_yang_validate_rpc(xrpc, cbret)) < 0)
|
if ((ret = xml_yang_validate_rpc(xrpc, cbret)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0){
|
if (ret == 0){
|
||||||
|
|
|
||||||
|
|
@ -905,13 +905,9 @@ netconf_application_rpc(clicon_handle h,
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
yrpc = yang_find((yang_node*)ymod, Y_RPC, xml_name(xn));
|
yrpc = yang_find((yang_node*)ymod, Y_RPC, xml_name(xn));
|
||||||
if ((yrpc==NULL) && _CLICON_XML_NS_ITERATE){
|
if ((yrpc==NULL) && !_CLICON_XML_NS_STRICT){
|
||||||
int i;
|
if (xml_yang_find_non_strict(xn, yspec, &yrpc) < 0) /* Y_RPC */
|
||||||
for (i=0; i<yspec->yp_len; i++){
|
goto done;
|
||||||
ymod = yspec->yp_stmt[i];
|
|
||||||
if ((yrpc = yang_find((yang_node*)ymod, Y_RPC, xml_name(xn))) != NULL)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/* Check if found */
|
/* Check if found */
|
||||||
if (yrpc != NULL){
|
if (yrpc != NULL){
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
# Clixon Restconf
|
# Clixon Restconf
|
||||||
|
|
||||||
* [Installation](#Installation)
|
* [Installation](#installation)
|
||||||
* [Streams](Streams)
|
* [Streams](#streams)
|
||||||
* [Nchan Streams](Nchan)
|
* [Nchan Streams](#nchan-streams)
|
||||||
* [Debugging](Debugging)
|
* [Debugging](#debugging)
|
||||||
|
|
||||||
### 1. Installation
|
## 1. Installation
|
||||||
|
|
||||||
The examples are based on Nginx. Other reverse proxies should work but are not verified.
|
The examples are based on Nginx. Other reverse proxies should work but are not verified.
|
||||||
|
|
||||||
|
|
@ -44,39 +44,39 @@ sudo systemctl start start.service
|
||||||
|
|
||||||
Start clixon restconf daemon
|
Start clixon restconf daemon
|
||||||
```
|
```
|
||||||
olof@vandal> sudo su -c "/www-data/clixon_restconf -f /usr/local/etc/example.xml " -s /bin/sh www-data
|
> sudo su -c "/www-data/clixon_restconf -f /usr/local/etc/example.xml " -s /bin/sh www-data
|
||||||
```
|
```
|
||||||
|
|
||||||
Make restconf calls with curl
|
Make restconf calls with curl
|
||||||
```
|
```
|
||||||
olof@vandal> curl -G http://127.0.0.1/restconf/data/interfaces
|
> curl -G http://127.0.0.1/restconf/data/ietf-interfaces:interfaces
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"interfaces": {
|
"ietf-interfaces:interfaces": {
|
||||||
"interface":[
|
"interface":[
|
||||||
{
|
{
|
||||||
"name": "eth0",
|
|
||||||
"type": "eth",
|
|
||||||
"enabled": "true",
|
|
||||||
"name": "eth9",
|
"name": "eth9",
|
||||||
"type": "eth",
|
"type": "ex:eth",
|
||||||
"enabled": "true"
|
"enabled": true,
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
olof@vandal> curl -G http://127.0.0.1/restconf/data/interfaces/interface/name=eth9/type
|
```
|
||||||
[
|
Get the type of a specific interface:
|
||||||
{
|
```
|
||||||
"type": "eth"
|
> curl -G http://127.0.0.1/restconf/data/interfaces/interface=eth9/type
|
||||||
}
|
{
|
||||||
]
|
"ietf-interfaces:type": "eth"
|
||||||
|
}
|
||||||
curl -sX POST -d '{"interfaces":{"interface":{"name":"eth1","type":"eth","enabled":"true"}}}' http://localhost/restconf/data
|
```
|
||||||
|
Example of writing a new interfaces specification:
|
||||||
|
```
|
||||||
|
curl -sX PUT http://localhost/restconf/data -d '{"ietf-interfaces:interfaces":{"interface":{"name":"eth1","type":"ex:eth","enabled":true}}}'
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. Streams
|
## 2. Streams
|
||||||
|
|
||||||
Clixon have two experimental restconf event stream implementations following
|
Clixon have two experimental restconf event stream implementations following
|
||||||
RFC8040 Section 6 using SSE. One native and one using Nginx
|
RFC8040 Section 6 using SSE. One native and one using Nginx
|
||||||
|
|
@ -112,7 +112,7 @@ Add the following to extend the nginx configuration file with the following stat
|
||||||
|
|
||||||
AN example of a stream access is as follows:
|
AN example of a stream access is as follows:
|
||||||
```
|
```
|
||||||
vandal> curl -H "Accept: text/event-stream" -s -X GET http://localhost/streams/EXAMPLE
|
> curl -H "Accept: text/event-stream" -s -X GET http://localhost/streams/EXAMPLE
|
||||||
data: <notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>2018-11-04T14:47:11.373124</eventTime><event><event-class>fault</event-class><reportingEntity><card>Ethernet0</card></reportingEntity><severity>major</severity></event></notification>
|
data: <notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>2018-11-04T14:47:11.373124</eventTime><event><event-class>fault</event-class><reportingEntity><card>Ethernet0</card></reportingEntity><severity>major</severity></event></notification>
|
||||||
|
|
||||||
data: <notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>2018-11-04T14:47:16.375265</eventTime><event><event-class>fault</event-class><reportingEntity><card>Ethernet0</card></reportingEntity><severity>major</severity></event></notification>
|
data: <notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>2018-11-04T14:47:16.375265</eventTime><event><event-class>fault</event-class><reportingEntity><card>Ethernet0</card></reportingEntity><severity>major</severity></event></notification>
|
||||||
|
|
@ -125,7 +125,7 @@ You can also specify start and stop time. Start-time enables replay of existing
|
||||||
|
|
||||||
See (stream tests)[../test/test_streams.sh] for more examples.
|
See (stream tests)[../test/test_streams.sh] for more examples.
|
||||||
|
|
||||||
### 3. Nchan
|
## 3. Nchan
|
||||||
|
|
||||||
As an alternative streams implementation, Nginx/Nchan can be used.
|
As an alternative streams implementation, Nginx/Nchan can be used.
|
||||||
Nginx uses pub/sub channels and can be configured in a variety of
|
Nginx uses pub/sub channels and can be configured in a variety of
|
||||||
|
|
@ -180,7 +180,7 @@ curl -H "Accept: text/event-stream" -H "Last-Event-ID: 1539961709:0" -s -X GET h
|
||||||
|
|
||||||
See (https://nchan.io/#eventsource) on more info on how to access an SSE sub endpoint.
|
See (https://nchan.io/#eventsource) on more info on how to access an SSE sub endpoint.
|
||||||
|
|
||||||
### 4. Debugging
|
## 4. Debugging
|
||||||
|
|
||||||
Start the restconf fastcgi program with debug flag:
|
Start the restconf fastcgi program with debug flag:
|
||||||
```
|
```
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -249,7 +249,7 @@ restconf_stream(clicon_handle h,
|
||||||
clicon_err(OE_XML, errno, "cbuf_new");
|
clicon_err(OE_XML, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
cprintf(cb, "<rpc><create-subscription><stream>%s</stream>", name);
|
cprintf(cb, "<rpc><create-subscription xmlns=\"urn:ietf:params:xml:ns:netmod:notification\"><stream>%s</stream>", name);
|
||||||
/* Print all fields */
|
/* Print all fields */
|
||||||
for (i=0; i<cvec_len(qvec); i++){
|
for (i=0; i<cvec_len(qvec); i++){
|
||||||
cv = cvec_i(qvec, i);
|
cv = cvec_i(qvec, i);
|
||||||
|
|
|
||||||
|
|
@ -239,15 +239,18 @@ main(int argc, char **argv)
|
||||||
clicon_err(OE_DB, 0, "Unrecognized operation: %s", argv[1]);
|
clicon_err(OE_DB, 0, "Unrecognized operation: %s", argv[1]);
|
||||||
usage(argv0);
|
usage(argv0);
|
||||||
}
|
}
|
||||||
_CLICON_XML_NS_ITERATE = 1;
|
_CLICON_XML_NS_STRICT = 0;
|
||||||
if (xml_parse_string(argv[2], NULL, &xt) < 0)
|
if (xml_parse_string(argv[2], NULL, &xt) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (xml_rootchild(xt, 0, &xt) < 0)
|
if (xml_rootchild(xt, 0, &xt) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((cbret = cbuf_new()) == NULL)
|
if ((cbret = cbuf_new()) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
if (xmldb_put(h, db, op, xt, cbret) < 0)
|
}
|
||||||
|
if (xmldb_put(h, db, op, xt, cbret) < 1)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (strcmp(cmd, "copy")==0){
|
else if (strcmp(cmd, "copy")==0){
|
||||||
if (argc != 2)
|
if (argc != 2)
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,8 @@ struct text_handle {
|
||||||
Assumes single backend*/
|
Assumes single backend*/
|
||||||
char *th_format; /* Datastroe format: xml / json */
|
char *th_format; /* Datastroe format: xml / json */
|
||||||
int th_pretty; /* Store xml/json pretty-printed. */
|
int th_pretty; /* Store xml/json pretty-printed. */
|
||||||
|
int th_sort; /* Sort XML lists and leaf-lists alphabetically
|
||||||
|
(unless ordered-by user) */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Struct per database in hash */
|
/* Struct per database in hash */
|
||||||
|
|
@ -239,6 +241,8 @@ text_getopt(xmldb_handle xh,
|
||||||
*value = th->th_format;
|
*value = th->th_format;
|
||||||
else if (strcmp(optname, "pretty") == 0)
|
else if (strcmp(optname, "pretty") == 0)
|
||||||
*value = &th->th_pretty;
|
*value = &th->th_pretty;
|
||||||
|
else if (strcmp(optname, "sort") == 0)
|
||||||
|
*value = &th->th_sort;
|
||||||
else{
|
else{
|
||||||
clicon_err(OE_PLUGIN, 0, "Option %s not implemented by plugin", optname);
|
clicon_err(OE_PLUGIN, 0, "Option %s not implemented by plugin", optname);
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -288,6 +292,9 @@ text_setopt(xmldb_handle xh,
|
||||||
else if (strcmp(optname, "pretty") == 0){
|
else if (strcmp(optname, "pretty") == 0){
|
||||||
th->th_pretty = (intptr_t)value;
|
th->th_pretty = (intptr_t)value;
|
||||||
}
|
}
|
||||||
|
else if (strcmp(optname, "sort") == 0){
|
||||||
|
th->th_sort = (intptr_t)value;
|
||||||
|
}
|
||||||
else{
|
else{
|
||||||
clicon_err(OE_PLUGIN, 0, "Option %s not implemented by plugin", optname);
|
clicon_err(OE_PLUGIN, 0, "Option %s not implemented by plugin", optname);
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -358,6 +365,16 @@ xml_copy_marked(cxobj *x0,
|
||||||
|
|
||||||
assert(x0 && x1);
|
assert(x0 && x1);
|
||||||
yt = xml_spec(x0); /* can be null */
|
yt = xml_spec(x0); /* can be null */
|
||||||
|
/* Copy all attributes */
|
||||||
|
x = NULL;
|
||||||
|
while ((x = xml_child_each(x0, x, CX_ATTR)) != NULL) {
|
||||||
|
name = xml_name(x);
|
||||||
|
if ((xcopy = xml_new(name, x1, xml_spec(x))) == NULL)
|
||||||
|
goto done;
|
||||||
|
if (xml_copy(x, xcopy) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
/* Go through children to detect any marked nodes:
|
/* Go through children to detect any marked nodes:
|
||||||
* (3) Special case: key nodes in lists are copied if any
|
* (3) Special case: key nodes in lists are copied if any
|
||||||
* node in list is marked
|
* node in list is marked
|
||||||
|
|
@ -470,6 +487,10 @@ text_get(xmldb_handle xh,
|
||||||
if (singleconfigroot(xt, &xt) < 0)
|
if (singleconfigroot(xt, &xt) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
/* XXX: should we validate file if read from disk?
|
||||||
|
* Argument against: we may want to have a semantically wrong file and wish
|
||||||
|
* to edit?
|
||||||
|
*/
|
||||||
} /* xt == NULL */
|
} /* xt == NULL */
|
||||||
/* Here xt looks like: <config>...</config> */
|
/* Here xt looks like: <config>...</config> */
|
||||||
|
|
||||||
|
|
@ -530,12 +551,15 @@ text_get(xmldb_handle xh,
|
||||||
/* Add default values (if not set) */
|
/* Add default values (if not set) */
|
||||||
if (xml_apply(xt, CX_ELMNT, xml_default, NULL) < 0)
|
if (xml_apply(xt, CX_ELMNT, xml_default, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Order XML children according to YANG */
|
/* Order XML children according to YANG.
|
||||||
if (!xml_child_sort && xml_apply(xt, CX_ELMNT, xml_order, NULL) < 0)
|
* XXX: should this be !th->th_sort?
|
||||||
goto done;
|
*/
|
||||||
#if 0 /* debug */
|
if (!th->th_sort)
|
||||||
if (xml_child_sort && xml_apply0(xt, -1, xml_sort_verify, NULL) < 0)
|
if (xml_apply(xt, CX_ELMNT, xml_order, NULL) < 0)
|
||||||
clicon_log(LOG_NOTICE, "%s: verify failed #2", __FUNCTION__);
|
goto done;
|
||||||
|
#if 1 /* debug */
|
||||||
|
if (th->th_sort && xml_apply0(xt, -1, xml_sort_verify, NULL) < 0)
|
||||||
|
clicon_log(LOG_NOTICE, "%s: sort verify failed #2", __FUNCTION__);
|
||||||
#endif
|
#endif
|
||||||
if (debug>1)
|
if (debug>1)
|
||||||
clicon_xml2file(stderr, xt, 0, 1);
|
clicon_xml2file(stderr, xt, 0, 1);
|
||||||
|
|
@ -555,6 +579,7 @@ text_get(xmldb_handle xh,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Modify a base tree x0 with x1 with yang spec y according to operation op
|
/*! Modify a base tree x0 with x1 with yang spec y according to operation op
|
||||||
|
* @param[in] th text handle
|
||||||
* @param[in] x0 Base xml tree (can be NULL in add scenarios)
|
* @param[in] x0 Base xml tree (can be NULL in add scenarios)
|
||||||
* @param[in] y0 Yang spec corresponding to xml-node x0. NULL if x0 is NULL
|
* @param[in] y0 Yang spec corresponding to xml-node x0. NULL if x0 is NULL
|
||||||
* @param[in] x0p Parent of x0
|
* @param[in] x0p Parent of x0
|
||||||
|
|
@ -562,10 +587,11 @@ text_get(xmldb_handle xh,
|
||||||
* @param[in] op OP_MERGE, OP_REPLACE, OP_REMOVE, etc
|
* @param[in] op OP_MERGE, OP_REPLACE, OP_REMOVE, etc
|
||||||
* @param[out] cbret Initialized cligen buffer. Contains return XML or "".
|
* @param[out] cbret Initialized cligen buffer. Contains return XML or "".
|
||||||
* Assume x0 and x1 are same on entry and that y is the spec
|
* Assume x0 and x1 are same on entry and that y is the spec
|
||||||
* @see put in clixon_keyvalue.c
|
* @see text_modify_top
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
text_modify(cxobj *x0,
|
text_modify(struct text_handle *th,
|
||||||
|
cxobj *x0,
|
||||||
yang_node *y0,
|
yang_node *y0,
|
||||||
cxobj *x0p,
|
cxobj *x0p,
|
||||||
cxobj *x1,
|
cxobj *x1,
|
||||||
|
|
@ -576,6 +602,8 @@ text_modify(cxobj *x0,
|
||||||
char *opstr;
|
char *opstr;
|
||||||
char *x1name;
|
char *x1name;
|
||||||
char *x1cname; /* child name */
|
char *x1cname; /* child name */
|
||||||
|
cxobj *x0a; /* attribute */
|
||||||
|
cxobj *x1a; /* attribute */
|
||||||
cxobj *x0c; /* base child */
|
cxobj *x0c; /* base child */
|
||||||
cxobj *x0b; /* base body */
|
cxobj *x0b; /* base body */
|
||||||
cxobj *x1c; /* mod child */
|
cxobj *x1c; /* mod child */
|
||||||
|
|
@ -607,6 +635,13 @@ text_modify(cxobj *x0,
|
||||||
// int iamkey=0;
|
// int iamkey=0;
|
||||||
if ((x0 = xml_new(x1name, x0p, (yang_stmt*)y0)) == NULL)
|
if ((x0 = xml_new(x1name, x0p, (yang_stmt*)y0)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
|
/* Copy xmlns attributes */
|
||||||
|
if ((x1a = xml_find_type(x1, NULL, "xmlns", CX_ATTR)) != 0){
|
||||||
|
if ((x0a = xml_dup(x1a)) == NULL)
|
||||||
|
goto done;
|
||||||
|
if (xml_addsub(x0, x0a) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
#if 0
|
#if 0
|
||||||
/* If it is key I dont want to mark it */
|
/* If it is key I dont want to mark it */
|
||||||
if ((iamkey=yang_key_match(y0->yn_parent, x1name)) < 0)
|
if ((iamkey=yang_key_match(y0->yn_parent, x1name)) < 0)
|
||||||
|
|
@ -679,6 +714,13 @@ text_modify(cxobj *x0,
|
||||||
if (x0==NULL){
|
if (x0==NULL){
|
||||||
if ((x0 = xml_new(x1name, x0p, (yang_stmt*)y0)) == NULL)
|
if ((x0 = xml_new(x1name, x0p, (yang_stmt*)y0)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
|
/* Copy xmlns attributes */
|
||||||
|
if ((x1a = xml_find_type(x1, NULL, "xmlns", CX_ATTR)) != 0){
|
||||||
|
if ((x0a = xml_dup(x1a)) == NULL)
|
||||||
|
goto done;
|
||||||
|
if (xml_addsub(x0, x0a) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
if (op==OP_NONE)
|
if (op==OP_NONE)
|
||||||
xml_flag_set(x0, XML_FLAG_NONE); /* Mark for potential deletion */
|
xml_flag_set(x0, XML_FLAG_NONE); /* Mark for potential deletion */
|
||||||
}
|
}
|
||||||
|
|
@ -699,7 +741,7 @@ text_modify(cxobj *x0,
|
||||||
}
|
}
|
||||||
/* See if there is a corresponding node in the base tree */
|
/* See if there is a corresponding node in the base tree */
|
||||||
x0c = NULL;
|
x0c = NULL;
|
||||||
if (match_base_child(x0, x1c, &x0c, yc) < 0)
|
if (match_base_child(x0, x1c, &x0c, th->th_sort, yc) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
x0vec[i++] = x0c;
|
x0vec[i++] = x0c;
|
||||||
}
|
}
|
||||||
|
|
@ -709,7 +751,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);
|
||||||
yc = yang_find_datanode(y0, x1cname);
|
yc = yang_find_datanode(y0, x1cname);
|
||||||
if (text_modify(x0vec[i++], (yang_node*)yc, x0, x1c, op, cbret) < 0)
|
if (text_modify(th, x0vec[i++], (yang_node*)yc, x0, x1c, op, cbret) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* If xml return - ie netconf error xml tree, then stop and return OK */
|
/* If xml return - ie netconf error xml tree, then stop and return OK */
|
||||||
if (cbuf_len(cbret))
|
if (cbuf_len(cbret))
|
||||||
|
|
@ -740,6 +782,7 @@ text_modify(cxobj *x0,
|
||||||
} /* text_modify */
|
} /* text_modify */
|
||||||
|
|
||||||
/*! Modify a top-level base tree x0 with modification tree x1
|
/*! Modify a top-level base tree x0 with modification tree x1
|
||||||
|
* @param[in] th text handle
|
||||||
* @param[in] x0 Base xml tree (can be NULL in add scenarios)
|
* @param[in] x0 Base xml tree (can be NULL in add scenarios)
|
||||||
* @param[in] x1 xml tree which modifies base
|
* @param[in] x1 xml tree which modifies base
|
||||||
* @param[in] yspec Top-level yang spec (if y is NULL)
|
* @param[in] yspec Top-level yang spec (if y is NULL)
|
||||||
|
|
@ -812,23 +855,19 @@ text_modify_top(struct text_handle *th,
|
||||||
goto done;
|
goto done;
|
||||||
if (ymod != NULL)
|
if (ymod != NULL)
|
||||||
yc = yang_find_datanode((yang_node*)ymod, x1cname);
|
yc = yang_find_datanode((yang_node*)ymod, x1cname);
|
||||||
if (yc == NULL && _CLICON_XML_NS_ITERATE){
|
if (yc == NULL && !_CLICON_XML_NS_STRICT){
|
||||||
int i;
|
if (xml_yang_find_non_strict(x1c, yspec, &yc) < 0)
|
||||||
for (i=0; i<yspec->yp_len; i++){
|
goto done;
|
||||||
ymod = yspec->yp_stmt[i];
|
|
||||||
if ((yc = yang_find_datanode((yang_node*)ymod, x1cname)) != NULL)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (yc == NULL){
|
if (yc == NULL){
|
||||||
if (netconf_operation_failed(cbret, "application", "Validation failed")< 0)
|
if (netconf_unknown_element(cbret, "application", x1cname, "Unassigned yang spec") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
/* See if there is a corresponding node in the base tree */
|
/* See if there is a corresponding node in the base tree */
|
||||||
if (match_base_child(x0, x1c, &x0c, yc) < 0)
|
if (match_base_child(x0, x1c, &x0c, th->th_sort, yc) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (text_modify(x0c, (yang_node*)yc, x0, x1c, op, cbret) < 0)
|
if (text_modify(th, x0c, (yang_node*)yc, x0, x1c, op, cbret) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* If xml return - ie netconf error xml tree, then stop and return OK */
|
/* If xml return - ie netconf error xml tree, then stop and return OK */
|
||||||
if (cbuf_len(cbret))
|
if (cbuf_len(cbret))
|
||||||
|
|
@ -840,7 +879,7 @@ text_modify_top(struct text_handle *th,
|
||||||
return retval;
|
return retval;
|
||||||
} /* text_modify_top */
|
} /* text_modify_top */
|
||||||
|
|
||||||
/*! For containers without presence and no children, remove
|
/*! For containers without presence and no children(except attrs), remove
|
||||||
* @param[in] x XML tree node
|
* @param[in] x XML tree node
|
||||||
* See section 7.5.1 in rfc6020bis-02.txt:
|
* See section 7.5.1 in rfc6020bis-02.txt:
|
||||||
* No presence:
|
* No presence:
|
||||||
|
|
@ -869,7 +908,7 @@ xml_container_presence(cxobj *x,
|
||||||
}
|
}
|
||||||
/* Mark node that is: container, have no children, dont have presence */
|
/* Mark node that is: container, have no children, dont have presence */
|
||||||
if (y->ys_keyword == Y_CONTAINER &&
|
if (y->ys_keyword == Y_CONTAINER &&
|
||||||
xml_child_nr(x)==0 &&
|
xml_child_nr_notype(x, CX_ATTR)==0 &&
|
||||||
yang_find((yang_node*)y, Y_PRESENCE, NULL) == NULL)
|
yang_find((yang_node*)y, Y_PRESENCE, NULL) == NULL)
|
||||||
xml_flag_set(x, XML_FLAG_MARK); /* Mark, remove later */
|
xml_flag_set(x, XML_FLAG_MARK); /* Mark, remove later */
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
@ -964,7 +1003,7 @@ text_put(xmldb_handle xh,
|
||||||
goto done;
|
goto done;
|
||||||
#endif
|
#endif
|
||||||
#if 0 /* debug */
|
#if 0 /* debug */
|
||||||
if (xml_child_sort && xml_apply0(x1, -1, xml_sort_verify, NULL) < 0)
|
if (th->th_sort && xml_apply0(x1, -1, xml_sort_verify, NULL) < 0)
|
||||||
clicon_log(LOG_NOTICE, "%s: verify failed #1", __FUNCTION__);
|
clicon_log(LOG_NOTICE, "%s: verify failed #1", __FUNCTION__);
|
||||||
#endif
|
#endif
|
||||||
/*
|
/*
|
||||||
|
|
@ -975,7 +1014,7 @@ text_put(xmldb_handle xh,
|
||||||
goto done;
|
goto done;
|
||||||
/* If xml return - ie netconf error xml tree, then stop and return OK */
|
/* If xml return - ie netconf error xml tree, then stop and return OK */
|
||||||
if (cbuf_len(cbret))
|
if (cbuf_len(cbret))
|
||||||
goto ok;
|
goto fail;
|
||||||
|
|
||||||
/* Remove NONE nodes if all subs recursively are also NONE */
|
/* Remove NONE nodes if all subs recursively are also NONE */
|
||||||
if (xml_tree_prune_flagged_sub(x0, XML_FLAG_NONE, 0, NULL) <0)
|
if (xml_tree_prune_flagged_sub(x0, XML_FLAG_NONE, 0, NULL) <0)
|
||||||
|
|
@ -990,7 +1029,7 @@ text_put(xmldb_handle xh,
|
||||||
if (xml_tree_prune_flagged(x0, XML_FLAG_MARK, 1) < 0)
|
if (xml_tree_prune_flagged(x0, XML_FLAG_MARK, 1) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
#if 0 /* debug */
|
#if 0 /* debug */
|
||||||
if (xml_child_sort && xml_apply0(x0, -1, xml_sort_verify, NULL) < 0)
|
if (th->th_sort && xml_apply0(x0, -1, xml_sort_verify, NULL) < 0)
|
||||||
clicon_log(LOG_NOTICE, "%s: verify failed #3", __FUNCTION__);
|
clicon_log(LOG_NOTICE, "%s: verify failed #3", __FUNCTION__);
|
||||||
#endif
|
#endif
|
||||||
/* Write back to datastore cache if first time */
|
/* Write back to datastore cache if first time */
|
||||||
|
|
@ -1025,8 +1064,7 @@ text_put(xmldb_handle xh,
|
||||||
}
|
}
|
||||||
else if (clicon_xml2file(f, x0, 0, th->th_pretty) < 0)
|
else if (clicon_xml2file(f, x0, 0, th->th_pretty) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
ok:
|
retval = 1;
|
||||||
retval = 0;
|
|
||||||
done:
|
done:
|
||||||
if (cbretlocal && cbret)
|
if (cbretlocal && cbret)
|
||||||
cbuf_free(cbret);
|
cbuf_free(cbret);
|
||||||
|
|
@ -1041,6 +1079,9 @@ text_put(xmldb_handle xh,
|
||||||
if (!th->th_cache && x0)
|
if (!th->th_cache && x0)
|
||||||
xml_free(x0);
|
xml_free(x0);
|
||||||
return retval;
|
return retval;
|
||||||
|
fail:
|
||||||
|
retval = 0;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Copy database from db1 to db2
|
/*! Copy database from db1 to db2
|
||||||
|
|
@ -1434,7 +1475,7 @@ main(int argc,
|
||||||
op = OP_REMOVE;
|
op = OP_REMOVE;
|
||||||
else
|
else
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
if (xmldb_put(h, db, op, NULL, xn, NULL) < 0)
|
if (xmldb_put(h, db, op, NULL, xn, NULL) < 1)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
144
doc/FAQ.md
144
doc/FAQ.md
|
|
@ -42,9 +42,9 @@ The example:
|
||||||
sudo make install
|
sudo make install
|
||||||
```
|
```
|
||||||
|
|
||||||
## How do you run Clixon example commands?
|
## How do I run Clixon example commands?
|
||||||
|
|
||||||
- Start a backend server: `clixon_backend -Ff /usr/local/etc/example.xml`
|
- Start a backend server: `clixon_backend -F -s init -f /usr/local/etc/example.xml`
|
||||||
- Start a cli session: `clixon_cli -f /usr/local/etc/example.xml`
|
- Start a cli session: `clixon_cli -f /usr/local/etc/example.xml`
|
||||||
- Start a netconf session: `clixon_netconf -f /usr/local/etc/example.xml`
|
- Start a netconf session: `clixon_netconf -f /usr/local/etc/example.xml`
|
||||||
- Start a restconf daemon: `sudo su -c "/www-data/clixon_restconf -f /usr/local/etc/example.xml " -s /bin/sh www-data`
|
- Start a restconf daemon: `sudo su -c "/www-data/clixon_restconf -f /usr/local/etc/example.xml " -s /bin/sh www-data`
|
||||||
|
|
@ -72,6 +72,82 @@ grep clicon /etc/group
|
||||||
clicon:x:1001:<user>,www-data
|
clicon:x:1001:<user>,www-data
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## How do I use the CLI?
|
||||||
|
|
||||||
|
The easiest way to use Clixon is via the CLI. Once the backend is started
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
clixon_cli -f /usr/local/etc/example.xml
|
||||||
|
cli> set interfaces interface eth9 ?
|
||||||
|
description enabled ipv4
|
||||||
|
ipv6 link-up-down-trap-enable type
|
||||||
|
cli> set interfaces interface eth9 type ex:eth
|
||||||
|
cli> validate
|
||||||
|
cli> commit
|
||||||
|
cli> show configuration xml
|
||||||
|
<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
|
||||||
|
<interface>
|
||||||
|
<name>eth9</name>
|
||||||
|
<type>ex:eth</type>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
</interface>
|
||||||
|
</interfaces>
|
||||||
|
cli> delete interfaces interface eth9
|
||||||
|
```
|
||||||
|
|
||||||
|
## How do I use netconf?
|
||||||
|
|
||||||
|
As an alternative to cli configuration, you can use netconf. Easiest is to just pipe netconf commands to the clixon_netconf application.
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
clixon_netconf -qf /usr/local/etc/example.xml
|
||||||
|
<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>
|
||||||
|
<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth9</name><type>ex:eth</type><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>
|
||||||
|
```
|
||||||
|
|
||||||
|
However, more useful is to run clixon_netconf as an SSH
|
||||||
|
subsystem. Register the subsystem in /etc/sshd_config:
|
||||||
|
```
|
||||||
|
Subsystem netconf /usr/local/bin/clixon_netconf -f /usr/local/etc/example.xml
|
||||||
|
```
|
||||||
|
and then invoke it from a client using
|
||||||
|
```
|
||||||
|
ssh -s <host> netconf
|
||||||
|
```
|
||||||
|
|
||||||
|
## How do I use restconf?
|
||||||
|
|
||||||
|
You can access clixon via REST API using restconf, such as using
|
||||||
|
curl. GET, PUT, POST are supported.
|
||||||
|
|
||||||
|
You need a web-server, such as nginx, and start a restconf fcgi
|
||||||
|
daemon, clixon_restconf.
|
||||||
|
|
||||||
|
For example, using nginx, install, and edit config file: /etc/nginx/sites-available/default:
|
||||||
|
```
|
||||||
|
server {
|
||||||
|
...
|
||||||
|
location /restconf {
|
||||||
|
fastcgi_pass unix:/www-data/fastcgi_restconf.sock;
|
||||||
|
include fastcgi_params;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Start nginx daemon
|
||||||
|
```
|
||||||
|
sudo /etc/init.d/nginx start
|
||||||
|
```
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
curl -G http://127.0.0.1/restconf/data/ietf-interfaces:interfaces/interface=eth9/type
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"ietf-interfaces:type": "ex:eth"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
Read more in the (restconf)[../apps/restconf] docs.
|
||||||
## What about reference documentation?
|
## What about reference documentation?
|
||||||
Clixon uses [Doxygen](http://www.doxygen.nl/index.html) for reference documentation.
|
Clixon uses [Doxygen](http://www.doxygen.nl/index.html) for reference documentation.
|
||||||
You need to install doxygen and graphviz on your system.
|
You need to install doxygen and graphviz on your system.
|
||||||
|
|
@ -161,59 +237,6 @@ sudo docker run -td olofhagsand/clixon_example
|
||||||
```
|
```
|
||||||
Look in the example documentation for more info.
|
Look in the example documentation for more info.
|
||||||
|
|
||||||
## How do I use netconf?
|
|
||||||
|
|
||||||
As an alternative to cli configuration, you can use netconf. Easiest is to just pipe netconf commands to the clixon_netconf application.
|
|
||||||
Example:
|
|
||||||
```
|
|
||||||
echo "<rpc><get-config><source><candidate/></source><configuration/></get-config></rpc>]]>]]>" | clixon_netconf -f /usr/local/etc/example.xml
|
|
||||||
```
|
|
||||||
|
|
||||||
However, more useful is to run clixon_netconf as an SSH
|
|
||||||
subsystem. Register the subsystem in /etc/sshd_config:
|
|
||||||
```
|
|
||||||
Subsystem netconf /usr/local/bin/clixon_netconf -f /usr/local/etc/example.xml
|
|
||||||
```
|
|
||||||
and then invoke it from a client using
|
|
||||||
```
|
|
||||||
ssh -s <host> netconf
|
|
||||||
```
|
|
||||||
|
|
||||||
## How do I use restconf?
|
|
||||||
|
|
||||||
You can access clixon via REST API using restconf, such as using
|
|
||||||
curl. GET, PUT, POST are supported.
|
|
||||||
|
|
||||||
You need a web-server, such as nginx, and start a restconf fcgi
|
|
||||||
daemon, clixon_restconf.
|
|
||||||
|
|
||||||
For example, using nginx, install, and edit config file: /etc/nginx/sites-available/default:
|
|
||||||
```
|
|
||||||
server {
|
|
||||||
...
|
|
||||||
location /restconf {
|
|
||||||
fastcgi_pass unix:/www-data/fastcgi_restconf.sock;
|
|
||||||
include fastcgi_params;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
Start nginx daemon
|
|
||||||
```
|
|
||||||
sudo /etc/init.d/nginx start
|
|
||||||
```
|
|
||||||
|
|
||||||
Example:
|
|
||||||
```
|
|
||||||
curl -G http://127.0.0.1/restconf/data/interfaces/interface/name=eth9/type
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"type": "eth"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
```
|
|
||||||
Read more in the (restconf)[../apps/restconf] docs.
|
|
||||||
|
|
||||||
|
|
||||||
## Does Clixon support event streams?
|
## Does Clixon support event streams?
|
||||||
|
|
||||||
Yes, Clixon supports event notification streams in the CLI, Netconf and Restconf API:s.
|
Yes, Clixon supports event notification streams in the CLI, Netconf and Restconf API:s.
|
||||||
|
|
@ -233,7 +256,7 @@ severity major;
|
||||||
or via NETCONF:
|
or via NETCONF:
|
||||||
```
|
```
|
||||||
clixon_netconf -qf /usr/local/etc/example.xml
|
clixon_netconf -qf /usr/local/etc/example.xml
|
||||||
<rpc><create-subscription><stream>EXAMPLE</stream></create-subscription></rpc>]]>]]>
|
<rpc><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"><stream>EXAMPLE</stream></create-subscription></rpc>]]>]]>
|
||||||
<rpc-reply><ok/></rpc-reply>]]>]]>
|
<rpc-reply><ok/></rpc-reply>]]>]]>
|
||||||
<notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>2018-09-30T12:44:59.657276</eventTime><event xmlns="http://example.com/event/1.0"><event-class>fault</event-class><reportingEntity><card>Ethernet0</card></reportingEntity><severity>major</severity></event></notification>]]>]]>
|
<notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>2018-09-30T12:44:59.657276</eventTime><event xmlns="http://example.com/event/1.0"><event-class>fault</event-class><reportingEntity><card>Ethernet0</card></reportingEntity><severity>major</severity></event></notification>]]>]]>
|
||||||
...
|
...
|
||||||
|
|
@ -242,11 +265,11 @@ or via restconf:
|
||||||
```
|
```
|
||||||
curl -H "Accept: text/event-stream" -s -X GET http://localhost/streams/EXAMPLE
|
curl -H "Accept: text/event-stream" -s -X GET http://localhost/streams/EXAMPLE
|
||||||
```
|
```
|
||||||
Consult (../apps/restconf/README.md) on more information on how to setup a reverse proxy for restconf streams. It is also possible to configure a pub/sub system such as (Nginx Nchan)[https://nchan.io].
|
Consult [clixon restconf](../apps/restconf/README.md) on more information on how to setup a reverse proxy for restconf streams. It is also possible to configure a pub/sub system such as [Nginx Nchan](https://nchan.io).
|
||||||
|
|
||||||
## How should I start the backend daemon?
|
## How should I start the backend daemon?
|
||||||
|
|
||||||
There are four different backend startup modes. There is differences in running state treatment, ie what state the machine is when you startthe daemon and how loading the configuration affects it:
|
There are four different backend startup modes. There is differences in running state treatment, ie what state the machine is when you start the daemon and how loading the configuration affects it:
|
||||||
- none - Do not touch running state. Typically after crash when running state and db are synched.
|
- none - Do not touch running state. Typically after crash when running state and db are synched.
|
||||||
- init - Initialize running state. Start with a completely clean running state.
|
- init - Initialize running state. Start with a completely clean running state.
|
||||||
- running - Commit running db configuration into running state. Typically after reboot if a persistent running db exists.
|
- running - Commit running db configuration into running state. Typically after reboot if a persistent running db exists.
|
||||||
|
|
@ -277,7 +300,7 @@ There are two ways to add extra XML to running database after start. Note that
|
||||||
The first way is via a file. Assume you want to add this xml (the config tag is a necessary top-level tag):
|
The first way is via a file. Assume you want to add this xml (the config tag is a necessary top-level tag):
|
||||||
```
|
```
|
||||||
<config>
|
<config>
|
||||||
<x>extra</x>
|
<x xmlns="urn:example:clixon">extra</x>
|
||||||
</config>
|
</config>
|
||||||
```
|
```
|
||||||
You add this via the -c option:
|
You add this via the -c option:
|
||||||
|
|
@ -289,12 +312,13 @@ The second way is by programming the plugin_reset() in the backend
|
||||||
plugin. The example code contains an example on how to do this (see plugin_reset() in example_backend.c).
|
plugin. The example code contains an example on how to do this (see plugin_reset() in example_backend.c).
|
||||||
|
|
||||||
## I want to program. How do I extend the example?
|
## I want to program. How do I extend the example?
|
||||||
See [../apps/example]
|
See [../apps/example](../apps/example)
|
||||||
- example.xml - Change the configuration file
|
- example.xml - Change the configuration file
|
||||||
- The yang specifications - This is the central part. It changes the XML, database and the config cli.
|
- The yang specifications - This is the central part. It changes the XML, database and the config cli.
|
||||||
- example_cli.cli - Change the fixed part of the CLI commands
|
- example_cli.cli - Change the fixed part of the CLI commands
|
||||||
- example_cli.c - Cli C-commands are placed here.
|
- example_cli.c - Cli C-commands are placed here.
|
||||||
- example_backend.c - Commit and validate functions.
|
- example_backend.c - Commit and validate functions.
|
||||||
|
- example_backend_nacm.c - Secondary example plugin (for authorization)
|
||||||
- example_netconf.c - Netconf plugin
|
- example_netconf.c - Netconf plugin
|
||||||
- example_restconf.c - Add restconf authentication, etc.
|
- example_restconf.c - Add restconf authentication, etc.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,33 @@
|
||||||
# Clixon example
|
# Clixon example
|
||||||
|
|
||||||
|
* [Content](#content)
|
||||||
|
* [Compile and run](#compile)
|
||||||
|
* [Using the CLI](#using-the-cli)
|
||||||
|
* [Using netconf](#using-netconf)
|
||||||
|
* [Streams](#streams)
|
||||||
|
* [RPC Operations](#rpc-operations)
|
||||||
|
* [State data](#state-data)
|
||||||
|
* [Authentication and NACM](#authentication-and-nacm)
|
||||||
|
* [Systemd](#systemd)
|
||||||
|
* [Docker](#docker)
|
||||||
|
* [Plugins](#plugins)
|
||||||
|
|
||||||
|
## Content
|
||||||
|
|
||||||
This directory contains a Clixon example which includes a simple example. It contains the following files:
|
This directory contains a Clixon example which includes a simple example. It contains the following files:
|
||||||
* example.xml The configuration file. See yang/clixon-config@<date>.yang for all available fields.
|
* `example.xml` The configuration file. See (yang/clixon-config@<date>.yang)[../yang/clixon-config@2018-10-21.yang] for the documentation of all available fields.
|
||||||
* example.yang The yang spec of the example. It mainly includes ietf routing and IP modules.
|
* `example.yang` The yang spec of the example. It mainly includes ietf routing and IP modules.
|
||||||
* example_cli.cli CLIgen specification.
|
* `example_cli.cli` CLIgen specification.
|
||||||
* example_cli.c CLI callback plugin containing functions called in the cli file above: a generic callback (`mycallback`) and an RPC (`fib_route_rpc`).
|
* `example_cli.c` CLI callback plugin containing functions called in the cli file above: a generic callback (`mycallback`) and an RPC (`fib_route_rpc`).
|
||||||
* example_backend.c Backend callback plugin including example of:
|
* `example_backend.c` Backend callback plugin including example of:
|
||||||
* transaction callbacks (validate/commit),
|
* transaction callbacks (validate/commit),
|
||||||
* notification,
|
* notification,
|
||||||
* rpc handler
|
* rpc handler
|
||||||
* state-data handler, ie non-config data
|
* state-data handler, ie non-config data
|
||||||
* example_backend_nacm.c Secondary backend plugin. Plugins are loaded alphabetically.
|
* `example_backend_nacm.c` Secondary backend plugin. Plugins are loaded alphabetically.
|
||||||
* example_restconf.c Restconf callback plugin containing an HTTP basic authentication callback
|
* `example_restconf.c` Restconf callback plugin containing an HTTP basic authentication callback
|
||||||
* example_netconf.c Netconf callback plugin
|
* `example_netconf.c` Netconf callback plugin
|
||||||
* Makefile.in Example makefile where plugins are built and installed
|
* `Makefile.in` Example makefile where plugins are built and installed
|
||||||
|
|
||||||
|
|
||||||
## Compile and run
|
## Compile and run
|
||||||
|
|
@ -47,10 +61,37 @@ Send restconf command
|
||||||
curl -G http://127.0.0.1/restconf/data
|
curl -G http://127.0.0.1/restconf/data
|
||||||
```
|
```
|
||||||
|
|
||||||
## Setting data example using netconf
|
## Using the CLI
|
||||||
|
|
||||||
|
The example CLI allows you to modify and view the data model using `set`, `delete` and `show` via generated code.
|
||||||
|
There are also many other commands available as examples. View the source file (example_cli.cli)[example_cli.cli] for more details.
|
||||||
|
|
||||||
|
The following example shows how to add an interface in candidate, validate and commit it to running, then look at it (as xml) and finally delete it.
|
||||||
|
```
|
||||||
|
clixon_cli -f /usr/local/etc/example.xml
|
||||||
|
cli> set interfaces interface eth9 ?
|
||||||
|
description enabled ipv4
|
||||||
|
ipv6 link-up-down-trap-enable type
|
||||||
|
cli> set interfaces interface eth9 type ex:eth
|
||||||
|
cli> validate
|
||||||
|
cli> commit
|
||||||
|
cli> show configuration xml
|
||||||
|
<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
|
||||||
|
<interface>
|
||||||
|
<name>eth9</name>
|
||||||
|
<type>ex:eth</type>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
</interface>
|
||||||
|
</interfaces>
|
||||||
|
cli> delete interfaces interface eth9
|
||||||
|
```
|
||||||
|
|
||||||
|
## Using Netconf
|
||||||
|
|
||||||
|
The following example shows how to set data using netconf:
|
||||||
```
|
```
|
||||||
<rpc><edit-config><target><candidate/></target><config>
|
<rpc><edit-config><target><candidate/></target><config>
|
||||||
<interfaces>
|
<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
|
||||||
<interface>
|
<interface>
|
||||||
<name>eth1</name>
|
<name>eth1</name>
|
||||||
<enabled>true</enabled>
|
<enabled>true</enabled>
|
||||||
|
|
@ -65,13 +106,13 @@ Send restconf command
|
||||||
</config></edit-config></rpc>]]>]]>
|
</config></edit-config></rpc>]]>]]>
|
||||||
```
|
```
|
||||||
|
|
||||||
## Getting data using netconf
|
### Getting data using netconf
|
||||||
```
|
```
|
||||||
<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>
|
<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>
|
||||||
<rpc><get-config><source><candidate/></source><filter/></get-config></rpc>]]>]]>
|
<rpc><get-config><source><candidate/></source><filter/></get-config></rpc>]]>]]>
|
||||||
<rpc><get-config><source><candidate/></source><filter type="xpath"/></get-config></rpc>]]>]]>
|
<rpc><get-config><source><candidate/></source><filter type="xpath"/></get-config></rpc>]]>]]>
|
||||||
<rpc><get-config><source><candidate/></source><filter type="subtree"><configuration><interfaces><interface><ipv4/></interface></interfaces></configuration></filter></get-config></rpc>]]>]]>
|
<rpc><get-config><source><candidate/></source><filter type="subtree"><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth9</name><type>ex:eth</type></interface></interfaces></data></filter></get-config></rpc>]]>]]>
|
||||||
<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface/ipv4"/></get-config></rpc>]]>]]>
|
<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface"/></get-config></rpc>]]>]]>
|
||||||
<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>
|
<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -80,23 +121,134 @@ Send restconf command
|
||||||
The example has an EXAMPLE stream notification triggering every 5s. To start a notification
|
The example has an EXAMPLE stream notification triggering every 5s. To start a notification
|
||||||
stream in the session using netconf, create a subscription:
|
stream in the session using netconf, create a subscription:
|
||||||
```
|
```
|
||||||
<rpc><create-subscription><stream>EXAMPLE</stream></create-subscription></rpc>]]>]]>
|
<rpc><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"><stream>EXAMPLE</stream></create-subscription></rpc>]]>]]>
|
||||||
<rpc-reply><ok/></rpc-reply>]]>]]>
|
<rpc-reply><ok/></rpc-reply>]]>]]>
|
||||||
<notification><event>Routing notification</event></notification>]]>]]>
|
<notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>2019-01-02T10:20:05.929272</eventTime><event><event-class>fault</event-class><reportingEntity><card>Ethernet0</card></reportingEntity><severity>major</severity></event></notification>]]>]]>
|
||||||
<notification><event>Routing notification</event></notification>]]>]]>
|
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
This can also be triggered via the CLI:
|
This can also be triggered via the CLI:
|
||||||
```
|
```
|
||||||
|
clixon_cli -f /usr/local/etc/example.xml
|
||||||
cli> notify
|
cli> notify
|
||||||
cli> Routing notification
|
cli> event-class fault;
|
||||||
Routing notification
|
reportingEntity {
|
||||||
|
card Ethernet0;
|
||||||
|
}
|
||||||
|
severity major;
|
||||||
...
|
...
|
||||||
|
cli> no notify
|
||||||
|
cli>
|
||||||
```
|
```
|
||||||
|
|
||||||
Restconf support is also supported, see [../apps/restconf/README.md].
|
Restconf support is also supported, see (restc)[../apps/restconf/README.md].
|
||||||
|
|
||||||
## Initializing a plugin
|
|
||||||
|
## RPC Operations
|
||||||
|
|
||||||
|
Clixon implements Yang RPC operations by an extension mechanism. The
|
||||||
|
extension mechanism enables you to add application-specific
|
||||||
|
operations. It works by adding user-defined callbacks for added
|
||||||
|
netconf operations. It is possible to use the extension mechanism
|
||||||
|
independent of the yang rpc construct, but it is recommended. The example includes an example:
|
||||||
|
|
||||||
|
Example using CLI:
|
||||||
|
```
|
||||||
|
cli> rpc ipv4
|
||||||
|
rpc-reply {
|
||||||
|
route {
|
||||||
|
address-family ipv4;
|
||||||
|
next-hop {
|
||||||
|
next-hop-list 2.3.4.5;
|
||||||
|
}
|
||||||
|
source-protocol static;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Netconf:
|
||||||
|
```
|
||||||
|
<rpc><fib-route xmlns="urn:ietf:params:xml:ns:yang:ietf-routing"><routing-instance-name>ipv4</routing-instance-name></fib-route></rpc>]]>]]>
|
||||||
|
<rpc-reply><route xmlns="urn:ietf:params:xml:ns:yang:ietf-routing"><address-family>ipv4</address-family><next-hop><next-hop-list>2.3.4.5</next-hop-list></next-hop><source-protocol>static</source-protocol></route></rpc-reply>]]>]]>
|
||||||
|
```
|
||||||
|
Restconf:
|
||||||
|
```
|
||||||
|
curl -X POST http://localhost/restconf/operations/ietf-routing:fib-route -d '{"ietf-routing:input":{"routing-instance-name":"ipv4"}}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Details
|
||||||
|
|
||||||
|
The example works by creating a netconf rpc call and sending it to the backend: (see the fib_route_rpc() function in [example_cli.c](example_cli.c)).
|
||||||
|
|
||||||
|
In the (example_backend.c)[example_backend.c], a callback is registered (fib_route()) which handles the RPC (this is just dummy data):
|
||||||
|
```
|
||||||
|
static int
|
||||||
|
fib_route(clicon_handle h,
|
||||||
|
cxobj *xe, /* Request: <rpc><xn></rpc> */
|
||||||
|
cbuf *cbret, /* Reply eg <rpc-reply>... */
|
||||||
|
void *arg, /* Client session */
|
||||||
|
void *regarg) /* Argument given at register */
|
||||||
|
{
|
||||||
|
cprintf(cbret, "<rpc-reply><route xmlns=\"urn:ietf:params:xml:ns:yang:ietf-routing\">"
|
||||||
|
"<address-family>ipv4</address-family>"
|
||||||
|
"<next-hop><next-hop-list>2.3.4.5</next-hop-list></next-hop>"
|
||||||
|
"<source-protocol>static</source-protocol>"
|
||||||
|
"</route></rpc-reply>");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int
|
||||||
|
clixon_plugin_init(clicon_handle h)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
rpc_callback_register(h, fib_route, NULL, "fib-route");
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## State data
|
||||||
|
|
||||||
|
Netconf <get> and restconf GET also returns state data(not only configuration data).
|
||||||
|
|
||||||
|
In YANG state data is specified with `config false;`. In the example,
|
||||||
|
`state` is state data, see (example.yang)[example.yang]
|
||||||
|
|
||||||
|
To return state data, you need to write a backend state data callback
|
||||||
|
with the name "plugin_statedata" where you return an XML tree with
|
||||||
|
state. This is then merged with config data by the system.
|
||||||
|
|
||||||
|
A static example of returning state data is in the example. Note that
|
||||||
|
a real example would poll or get the interface counters via a system
|
||||||
|
call, as well as use the "xpath" argument to identify the requested
|
||||||
|
state data.
|
||||||
|
|
||||||
|
## Authentication and NACM
|
||||||
|
The example contains some stubs for authorization according to [RFC8341(NACM)](https://tools.ietf.org/html/rfc8341):
|
||||||
|
* A basic auth HTTP callback, see: example_restconf_credentials() containing three example users: andy, wilma, and guest, according to the examples in Appendix A in [RFC8341](https://tools.ietf.org/html/rfc8341).
|
||||||
|
* A NACM backend plugin reporting the mandatory NACM state variables.
|
||||||
|
|
||||||
|
## Systemd
|
||||||
|
|
||||||
|
Example systemd files for backend and restconf daemons are found under the systemd directory. Install them under /etc/systemd/system for example.
|
||||||
|
|
||||||
|
## Docker
|
||||||
|
|
||||||
|
Run the example as a docker container and access it from a host CLI as follows:
|
||||||
|
```
|
||||||
|
ID=$(sudo docker run -td olofhagsand/clixon_example)
|
||||||
|
IP=$(sudo docker inspect -f '{{.NetworkSettings.IPAddress }}' $ID)
|
||||||
|
clixon_cli -a IPv4 -u $IP -f ./example.xml
|
||||||
|
```
|
||||||
|
|
||||||
|
Build the container and push yourself: First change the IMAGE variable in Makefile (eg to "you/clixon_example). Then build and push:
|
||||||
|
```
|
||||||
|
make docker
|
||||||
|
make push
|
||||||
|
sudo docker run -ti --rm you/clixon_example
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that the configuration database is internal in the container, so
|
||||||
|
it is deleted if the container is restarted. To make the configuration
|
||||||
|
database persistent, you need to mount running_db using `-v`
|
||||||
|
|
||||||
|
## Plugins
|
||||||
|
|
||||||
The example includes a restonf, netconf, CLI and two backend plugins.
|
The example includes a restonf, netconf, CLI and two backend plugins.
|
||||||
Each plugin is initiated with an API struct followed by a plugin init function.
|
Each plugin is initiated with an API struct followed by a plugin init function.
|
||||||
|
|
@ -127,96 +279,3 @@ clixon_plugin_init(clicon_handle h)
|
||||||
return &api; /* Return NULL on error */
|
return &api; /* Return NULL on error */
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Operation data
|
|
||||||
|
|
||||||
Clixon implements Yang RPC operations by an extension mechanism. The
|
|
||||||
extension mechanism enables you to add application-specific
|
|
||||||
operations. It works by adding user-defined callbacks for added
|
|
||||||
netconf operations. It is possible to use the extension mechanism
|
|
||||||
independent of the yang rpc construct, but it is recommended. The example includes an example:
|
|
||||||
|
|
||||||
Example:
|
|
||||||
```
|
|
||||||
cli> rpc ipv4
|
|
||||||
<rpc-reply>
|
|
||||||
<ok/>
|
|
||||||
</rpc-reply>
|
|
||||||
```
|
|
||||||
|
|
||||||
The example works by creating a netconf rpc call and sending it to the backend: (see the fib_route_rpc() function).
|
|
||||||
```
|
|
||||||
<rpc>
|
|
||||||
<fib-route>
|
|
||||||
<routing-instance-name>ipv4</routing-instance-name>
|
|
||||||
</fib-route>
|
|
||||||
</rpc>
|
|
||||||
```
|
|
||||||
|
|
||||||
In the backend, a callback is registered (fib_route()) which handles the RPC.
|
|
||||||
```
|
|
||||||
static int
|
|
||||||
fib_route(clicon_handle h,
|
|
||||||
cxobj *xe, /* Request: <rpc><xn></rpc> */
|
|
||||||
cbuf *cbret, /* Reply eg <rpc-reply>... */
|
|
||||||
void *arg, /* Client session */
|
|
||||||
void *regarg) /* Argument given at register */
|
|
||||||
{
|
|
||||||
cprintf(cbret, "<rpc-reply><ok/></rpc-reply>");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
int
|
|
||||||
clixon_plugin_init(clicon_handle h)
|
|
||||||
{
|
|
||||||
...
|
|
||||||
rpc_callback_register(h, fib_route, NULL, "fib-route");
|
|
||||||
...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
## State data
|
|
||||||
|
|
||||||
Netconf <get> and restconf GET also returns state data, in contrast to
|
|
||||||
config data.
|
|
||||||
p
|
|
||||||
In YANG state data is specified with "config false;". In the example, interface-state is state data.
|
|
||||||
|
|
||||||
To return state data, you need to write a backend state data callback
|
|
||||||
with the name "plugin_statedata" where you return an XML tree with
|
|
||||||
state. This is then merged with config data by the system.
|
|
||||||
|
|
||||||
A static example of returning state data is in the example. Note that
|
|
||||||
a real example would poll or get the interface counters via a system
|
|
||||||
call, as well as use the "xpath" argument to identify the requested
|
|
||||||
state data.
|
|
||||||
|
|
||||||
## Authentication and NACM
|
|
||||||
The example contains some stubs for authorization according to [RFC8341(NACM)](https://tools.ietf.org/html/rfc8341):
|
|
||||||
* A basic auth HTTP callback, see: example_restconf_credentials() containing three example users: andy, wilma, and guest, according to the examples in Appendix A in [RFC8341](https://tools.ietf.org/html/rfc8341).
|
|
||||||
* A NACM backend plugin reporting the mandatory NACM state variables.
|
|
||||||
|
|
||||||
## Systemd files
|
|
||||||
|
|
||||||
Example systemd files for backend and restconf daemons are found under the systemd directory. Install them under /etc/systemd/system for example.
|
|
||||||
|
|
||||||
## Docker
|
|
||||||
|
|
||||||
Run the example as a docker container and access it from a host CLI as follows:
|
|
||||||
```
|
|
||||||
ID=$(sudo docker run -td olofhagsand/clixon_example)
|
|
||||||
IP=$(sudo docker inspect -f '{{.NetworkSettings.IPAddress }}' $ID)
|
|
||||||
clixon_cli -a IPv4 -u $IP -f ./example.xml
|
|
||||||
```
|
|
||||||
|
|
||||||
Build the container and push yourself: First change the IMAGE variable in Makefile (eg to "you/clixon_example). Then build and push:
|
|
||||||
```
|
|
||||||
make docker
|
|
||||||
make push
|
|
||||||
sudo docker run -ti --rm you/clixon_example
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that the configuration database is internal in the container, so
|
|
||||||
it is deleted if the container is restarted. To make the configuration
|
|
||||||
database persistent, you need to mount running_db using `-v`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ example_stream_timer(int fd,
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
clicon_handle h = (clicon_handle)arg;
|
clicon_handle h = (clicon_handle)arg;
|
||||||
|
|
||||||
/* XXX Change to actual netconf notifications */
|
/* XXX Change to actual netconf notifications and namespace */
|
||||||
if (stream_notify(h, "EXAMPLE", "<event><event-class>fault</event-class><reportingEntity><card>Ethernet0</card></reportingEntity><severity>major</severity></event>") < 0)
|
if (stream_notify(h, "EXAMPLE", "<event><event-class>fault</event-class><reportingEntity><card>Ethernet0</card></reportingEntity><severity>major</severity></event>") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (example_stream_timer_setup(h) < 0)
|
if (example_stream_timer_setup(h) < 0)
|
||||||
|
|
@ -129,7 +129,7 @@ fib_route(clicon_handle h, /* Clicon handle */
|
||||||
void *arg, /* Client session */
|
void *arg, /* Client session */
|
||||||
void *regarg) /* Argument given at register */
|
void *regarg) /* Argument given at register */
|
||||||
{
|
{
|
||||||
cprintf(cbret, "<rpc-reply><route>"
|
cprintf(cbret, "<rpc-reply><route xmlns=\"urn:ietf:params:xml:ns:yang:ietf-routing\">"
|
||||||
"<address-family>ipv4</address-family>"
|
"<address-family>ipv4</address-family>"
|
||||||
"<next-hop><next-hop-list>2.3.4.5</next-hop-list></next-hop>"
|
"<next-hop><next-hop-list>2.3.4.5</next-hop-list></next-hop>"
|
||||||
"<source-protocol>static</source-protocol>"
|
"<source-protocol>static</source-protocol>"
|
||||||
|
|
@ -147,7 +147,7 @@ route_count(clicon_handle h,
|
||||||
void *arg,
|
void *arg,
|
||||||
void *regarg) /* Argument given at register */
|
void *regarg) /* Argument given at register */
|
||||||
{
|
{
|
||||||
cprintf(cbret, "<rpc-reply><number-of-routes>42</number-of-routes></rpc-reply>");
|
cprintf(cbret, "<rpc-reply><number-of-routes xmlns=\"urn:ietf:params:xml:ns:yang:ietf-routing\">42</number-of-routes></rpc-reply>");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -180,9 +180,17 @@ example_rpc(clicon_handle h, /* Clicon handle */
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *x = NULL;
|
cxobj *x = NULL;
|
||||||
|
char *namespace;
|
||||||
|
|
||||||
|
/* get namespace from rpc name, return back in each output parameter */
|
||||||
|
if ((namespace = xml_find_type_value(xe, NULL, "xmlns", CX_ATTR)) == NULL){
|
||||||
|
clicon_err(OE_XML, ENOENT, "No namespace given in rpc %s", xml_name(xe));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
cprintf(cbret, "<rpc-reply>");
|
cprintf(cbret, "<rpc-reply>");
|
||||||
while ((x = xml_child_each(xe, x, CX_ELMNT)) != NULL) {
|
while ((x = xml_child_each(xe, x, CX_ELMNT)) != NULL) {
|
||||||
|
if (xmlns_set(x, NULL, namespace) < 0)
|
||||||
|
goto done;
|
||||||
if (clicon_xml2cbuf(cbret, x, 0, 0) < 0)
|
if (clicon_xml2cbuf(cbret, x, 0, 0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -222,7 +230,7 @@ example_statedata(clicon_handle h,
|
||||||
* Note this state needs to be accomanied by yang snippet
|
* Note this state needs to be accomanied by yang snippet
|
||||||
* above
|
* above
|
||||||
*/
|
*/
|
||||||
if (xml_parse_string("<state>"
|
if (xml_parse_string("<state xmlns=\"urn:example:clixon\">"
|
||||||
"<op>42</op>"
|
"<op>42</op>"
|
||||||
"</state>", NULL, &xstate) < 0)
|
"</state>", NULL, &xstate) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -251,17 +259,22 @@ example_reset(clicon_handle h,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *xt = NULL;
|
cxobj *xt = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (xml_parse_string("<config><interfaces><interface>"
|
if (xml_parse_string("<config><interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\"><interface>"
|
||||||
"<name>lo</name><type>ex:loopback</type>"
|
"<name>lo</name><type>ex:loopback</type>"
|
||||||
"</interface></interfaces></config>", NULL, &xt) < 0)
|
"</interface></interfaces></config>", NULL, &xt) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Replace parent w fiorst child */
|
/* Replace parent w first child */
|
||||||
if (xml_rootchild(xt, 0, &xt) < 0)
|
if (xml_rootchild(xt, 0, &xt) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Merge user reset state */
|
/* Merge user reset state */
|
||||||
if (xmldb_put(h, (char*)db, OP_MERGE, xt, NULL) < 0)
|
if ((ret = xmldb_put(h, (char*)db, OP_MERGE, xt, NULL)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
if (ret == 0){
|
||||||
|
clicon_err(OE_XML, 0, "Error when writing to XML database");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (xt != NULL)
|
if (xt != NULL)
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ fib_route_rpc(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Print result */
|
/* Print result */
|
||||||
xml_print(stdout, xml_child_i(xret, 0));
|
xml2txt(stdout, xml_child_i(xret, 0), 1);
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (xret)
|
if (xret)
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ debug("Debugging parts of the system"), cli_debug_cli((int32)1);{
|
||||||
}
|
}
|
||||||
copy("Copy and create a new object") {
|
copy("Copy and create a new object") {
|
||||||
interface("Copy interface"){
|
interface("Copy interface"){
|
||||||
<name:string expand_dbvar("candidate","/interfaces/interface=%s/name")>("name of interface to copy from") to("Copy to interface") <toname:string>("Name of interface to copy to"), cli_copy_config("candidate","//interface[%s='%s']","name","name","toname");
|
<name:string expand_dbvar("candidate","/ietf-interfaces:interfaces/interface=%s/name")>("name of interface to copy from") to("Copy to interface") <toname:string>("Name of interface to copy to"), cli_copy_config("candidate","//interface[%s='%s']","name","name","toname");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
discard("Discard edits (rollback 0)"), discard_changes();
|
discard("Discard edits (rollback 0)"), discard_changes();
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ int netconf_client_rpc(clicon_handle h,
|
||||||
void *regarg)
|
void *regarg)
|
||||||
{
|
{
|
||||||
clicon_debug(1, "%s restconf", __FUNCTION__);
|
clicon_debug(1, "%s restconf", __FUNCTION__);
|
||||||
cprintf(cbret, "<rpc-reply><result>ok</result></rpc-reply>");
|
cprintf(cbret, "<rpc-reply><result xmlns=\"urn:example:clixon\">ok</result></rpc-reply>");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -275,7 +275,7 @@ restconf_client_rpc(clicon_handle h,
|
||||||
{
|
{
|
||||||
// FCGX_Request *r = (FCGX_Request *)arg;
|
// FCGX_Request *r = (FCGX_Request *)arg;
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
cprintf(cbret, "<rpc-reply><result>ok</result></rpc-reply>");
|
cprintf(cbret, "<rpc-reply><result xmlns=\"urn:example:clixon\">ok</result></rpc-reply>");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,11 +51,6 @@ int strverscmp (__const char *__s1, __const char *__s2);
|
||||||
*/
|
*/
|
||||||
#define XMLNS_YANG_ONLY 1
|
#define XMLNS_YANG_ONLY 1
|
||||||
|
|
||||||
/* Set for full XML namespace code in XML, NETCONF and YANG
|
|
||||||
* Experimental
|
|
||||||
*/
|
|
||||||
#undef ENABLE_XMLNS
|
|
||||||
|
|
||||||
/* If set, patch all CLI spec calls to @datamodel:tree to @datamodel.
|
/* If set, patch all CLI spec calls to @datamodel:tree to @datamodel.
|
||||||
* This is a backward compatible fix for 3.9 for CLIgen specification files
|
* This is a backward compatible fix for 3.9 for CLIgen specification files
|
||||||
* using model generation (CLIXON_CLI_GENMODEL).
|
* using model generation (CLIXON_CLI_GENMODEL).
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ int xml2json_cbuf(cbuf *cb, cxobj *x, int pretty);
|
||||||
int xml2json_cbuf_vec(cbuf *cb, cxobj **vec, size_t veclen, int pretty);
|
int xml2json_cbuf_vec(cbuf *cb, cxobj **vec, size_t veclen, int pretty);
|
||||||
int xml2json(FILE *f, cxobj *x, int pretty);
|
int xml2json(FILE *f, cxobj *x, int pretty);
|
||||||
int xml2json_vec(FILE *f, cxobj **vec, size_t veclen, int pretty);
|
int xml2json_vec(FILE *f, cxobj **vec, size_t veclen, int pretty);
|
||||||
|
int json2xml_ns(yang_spec *yspec, cxobj *x, cxobj **xerr);
|
||||||
int json_parse_str(char *str, cxobj **xt);
|
int json_parse_str(char *str, cxobj **xt);
|
||||||
int json_parse_file(int fd, yang_spec *yspec, cxobj **xt);
|
int json_parse_file(int fd, yang_spec *yspec, cxobj **xt);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,8 @@ int netconf_bad_element(cbuf *cb, char *type, char *info, char *element);
|
||||||
int netconf_bad_element_xml(cxobj **xret, char *type, char *info, char *element);
|
int netconf_bad_element_xml(cxobj **xret, char *type, char *info, char *element);
|
||||||
int netconf_unknown_element(cbuf *cb, char *type, char *element, char *message);
|
int netconf_unknown_element(cbuf *cb, char *type, char *element, char *message);
|
||||||
int netconf_unknown_element_xml(cxobj **xret, char *type, char *element, char *message);
|
int netconf_unknown_element_xml(cxobj **xret, char *type, char *element, char *message);
|
||||||
int netconf_unknown_namespace(cbuf *cb, char *type, char *info, char *message);
|
int netconf_unknown_namespace(cbuf *cb, char *type, char *namespace, char *message);
|
||||||
|
int netconf_unknown_namespace_xml(cxobj **xret, char *type, char *namespace, char *message);
|
||||||
int netconf_access_denied(cbuf *cb, char *type, char *message);
|
int netconf_access_denied(cbuf *cb, char *type, char *message);
|
||||||
int netconf_access_denied_xml(cxobj **xret, char *type, char *message);
|
int netconf_access_denied_xml(cxobj **xret, char *type, char *message);
|
||||||
int netconf_lock_denied(cbuf *cb, char *info, char *message);
|
int netconf_lock_denied(cbuf *cb, char *info, char *message);
|
||||||
|
|
|
||||||
|
|
@ -153,6 +153,9 @@ static inline char *clicon_xmldb_dir(clicon_handle h){
|
||||||
static inline char *clicon_xmldb_plugin(clicon_handle h){
|
static inline char *clicon_xmldb_plugin(clicon_handle h){
|
||||||
return clicon_option_str(h, "CLICON_XMLDB_PLUGIN");
|
return clicon_option_str(h, "CLICON_XMLDB_PLUGIN");
|
||||||
}
|
}
|
||||||
|
static inline int clicon_xml_sort(clicon_handle h){
|
||||||
|
return clicon_option_bool(h, "CLICON_XML_SORT");
|
||||||
|
}
|
||||||
|
|
||||||
/*-- Specific option access functions for YANG options w type conversion--*/
|
/*-- Specific option access functions for YANG options w type conversion--*/
|
||||||
int clicon_cli_genmodel(clicon_handle h);
|
int clicon_cli_genmodel(clicon_handle h);
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ int xml_chardata_encode(char **escp, char *fmt, ...);
|
||||||
int uri_percent_decode(char *enc, char **str);
|
int uri_percent_decode(char *enc, char **str);
|
||||||
const char *clicon_int2str(const map_str2int *mstab, int i);
|
const char *clicon_int2str(const map_str2int *mstab, int i);
|
||||||
int clicon_str2int(const map_str2int *mstab, char *str);
|
int clicon_str2int(const map_str2int *mstab, char *str);
|
||||||
|
int nodeid_split(char *nodeid, char **prefix, char **id);
|
||||||
#ifndef HAVE_STRNDUP
|
#ifndef HAVE_STRNDUP
|
||||||
char *clicon_strndup (const char *, size_t);
|
char *clicon_strndup (const char *, size_t);
|
||||||
#endif /* ! HAVE_STRNDUP */
|
#endif /* ! HAVE_STRNDUP */
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,8 @@
|
||||||
* namespace (rfc6241 3.1)
|
* namespace (rfc6241 3.1)
|
||||||
*/
|
*/
|
||||||
#define DEFAULT_XML_RPC_NAMESPACE "urn:ietf:params:xml:ns:netconf:base:1.0"
|
#define DEFAULT_XML_RPC_NAMESPACE "urn:ietf:params:xml:ns:netconf:base:1.0"
|
||||||
|
/* default namespace statement, such as in <rpc xmlns="..."> */
|
||||||
|
#define DEFAULT_XMLNS "xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\""
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Types
|
* Types
|
||||||
|
|
@ -84,14 +86,13 @@ typedef int (xml_applyfn_t)(cxobj *x, void *arg);
|
||||||
#define XML_FLAG_CHANGE 0x08 /* Node is changed (commits) or child changed rec */
|
#define XML_FLAG_CHANGE 0x08 /* Node is changed (commits) or child changed rec */
|
||||||
#define XML_FLAG_NONE 0x10 /* Node is added as NONE */
|
#define XML_FLAG_NONE 0x10 /* Node is added as NONE */
|
||||||
|
|
||||||
|
|
||||||
/* Iterate through modules to find the matching datanode
|
/* Iterate through modules to find the matching datanode
|
||||||
* or rpc if no xmlns attribute specifies namespace.
|
* or rpc if no xmlns attribute specifies namespace.
|
||||||
* This is loose semantics of finding namespaces.
|
* This is lazy non-strict semantics of finding namespaces.
|
||||||
* And it is wrong, but is the way Clixon originally was written."
|
* And it is wrong, but is the way Clixon originally was written."
|
||||||
* @see CLICON_XML_NS_ITERATE clixon configure option
|
* @see CLICON_XML_NS_STRICT clixon configure option
|
||||||
*/
|
*/
|
||||||
extern int _CLICON_XML_NS_ITERATE;
|
extern int _CLICON_XML_NS_STRICT;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prototypes
|
* Prototypes
|
||||||
|
|
@ -102,6 +103,7 @@ int xml_name_set(cxobj *xn, char *name);
|
||||||
char *xml_prefix(cxobj *xn);
|
char *xml_prefix(cxobj *xn);
|
||||||
int xml_prefix_set(cxobj *xn, char *name);
|
int xml_prefix_set(cxobj *xn, char *name);
|
||||||
int xml2ns(cxobj *x, char *localname, char **namespace);
|
int xml2ns(cxobj *x, char *localname, char **namespace);
|
||||||
|
int xmlns_set(cxobj *x, char *prefix, char *namespace);
|
||||||
cxobj *xml_parent(cxobj *xn);
|
cxobj *xml_parent(cxobj *xn);
|
||||||
int xml_parent_set(cxobj *xn, cxobj *parent);
|
int xml_parent_set(cxobj *xn, cxobj *parent);
|
||||||
|
|
||||||
|
|
@ -117,7 +119,9 @@ int xml_type_set(cxobj *xn, enum cxobj_type type);
|
||||||
|
|
||||||
int xml_child_nr(cxobj *xn);
|
int xml_child_nr(cxobj *xn);
|
||||||
int xml_child_nr_type(cxobj *xn, enum cxobj_type type);
|
int xml_child_nr_type(cxobj *xn, enum cxobj_type type);
|
||||||
|
int xml_child_nr_notype(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_type(cxobj *xn, int i, enum cxobj_type type);
|
||||||
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);
|
||||||
|
|
||||||
|
|
@ -139,6 +143,7 @@ char *xml_body(cxobj *xn);
|
||||||
cxobj *xml_body_get(cxobj *xn);
|
cxobj *xml_body_get(cxobj *xn);
|
||||||
char *xml_find_type_value(cxobj *xn_parent, char *prefix,
|
char *xml_find_type_value(cxobj *xn_parent, char *prefix,
|
||||||
char *name, enum cxobj_type type);
|
char *name, enum cxobj_type type);
|
||||||
|
cxobj *xml_find_type(cxobj *xn_parent, char *prefix, char *name, enum cxobj_type type);
|
||||||
char *xml_find_value(cxobj *xn_parent, char *name);
|
char *xml_find_value(cxobj *xn_parent, char *name);
|
||||||
char *xml_find_body(cxobj *xn, char *name);
|
char *xml_find_body(cxobj *xn, char *name);
|
||||||
cxobj *xml_find_body_obj(cxobj *xt, char *name, char *val);
|
cxobj *xml_find_body_obj(cxobj *xt, char *name, char *val);
|
||||||
|
|
|
||||||
|
|
@ -43,10 +43,13 @@
|
||||||
*/
|
*/
|
||||||
int xml2txt(FILE *f, cxobj *x, int level);
|
int xml2txt(FILE *f, cxobj *x, int level);
|
||||||
int xml2cli(FILE *f, cxobj *x, char *prepend, enum genmodel_type gt);
|
int xml2cli(FILE *f, cxobj *x, char *prepend, enum genmodel_type gt);
|
||||||
|
int xml_yang_root(cxobj *x, cxobj **xr);
|
||||||
|
int xmlns_assign(cxobj *x);
|
||||||
int xml_yang_validate_rpc(cxobj *xrpc, cbuf *cbret);
|
int xml_yang_validate_rpc(cxobj *xrpc, cbuf *cbret);
|
||||||
int xml_yang_validate_add(cxobj *xt, cbuf *cbret);
|
int xml_yang_validate_add(cxobj *xt, cbuf *cbret);
|
||||||
int xml_yang_validate_all(cxobj *xt, cbuf *cbret);
|
int xml_yang_validate_all(cxobj *xt, cbuf *cbret);
|
||||||
int xml_yang_validate_all_top(cxobj *xt, cbuf *cbret);
|
int xml_yang_validate_all_top(cxobj *xt, cbuf *cbret);
|
||||||
|
int xml_yang_find_non_strict(cxobj *x, yang_spec *yspec, yang_stmt **y);
|
||||||
int xml2cvec(cxobj *xt, yang_stmt *ys, cvec **cvv0);
|
int xml2cvec(cxobj *xt, yang_stmt *ys, cvec **cvv0);
|
||||||
int cvec2xml_1(cvec *cvv, char *toptag, cxobj *xp, cxobj **xt0);
|
int cvec2xml_1(cvec *cvv, char *toptag, cxobj *xp, cxobj **xt0);
|
||||||
int xml_diff(yang_spec *yspec, cxobj *xt1, cxobj *xt2,
|
int xml_diff(yang_spec *yspec, cxobj *xt1, cxobj *xt2,
|
||||||
|
|
@ -64,8 +67,7 @@ int xml_sanity(cxobj *x, void *arg);
|
||||||
int xml_non_config_data(cxobj *xt, void *arg);
|
int xml_non_config_data(cxobj *xt, void *arg);
|
||||||
int xml_spec_populate_rpc(clicon_handle h, cxobj *x, yang_spec *yspec);
|
int xml_spec_populate_rpc(clicon_handle h, cxobj *x, yang_spec *yspec);
|
||||||
int xml_spec_populate(cxobj *x, void *arg);
|
int xml_spec_populate(cxobj *x, void *arg);
|
||||||
int api_path2xpath_cvv(yang_spec *yspec, cvec *cvv, int offset, cbuf *xpath);
|
int api_path2xpath(yang_spec *yspec, cvec *cvv, int offset, cbuf *xpath);
|
||||||
int api_path2xpath(yang_spec *yspec, char *api_path, cbuf *xpath);
|
|
||||||
int api_path2xml(char *api_path, yang_spec *yspec, cxobj *xtop,
|
int api_path2xml(char *api_path, yang_spec *yspec, cxobj *xtop,
|
||||||
yang_class nodeclass, cxobj **xpathp, yang_node **ypathp);
|
yang_class nodeclass, cxobj **xpathp, yang_node **ypathp);
|
||||||
int xml_merge(cxobj *x0, cxobj *x1, yang_spec *yspec, char **reason);
|
int xml_merge(cxobj *x0, cxobj *x1, yang_spec *yspec, char **reason);
|
||||||
|
|
|
||||||
|
|
@ -37,14 +37,16 @@
|
||||||
#define _CLIXON_XML_SORT_H
|
#define _CLIXON_XML_SORT_H
|
||||||
|
|
||||||
/* Sort and binary search of XML children
|
/* Sort and binary search of XML children
|
||||||
* Experimental
|
* XXX This variable is a kludge since low-level functions xml_merge/xml_diff calls
|
||||||
|
* match_base_child without handle
|
||||||
|
* @see clicon_xml_sort
|
||||||
*/
|
*/
|
||||||
extern int xml_child_sort;
|
extern int xml_child_sort;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prototypes
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
int xml_child_spec(char *name, cxobj *xp, yang_spec *yspec, yang_stmt **yp);
|
int xml_child_spec(cxobj *x, cxobj *xp, yang_spec *yspec, yang_stmt **yp);
|
||||||
int xml_cmp(const void* arg1, const void* arg2);
|
int xml_cmp(const void* arg1, const void* arg2);
|
||||||
int xml_sort(cxobj *x0, void *arg);
|
int xml_sort(cxobj *x0, void *arg);
|
||||||
cxobj *xml_search(cxobj *x, char *name, int yangi, enum rfc_6020 keyword, int keynr, char **keyvec, char **keyval);
|
cxobj *xml_search(cxobj *x, char *name, int yangi, enum rfc_6020 keyword, int keynr, char **keyvec, char **keyval);
|
||||||
|
|
@ -53,6 +55,6 @@ int xml_insert_pos(cxobj *x0, char *name, int yangi, enum rfc_6020 keyword,
|
||||||
int upper);
|
int upper);
|
||||||
cxobj *xml_match(cxobj *x0, char *name, enum rfc_6020 keyword, int keynr, char **keyvec, char **keyval);
|
cxobj *xml_match(cxobj *x0, char *name, enum rfc_6020 keyword, int keynr, char **keyvec, char **keyval);
|
||||||
int xml_sort_verify(cxobj *x, void *arg);
|
int xml_sort_verify(cxobj *x, void *arg);
|
||||||
int match_base_child(cxobj *x0, cxobj *x1c, cxobj **x0cp, yang_stmt *yc);
|
int match_base_child(cxobj *x0, cxobj *x1c, cxobj **x0cp, int xml_sort, yang_stmt *yc);
|
||||||
|
|
||||||
#endif /* _CLIXON_XML_SORT_H */
|
#endif /* _CLIXON_XML_SORT_H */
|
||||||
|
|
|
||||||
|
|
@ -252,17 +252,16 @@ yang_stmt *yn_each(yang_node *yn, yang_stmt *ys);
|
||||||
char *yang_key2str(int keyword);
|
char *yang_key2str(int keyword);
|
||||||
char *yarg_prefix(yang_stmt *ys);
|
char *yarg_prefix(yang_stmt *ys);
|
||||||
char *yarg_id(yang_stmt *ys);
|
char *yarg_id(yang_stmt *ys);
|
||||||
int yang_nodeid_split(char *nodeid, char **prefix, char **id);
|
|
||||||
int ys_module_by_xml(yang_spec *ysp, struct xml *xt, yang_stmt **ymodp);
|
int ys_module_by_xml(yang_spec *ysp, struct xml *xt, yang_stmt **ymodp);
|
||||||
yang_stmt *ys_module(yang_stmt *ys);
|
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_module_by_namespace(yang_spec *yspec, char *namespace);
|
yang_stmt *yang_find_module_by_namespace(yang_spec *yspec, char *namespace);
|
||||||
|
yang_stmt *yang_find_module_by_name(yang_spec *yspec, char *name);
|
||||||
yang_stmt *yang_find(yang_node *yn, int keyword, const char *argument);
|
yang_stmt *yang_find(yang_node *yn, int keyword, const char *argument);
|
||||||
int yang_match(yang_node *yn, int keyword, char *argument);
|
int yang_match(yang_node *yn, int keyword, char *argument);
|
||||||
yang_stmt *yang_find_datanode(yang_node *yn, char *argument);
|
yang_stmt *yang_find_datanode(yang_node *yn, char *argument);
|
||||||
yang_stmt *yang_find_schemanode(yang_node *yn, char *argument);
|
yang_stmt *yang_find_schemanode(yang_node *yn, char *argument);
|
||||||
yang_stmt *yang_find_topnode(yang_spec *ysp, char *name, yang_class class);
|
|
||||||
char *yang_find_myprefix(yang_stmt *ys);
|
char *yang_find_myprefix(yang_stmt *ys);
|
||||||
char *yang_find_mynamespace(yang_stmt *ys);
|
char *yang_find_mynamespace(yang_stmt *ys);
|
||||||
int yang_order(yang_stmt *y);
|
int yang_order(yang_stmt *y);
|
||||||
|
|
|
||||||
|
|
@ -140,6 +140,7 @@ clicon_err_reset(void)
|
||||||
* @param[in] err Error number, typically errno
|
* @param[in] err Error number, typically errno
|
||||||
* @param[in] suberr Sub-error number
|
* @param[in] suberr Sub-error number
|
||||||
* @param[in] reason Error string, format with argv
|
* @param[in] reason Error string, format with argv
|
||||||
|
* @see clicon_err_reser Resetting the global error variables.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clicon_err_fn(const char *fn,
|
clicon_err_fn(const char *fn,
|
||||||
|
|
|
||||||
|
|
@ -55,10 +55,12 @@
|
||||||
#include "clixon_err.h"
|
#include "clixon_err.h"
|
||||||
#include "clixon_log.h"
|
#include "clixon_log.h"
|
||||||
#include "clixon_queue.h"
|
#include "clixon_queue.h"
|
||||||
|
#include "clixon_string.h"
|
||||||
#include "clixon_hash.h"
|
#include "clixon_hash.h"
|
||||||
#include "clixon_handle.h"
|
#include "clixon_handle.h"
|
||||||
#include "clixon_yang.h"
|
#include "clixon_yang.h"
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
|
#include "clixon_netconf_lib.h"
|
||||||
#include "clixon_json.h"
|
#include "clixon_json.h"
|
||||||
#include "clixon_json_parse.h"
|
#include "clixon_json_parse.h"
|
||||||
|
|
||||||
|
|
@ -90,43 +92,31 @@ enum childtype{
|
||||||
ANY_CHILD, /* eg <a><b/></a> or <a><b/><c/></a> */
|
ANY_CHILD, /* eg <a><b/></a> or <a><b/><c/></a> */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*! Number of children EXCEPT attributes
|
|
||||||
* @param[in] xn xml node
|
|
||||||
* @retval number of children in XML tree (except children of type CX_ATTR)
|
|
||||||
* @see xml_child_nr
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
xml_child_nr_noattr(cxobj *xn)
|
|
||||||
{
|
|
||||||
cxobj *x = NULL;
|
|
||||||
int nr = 0;
|
|
||||||
|
|
||||||
while ((x = xml_child_each(xn, x, -1)) != NULL) {
|
|
||||||
if (xml_type(x) != CX_ATTR)
|
|
||||||
nr++;
|
|
||||||
}
|
|
||||||
return nr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! x is element and has exactly one child which in turn has none
|
/*! x is element and has exactly one child which in turn has none
|
||||||
* remove attributes from x
|
* remove attributes from x
|
||||||
* Clone from clixon_xml_map.c
|
* Clone from clixon_xml_map.c
|
||||||
*/
|
*/
|
||||||
static enum childtype
|
static enum childtype
|
||||||
childtype(cxobj *x)
|
child_type(cxobj *x)
|
||||||
{
|
{
|
||||||
cxobj *xc1; /* the only child of x */
|
cxobj *xc; /* the only child of x */
|
||||||
int clen; /* nr of children */
|
int clen; /* nr of children */
|
||||||
|
|
||||||
clen = xml_child_nr_noattr(x);
|
clen = xml_child_nr_notype(x, CX_ATTR);
|
||||||
if (xml_type(x) != CX_ELMNT)
|
if (xml_type(x) != CX_ELMNT)
|
||||||
return -1; /* n/a */
|
return -1; /* n/a */
|
||||||
if (clen == 0)
|
if (clen == 0)
|
||||||
return NULL_CHILD;
|
return NULL_CHILD;
|
||||||
if (clen > 1)
|
if (clen > 1)
|
||||||
return ANY_CHILD;
|
return ANY_CHILD;
|
||||||
xc1 = xml_child_i(x, 0); /* From here exactly one child */
|
/* From here exactly one noattr child, get it */
|
||||||
if (xml_child_nr_noattr(xc1) == 0 && xml_type(xc1)==CX_BODY)
|
xc = NULL;
|
||||||
|
while ((xc = xml_child_each(x, xc, -1)) != NULL)
|
||||||
|
if (xml_type(xc) != CX_ATTR)
|
||||||
|
break;
|
||||||
|
if (xc == NULL)
|
||||||
|
return -2; /* n/a */
|
||||||
|
if (xml_child_nr_notype(xc, CX_ATTR) == 0 && xml_type(xc)==CX_BODY)
|
||||||
return BODY_CHILD;
|
return BODY_CHILD;
|
||||||
else
|
else
|
||||||
return ANY_CHILD;
|
return ANY_CHILD;
|
||||||
|
|
@ -175,6 +165,9 @@ arraytype2str(enum array_element_type lt)
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Check typeof x in array
|
||||||
|
* Some complexity when x is in different namespaces
|
||||||
|
*/
|
||||||
static enum array_element_type
|
static enum array_element_type
|
||||||
array_eval(cxobj *xprev,
|
array_eval(cxobj *xprev,
|
||||||
cxobj *x,
|
cxobj *x,
|
||||||
|
|
@ -184,7 +177,10 @@ array_eval(cxobj *xprev,
|
||||||
int eqprev=0;
|
int eqprev=0;
|
||||||
int eqnext=0;
|
int eqnext=0;
|
||||||
yang_stmt *ys;
|
yang_stmt *ys;
|
||||||
|
char *nsx; /* namespace of x */
|
||||||
|
char *ns2;
|
||||||
|
|
||||||
|
nsx = xml_find_type_value(x, NULL, "xmlns", CX_ATTR);
|
||||||
if (xml_type(x)!=CX_ELMNT){
|
if (xml_type(x)!=CX_ELMNT){
|
||||||
array=BODY_ARRAY;
|
array=BODY_ARRAY;
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -192,12 +188,18 @@ array_eval(cxobj *xprev,
|
||||||
ys = xml_spec(x);
|
ys = xml_spec(x);
|
||||||
if (xnext &&
|
if (xnext &&
|
||||||
xml_type(xnext)==CX_ELMNT &&
|
xml_type(xnext)==CX_ELMNT &&
|
||||||
strcmp(xml_name(x),xml_name(xnext))==0)
|
strcmp(xml_name(x),xml_name(xnext))==0){
|
||||||
eqnext++;
|
ns2 = xml_find_type_value(xnext, NULL, "xmlns", CX_ATTR);
|
||||||
|
if (nsx && ns2 && strcmp(nsx,ns2)==0)
|
||||||
|
eqnext++;
|
||||||
|
}
|
||||||
if (xprev &&
|
if (xprev &&
|
||||||
xml_type(xprev)==CX_ELMNT &&
|
xml_type(xprev)==CX_ELMNT &&
|
||||||
strcmp(xml_name(x),xml_name(xprev))==0)
|
strcmp(xml_name(x),xml_name(xprev))==0){
|
||||||
eqprev++;
|
ns2 = xml_find_type_value(xprev, NULL, "xmlns", CX_ATTR);
|
||||||
|
if (nsx && ns2 && strcmp(nsx,ns2)==0)
|
||||||
|
eqprev++;
|
||||||
|
}
|
||||||
if (eqprev && eqnext)
|
if (eqprev && eqnext)
|
||||||
array = MIDDLE_ARRAY;
|
array = MIDDLE_ARRAY;
|
||||||
else if (eqprev)
|
else if (eqprev)
|
||||||
|
|
@ -316,8 +318,8 @@ xml2json1_cbuf(cbuf *cb,
|
||||||
* module name
|
* module name
|
||||||
*/
|
*/
|
||||||
prefix = xml_prefix(x);
|
prefix = xml_prefix(x);
|
||||||
if (xml2ns(x, prefix, &namespace) < 0)
|
namespace = xml_find_type_value(x, prefix, "xmlns", CX_ATTR);
|
||||||
goto done;
|
|
||||||
if ((ys = xml_spec(x)) != NULL) /* yang spec associated with x */
|
if ((ys = xml_spec(x)) != NULL) /* yang spec associated with x */
|
||||||
yspec = ys_spec(ys);
|
yspec = ys_spec(ys);
|
||||||
/* Find module name associated with namspace URI */
|
/* Find module name associated with namspace URI */
|
||||||
|
|
@ -325,7 +327,7 @@ xml2json1_cbuf(cbuf *cb,
|
||||||
(ymod = yang_find_module_by_namespace(yspec, namespace)) != NULL){
|
(ymod = yang_find_module_by_namespace(yspec, namespace)) != NULL){
|
||||||
modname = ymod->ys_argument;
|
modname = ymod->ys_argument;
|
||||||
}
|
}
|
||||||
childt = childtype(x);
|
childt = child_type(x);
|
||||||
if (pretty==2)
|
if (pretty==2)
|
||||||
cprintf(cb, "#%s_array, %s_child ",
|
cprintf(cb, "#%s_array, %s_child ",
|
||||||
arraytype2str(arraytype),
|
arraytype2str(arraytype),
|
||||||
|
|
@ -442,7 +444,7 @@ xml2json1_cbuf(cbuf *cb,
|
||||||
xc_arraytype,
|
xc_arraytype,
|
||||||
level+1, pretty, 0, bodystr0) < 0)
|
level+1, pretty, 0, bodystr0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (i<xml_child_nr_noattr(x)-1)
|
if (i<xml_child_nr_notype(x, CX_ATTR)-1)
|
||||||
cprintf(cb, ",%s", pretty?"\n":"");
|
cprintf(cb, ",%s", pretty?"\n":"");
|
||||||
}
|
}
|
||||||
switch (arraytype){
|
switch (arraytype){
|
||||||
|
|
@ -532,10 +534,24 @@ xml2json_cbuf(cbuf *cb,
|
||||||
{
|
{
|
||||||
int retval = 1;
|
int retval = 1;
|
||||||
int level = 0;
|
int level = 0;
|
||||||
|
char *prefix;
|
||||||
|
char *namespace;
|
||||||
|
|
||||||
cprintf(cb, "%*s{%s",
|
cprintf(cb, "%*s{%s",
|
||||||
pretty?level*JSON_INDENT:0,"",
|
pretty?level*JSON_INDENT:0,"",
|
||||||
pretty?"\n":"");
|
pretty?"\n":"");
|
||||||
|
/* If x is labelled with a default namespace, it should be translated
|
||||||
|
* to a module name.
|
||||||
|
* Harder if x has a prefix, then that should also be translated to associated
|
||||||
|
* module name
|
||||||
|
*/
|
||||||
|
prefix = xml_prefix(x);
|
||||||
|
if (xml2ns(x, prefix, &namespace) < 0)
|
||||||
|
goto done;
|
||||||
|
/* Some complexities in grafting namespace in existing trees to new */
|
||||||
|
if (xml_find_type_value(x, prefix, "xmlns", CX_ATTR) == NULL && namespace)
|
||||||
|
if (xmlns_set(x, prefix, namespace) < 0)
|
||||||
|
goto done;
|
||||||
if (xml2json1_cbuf(cb,
|
if (xml2json1_cbuf(cb,
|
||||||
x,
|
x,
|
||||||
NO_ARRAY,
|
NO_ARRAY,
|
||||||
|
|
@ -551,7 +567,7 @@ xml2json_cbuf(cbuf *cb,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Translate a vector of xml objects to JSON CLigen buffer.
|
/*! Translate a vector of xml objects to JSON Cligen buffer.
|
||||||
* This is done by adding a top pseudo-object, and add the vector as subs,
|
* This is done by adding a top pseudo-object, and add the vector as subs,
|
||||||
* and then not printing the top pseudo-object using the 'flat' option.
|
* and then not printing the top pseudo-object using the 'flat' option.
|
||||||
* @param[out] cb Cligen buffer to write to
|
* @param[out] cb Cligen buffer to write to
|
||||||
|
|
@ -575,12 +591,21 @@ xml2json_cbuf_vec(cbuf *cb,
|
||||||
int i;
|
int i;
|
||||||
cxobj *xp = NULL;
|
cxobj *xp = NULL;
|
||||||
cxobj *xc;
|
cxobj *xc;
|
||||||
|
char *prefix;
|
||||||
|
char *namespace;
|
||||||
|
|
||||||
if ((xp = xml_new("", NULL, NULL)) == NULL)
|
if ((xp = xml_new("xml2json", NULL, NULL)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
|
/* Some complexities in grafting namespace in existing trees to new */
|
||||||
for (i=0; i<veclen; i++){
|
for (i=0; i<veclen; i++){
|
||||||
|
prefix = xml_prefix(vec[i]);
|
||||||
|
if (xml2ns(vec[i], prefix, &namespace) < 0)
|
||||||
|
goto done;
|
||||||
xc = xml_dup(vec[i]);
|
xc = xml_dup(vec[i]);
|
||||||
xml_addsub(xp, xc);
|
xml_addsub(xp, xc);
|
||||||
|
if (xml_find_type_value(xc, prefix, "xmlns", CX_ATTR) == NULL && namespace)
|
||||||
|
if (xmlns_set(xc, prefix, namespace) < 0)
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
if (0){
|
if (0){
|
||||||
cprintf(cb, "[%s", pretty?"\n":" ");
|
cprintf(cb, "[%s", pretty?"\n":" ");
|
||||||
|
|
@ -677,6 +702,66 @@ xml2json_vec(FILE *f,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Translate from JSON module:name to XML name xmlns="uri" recursively
|
||||||
|
* @param[in] yspec Yang spec
|
||||||
|
* @param[in,out] x XML tree. Translate it in-line
|
||||||
|
* @param[out] xerr If namespace not set, create xml error tree
|
||||||
|
* @retval 0 OK (if xerr set see above)
|
||||||
|
* @retval -1 Error
|
||||||
|
* @note the opposite - xml2ns is made inline in xml2json1_cbuf
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
json2xml_ns(yang_spec *yspec,
|
||||||
|
cxobj *x,
|
||||||
|
cxobj **xerr)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
yang_stmt *ymod;
|
||||||
|
char *namespace0;
|
||||||
|
char *namespace;
|
||||||
|
char *name = NULL;
|
||||||
|
char *prefix = NULL;
|
||||||
|
cxobj *xc;
|
||||||
|
|
||||||
|
if (nodeid_split(xml_name(x), &prefix, &name) < 0)
|
||||||
|
goto done;
|
||||||
|
if (prefix != NULL){
|
||||||
|
if ((ymod = yang_find_module_by_name(yspec, prefix)) == NULL){
|
||||||
|
if (netconf_unknown_namespace_xml(xerr, "application",
|
||||||
|
prefix,
|
||||||
|
"No yang module found corresponding to prefix") < 0)
|
||||||
|
goto done;
|
||||||
|
goto ok;
|
||||||
|
}
|
||||||
|
namespace = yang_find_mynamespace(ymod);
|
||||||
|
/* Get existing default namespace in tree */
|
||||||
|
if (xml2ns(x, NULL, &namespace0) < 0)
|
||||||
|
goto done;
|
||||||
|
/* Set xmlns="" default namespace attribute (if diff from default) */
|
||||||
|
if (namespace0==NULL || strcmp(namespace0, namespace))
|
||||||
|
if (xmlns_set(x, NULL, namespace) < 0)
|
||||||
|
goto done;
|
||||||
|
/* Remove prefix from name */
|
||||||
|
if (xml_name_set(x, name) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
xc = NULL;
|
||||||
|
while ((xc = xml_child_each(x, xc, CX_ELMNT)) != NULL){
|
||||||
|
if (json2xml_ns(yspec, xc, xerr) < 0)
|
||||||
|
goto done;
|
||||||
|
if (*xerr != NULL)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ok:
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (prefix)
|
||||||
|
free(prefix);
|
||||||
|
if (name)
|
||||||
|
free(name);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Parse a string containing JSON and return an XML tree
|
/*! Parse a string containing JSON and return an XML tree
|
||||||
* @param[in] str Input string containing JSON
|
* @param[in] str Input string containing JSON
|
||||||
* @param[in] name Log string, typically filename
|
* @param[in] name Log string, typically filename
|
||||||
|
|
|
||||||
|
|
@ -315,11 +315,12 @@ netconf_unknown_attribute(cbuf *cb,
|
||||||
* @param[in] message Error message
|
* @param[in] message Error message
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
netconf_element_xml_common(cxobj **xret,
|
netconf_common_xml(cxobj **xret,
|
||||||
char *type,
|
char *type,
|
||||||
char *tag,
|
char *tag,
|
||||||
char *element,
|
char *infotag,
|
||||||
char *message)
|
char *element,
|
||||||
|
char *message)
|
||||||
{
|
{
|
||||||
int retval =-1;
|
int retval =-1;
|
||||||
cxobj *xerr;
|
cxobj *xerr;
|
||||||
|
|
@ -334,9 +335,9 @@ netconf_element_xml_common(cxobj **xret,
|
||||||
goto done;
|
goto done;
|
||||||
if (xml_parse_va(&xerr, NULL, "<error-type>%s</error-type>"
|
if (xml_parse_va(&xerr, NULL, "<error-type>%s</error-type>"
|
||||||
"<error-tag>%s</error-tag>"
|
"<error-tag>%s</error-tag>"
|
||||||
"<error-info><bad-element>%s</bad-element></error-info>"
|
"<error-info><%s>%s</%s></error-info>"
|
||||||
"<error-severity>error</error-severity>",
|
"<error-severity>error</error-severity>",
|
||||||
type, tag, element) < 0)
|
type, tag, infotag, element, infotag) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (message && xml_parse_va(&xerr, NULL, "<error-message>%s</error-message>",
|
if (message && xml_parse_va(&xerr, NULL, "<error-message>%s</error-message>",
|
||||||
message) < 0)
|
message) < 0)
|
||||||
|
|
@ -363,7 +364,8 @@ netconf_missing_element(cbuf *cb,
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *xret = NULL;
|
cxobj *xret = NULL;
|
||||||
|
|
||||||
if (netconf_element_xml_common(&xret, type, "missing-element", element, message) < 0)
|
if (netconf_common_xml(&xret, type, "missing-element",
|
||||||
|
"bad-element", element, message) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_xml2cbuf(cb, xret, 0, 0) < 0)
|
if (clicon_xml2cbuf(cb, xret, 0, 0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -387,7 +389,8 @@ netconf_missing_element_xml(cxobj **xret,
|
||||||
char *element,
|
char *element,
|
||||||
char *message)
|
char *message)
|
||||||
{
|
{
|
||||||
return netconf_element_xml_common(xret, type, "missing-element", element, message);
|
return netconf_common_xml(xret, type, "missing-element",
|
||||||
|
"bad-element", element, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Create Netconf bad-element error XML tree according to RFC 6241 App A
|
/*! Create Netconf bad-element error XML tree according to RFC 6241 App A
|
||||||
|
|
@ -408,7 +411,8 @@ netconf_bad_element(cbuf *cb,
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *xret = NULL;
|
cxobj *xret = NULL;
|
||||||
|
|
||||||
if (netconf_element_xml_common(&xret, type, "bad-element", element, message) < 0)
|
if (netconf_common_xml(&xret, type, "bad-element",
|
||||||
|
"bad-element",element, message) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_xml2cbuf(cb, xret, 0, 0) < 0)
|
if (clicon_xml2cbuf(cb, xret, 0, 0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -424,7 +428,7 @@ netconf_bad_element_xml(cxobj **xret,
|
||||||
char *element,
|
char *element,
|
||||||
char *message)
|
char *message)
|
||||||
{
|
{
|
||||||
return netconf_element_xml_common(xret, type, "bad-element", element, message);
|
return netconf_common_xml(xret, type, "bad-element", "bad-element", element, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Create Netconf unknown-element error XML tree according to RFC 6241 App A
|
/*! Create Netconf unknown-element error XML tree according to RFC 6241 App A
|
||||||
|
|
@ -444,7 +448,8 @@ netconf_unknown_element(cbuf *cb,
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *xret = NULL;
|
cxobj *xret = NULL;
|
||||||
|
|
||||||
if (netconf_element_xml_common(&xret, type, "unknown-element", element, message) < 0)
|
if (netconf_common_xml(&xret, type, "unknown-element",
|
||||||
|
"bad-element", element, message) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_xml2cbuf(cb, xret, 0, 0) < 0)
|
if (clicon_xml2cbuf(cb, xret, 0, 0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -454,13 +459,23 @@ netconf_unknown_element(cbuf *cb,
|
||||||
xml_free(xret);
|
xml_free(xret);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Create Netconf unknown-element error XML tree according to RFC 6241 App A
|
||||||
|
*
|
||||||
|
* An unexpected element is present.
|
||||||
|
* @param[out] xret XML buffer
|
||||||
|
* @param[in] type Error type: "application" or "protocol"
|
||||||
|
* @param[in] element Bad element name
|
||||||
|
* @param[in] message Error message
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
netconf_unknown_element_xml(cxobj **xret,
|
netconf_unknown_element_xml(cxobj **xret,
|
||||||
char *type,
|
char *type,
|
||||||
char *element,
|
char *element,
|
||||||
char *message)
|
char *message)
|
||||||
{
|
{
|
||||||
return netconf_element_xml_common(xret, type, "unknown-element", element, message);
|
return netconf_common_xml(xret, type, "unknown-element",
|
||||||
|
"bad-element", element, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Create Netconf unknown-namespace error XML tree according to RFC 6241 App A
|
/*! Create Netconf unknown-namespace error XML tree according to RFC 6241 App A
|
||||||
|
|
@ -474,35 +489,32 @@ netconf_unknown_element_xml(cxobj **xret,
|
||||||
int
|
int
|
||||||
netconf_unknown_namespace(cbuf *cb,
|
netconf_unknown_namespace(cbuf *cb,
|
||||||
char *type,
|
char *type,
|
||||||
char *info,
|
char *namespace,
|
||||||
char *message)
|
char *message)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *encstr = NULL;
|
cxobj *xret = NULL;
|
||||||
|
|
||||||
if (cprintf(cb, "<rpc-reply><rpc-error>"
|
if (netconf_common_xml(&xret, type, "unknown-namespace",
|
||||||
"<error-type>%s</error-type>"
|
"bad-namespace", namespace, message) < 0)
|
||||||
"<error-tag>unknown-namespace</error-tag>"
|
goto done;
|
||||||
"<error-info>%s</error-info>"
|
if (clicon_xml2cbuf(cb, xret, 0, 0) < 0)
|
||||||
"<error-severity>error</error-severity>",
|
goto done;
|
||||||
type, info) <0)
|
|
||||||
goto err;
|
|
||||||
if (message){
|
|
||||||
if (xml_chardata_encode(&encstr, "%s", message) < 0)
|
|
||||||
goto done;
|
|
||||||
if (cprintf(cb, "<error-message>%s</error-message>", encstr) < 0)
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
if (cprintf(cb, "</rpc-error></rpc-reply>") <0)
|
|
||||||
goto err;
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (encstr)
|
if (xret)
|
||||||
free(encstr);
|
xml_free(xret);
|
||||||
return retval;
|
return retval;
|
||||||
err:
|
}
|
||||||
clicon_err(OE_XML, errno, "cprintf");
|
|
||||||
goto done;
|
int
|
||||||
|
netconf_unknown_namespace_xml(cxobj **xret,
|
||||||
|
char *type,
|
||||||
|
char *namespace,
|
||||||
|
char *message)
|
||||||
|
{
|
||||||
|
return netconf_common_xml(xret, type, "unknown-namespace",
|
||||||
|
"bad-namespace", namespace, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Create Netconf access-denied error cbuf according to RFC 6241 App A
|
/*! Create Netconf access-denied error cbuf according to RFC 6241 App A
|
||||||
|
|
@ -989,7 +1001,7 @@ netconf_trymerge(cxobj *x,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Load ietf netconf yang module and set enabled features
|
/*! Load ietf netconf yang module and set enabled features
|
||||||
* The features added are:
|
* The features added are (in order):
|
||||||
* candidate (8.3)
|
* candidate (8.3)
|
||||||
* validate (8.6)
|
* validate (8.6)
|
||||||
* startup (8.7)
|
* startup (8.7)
|
||||||
|
|
|
||||||
|
|
@ -253,9 +253,8 @@ clicon_options_main(clicon_handle h,
|
||||||
clicon_err(OE_CFG, 0, "%s: suffix %s not recognized (Run ./configure --with-config-compat?)", configfile, suffix);
|
clicon_err(OE_CFG, 0, "%s: suffix %s not recognized (Run ./configure --with-config-compat?)", configfile, suffix);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
#if 1 /* XXX Kludge to low-level functions to iterate over namspaces or not */
|
/* XXX Kludge to low-level functions to search for xml in all yang modules */
|
||||||
_CLICON_XML_NS_ITERATE = 1;
|
_CLICON_XML_NS_STRICT = 0;
|
||||||
#endif
|
|
||||||
/* Read configfile first without yangspec, for bootstrapping */
|
/* Read configfile first without yangspec, for bootstrapping */
|
||||||
if (parse_configfile(h, configfile, yspec, &xconfig) < 0)
|
if (parse_configfile(h, configfile, yspec, &xconfig) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -281,9 +280,8 @@ clicon_options_main(clicon_handle h,
|
||||||
xml_child_sort = 1;
|
xml_child_sort = 1;
|
||||||
else
|
else
|
||||||
xml_child_sort = 0;
|
xml_child_sort = 0;
|
||||||
#if 1 /* XXX Kludge to low-level functions to iterate over namspaces or not */
|
/* XXX Kludge to low-level functions to search for xml in all yang modules */
|
||||||
_CLICON_XML_NS_ITERATE = clicon_option_bool(h, "CLICON_XML_NS_ITERATE");
|
_CLICON_XML_NS_STRICT = clicon_option_bool(h, "CLICON_XML_NS_STRICT");
|
||||||
#endif
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
|
|
|
||||||
|
|
@ -351,7 +351,7 @@ clicon_rpc_edit_config(clicon_handle h,
|
||||||
|
|
||||||
if ((cb = cbuf_new()) == NULL)
|
if ((cb = cbuf_new()) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
cprintf(cb, "<rpc");
|
cprintf(cb, "<rpc %s", DEFAULT_XMLNS);
|
||||||
if ((username = clicon_username_get(h)) != NULL)
|
if ((username = clicon_username_get(h)) != NULL)
|
||||||
cprintf(cb, " username=\"%s\"", username);
|
cprintf(cb, " username=\"%s\"", username);
|
||||||
cprintf(cb, "><edit-config><target><%s/></target>", db);
|
cprintf(cb, "><edit-config><target><%s/></target>", db);
|
||||||
|
|
@ -787,7 +787,7 @@ clicon_rpc_create_subscription(clicon_handle h,
|
||||||
char *username;
|
char *username;
|
||||||
|
|
||||||
username = clicon_username_get(h);
|
username = clicon_username_get(h);
|
||||||
if ((msg = clicon_msg_encode("<rpc username=\"%s\"><create-subscription>"
|
if ((msg = clicon_msg_encode("<rpc username=\"%s\"><create-subscription xmlns=\"urn:ietf:params:xml:ns:netmod:notification\">"
|
||||||
"<stream>%s</stream>"
|
"<stream>%s</stream>"
|
||||||
"<filter type=\"xpath\" select=\"%s\" />"
|
"<filter type=\"xpath\" select=\"%s\" />"
|
||||||
"</create-subscription></rpc>",
|
"</create-subscription></rpc>",
|
||||||
|
|
|
||||||
|
|
@ -562,6 +562,54 @@ clicon_str2int(const map_str2int *mstab,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Split colon-separated node identifier into prefix and name
|
||||||
|
* @param[in] node-id
|
||||||
|
* @param[out] prefix Malloced string. May be NULL.
|
||||||
|
* @param[out] id Malloced identifier.
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
|
* @code
|
||||||
|
* char *prefix = NULL;
|
||||||
|
* char *id = NULL;
|
||||||
|
* if (nodeid_split(nodeid, &prefix, &id) < 0)
|
||||||
|
* goto done;
|
||||||
|
* if (prefix)
|
||||||
|
* free(prefix);
|
||||||
|
* if (id)
|
||||||
|
* free(id);
|
||||||
|
* @note caller need to free id and prefix after use
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
nodeid_split(char *nodeid,
|
||||||
|
char **prefix,
|
||||||
|
char **id)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
if ((str = strchr(nodeid, ':')) == NULL){
|
||||||
|
if ((*id = strdup(nodeid)) == NULL){
|
||||||
|
clicon_err(OE_YANG, errno, "strdup");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if ((*prefix = strdup(nodeid)) == NULL){
|
||||||
|
clicon_err(OE_YANG, errno, "strdup");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
(*prefix)[str-nodeid] = '\0';
|
||||||
|
str++;
|
||||||
|
if ((*id = strdup(str)) == NULL){
|
||||||
|
clicon_err(OE_YANG, errno, "strdup");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*! strndup() for systems without it, such as xBSD
|
/*! strndup() for systems without it, such as xBSD
|
||||||
*/
|
*/
|
||||||
#ifndef HAVE_STRNDUP
|
#ifndef HAVE_STRNDUP
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,8 @@
|
||||||
#include "clixon_log.h"
|
#include "clixon_log.h"
|
||||||
#include "clixon_yang.h"
|
#include "clixon_yang.h"
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
|
#include "clixon_options.h" /* xml_spec_populate */
|
||||||
|
#include "clixon_xml_map.h" /* xml_spec_populate */
|
||||||
#include "clixon_xml_sort.h"
|
#include "clixon_xml_sort.h"
|
||||||
#include "clixon_xml_parse.h"
|
#include "clixon_xml_parse.h"
|
||||||
|
|
||||||
|
|
@ -133,9 +135,9 @@ struct xml{
|
||||||
* or rpc if no xmlns attribute specifies namespace.
|
* or rpc if no xmlns attribute specifies namespace.
|
||||||
* This is loose semantics of finding namespaces.
|
* This is loose semantics of finding namespaces.
|
||||||
* And it is wrong, but is the way Clixon originally was written."
|
* And it is wrong, but is the way Clixon originally was written."
|
||||||
* @see CLICON_XML_NS_ITERATE clixon configure option
|
* @see CLICON_XML_NS_STRICT clixon configure option
|
||||||
*/
|
*/
|
||||||
int _CLICON_XML_NS_ITERATE = 0;
|
int _CLICON_XML_NS_STRICT = 1;
|
||||||
|
|
||||||
/* Mapping between xml type <--> string */
|
/* Mapping between xml type <--> string */
|
||||||
static const map_str2int xsmap[] = {
|
static const map_str2int xsmap[] = {
|
||||||
|
|
@ -226,8 +228,7 @@ xml_prefix_set(cxobj *xn,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Given an xml tree return URI namespace recursively : default or localname given
|
||||||
/*! Given an xml tree return URI namespace: default or localname given
|
|
||||||
*
|
*
|
||||||
* Given an XML tree and a prefix (or NULL) return URI namespace.
|
* Given an XML tree and a prefix (or NULL) return URI namespace.
|
||||||
* @param[in] x XML tree
|
* @param[in] x XML tree
|
||||||
|
|
@ -235,7 +236,7 @@ xml_prefix_set(cxobj *xn,
|
||||||
* @param[out] namespace URI namespace (or NULL). Note pointer into xml tree
|
* @param[out] namespace URI namespace (or NULL). Note pointer into xml tree
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
* @see xmlns_check XXX coordinate
|
* @see xmlns_check XXX can these be merged?
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xml2ns(cxobj *x,
|
xml2ns(cxobj *x,
|
||||||
|
|
@ -246,9 +247,9 @@ xml2ns(cxobj *x,
|
||||||
char *ns;
|
char *ns;
|
||||||
cxobj *xp;
|
cxobj *xp;
|
||||||
|
|
||||||
if (prefix != NULL) /* xmlns:<prefix> */
|
if (prefix != NULL) /* xmlns:<prefix>="<uri>" */
|
||||||
ns = xml_find_type_value(x, "xmlns", prefix, CX_ATTR);
|
ns = xml_find_type_value(x, "xmlns", prefix, CX_ATTR);
|
||||||
else /* default ns */
|
else /* xmlns="<uri>" */
|
||||||
ns = xml_find_type_value(x, NULL, "xmlns", CX_ATTR);
|
ns = xml_find_type_value(x, NULL, "xmlns", CX_ATTR);
|
||||||
|
|
||||||
/* namespace not found, try parent */
|
/* namespace not found, try parent */
|
||||||
|
|
@ -270,6 +271,40 @@ xml2ns(cxobj *x,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Add a namespace attribute to an XML node, either default or specific prefix
|
||||||
|
* @param[in] x XML tree
|
||||||
|
* @param[in] prefix prefix/ns localname. If NULL then set default xmlns
|
||||||
|
* @param[out] namespace URI namespace (or NULL). Will be copied
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
|
* @see xml2ns
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xmlns_set(cxobj *x,
|
||||||
|
char *prefix,
|
||||||
|
char *namespace)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cxobj *xa;
|
||||||
|
|
||||||
|
if (prefix != NULL){ /* xmlns:<prefix>="<uri>" */
|
||||||
|
if ((xa = xml_new(prefix, x, NULL)) == NULL)
|
||||||
|
goto done;
|
||||||
|
if (xml_prefix_set(xa, "xmlns") < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
else{ /* xmlns="<uri>" */
|
||||||
|
if ((xa = xml_new("xmlns", x, NULL)) == NULL)
|
||||||
|
goto done;
|
||||||
|
xml_type_set(xa, CX_ATTR);
|
||||||
|
}
|
||||||
|
if (xml_value_set(xa, namespace) < 0)
|
||||||
|
goto done;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*! See if xmlns:[<localname>=]<uri> exists, if so return <uri>
|
/*! See if xmlns:[<localname>=]<uri> exists, if so return <uri>
|
||||||
*
|
*
|
||||||
* @param[in] xn XML node
|
* @param[in] xn XML node
|
||||||
|
|
@ -483,6 +518,8 @@ xml_type_set(cxobj *xn,
|
||||||
/*! Get number of children
|
/*! Get number of children
|
||||||
* @param[in] xn xml node
|
* @param[in] xn xml node
|
||||||
* @retval number of children in XML tree
|
* @retval number of children in XML tree
|
||||||
|
* @see xml_child_nr_type
|
||||||
|
* @see xml_child_nr_notype
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xml_child_nr(cxobj *xn)
|
xml_child_nr(cxobj *xn)
|
||||||
|
|
@ -490,10 +527,33 @@ xml_child_nr(cxobj *xn)
|
||||||
return xn->x_childvec_len;
|
return xn->x_childvec_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Get number of children of EXCEPT specific type
|
||||||
|
* @param[in] xn xml node
|
||||||
|
* @param[in] type XML type or -1 for all
|
||||||
|
* @retval number of typed children in XML tree (except type)
|
||||||
|
* @see xml_child_nr
|
||||||
|
* @see xml_child_nr_type
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml_child_nr_notype(cxobj *xn,
|
||||||
|
enum cxobj_type type)
|
||||||
|
{
|
||||||
|
cxobj *x = NULL;
|
||||||
|
int nr = 0;
|
||||||
|
|
||||||
|
while ((x = xml_child_each(xn, x, -1)) != NULL) {
|
||||||
|
if (xml_type(x) != type)
|
||||||
|
nr++;
|
||||||
|
}
|
||||||
|
return nr;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Get number of children of specific type
|
/*! Get number of children of specific type
|
||||||
* @param[in] xn xml node
|
* @param[in] xn xml node
|
||||||
* @param[in] type XML type or -1 for all
|
* @param[in] type XML type or -1 for all
|
||||||
* @retval number of typed children in XML tree
|
* @retval number of typed children in XML tree
|
||||||
|
* @see xml_child_nr
|
||||||
|
* @see xml_child_nr_notype
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xml_child_nr_type(cxobj *xn,
|
xml_child_nr_type(cxobj *xn,
|
||||||
|
|
@ -521,6 +581,28 @@ xml_child_i(cxobj *xn,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Get a specific child of a specific type
|
||||||
|
* @param[in] xn xml node
|
||||||
|
* @param[in] i the number of the child of specific type
|
||||||
|
* @param[in] type Child type
|
||||||
|
* @retval child in XML tree, or NULL if no such child, or empty child
|
||||||
|
* @see xml_child_i
|
||||||
|
*/
|
||||||
|
cxobj *
|
||||||
|
xml_child_i_type(cxobj *xn,
|
||||||
|
int i,
|
||||||
|
enum cxobj_type type)
|
||||||
|
{
|
||||||
|
cxobj *x = NULL;
|
||||||
|
int it = 0;
|
||||||
|
|
||||||
|
while ((x = xml_child_each(xn, x, type)) != NULL) {
|
||||||
|
if (x->x_type == type && (i == it++))
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Set specific child
|
/*! Set 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
|
||||||
|
|
@ -938,7 +1020,7 @@ xml_body_get(cxobj *xt)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Find and return the value of an xml child of specific type
|
/*! Find and return the value of an xml child of specific type given prefix and name
|
||||||
*
|
*
|
||||||
* The value can be of an attribute only
|
* The value can be of an attribute only
|
||||||
* @param[in] xt xml tree node
|
* @param[in] xt xml tree node
|
||||||
|
|
@ -950,6 +1032,7 @@ xml_body_get(cxobj *xt)
|
||||||
* char *str = xml_find_type_value(x, "prefix", "name", CX_ATTR);
|
* char *str = xml_find_type_value(x, "prefix", "name", CX_ATTR);
|
||||||
* @endcode
|
* @endcode
|
||||||
* @note, make a copy of the return value to use it properly
|
* @note, make a copy of the return value to use it properly
|
||||||
|
* @see xml_find_type return the xml object
|
||||||
* @see xml_find_value where a body can be found as well
|
* @see xml_find_value where a body can be found as well
|
||||||
*/
|
*/
|
||||||
char *
|
char *
|
||||||
|
|
@ -957,6 +1040,32 @@ xml_find_type_value(cxobj *xt,
|
||||||
char *prefix,
|
char *prefix,
|
||||||
char *name,
|
char *name,
|
||||||
enum cxobj_type type)
|
enum cxobj_type type)
|
||||||
|
{
|
||||||
|
cxobj *x;
|
||||||
|
|
||||||
|
if ((x = xml_find_type(xt, prefix, name, type)) != NULL)
|
||||||
|
return xml_value(x);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Find and return the xml child of specific type given prefix and name
|
||||||
|
*
|
||||||
|
* The value can be of an attribute only
|
||||||
|
* @param[in] xt xml tree node
|
||||||
|
* @param[in] prefix Prefix (namespace local name) or NULL
|
||||||
|
* @param[in] name name of xml tree node (eg attr name or "body")
|
||||||
|
* @retval val Pointer to the name string
|
||||||
|
* @retval NULL No such node or no value in node
|
||||||
|
* @code
|
||||||
|
* cxobj *x = xml_find_type(x, "prefix", "name", CX_ATTR);
|
||||||
|
* @endcode
|
||||||
|
* @see xml_find_value where a body can be found as well
|
||||||
|
*/
|
||||||
|
cxobj *
|
||||||
|
xml_find_type(cxobj *xt,
|
||||||
|
char *prefix,
|
||||||
|
char *name,
|
||||||
|
enum cxobj_type type)
|
||||||
{
|
{
|
||||||
cxobj *x = NULL;
|
cxobj *x = NULL;
|
||||||
int pmatch; /* prefix match */
|
int pmatch; /* prefix match */
|
||||||
|
|
@ -969,7 +1078,7 @@ xml_find_type_value(cxobj *xt,
|
||||||
else
|
else
|
||||||
pmatch = 1;
|
pmatch = 1;
|
||||||
if (pmatch && strcmp(name, xml_name(x)) == 0)
|
if (pmatch && strcmp(name, xml_name(x)) == 0)
|
||||||
return xml_value(x);
|
return x;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -1397,6 +1506,8 @@ _xml_parse(const char *str,
|
||||||
goto done;
|
goto done;
|
||||||
/* Sort the complete tree after parsing */
|
/* Sort the complete tree after parsing */
|
||||||
if (yspec){
|
if (yspec){
|
||||||
|
if (xml_apply0(xt, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
||||||
|
goto done;
|
||||||
if (xml_apply0(xt, CX_ELMNT, xml_sort, NULL) < 0)
|
if (xml_apply0(xt, CX_ELMNT, xml_sort, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (xml_apply0(xt, -1, xml_sort_verify, NULL) < 0)
|
if (xml_apply0(xt, -1, xml_sort_verify, NULL) < 0)
|
||||||
|
|
@ -1592,7 +1703,7 @@ xml_parse_va(cxobj **xtop,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Copy single xml node without copying children
|
/*! Copy single xml node frm x0 to x1 without copying children
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xml_copy_one(cxobj *x0,
|
xml_copy_one(cxobj *x0,
|
||||||
|
|
|
||||||
|
|
@ -380,7 +380,8 @@ xmldb_get(clicon_handle h,
|
||||||
* @param[in] op Top-level operation, can be superceded by other op in tree
|
* @param[in] op Top-level operation, can be superceded by other op in tree
|
||||||
* @param[in] xt xml-tree. Top-level symbol is dummy
|
* @param[in] xt xml-tree. Top-level symbol is dummy
|
||||||
* @param[out] cbret Initialized cligen buffer or NULL. On exit contains XML or "".
|
* @param[out] cbret Initialized cligen buffer or NULL. On exit contains XML or "".
|
||||||
* @retval 0 OK
|
* @retval 1 OK
|
||||||
|
* @retval 0 Failed, cbret contains error xml message
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
* The xml may contain the "operation" attribute which defines the operation.
|
* The xml may contain the "operation" attribute which defines the operation.
|
||||||
* @code
|
* @code
|
||||||
|
|
@ -388,8 +389,10 @@ xmldb_get(clicon_handle h,
|
||||||
* cxobj *xret = NULL;
|
* cxobj *xret = NULL;
|
||||||
* if (xml_parse_string("<a>17</a>", yspec, &xt) < 0)
|
* if (xml_parse_string("<a>17</a>", yspec, &xt) < 0)
|
||||||
* err;
|
* err;
|
||||||
* if (xmldb_put(xh, "running", OP_MERGE, xt, cbret) < 0)
|
* if ((ret = xmldb_put(xh, "running", OP_MERGE, xt, cbret)) < 0)
|
||||||
* err;
|
* err;
|
||||||
|
* if (ret==0)
|
||||||
|
* cbret contains netconf error message
|
||||||
* @endcode
|
* @endcode
|
||||||
* @note that you can add both config data and state data. In comparison,
|
* @note that you can add both config data and state data. In comparison,
|
||||||
* xmldb_get has a parameter to get config data only.
|
* xmldb_get has a parameter to get config data only.
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -130,6 +130,7 @@ xml_parse_version(struct xml_parse_yacc_arg *ya,
|
||||||
* @param[in] ya XML parser yacc handler struct
|
* @param[in] ya XML parser yacc handler struct
|
||||||
* @param[in] prefix Prefix, namespace, or NULL
|
* @param[in] prefix Prefix, namespace, or NULL
|
||||||
* @param[in] localpart Name
|
* @param[in] localpart Name
|
||||||
|
* @note the call to xml_child_spec() may not have xmlns attribute read yet XXX
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
xml_parse_unprefixed_name(struct xml_parse_yacc_arg *ya,
|
xml_parse_unprefixed_name(struct xml_parse_yacc_arg *ya,
|
||||||
|
|
@ -138,12 +139,14 @@ xml_parse_unprefixed_name(struct xml_parse_yacc_arg *ya,
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *x;
|
cxobj *x;
|
||||||
yang_stmt *y = NULL; /* yang node */
|
yang_stmt *y = NULL; /* yang node */
|
||||||
cxobj *xp; /* xml parent */
|
cxobj *xp; /* xml parent */
|
||||||
|
|
||||||
xp = ya->ya_xparent;
|
xp = ya->ya_xparent;
|
||||||
if (xml_child_spec(name, xp, ya->ya_yspec, &y) < 0)
|
if ((x = xml_new(name, xp, NULL)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if ((x = xml_new(name, xp, y)) == NULL)
|
if (xml_child_spec(x, xp, ya->ya_yspec, &y) < 0)
|
||||||
|
goto done;
|
||||||
|
if (y && xml_spec_set(x, y) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
ya->ya_xelement = x;
|
ya->ya_xelement = x;
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
@ -168,9 +171,11 @@ xml_parse_prefixed_name(struct xml_parse_yacc_arg *ya,
|
||||||
cxobj *xp; /* xml parent */
|
cxobj *xp; /* xml parent */
|
||||||
|
|
||||||
xp = ya->ya_xparent;
|
xp = ya->ya_xparent;
|
||||||
if (xml_child_spec(name, xp, ya->ya_yspec, &y) < 0)
|
if ((x = xml_new(name, xp, NULL)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if ((x = xml_new(name, xp, y)) == NULL)
|
if (xml_child_spec(x, xp, ya->ya_yspec, &y) < 0)
|
||||||
|
goto done;
|
||||||
|
if (y && xml_spec_set(x, y) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (xml_prefix_set(x, prefix) < 0)
|
if (xml_prefix_set(x, prefix) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -313,19 +318,15 @@ xml_parse_attr(struct xml_parse_yacc_arg *ya,
|
||||||
char *attval)
|
char *attval)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *xa;
|
cxobj *xa = NULL;
|
||||||
|
|
||||||
#ifdef ENABLE_XMLNS
|
if ((xa = xml_find_type(ya->ya_xelement, prefix, name, CX_ATTR)) == NULL){
|
||||||
if (prefix && strcmp(prefix,"xmlns")==0)
|
if ((xa = xml_new(name, ya->ya_xelement, NULL)) == NULL)
|
||||||
fprintf(stderr, "PrefixedAttName NCNAME:%s = %s\n", name, attval);
|
goto done;
|
||||||
if (prefix==NULL && strcmp(name,"xmlns")==0)
|
xml_type_set(xa, CX_ATTR);
|
||||||
fprintf(stderr, "DefaultAttName = %s\n", attval);
|
if (prefix && xml_prefix_set(xa, prefix) < 0)
|
||||||
#endif /* notyet */
|
goto done;
|
||||||
if ((xa = xml_new(name, ya->ya_xelement, NULL)) == NULL)
|
}
|
||||||
goto done;
|
|
||||||
xml_type_set(xa, CX_ATTR);
|
|
||||||
if (prefix && xml_prefix_set(xa, prefix) < 0)
|
|
||||||
goto done;
|
|
||||||
if (xml_value_set(xa, attval) < 0)
|
if (xml_value_set(xa, attval) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,8 @@
|
||||||
#include "clixon_handle.h"
|
#include "clixon_handle.h"
|
||||||
#include "clixon_yang.h"
|
#include "clixon_yang.h"
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
|
#include "clixon_options.h"
|
||||||
|
#include "clixon_xml_map.h"
|
||||||
#include "clixon_xml_sort.h"
|
#include "clixon_xml_sort.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -68,7 +70,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Sort and binary search of XML children
|
/* Sort and binary search of XML children
|
||||||
* Experimental
|
* XXX kludge since low-level functions xml_merge/xml_diff calls
|
||||||
|
* match_base_child without handle
|
||||||
|
* @see clicon_xml_sort
|
||||||
*/
|
*/
|
||||||
int xml_child_sort = 1;
|
int xml_child_sort = 1;
|
||||||
|
|
||||||
|
|
@ -83,7 +87,7 @@ int xml_child_sort = 1;
|
||||||
* xmlns and xmlns:ns are used.
|
* xmlns and xmlns:ns are used.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xml_child_spec(char *name,
|
xml_child_spec(cxobj *x,
|
||||||
cxobj *xp,
|
cxobj *xp,
|
||||||
yang_spec *yspec,
|
yang_spec *yspec,
|
||||||
yang_stmt **yresult)
|
yang_stmt **yresult)
|
||||||
|
|
@ -93,8 +97,9 @@ xml_child_spec(char *name,
|
||||||
yang_stmt *yparent; /* parent yang */
|
yang_stmt *yparent; /* parent yang */
|
||||||
yang_stmt *ymod = NULL;
|
yang_stmt *ymod = NULL;
|
||||||
yang_stmt *yi;
|
yang_stmt *yi;
|
||||||
int i;
|
char *name;
|
||||||
|
|
||||||
|
name = xml_name(x);
|
||||||
if (xp && (yparent = xml_spec(xp)) != NULL){
|
if (xp && (yparent = xml_spec(xp)) != NULL){
|
||||||
if (yparent->ys_keyword == Y_RPC){
|
if (yparent->ys_keyword == Y_RPC){
|
||||||
if ((yi = yang_find((yang_node*)yparent, Y_INPUT, NULL)) != NULL)
|
if ((yi = yang_find((yang_node*)yparent, Y_INPUT, NULL)) != NULL)
|
||||||
|
|
@ -108,12 +113,9 @@ xml_child_spec(char *name,
|
||||||
goto done;
|
goto done;
|
||||||
if (ymod != NULL)
|
if (ymod != NULL)
|
||||||
y = yang_find_schemanode((yang_node*)ymod, name);
|
y = yang_find_schemanode((yang_node*)ymod, name);
|
||||||
if (y == NULL && _CLICON_XML_NS_ITERATE){
|
if (y == NULL && !_CLICON_XML_NS_STRICT){
|
||||||
for (i=0; i<yspec->yp_len; i++){
|
if (xml_yang_find_non_strict(x, yspec, &y) < 0) /* schemanode */
|
||||||
ymod = yspec->yp_stmt[i];
|
goto done;
|
||||||
if ((y = yang_find_schemanode((yang_node*)ymod, name)) != NULL)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -265,6 +267,7 @@ xml_cmp1(cxobj *x,
|
||||||
* Assume populated by yang spec.
|
* Assume populated by yang spec.
|
||||||
* @param[in] x0 XML node
|
* @param[in] x0 XML node
|
||||||
* @param[in] arg Dummy so it can be called by xml_apply()
|
* @param[in] arg Dummy so it can be called by xml_apply()
|
||||||
|
* @see xml_order XXX: how do they relate?
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xml_sort(cxobj *x,
|
xml_sort(cxobj *x,
|
||||||
|
|
@ -560,9 +563,10 @@ xml_sort_verify(cxobj *x0,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Given child tree x1c, find matching child in base tree x0 and return as x0cp
|
/*! Given child tree x1c, find matching child in base tree x0 and return as x0cp
|
||||||
* param[in] x0 Base tree node
|
* param[in] x0 Base tree node
|
||||||
* param[in] x1c Modification tree child
|
* param[in] x1c Modification tree child
|
||||||
* param[in] yc Yang spec of tree child
|
* param[in] yc Yang spec of tree child
|
||||||
|
* param[in] xml_sort Value of CLICON_XML_SORT option
|
||||||
* param[out] x0cp Matching base tree child (if any)
|
* param[out] x0cp Matching base tree child (if any)
|
||||||
* @note XXX: room for optimization? on 1K calls we have 1M body calls and
|
* @note XXX: room for optimization? on 1K calls we have 1M body calls and
|
||||||
500K xml_child_each/cvec_each calls.
|
500K xml_child_each/cvec_each calls.
|
||||||
|
|
@ -575,6 +579,7 @@ int
|
||||||
match_base_child(cxobj *x0,
|
match_base_child(cxobj *x0,
|
||||||
cxobj *x1c,
|
cxobj *x1c,
|
||||||
cxobj **x0cp,
|
cxobj **x0cp,
|
||||||
|
int xml_sort,
|
||||||
yang_stmt *yc)
|
yang_stmt *yc)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
@ -632,7 +637,7 @@ match_base_child(cxobj *x0,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Get match. Sorting mode(optimized) or not?*/
|
/* Get match. Sorting mode(optimized) or not?*/
|
||||||
if (xml_child_sort==0)
|
if (xml_sort==0)
|
||||||
*x0cp = xml_match(x0, xml_name(x1c), yc->ys_keyword, keynr, keyvec, keyval);
|
*x0cp = xml_match(x0, xml_name(x1c), yc->ys_keyword, keynr, keyvec, keyval);
|
||||||
else{
|
else{
|
||||||
if (xml_child_nr(x0)==0 || xml_spec(xml_child_i(x0,0))!=NULL){
|
if (xml_child_nr(x0)==0 || xml_spec(xml_child_i(x0,0))!=NULL){
|
||||||
|
|
@ -640,12 +645,6 @@ match_base_child(cxobj *x0,
|
||||||
*x0cp = xml_search(x0, xml_name(x1c), yorder, yc->ys_keyword, keynr, keyvec, keyval);
|
*x0cp = xml_search(x0, xml_name(x1c), yorder, yc->ys_keyword, keynr, keyvec, keyval);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
#if 1 /* This is just a warning, but a catcher for when xml tree is not
|
|
||||||
populated with yang spec. If you see this, a previous invacation of,
|
|
||||||
for example xml_spec_populate() may be missing
|
|
||||||
*/
|
|
||||||
clicon_log(LOG_WARNING, "%s No yspec", __FUNCTION__);
|
|
||||||
#endif
|
|
||||||
*x0cp = xml_match(x0, xml_name(x1c), yc->ys_keyword, keynr, keyvec, keyval);
|
*x0cp = xml_match(x0, xml_name(x1c), yc->ys_keyword, keynr, keyvec, keyval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -469,94 +469,6 @@ yang_match(yang_node *yn,
|
||||||
}
|
}
|
||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
#ifdef NOTYET
|
|
||||||
/*! Prototype more generic than yang_find_datanode and yang_find_schemanode
|
|
||||||
*/
|
|
||||||
yang_stmt *
|
|
||||||
yang_find_class(yang_node *yn,
|
|
||||||
char *argument,
|
|
||||||
yang_class class)
|
|
||||||
{
|
|
||||||
yang_stmt *ys = NULL;
|
|
||||||
yang_stmt *yc = NULL;
|
|
||||||
yang_stmt *ysmatch = NULL;
|
|
||||||
int i, j;
|
|
||||||
int ok;
|
|
||||||
|
|
||||||
for (i=0; i<yn->yn_len; i++){
|
|
||||||
ys = yn->yn_stmt[i];
|
|
||||||
switch(class){
|
|
||||||
case YC_NONE:
|
|
||||||
ok = 1;
|
|
||||||
break;
|
|
||||||
case YC_DATANODE:
|
|
||||||
ok = yang_datanode(ys);
|
|
||||||
break;
|
|
||||||
case YC_DATADEFINITION:
|
|
||||||
ok = yang_datadefinition(ys);
|
|
||||||
break;
|
|
||||||
case YC_SCHEMANODE:
|
|
||||||
ok = yang_schemanode(ys);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!ok)
|
|
||||||
continue;
|
|
||||||
switch(class){
|
|
||||||
case YC_NONE:
|
|
||||||
if (argument == NULL)
|
|
||||||
ysmatch = ys;
|
|
||||||
else
|
|
||||||
if (ys->ys_argument && strcmp(argument, ys->ys_argument) == 0)
|
|
||||||
ysmatch = ys;
|
|
||||||
if (ysmatch)
|
|
||||||
goto match;
|
|
||||||
break;
|
|
||||||
case YC_DATANODE:
|
|
||||||
case YC_DATADEFINITION:
|
|
||||||
if (argument == NULL)
|
|
||||||
ysmatch = ys;
|
|
||||||
else
|
|
||||||
if (ys->ys_argument && strcmp(argument, ys->ys_argument) == 0)
|
|
||||||
ysmatch = ys;
|
|
||||||
if (ysmatch)
|
|
||||||
goto match;
|
|
||||||
break;
|
|
||||||
case YC_SCHEMANODE:
|
|
||||||
if (ys->ys_keyword == Y_CHOICE){ /* Look for its children */
|
|
||||||
for (j=0; j<ys->ys_len; j++){
|
|
||||||
yc = ys->ys_stmt[j];
|
|
||||||
if (yc->ys_keyword == Y_CASE) /* Look for its children */
|
|
||||||
ysmatch = yang_find_class((yang_node*)yc, argument, class);
|
|
||||||
else{
|
|
||||||
if (yang_schemanode(yc)){
|
|
||||||
if (argument == NULL)
|
|
||||||
ysmatch = yc;
|
|
||||||
else
|
|
||||||
if (yc->ys_argument && strcmp(argument, yc->ys_argument) == 0)
|
|
||||||
ysmatch = yc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ysmatch)
|
|
||||||
goto match;
|
|
||||||
}
|
|
||||||
} /* Y_CHOICE */
|
|
||||||
else{
|
|
||||||
if (argument == NULL)
|
|
||||||
ysmatch = ys;
|
|
||||||
else
|
|
||||||
if (ys->ys_argument && strcmp(argument, ys->ys_argument) == 0)
|
|
||||||
ysmatch = ys;
|
|
||||||
if (ysmatch)
|
|
||||||
goto match;
|
|
||||||
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
} /* switch */
|
|
||||||
} /* for */
|
|
||||||
match:
|
|
||||||
return ysmatch;
|
|
||||||
}
|
|
||||||
#endif /* NOTYET */
|
|
||||||
|
|
||||||
/*! Find child data node with matching argument (container, leaf, etc)
|
/*! Find child data node with matching argument (container, leaf, etc)
|
||||||
*
|
*
|
||||||
|
|
@ -658,69 +570,6 @@ yang_find_schemanode(yang_node *yn,
|
||||||
return ysmatch;
|
return ysmatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Find first matching data node in all modules in a yang spec (prefixes)
|
|
||||||
*
|
|
||||||
* @param[in] ysp Yang specification
|
|
||||||
* @param[in] nodeid Name of node. If NULL match first
|
|
||||||
* @param[in] class See yang_class for class of yang nodes
|
|
||||||
* A yang specification has modules as children which in turn can have
|
|
||||||
* syntax-nodes as children. This function goes through all the modules to
|
|
||||||
* look for nodes. Note that if a child to a module is a choice,
|
|
||||||
* the search is made recursively made to the choice's children.
|
|
||||||
* @note works for import prefix, but not work for generic XML parsing where
|
|
||||||
* xmlns and xmlns:ns are used.
|
|
||||||
* @see yang_find_top_ns
|
|
||||||
*/
|
|
||||||
yang_stmt *
|
|
||||||
yang_find_topnode(yang_spec *ysp,
|
|
||||||
char *nodeid,
|
|
||||||
yang_class class)
|
|
||||||
{
|
|
||||||
yang_stmt *ymod = NULL; /* module */
|
|
||||||
yang_stmt *yres = NULL; /* result */
|
|
||||||
char *prefix = NULL;
|
|
||||||
char *id = NULL;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (yang_nodeid_split(nodeid, &prefix, &id) < 0)
|
|
||||||
goto done;
|
|
||||||
if (prefix){
|
|
||||||
if ((ymod = yang_find((yang_node*)ysp, Y_MODULE, prefix)) != NULL ||
|
|
||||||
(ymod = yang_find((yang_node*)ysp, Y_SUBMODULE, prefix)) != NULL){
|
|
||||||
if ((yres = yang_find((yang_node*)ymod, 0, id)) != NULL)
|
|
||||||
goto ok;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else /* No prefix given - loop through and find first */
|
|
||||||
for (i=0; i<ysp->yp_len; i++){
|
|
||||||
ymod = ysp->yp_stmt[i];
|
|
||||||
switch (class){
|
|
||||||
case YC_NONE:
|
|
||||||
if ((yres = yang_find((yang_node*)ymod, 0, id)) != NULL)
|
|
||||||
goto ok;
|
|
||||||
break;
|
|
||||||
case YC_DATANODE:
|
|
||||||
if ((yres = yang_find_datanode((yang_node*)ymod, id)) != NULL)
|
|
||||||
goto ok;
|
|
||||||
break;
|
|
||||||
case YC_SCHEMANODE:
|
|
||||||
if ((yres = yang_find_schemanode((yang_node*)ymod, id)) != NULL)
|
|
||||||
goto ok;
|
|
||||||
break;
|
|
||||||
case YC_DATADEFINITION:
|
|
||||||
break; /* nyi */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ok:
|
|
||||||
done:
|
|
||||||
if (prefix)
|
|
||||||
free(prefix);
|
|
||||||
if (id)
|
|
||||||
free(id);
|
|
||||||
return yres;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Given a yang statement, find the prefix associated to this module
|
/*! Given a yang statement, find the prefix associated to this module
|
||||||
* @param[in] ys Yang statement in module tree (or module itself)
|
* @param[in] ys Yang statement in module tree (or module itself)
|
||||||
* @retval NULL Not found
|
* @retval NULL Not found
|
||||||
|
|
@ -775,7 +624,6 @@ yang_find_mynamespace(yang_stmt *ys)
|
||||||
return namespace;
|
return namespace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Find matching y in yp:s children, return 0 and index or -1 if not found.
|
/*! Find matching y in yp:s children, return 0 and index or -1 if not found.
|
||||||
* @retval 0 not found
|
* @retval 0 not found
|
||||||
* @retval 1 found
|
* @retval 1 found
|
||||||
|
|
@ -972,60 +820,15 @@ yarg_prefix(yang_stmt *ys)
|
||||||
return prefix;
|
return prefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Split yang node identifier into prefix and identifer.
|
/*! Given a yang statement and a prefix, return yang module to that relative prefix
|
||||||
* @param[in] node-id
|
|
||||||
* @param[out] prefix Malloced string. May be NULL.
|
|
||||||
* @param[out] id Malloced identifier.
|
|
||||||
* @retval 0 OK
|
|
||||||
* @retval -1 Error
|
|
||||||
* @code
|
|
||||||
* char *prefix = NULL;
|
|
||||||
* char *id = NULL;
|
|
||||||
* if (yang_nodeid_split(nodeid, &prefix, &id) < 0)
|
|
||||||
* goto done;
|
|
||||||
* if (prefix)
|
|
||||||
* free(prefix);
|
|
||||||
* if (id)
|
|
||||||
* free(id);
|
|
||||||
* @note caller need to free id and prefix after use
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
yang_nodeid_split(char *nodeid,
|
|
||||||
char **prefix,
|
|
||||||
char **id)
|
|
||||||
{
|
|
||||||
int retval = -1;
|
|
||||||
char *str;
|
|
||||||
|
|
||||||
if ((str = strchr(nodeid, ':')) == NULL){
|
|
||||||
if ((*id = strdup(nodeid)) == NULL){
|
|
||||||
clicon_err(OE_YANG, errno, "strdup");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
if ((*prefix = strdup(nodeid)) == NULL){
|
|
||||||
clicon_err(OE_YANG, errno, "strdup");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
(*prefix)[str-nodeid] = '\0';
|
|
||||||
str++;
|
|
||||||
if ((*id = strdup(str)) == NULL){
|
|
||||||
clicon_err(OE_YANG, errno, "strdup");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Given a yang statement and a prefix, return yang module to that prefix
|
|
||||||
* Note, not the other module but the proxy import statement only
|
* Note, not the other module but the proxy import statement only
|
||||||
* @param[in] ys A yang statement
|
* @param[in] ys A yang statement
|
||||||
* @param[in] prefix prefix
|
* @param[in] prefix prefix
|
||||||
* @retval ymod Yang module statement if found
|
* @retval ymod Yang module statement if found
|
||||||
* @retval NULL not found
|
* @retval NULL not found
|
||||||
|
* @node Prefixes are relative to the module they are defined
|
||||||
|
* @see yang_find_module_by_name
|
||||||
|
* @see yang_find_module_by_namespace
|
||||||
*/
|
*/
|
||||||
yang_stmt *
|
yang_stmt *
|
||||||
yang_find_module_by_prefix(yang_stmt *ys,
|
yang_find_module_by_prefix(yang_stmt *ys,
|
||||||
|
|
@ -1081,12 +884,14 @@ yang_find_module_by_prefix(yang_stmt *ys,
|
||||||
return ymod;
|
return ymod;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Given a yang statement and a namespace, return yang module
|
/*! Given a yang spec and a namespace, return yang module
|
||||||
*
|
*
|
||||||
* @param[in] yspec A yang specification
|
* @param[in] yspec A yang specification
|
||||||
* @param[in] namespace namespace
|
* @param[in] namespace namespace
|
||||||
* @retval ymod Yang module statement if found
|
* @retval ymod Yang module statement if found
|
||||||
* @retval NULL not found
|
* @retval NULL not found
|
||||||
|
* @see yang_find_module_by_name
|
||||||
|
* @see yang_find_module_by_prefix module-specific prefix
|
||||||
*/
|
*/
|
||||||
yang_stmt *
|
yang_stmt *
|
||||||
yang_find_module_by_namespace(yang_spec *yspec,
|
yang_find_module_by_namespace(yang_spec *yspec,
|
||||||
|
|
@ -1104,6 +909,28 @@ yang_find_module_by_namespace(yang_spec *yspec,
|
||||||
return ymod;
|
return ymod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Given a yang spec and a module name, return yang module
|
||||||
|
*
|
||||||
|
* @param[in] yspec A yang specification
|
||||||
|
* @param[in] name Name of module
|
||||||
|
* @retval ymod Yang module statement if found
|
||||||
|
* @retval NULL not found
|
||||||
|
* @see yang_find_module_by_namespace
|
||||||
|
* @see yang_find_module_by_prefix module-specific prefix
|
||||||
|
*/
|
||||||
|
yang_stmt *
|
||||||
|
yang_find_module_by_name(yang_spec *yspec,
|
||||||
|
char *name)
|
||||||
|
{
|
||||||
|
yang_stmt *ymod = NULL;
|
||||||
|
|
||||||
|
while ((ymod = yn_each((yang_node*)yspec, ymod)) != NULL)
|
||||||
|
if ((ymod->ys_keyword == Y_MODULE || ymod->ys_keyword == Y_SUBMODULE) &&
|
||||||
|
strcmp(ymod->ys_argument, name)==0)
|
||||||
|
return ymod;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*! string is quoted if it contains space or tab, needs double '' */
|
/*! string is quoted if it contains space or tab, needs double '' */
|
||||||
static int inline
|
static int inline
|
||||||
quotedstring(char *s)
|
quotedstring(char *s)
|
||||||
|
|
@ -1541,7 +1368,7 @@ ys_populate_feature(clicon_handle h,
|
||||||
if (strcmp(xml_name(xc), "CLICON_FEATURE") != 0)
|
if (strcmp(xml_name(xc), "CLICON_FEATURE") != 0)
|
||||||
continue;
|
continue;
|
||||||
/* get m and f from configuration feature rules */
|
/* get m and f from configuration feature rules */
|
||||||
if (yang_nodeid_split(xml_body(xc), &m, &f) < 0)
|
if (nodeid_split(xml_body(xc), &m, &f) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (m && f &&
|
if (m && f &&
|
||||||
(strcmp(m,"*")==0 ||
|
(strcmp(m,"*")==0 ||
|
||||||
|
|
@ -1558,7 +1385,8 @@ ys_populate_feature(clicon_handle h,
|
||||||
}
|
}
|
||||||
cv_name_set(cv, feature);
|
cv_name_set(cv, feature);
|
||||||
cv_bool_set(cv, found);
|
cv_bool_set(cv, found);
|
||||||
clicon_debug(1, "%s %s:%s %d", __FUNCTION__, module, feature, found);
|
if (found)
|
||||||
|
clicon_debug(1, "%s %s:%s", __FUNCTION__, module, feature);
|
||||||
ys->ys_cv = cv;
|
ys->ys_cv = cv;
|
||||||
ok:
|
ok:
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
@ -1936,7 +1764,7 @@ yang_parse_str(char *str,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Parse yang spec from an open file descriptor
|
/*! Parse yang spec from an open file descriptor
|
||||||
* @param[in] fd File descriptor containing the YANG file as ASCII characters
|
* @param[in] fd File descriptor containing the YANG file as ASCII characters
|
||||||
* @param[in] name For debug, eg filename
|
* @param[in] name For debug, eg filename
|
||||||
* @param[in] ysp Yang specification. Should have 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
|
||||||
|
|
@ -2083,7 +1911,7 @@ yang_parse_filename(const char *filename,
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
// clicon_debug(1, "%s %s", __FUNCTION__, filename);
|
clicon_debug(1, "%s %s", __FUNCTION__, filename);
|
||||||
if (stat(filename, &st) < 0){
|
if (stat(filename, &st) < 0){
|
||||||
clicon_err(OE_YANG, errno, "%s not found", filename);
|
clicon_err(OE_YANG, errno, "%s not found", filename);
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -2258,7 +2086,7 @@ yang_features(clicon_handle h,
|
||||||
while (i<yt->ys_len){ /* Note, children may be removed */
|
while (i<yt->ys_len){ /* Note, children may be removed */
|
||||||
ys = yt->ys_stmt[i];
|
ys = yt->ys_stmt[i];
|
||||||
if (ys->ys_keyword == Y_IF_FEATURE){
|
if (ys->ys_keyword == Y_IF_FEATURE){
|
||||||
if (yang_nodeid_split(ys->ys_argument, &prefix, &feature) < 0)
|
if (nodeid_split(ys->ys_argument, &prefix, &feature) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Specifically need to handle? strcmp(prefix, myprefix)) */
|
/* Specifically need to handle? strcmp(prefix, myprefix)) */
|
||||||
if (prefix == NULL)
|
if (prefix == NULL)
|
||||||
|
|
@ -2680,7 +2508,6 @@ yang_abs_schema_nodeid(yang_spec *yspec,
|
||||||
char *id;
|
char *id;
|
||||||
char *prefix = NULL;
|
char *prefix = NULL;
|
||||||
yang_stmt *yprefix;
|
yang_stmt *yprefix;
|
||||||
yang_stmt *ys;
|
|
||||||
|
|
||||||
/* check absolute schema_nodeid */
|
/* check absolute schema_nodeid */
|
||||||
if (schema_nodeid[0] != '/'){
|
if (schema_nodeid[0] != '/'){
|
||||||
|
|
@ -2719,21 +2546,6 @@ yang_abs_schema_nodeid(yang_spec *yspec,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ymod == NULL){ /* Try find id from topnode without prefix XXX remove?*/
|
|
||||||
if ((ys = yang_find_topnode(yspec, id, YC_SCHEMANODE)) == NULL){
|
|
||||||
clicon_err(OE_YANG, 0, "Module with id:\"%s:%s\" not found", prefix,id);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if ((ymod = ys_module(ys)) == NULL){
|
|
||||||
clicon_err(OE_YANG, 0, "Module with id:%s:%s not found2", prefix,id);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if ((yprefix = yang_find((yang_node*)ymod, Y_PREFIX, NULL)) != NULL &&
|
|
||||||
strcmp(yprefix->ys_argument, prefix) != 0){
|
|
||||||
clicon_err(OE_YANG, 0, "Module with id:\"%s:%s\" not found", prefix,id);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (schema_nodeid_vec((yang_node*)ymod, vec+1, nvec-1, keyword, yres) < 0)
|
if (schema_nodeid_vec((yang_node*)ymod, vec+1, nvec-1, keyword, yres) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
ok: /* yres may not be set */
|
ok: /* yres may not be set */
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@
|
||||||
int
|
int
|
||||||
yang_modules_init(clicon_handle h)
|
yang_modules_init(clicon_handle h)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
yang_spec *yspec;
|
yang_spec *yspec;
|
||||||
|
|
||||||
yspec = clicon_dbspec_yang(h);
|
yspec = clicon_dbspec_yang(h);
|
||||||
|
|
@ -203,7 +203,7 @@ yang_modules_state_get(clicon_handle h,
|
||||||
cprintf(cb,"<namespace>%s</namespace>", ys->ys_argument);
|
cprintf(cb,"<namespace>%s</namespace>", ys->ys_argument);
|
||||||
else
|
else
|
||||||
cprintf(cb,"<namespace></namespace>");
|
cprintf(cb,"<namespace></namespace>");
|
||||||
cprintf(cb, "<conformance-type>implement</conformance-type>");
|
/* This follows order in rfc 7895: feature, conformance-type, submodules */
|
||||||
yc = NULL;
|
yc = NULL;
|
||||||
while ((yc = yn_each((yang_node*)ymod, yc)) != NULL) {
|
while ((yc = yn_each((yang_node*)ymod, yc)) != NULL) {
|
||||||
switch(yc->ys_keyword){
|
switch(yc->ys_keyword){
|
||||||
|
|
@ -211,6 +211,14 @@ yang_modules_state_get(clicon_handle h,
|
||||||
if (yc->ys_cv && cv_bool_get(yc->ys_cv))
|
if (yc->ys_cv && cv_bool_get(yc->ys_cv))
|
||||||
cprintf(cb,"<feature>%s</feature>", yc->ys_argument);
|
cprintf(cb,"<feature>%s</feature>", yc->ys_argument);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cprintf(cb, "<conformance-type>implement</conformance-type>");
|
||||||
|
yc = NULL;
|
||||||
|
while ((yc = yn_each((yang_node*)ymod, yc)) != NULL) {
|
||||||
|
switch(yc->ys_keyword){
|
||||||
case Y_SUBMODULE:
|
case Y_SUBMODULE:
|
||||||
cprintf(cb,"<submodule>");
|
cprintf(cb,"<submodule>");
|
||||||
cprintf(cb,"<name>%s</name>", yc->ys_argument);
|
cprintf(cb,"<name>%s</name>", yc->ys_argument);
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ if [ $err -eq 0 ]; then
|
||||||
else
|
else
|
||||||
echo -e "\e[31mError"
|
echo -e "\e[31mError"
|
||||||
echo -ne "\e[0m"
|
echo -ne "\e[0m"
|
||||||
|
exit -1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ expectfn "$clixon_cli -1 -f $cfg delete interfaces" 0 "^$"
|
||||||
new "cli show configuration delete top"
|
new "cli show configuration delete top"
|
||||||
expectfn "$clixon_cli -1 -f $cfg show conf cli" 0 "^$"
|
expectfn "$clixon_cli -1 -f $cfg show conf cli" 0 "^$"
|
||||||
|
|
||||||
new "cli configure"
|
new "cli configure set interfaces"
|
||||||
expectfn "$clixon_cli -1 -f $cfg set interfaces interface eth/0/0" 0 "^$"
|
expectfn "$clixon_cli -1 -f $cfg set interfaces interface eth/0/0" 0 "^$"
|
||||||
|
|
||||||
new "cli show configuration"
|
new "cli show configuration"
|
||||||
|
|
|
||||||
116
test/test_compat.sh
Executable file
116
test/test_compat.sh
Executable file
|
|
@ -0,0 +1,116 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Test of backward compatibility
|
||||||
|
# 1) Load <3.9 startup/running/extra files without namespaces - ensure it returns namespaces
|
||||||
|
#
|
||||||
|
|
||||||
|
APPNAME=example
|
||||||
|
# include err() and new() functions and creates $dir
|
||||||
|
. ./lib.sh
|
||||||
|
cfg=$dir/conf_startup.xml
|
||||||
|
|
||||||
|
cat <<EOF > $cfg
|
||||||
|
<config>
|
||||||
|
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
|
||||||
|
<CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
|
||||||
|
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
|
||||||
|
<CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN>
|
||||||
|
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
|
||||||
|
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
|
||||||
|
<CLICON_NETCONF_DIR>/usr/local/lib/$APPNAME/netconf</CLICON_NETCONF_DIR>
|
||||||
|
<CLICON_RESTCONF_DIR>/usr/local/lib/$APPNAME/restconf</CLICON_RESTCONF_DIR>
|
||||||
|
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
|
||||||
|
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
|
||||||
|
<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>
|
||||||
|
<CLICON_CLI_LINESCROLLING>0</CLICON_CLI_LINESCROLLING>
|
||||||
|
<CLICON_STARTUP_MODE>init</CLICON_STARTUP_MODE>
|
||||||
|
<CLICON_XML_SORT>true</CLICON_XML_SORT>
|
||||||
|
</config>
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
|
||||||
|
run(){
|
||||||
|
mode=$1
|
||||||
|
expect=$2
|
||||||
|
|
||||||
|
dbdir=$dir/db
|
||||||
|
cat <<EOF > $dbdir
|
||||||
|
<config>
|
||||||
|
<interfaces>
|
||||||
|
<interface>
|
||||||
|
<name>run</name>
|
||||||
|
<type>ex:eth</type>
|
||||||
|
</interface>
|
||||||
|
</interfaces>
|
||||||
|
</config>
|
||||||
|
EOF
|
||||||
|
sudo mv $dbdir /usr/local/var/$APPNAME/running_db
|
||||||
|
|
||||||
|
cat <<EOF > $dbdir
|
||||||
|
<config>
|
||||||
|
<interfaces>
|
||||||
|
<interface>
|
||||||
|
<name>startup</name>
|
||||||
|
<type>ex:eth</type>
|
||||||
|
</interface>
|
||||||
|
</interfaces>
|
||||||
|
</config>
|
||||||
|
EOF
|
||||||
|
sudo mv $dbdir /usr/local/var/$APPNAME/startup_db
|
||||||
|
|
||||||
|
cat <<EOF > $dir/config
|
||||||
|
<config>
|
||||||
|
<interfaces>
|
||||||
|
<interface>
|
||||||
|
<name>extra</name>
|
||||||
|
<type>ex:eth</type>
|
||||||
|
</interface>
|
||||||
|
</interfaces>
|
||||||
|
</config>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
new "test params: -f $cfg -s $mode -c $dir/config"
|
||||||
|
|
||||||
|
if [ $BE -ne 0 ]; then
|
||||||
|
new "kill old backend"
|
||||||
|
sudo clixon_backend -zf $cfg
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
err
|
||||||
|
fi
|
||||||
|
|
||||||
|
new "start backend -f $cfg -s $mode -c $dir/config"
|
||||||
|
sudo $clixon_backend -f $cfg -s $mode -c $dir/config
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
err
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
new "Check $mode"
|
||||||
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><running/></source></get-config></rpc>]]>]]>' "^<rpc-reply>$expect</rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
if [ $BE -eq 0 ]; then
|
||||||
|
exit # BE
|
||||||
|
fi
|
||||||
|
|
||||||
|
new "Kill backend"
|
||||||
|
# Check if premature kill
|
||||||
|
pid=`pgrep -u root -f clixon_backend`
|
||||||
|
if [ -z "$pid" ]; then
|
||||||
|
err "backend already dead"
|
||||||
|
fi
|
||||||
|
# kill backend
|
||||||
|
sudo clixon_backend -z -f $cfg
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
err "kill backend"
|
||||||
|
fi
|
||||||
|
|
||||||
|
} # run
|
||||||
|
|
||||||
|
run running '<data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>extra</name><type>ex:eth</type><enabled>true</enabled></interface><interface><name>lo</name><type>ex:loopback</type><enabled>true</enabled></interface><interface><name>run</name><type>ex:eth</type><enabled>true</enabled></interface></interfaces></data>'
|
||||||
|
run startup '<data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>extra</name><type>ex:eth</type><enabled>true</enabled></interface><interface><name>lo</name><type>ex:loopback</type><enabled>true</enabled></interface><interface><name>startup</name><type>ex:eth</type><enabled>true</enabled></interface></interfaces></data>'
|
||||||
|
|
||||||
|
rm -rf $dir
|
||||||
|
|
@ -50,9 +50,6 @@ EOF
|
||||||
|
|
||||||
xml='<config><x xmlns="urn:example:clixon"><y><a>1</a><b>2</b><c>first-entry</c></y><y><a>1</a><b>3</b><c>second-entry</c></y><y><a>2</a><b>3</b><c>third-entry</c></y><d/><f><e>a</e><e>b</e><e>c</e></f><g>astring</g></x></config>'
|
xml='<config><x xmlns="urn:example:clixon"><y><a>1</a><b>2</b><c>first-entry</c></y><y><a>1</a><b>3</b><c>second-entry</c></y><y><a>2</a><b>3</b><c>third-entry</c></y><d/><f><e>a</e><e>b</e><e>c</e></f><g>astring</g></x></config>'
|
||||||
|
|
||||||
# Without xmlns
|
|
||||||
xmlxxx='<config><x><y><a>1</a><b>2</b><c>first-entry</c></y><y><a>1</a><b>3</b><c>second-entry</c></y><y><a>2</a><b>3</b><c>third-entry</c></y><d/><f><e>a</e><e>b</e><e>c</e></f><g>astring</g></x></config>'
|
|
||||||
|
|
||||||
run(){
|
run(){
|
||||||
name=$1
|
name=$1
|
||||||
mydir=$dir/$name
|
mydir=$dir/$name
|
||||||
|
|
@ -72,7 +69,7 @@ run(){
|
||||||
expectmatch "$ret" $? "0" ""
|
expectmatch "$ret" $? "0" ""
|
||||||
|
|
||||||
new "datastore $name get"
|
new "datastore $name get"
|
||||||
expectfn "$datastore $conf get /" 0 "^$xmlxxx$"
|
expectfn "$datastore $conf get /" 0 "^$xml$"
|
||||||
|
|
||||||
new "datastore $name put all remove"
|
new "datastore $name put all remove"
|
||||||
expectfn "$datastore $conf put remove <config/>" 0 ""
|
expectfn "$datastore $conf put remove <config/>" 0 ""
|
||||||
|
|
@ -87,7 +84,7 @@ run(){
|
||||||
# expectfn "$datastore $conf put merge $xml" 0 ""
|
# expectfn "$datastore $conf put merge $xml" 0 ""
|
||||||
|
|
||||||
new "datastore $name get"
|
new "datastore $name get"
|
||||||
expectfn "$datastore $conf get /" 0 "^$xmlxxx$"
|
expectfn "$datastore $conf get /" 0 "^$xml$"
|
||||||
|
|
||||||
new "datastore $name put all delete"
|
new "datastore $name put all delete"
|
||||||
expectfn "$datastore $conf put remove <config/>" 0 ""
|
expectfn "$datastore $conf put remove <config/>" 0 ""
|
||||||
|
|
@ -100,7 +97,7 @@ run(){
|
||||||
expectmatch "$ret" $? "0" ""
|
expectmatch "$ret" $? "0" ""
|
||||||
|
|
||||||
new "datastore $name get"
|
new "datastore $name get"
|
||||||
expectfn "$datastore $conf get /" 0 "^$xmlxxx$"
|
expectfn "$datastore $conf get /" 0 "^$xml$"
|
||||||
|
|
||||||
new "datastore $name put top create"
|
new "datastore $name put top create"
|
||||||
expectfn "$datastore $conf put create <config><x/></config>" 0 "" # error
|
expectfn "$datastore $conf put create <config><x/></config>" 0 "" # error
|
||||||
|
|
|
||||||
|
|
@ -90,13 +90,13 @@ new "netconf discard-changes"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf enabled feature"
|
new "netconf enabled feature"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><x>foo</x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon">foo</x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf validate enabled feature"
|
new "netconf validate enabled feature"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf disabled feature"
|
new "netconf disabled feature"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><A>foo</A></config></edit-config></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>Validation failed</error-message></rpc-error></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><y xmlns="urn:example:clixon">foo</y></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>y</bad-element></error-info><error-severity>error</error-severity><error-message>Unassigned yang spec</error-message></rpc-error></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
# This test has been broken up into all different modules instead of one large
|
# This test has been broken up into all different modules instead of one large
|
||||||
# reply since the modules change so often
|
# reply since the modules change so often
|
||||||
|
|
@ -105,6 +105,13 @@ ret=$($clixon_netconf -qf $cfg -y $fyang<<EOF
|
||||||
<rpc><get><filter type="xpath" select="modules-state/module" xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library"/></get></rpc>]]>]]>
|
<rpc><get><filter type="xpath" select="modules-state/module" xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library"/></get></rpc>]]>]]>
|
||||||
EOF
|
EOF
|
||||||
)
|
)
|
||||||
|
new "netconf modules-state header"
|
||||||
|
expect='^<rpc-reply><data><modules-state xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library"><module><name>'
|
||||||
|
match=`echo "$ret" | grep -GZo "$expect"`
|
||||||
|
if [ -z "$match" ]; then
|
||||||
|
err "$expect" "$ret"
|
||||||
|
fi
|
||||||
|
|
||||||
new "netconf module A"
|
new "netconf module A"
|
||||||
expect="<module><name>example</name><revision/><namespace>urn:example:clixon</namespace><feature>A</feature><conformance-type>implement</conformance-type></module>"
|
expect="<module><name>example</name><revision/><namespace>urn:example:clixon</namespace><feature>A</feature><conformance-type>implement</conformance-type></module>"
|
||||||
match=`echo "$ret" | grep -GZo "$expect"`
|
match=`echo "$ret" | grep -GZo "$expect"`
|
||||||
|
|
@ -135,8 +142,9 @@ if [ -z "$match" ]; then
|
||||||
err "$expect" "$ret"
|
err "$expect" "$ret"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Note order of features in ietf-netconf yang is alphabetically: candidate, startup, validate, xpath
|
||||||
new "netconf module ietf-netconf"
|
new "netconf module ietf-netconf"
|
||||||
expect="module><name>ietf-netconf</name><revision>2011-06-01</revision><namespace>urn:ietf:params:xml:ns:netconf:base:1.0</namespace><feature>candidate</feature><feature>startup</feature><feature>validate</feature><feature>xpath</feature><conformance-type>implement</conformance-type></module>"
|
expect="<module><name>ietf-netconf</name><revision>2011-06-01</revision><namespace>urn:ietf:params:xml:ns:netconf:base:1.0</namespace><feature>candidate</feature><feature>startup</feature><feature>validate</feature><feature>xpath</feature><conformance-type>implement</conformance-type></module>"
|
||||||
match=`echo "$ret" | grep -GZo "$expect"`
|
match=`echo "$ret" | grep -GZo "$expect"`
|
||||||
if [ -z "$match" ]; then
|
if [ -z "$match" ]; then
|
||||||
err "$expect" "$ret"
|
err "$expect" "$ret"
|
||||||
|
|
|
||||||
|
|
@ -122,44 +122,44 @@ if [ $BE -ne 0 ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new "Set crypto to aes"
|
new "Set crypto to aes"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><edit-config><target><candidate/></target><config><crypto>aes</crypto></config></edit-config></rpc>]]>]]>' '^<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><ok/></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><edit-config><target><candidate/></target><config><crypto xmlns="urn:example:my-crypto">aes</crypto></config></edit-config></rpc>]]>]]>' '^<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "netconf validate "
|
new "netconf validate "
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "Set crypto to mc:aes"
|
new "Set crypto to mc:aes"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><crypto>mc:aes</crypto></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><crypto xmlns="urn:example:my-crypto">mc:aes</crypto></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf validate"
|
new "netconf validate"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "Set crypto to des:des3"
|
new "Set crypto to des:des3"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><crypto>des:des3</crypto></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><crypto xmlns="urn:example:my-crypto">des:des3</crypto></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf validate"
|
new "netconf validate"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "Set crypto to mc:foo"
|
new "Set crypto to mc:foo"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><crypto>mc:foo</crypto></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><crypto xmlns="urn:example:my-crypto">mc:foo</crypto></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf validate"
|
new "netconf validate"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "Set crypto to des:des3 using xmlns"
|
new "Set crypto to des:des3 using xmlns"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><crypto xmlns:des=\"urn:example:des\">des:des3</crypto></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><crypto xmlns="urn:example:my-crypto" xmlns:des="urn:example:des">des:des3</crypto></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf validate"
|
new "netconf validate"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
# XXX this is not supported
|
# XXX this is not supported
|
||||||
#new "Set crypto to x:des3 using xmlns"
|
#new "Set crypto to x:des3 using xmlns"
|
||||||
#expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><crypto xmlns:x=\"urn:example:des\">x:des3</crypto></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
#expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><crypto xmlns="urn:example:my-crypto" xmlns:x="urn:example:des">x:des3</crypto></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
#new "netconf validate"
|
new "netconf validate"
|
||||||
#expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "Set crypto to foo:bar"
|
new "Set crypto to foo:bar"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><crypto>foo:bar</crypto></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><crypto xmlns="urn:example:my-crypto">foo:bar</crypto></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf validate"
|
new "netconf validate"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>Identityref validation failed, foo:bar not derived from crypto-alg</error-message></rpc-error></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>Identityref validation failed, foo:bar not derived from crypto-alg</error-message></rpc-error></rpc-reply>]]>]]>$"
|
||||||
|
|
|
||||||
|
|
@ -88,22 +88,19 @@ if [ $BE -ne 0 ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new "leafref base config"
|
new "leafref base config"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><interfaces>
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth0</name><type>ex:eth</type> <ipv4><address><ip>192.0.2.1</ip></address><address><ip>192.0.2.2</ip></address></ipv4></interface><interface><name>lo</name><type>ex:lo</type><ipv4><address><ip>127.0.0.1</ip></address></ipv4></interface></interfaces></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
<interface><name>eth0</name><type>ex:eth</type> <ipv4><address><ip>192.0.2.1</ip></address><address><ip>192.0.2.2</ip></address></ipv4></interface>
|
|
||||||
<interface><name>lo</name><type>ex:lo</type><ipv4><address><ip>127.0.0.1</ip></address></ipv4></interface>
|
|
||||||
</interfaces></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
|
||||||
|
|
||||||
new "leafref get config"
|
new "leafref get config"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply><data><interfaces><interface><name>eth0</name>'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth0</name>'
|
||||||
|
|
||||||
new "leafref base commit"
|
new "leafref base commit"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "leafref get config"
|
new "leafref get config"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply><data><interfaces><interface><name>eth0</name>'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth0</name>'
|
||||||
|
|
||||||
new "leafref add wrong ref"
|
new "leafref add wrong ref"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><default-address><absname>eth3</absname><address>10.0.4.6</address></default-address></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><default-address xmlns="urn:example:clixon"><absname>eth3</absname><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 $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>eth3</bad-element></error-info><error-severity>error</error-severity><error-message>Leafref validation failed: No such leaf</error-message></rpc-error></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>eth3</bad-element></error-info><error-severity>error</error-severity><error-message>Leafref validation failed: No such leaf</error-message></rpc-error></rpc-reply>]]>]]>$'
|
||||||
|
|
@ -112,10 +109,10 @@ new "leafref discard-changes"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "leafref add correct absref"
|
new "leafref add correct absref"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><default-address><absname>eth0</absname></default-address></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><default-address xmlns="urn:example:clixon"><absname>eth0</absname></default-address></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "leafref add correct relref"
|
new "leafref add correct relref"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><default-address><relname>eth0</relname></default-address></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><default-address xmlns="urn:example:clixon"><relname>eth0</relname></default-address></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
# XXX add address
|
# XXX add address
|
||||||
|
|
||||||
|
|
@ -123,7 +120,7 @@ new "leafref validate (ok)"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>"
|
||||||
|
|
||||||
new "leafref delete leaf"
|
new "leafref delete leaf"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><interfaces><interface operation=\"delete\"><name>eth0</name></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 xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface operation="delete"><name>eth0</name></interface></interfaces></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>'
|
||||||
|
|
||||||
new "leafref validate (should fail)"
|
new "leafref validate (should fail)"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>eth0</bad-element></error-info><error-severity>error</error-severity><error-message>Leafref validation failed: No such leaf</error-message></rpc-error></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>eth0</bad-element></error-info><error-severity>error</error-severity><error-message>Leafref validation failed: No such leaf</error-message></rpc-error></rpc-reply>]]>]]>$'
|
||||||
|
|
|
||||||
|
|
@ -81,19 +81,19 @@ if [ $BE -ne 0 ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new "minmax: minimal"
|
new "minmax: minimal"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><c><a1><k>0</k></a1><b1>0</b1></c></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><c xmlns="urn:example:clixon"><a1><k>0</k></a1><b1>0</b1></c></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "minmax: minimal validate ok"
|
new "minmax: minimal validate ok"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "minmax: maximal"
|
new "minmax: maximal"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><c><a0><k>0</k></a0><a0><k>1</k></a0><a0><k>unbounded</k></a0><a1><k>0</k></a1><a1><k>1</k></a1><b0>0</b0><b0>1</b0><b0>unbounded</b0><b1>0</b1><b0>1</b0></c></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><c xmlns="urn:example:clixon"><a0><k>0</k></a0><a0><k>1</k></a0><a0><k>unbounded</k></a0><a1><k>0</k></a1><a1><k>1</k></a1><b0>0</b0><b0>1</b0><b0>unbounded</b0><b1>0</b1><b0>1</b0></c></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "minmax: validate ok"
|
new "minmax: validate ok"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "minmax: empty"
|
new "minmax: empty"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><c/></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><c xmlns="urn:example:clixon"/></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
# NYI
|
# NYI
|
||||||
if false; then
|
if false; then
|
||||||
|
|
@ -101,25 +101,25 @@ new "minmax: validate should fail"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "minmax: no list"
|
new "minmax: no list"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><c><b1>0</b1></c></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><c xmlns="urn:example:clixon"><b1>0</b1></c></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "minmax: validate should fail"
|
new "minmax: validate should fail"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "minmax: no leaf-list"
|
new "minmax: no leaf-list"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><c><a1><k>0</k></a1></c></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><c xmlns="urn:example:clixon"><a1><k>0</k></a1></c></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "minmax: validate should fail"
|
new "minmax: validate should fail"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "minmax: Too large list"
|
new "minmax: Too large list"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><c><a1><k>0</k></a1><a1><k>1</k></a1><a1><k>2</k></a1><b1>0</b1></c></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><c xmlns="urn:example:clixon"><a1><k>0</k></a1><a1><k>1</k></a1><a1><k>2</k></a1><b1>0</b1></c></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "minmax: validate should fail"
|
new "minmax: validate should fail"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "minmax: Too large leaf-list"
|
new "minmax: Too large leaf-list"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><c><a1><k>0</k></a1><b1>0</b1><b1>1</b1><b1>2</b1></c></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><c xmlns="urn:example:clixon"><a1><k>0</k></a1><b1>0</b1><b1>1</b1><b1>2</b1></c></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "minmax: validate should fail"
|
new "minmax: validate should fail"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error/></rpc-reply>]]>]]>$"
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ EOF
|
||||||
# The groups are slightly modified from RFC8341 A.1
|
# The groups are slightly modified from RFC8341 A.1
|
||||||
# The rule-list is from A.2
|
# The rule-list is from A.2
|
||||||
RULES=$(cat <<EOF
|
RULES=$(cat <<EOF
|
||||||
<nacm>
|
<nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm">
|
||||||
<enable-nacm>false</enable-nacm>
|
<enable-nacm>false</enable-nacm>
|
||||||
<read-default>deny</read-default>
|
<read-default>deny</read-default>
|
||||||
<write-default>deny</write-default>
|
<write-default>deny</write-default>
|
||||||
|
|
@ -99,7 +99,7 @@ RULES=$(cat <<EOF
|
||||||
$NADMIN
|
$NADMIN
|
||||||
|
|
||||||
</nacm>
|
</nacm>
|
||||||
<x>0</x>
|
<x xmlns="urn:example:clixon">0</x>
|
||||||
EOF
|
EOF
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -131,7 +131,7 @@ new "restconf DELETE whole datastore"
|
||||||
expecteq "$(curl -u andy:bar -sS -X DELETE http://localhost/restconf/data)" ""
|
expecteq "$(curl -u andy:bar -sS -X DELETE http://localhost/restconf/data)" ""
|
||||||
|
|
||||||
new2 "auth get"
|
new2 "auth get"
|
||||||
expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/x)" 'null
|
expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/example:x)" 'null
|
||||||
'
|
'
|
||||||
|
|
||||||
new "auth set authentication config"
|
new "auth set authentication config"
|
||||||
|
|
@ -147,33 +147,33 @@ new2 "auth get (wrong passwd: access denied)"
|
||||||
expecteq "$(curl -u andy:foo -sS -X GET http://localhost/restconf/data)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "The requested URL was unauthorized"}}}
'
|
expecteq "$(curl -u andy:foo -sS -X GET http://localhost/restconf/data)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "The requested URL was unauthorized"}}}
'
|
||||||
|
|
||||||
new2 "auth get (access)"
|
new2 "auth get (access)"
|
||||||
expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/x)" '{"x": 0}
|
expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/example:x)" '{"example:x": 0}
|
||||||
'
|
'
|
||||||
|
|
||||||
#----------------Enable NACM
|
#----------------Enable NACM
|
||||||
|
|
||||||
new "enable nacm"
|
new "enable nacm"
|
||||||
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"enable-nacm": true}' http://localhost/restconf/data/nacm/enable-nacm)" ""
|
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"ietf-netconf-acm:enable-nacm": true}' http://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" ""
|
||||||
|
|
||||||
new2 "admin get nacm"
|
new2 "admin get nacm"
|
||||||
expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/x)" '{"x": 0}
|
expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/example:x)" '{"example:x": 0}
|
||||||
'
|
'
|
||||||
|
|
||||||
new2 "limited get nacm"
|
new2 "limited get nacm"
|
||||||
expecteq "$(curl -u wilma:bar -sS -X GET http://localhost/restconf/data/x)" '{"x": 0}
|
expecteq "$(curl -u wilma:bar -sS -X GET http://localhost/restconf/data/example:x)" '{"example:x": 0}
|
||||||
'
|
'
|
||||||
|
|
||||||
new2 "guest get nacm"
|
new2 "guest get nacm"
|
||||||
expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/x)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "access denied"}}}
'
|
expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/example:x)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "access denied"}}}
'
|
||||||
|
|
||||||
new "admin edit nacm"
|
new "admin edit nacm"
|
||||||
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"x": 1}' http://localhost/restconf/data/x)" ""
|
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"example:x": 1}' http://localhost/restconf/data/example:x)" ""
|
||||||
|
|
||||||
new2 "limited edit nacm"
|
new2 "limited edit nacm"
|
||||||
expecteq "$(curl -u wilma:bar -sS -X PUT -d '{"x": 2}' http://localhost/restconf/data/x)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
expecteq "$(curl -u wilma:bar -sS -X PUT -d '{"example:x": 2}' http://localhost/restconf/data/example:x)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
||||||
|
|
||||||
new2 "guest edit nacm"
|
new2 "guest edit nacm"
|
||||||
expecteq "$(curl -u guest:bar -sS -X PUT -d '{"x": 3}' http://localhost/restconf/data/x)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "access denied"}}}
'
|
expecteq "$(curl -u guest:bar -sS -X PUT -d '{"example:x": 3}' http://localhost/restconf/data/example:x)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "access denied"}}}
'
|
||||||
|
|
||||||
new "Kill restconf daemon"
|
new "Kill restconf daemon"
|
||||||
sudo pkill -u www-data -f "/www-data/clixon_restconf"
|
sudo pkill -u www-data -f "/www-data/clixon_restconf"
|
||||||
|
|
|
||||||
|
|
@ -163,11 +163,11 @@ new "restconf DELETE whole datastore"
|
||||||
expecteq "$(curl -u andy:bar -sS -X DELETE http://localhost/restconf/data)" ""
|
expecteq "$(curl -u andy:bar -sS -X DELETE http://localhost/restconf/data)" ""
|
||||||
|
|
||||||
new2 "auth get"
|
new2 "auth get"
|
||||||
expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/state)" '{"state": {"op": "42"}}
|
expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/example:state)" '{"example:state": {"op": "42"}}
|
||||||
'
|
'
|
||||||
|
|
||||||
new "Set x to 0"
|
new "Set x to 0"
|
||||||
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"x": 0}' http://localhost/restconf/data/x)" ""
|
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"example:x": 0}' http://localhost/restconf/data/example:x)" ""
|
||||||
|
|
||||||
new2 "auth get (no user: access denied)"
|
new2 "auth get (no user: access denied)"
|
||||||
expecteq "$(curl -sS -X GET -H \"Accept:\ application/yang-data+json\" http://localhost/restconf/data)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "The requested URL was unauthorized"}}}
'
|
expecteq "$(curl -sS -X GET -H \"Accept:\ application/yang-data+json\" http://localhost/restconf/data)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "The requested URL was unauthorized"}}}
'
|
||||||
|
|
@ -176,28 +176,28 @@ new2 "auth get (wrong passwd: access denied)"
|
||||||
expecteq "$(curl -u andy:foo -sS -X GET http://localhost/restconf/data)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "The requested URL was unauthorized"}}}
'
|
expecteq "$(curl -u andy:foo -sS -X GET http://localhost/restconf/data)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "The requested URL was unauthorized"}}}
'
|
||||||
|
|
||||||
new2 "auth get (access)"
|
new2 "auth get (access)"
|
||||||
expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/x)" '{"x": 0}
|
expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/example:x)" '{"example:x": 0}
|
||||||
'
|
'
|
||||||
|
|
||||||
new2 "admin get nacm"
|
new2 "admin get nacm"
|
||||||
expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/x)" '{"x": 0}
|
expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/example:x)" '{"example:x": 0}
|
||||||
'
|
'
|
||||||
|
|
||||||
new2 "limited get nacm"
|
new2 "limited get nacm"
|
||||||
expecteq "$(curl -u wilma:bar -sS -X GET http://localhost/restconf/data/x)" '{"x": 0}
|
expecteq "$(curl -u wilma:bar -sS -X GET http://localhost/restconf/data/example:x)" '{"example:x": 0}
|
||||||
'
|
'
|
||||||
|
|
||||||
new2 "guest get nacm"
|
new2 "guest get nacm"
|
||||||
expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/x)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "access denied"}}}
'
|
expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/example:x)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "access denied"}}}
'
|
||||||
|
|
||||||
new "admin edit nacm"
|
new "admin edit nacm"
|
||||||
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"x": 1}' http://localhost/restconf/data/x)" ""
|
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"example:x": 1}' http://localhost/restconf/data/example:x)" ""
|
||||||
|
|
||||||
new2 "limited edit nacm"
|
new2 "limited edit nacm"
|
||||||
expecteq "$(curl -u wilma:bar -sS -X PUT -d '{"x": 2}' http://localhost/restconf/data/x)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
expecteq "$(curl -u wilma:bar -sS -X PUT -d '{"x": 2}' http://localhost/restconf/data/example:x)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
||||||
|
|
||||||
new2 "guest edit nacm"
|
new2 "guest edit nacm"
|
||||||
expecteq "$(curl -u guest:bar -sS -X PUT -d '{"x": 3}' http://localhost/restconf/data/x)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "access denied"}}}
'
|
expecteq "$(curl -u guest:bar -sS -X PUT -d '{"x": 3}' http://localhost/restconf/data/example:x)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "access denied"}}}
'
|
||||||
|
|
||||||
new "cli show conf as admin"
|
new "cli show conf as admin"
|
||||||
expectfn "$clixon_cli -1 -U andy -l o -f $cfg -y $fyang show conf" 0 "^x 1;$"
|
expectfn "$clixon_cli -1 -U andy -l o -f $cfg -y $fyang show conf" 0 "^x 1;$"
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@ RULES=$(cat <<EOF
|
||||||
$NADMIN
|
$NADMIN
|
||||||
|
|
||||||
</nacm>
|
</nacm>
|
||||||
<x>0</x>
|
<x xmlns="urn:example:clixon">0</x>
|
||||||
EOF
|
EOF
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -158,10 +158,10 @@ new "commit it"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "enable nacm"
|
new "enable nacm"
|
||||||
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"enable-nacm": true}' http://localhost/restconf/data/nacm/enable-nacm)" ""
|
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"enable-nacm": true}' http://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" ""
|
||||||
|
|
||||||
new2 "admin get nacm"
|
new2 "admin get nacm"
|
||||||
expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/x)" '{"x": 0}
|
expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/example:x)" '{"example:x": 0}
|
||||||
'
|
'
|
||||||
|
|
||||||
# Rule 1: deny-kill-session
|
# Rule 1: deny-kill-session
|
||||||
|
|
@ -186,7 +186,7 @@ new "deny-delete-config: limited fail (restconf) ok"
|
||||||
expecteq "$(curl -u wilma:bar -sS -X DELETE http://localhost/restconf/data)" ''
|
expecteq "$(curl -u wilma:bar -sS -X DELETE http://localhost/restconf/data)" ''
|
||||||
|
|
||||||
new2 "admin get nacm (should be null)"
|
new2 "admin get nacm (should be null)"
|
||||||
expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/x)" 'null
|
expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/example:x)" 'null
|
||||||
'
|
'
|
||||||
|
|
||||||
new "deny-delete-config: admin ok (restconf)"
|
new "deny-delete-config: admin ok (restconf)"
|
||||||
|
|
@ -200,14 +200,14 @@ new "commit it"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "enable nacm"
|
new "enable nacm"
|
||||||
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"enable-nacm": true}' http://localhost/restconf/data/nacm/enable-nacm)" ""
|
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"ietf-netconf-acm:enable-nacm": true}' http://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" ""
|
||||||
|
|
||||||
# Rule 3: permit-edit-config
|
# Rule 3: permit-edit-config
|
||||||
new "permit-edit-config: limited ok restconf"
|
new "permit-edit-config: limited ok restconf"
|
||||||
expecteq "$(curl -u wilma:bar -sS -X PUT -d '{"x": 2}' http://localhost/restconf/data/x)" ''
|
expecteq "$(curl -u wilma:bar -sS -X PUT -d '{"example:x": 2}' http://localhost/restconf/data/example:x)" ''
|
||||||
|
|
||||||
new2 "permit-edit-config: guest fail restconf"
|
new2 "permit-edit-config: guest fail restconf"
|
||||||
expecteq "$(curl -u guest:bar -sS -X PUT -d '{"x": 2}' http://localhost/restconf/data/x)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
expecteq "$(curl -u guest:bar -sS -X PUT -d '{"example:x": 2}' http://localhost/restconf/data/example:x)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
||||||
|
|
||||||
new "Kill restconf daemon"
|
new "Kill restconf daemon"
|
||||||
sudo pkill -u www-data -f "/www-data/clixon_restconf"
|
sudo pkill -u www-data -f "/www-data/clixon_restconf"
|
||||||
|
|
|
||||||
|
|
@ -114,14 +114,13 @@ new "netconf get-config single quotes"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc message-id='101' xmlns='urn:ietf:params:xml:ns:netconf:base:1.0'><get-config><source><candidate/></source></get-config></rpc>]]>]]>" '^<rpc-reply message-id="101" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><data/></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc message-id='101' xmlns='urn:ietf:params:xml:ns:netconf:base:1.0'><get-config><source><candidate/></source></get-config></rpc>]]>]]>" '^<rpc-reply message-id="101" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><data/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "Add subtree eth/0/0 using none which should not change anything"
|
new "Add subtree eth/0/0 using none which should not change anything"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><default-operation>none</default-operation><target><candidate/></target><config><interfaces><interface><name>eth/0/0</name></interface></interfaces></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><default-operation>none</default-operation><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth/0/0</name></interface></interfaces></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "Check nothing added"
|
new "Check nothing added"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc message-id="101"><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply message-id="101"><data/></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc message-id="101"><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply message-id="101"><data/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "Add subtree eth/0/0 using none and create which should add eth/0/0"
|
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 xmlns="urn:ietf:params:xml:ns:yang:ietf-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
|
||||||
cat <<EOF > $tmp # new
|
cat <<EOF > $tmp # new
|
||||||
|
|
@ -129,22 +128,22 @@ cat <<EOF > $tmp # new
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
new "Check eth/0/0 added using xpath"
|
new "Check eth/0/0 added using xpath"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "$(cat $tmp)" "^<rpc-reply><data><interfaces><interface><name>eth/0/0</name><type>ex:eth</type><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "$(cat $tmp)" '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth/0/0</name><type>ex:eth</type><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "Re-create same eth/0/0 which should generate error"
|
new "Re-create same eth/0/0 which should generate error"
|
||||||
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><rpc-error>"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-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><rpc-error>'
|
||||||
|
|
||||||
new "Delete eth/0/0 using none config"
|
new "Delete eth/0/0 using none config"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces><interface operation="delete"><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 xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface operation="delete"><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>]]>]]>$'
|
||||||
|
|
||||||
new "Check deleted eth/0/0 (non-presence container)"
|
new "Check deleted eth/0/0 (non-presence container)"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc message-id="101"><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply message-id="101"><data/></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc message-id="101"><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply message-id="101"><data/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "Re-Delete eth/0/0 using none should generate error"
|
new "Re-Delete eth/0/0 using none should generate error"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces><interface operation="delete"><name>eth/0/0</name><type>ex:eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>]]>]]>' "^<rpc-reply><rpc-error>"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface operation="delete"><name>eth/0/0</name><type>ex:eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error>'
|
||||||
|
|
||||||
new "netconf edit config"
|
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 xmlns="urn:ietf:params:xml:ns:yang:ietf-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
|
||||||
cat <<EOF > $tmp # new
|
cat <<EOF > $tmp # new
|
||||||
|
|
@ -152,7 +151,7 @@ cat <<EOF > $tmp # new
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
new "netconf get config xpath"
|
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 xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth1</name><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
# Too many quotes
|
# Too many quotes
|
||||||
cat <<EOF > $tmp # new
|
cat <<EOF > $tmp # new
|
||||||
|
|
@ -160,7 +159,7 @@ cat <<EOF > $tmp # new
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
new "netconf get config xpath parent"
|
new "netconf get config xpath parent"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "$(cat $tmp)" "^<rpc-reply><data><interfaces><interface><name>eth/0/0</name><enabled>true</enabled></interface><interface><name>eth1</name><enabled>true</enabled><ipv4><enabled>true</enabled><forwarding>false</forwarding><address><ip>9.2.3.4</ip><prefix-length>24</prefix-length></address></ipv4></interface></interfaces></data></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "$(cat $tmp)" '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth/0/0</name><enabled>true</enabled></interface><interface><name>eth1</name><enabled>true</enabled><ipv4><enabled>true</enabled><forwarding>false</forwarding><address><ip>9.2.3.4</ip><prefix-length>24</prefix-length></address></ipv4></interface></interfaces></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "netconf validate missing type"
|
new "netconf validate missing type"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error>"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error>"
|
||||||
|
|
@ -172,13 +171,13 @@ new "netconf get empty config2"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf edit extra xml"
|
new "netconf edit extra xml"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><interfaces><extra/></interfaces></config></edit-config></rpc>]]>]]>" "^<rpc-reply><rpc-error>"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><extra/></interfaces></config></edit-config></rpc>]]>]]>' "^<rpc-reply><rpc-error>"
|
||||||
|
|
||||||
new "netconf discard-changes"
|
new "netconf discard-changes"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf edit config eth1"
|
new "netconf edit config eth1"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><interfaces><interface><name>eth1</name><type>ex:eth</type></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 xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth1</name><type>ex:eth</type></interface></interfaces></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf validate"
|
new "netconf validate"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
@ -187,32 +186,32 @@ new "netconf commit"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf edit config merge"
|
new "netconf edit config merge"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><interfaces><interface><name>eth2</name><type>ex:eth</type></interface></interfaces></config><default-operation>merge</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 xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth2</name><type>ex:eth</type></interface></interfaces></config><default-operation>merge</default-operation></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf edit ampersand encoding(<&): name:'eth&' type:'t<>'"
|
new "netconf edit ampersand encoding(<&): name:'eth&' type:'t<>'"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><interfaces><interface><name>eth&</name><type>t<></type></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 xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth&</name><type>t<></type></interface></interfaces></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "netconf get replaced config"
|
new "netconf get replaced config"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><interfaces><interface><name>eth&</name><type>t<></type><enabled>true</enabled></interface><interface><name>eth1</name><type>ex:eth</type><enabled>true</enabled></interface><interface><name>eth2</name><type>ex:eth</type><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth&</name><type>t<></type><enabled>true</enabled></interface><interface><name>eth1</name><type>ex:eth</type><enabled>true</enabled></interface><interface><name>eth2</name><type>ex:eth</type><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "cli show configuration eth& - encoding tests"
|
new "cli show configuration eth& - encoding tests"
|
||||||
expectfn "$clixon_cli -1 -f $cfg -y $fyang show conf cli" 0 "interfaces interface eth& type t<>
|
expectfn "$clixon_cli -1 -f $cfg -y $fyang show conf cli" 0 "interfaces interface eth& type t<>
|
||||||
interfaces interface eth& enabled true"
|
interfaces interface eth& enabled true"
|
||||||
|
|
||||||
new "netconf edit CDATA"
|
new "netconf edit CDATA"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><interfaces><interface><name>eth/0/0</name><type>ex:eth</type><description><![CDATA[myeth&]]></description></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 xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth/0/0</name><type>ex:eth</type><description><![CDATA[myeth&]]></description></interface></interfaces></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
#new "netconf get CDATA"
|
#new "netconf get CDATA"
|
||||||
#expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/interfaces/interface[name='eth/0/0']/description\" /></get-config></rpc>]]>]]>" "<rpc-reply><data><interfaces><interface><name>eth/0/0</name><description><![CDATA[myeth&]]></description><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>"
|
#expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/interfaces/interface[name='eth/0/0']/description\" /></get-config></rpc>]]>]]>' '<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth/0/0</name><description><![CDATA[myeth&]]></description><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>'
|
||||||
|
|
||||||
new "netconf discard-changes"
|
new "netconf discard-changes"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf edit state operation should fail"
|
new "netconf edit state operation should fail"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><state><op>42</op></state></config></edit-config></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-type>protocol</error-type><error-tag>invalid-value</error-tag>"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><state xmlns="urn:example:clixon"><op>42</op></state></config></edit-config></rpc>]]>]]>' "^<rpc-reply><rpc-error><error-type>protocol</error-type><error-tag>invalid-value</error-tag>"
|
||||||
|
|
||||||
new "netconf get state operation"
|
new "netconf get state operation"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get><filter type=\"xpath\" select=\"/state\"/></get></rpc>]]>]]>" "^<rpc-reply><data><state><op>42</op></state></data></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get><filter type=\"xpath\" select=\"/state\"/></get></rpc>]]>]]>" '^<rpc-reply><data><state xmlns="urn:example:clixon"><op>42</op></state></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "netconf lock/unlock"
|
new "netconf lock/unlock"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><lock><target><candidate/></target></lock></rpc>]]>]]><rpc><unlock><target><candidate/></target></unlock></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]><rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><lock><target><candidate/></target></lock></rpc>]]>]]><rpc><unlock><target><candidate/></target></unlock></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]><rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
@ -234,7 +233,7 @@ new "copy startup"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><copy-config><target><startup/></target><source><candidate/></source></copy-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><copy-config><target><startup/></target><source><candidate/></source></copy-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf get startup"
|
new "netconf get startup"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><startup/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><interfaces><interface><name>eth1</name><type>ex:eth</type><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><startup/></source></get-config></rpc>]]>]]>" '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth1</name><type>ex:eth</type><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "netconf delete startup"
|
new "netconf delete startup"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><delete-config><target><startup/></target></delete-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><delete-config><target><startup/></target></delete-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
@ -243,16 +242,16 @@ new "netconf check empty startup"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><startup/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><startup/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf rpc"
|
new "netconf rpc"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><fib-route xmlns="urn:ietf:params:xml:ns:yang:ietf-routing"><routing-instance-name>ipv4</routing-instance-name><destination-address><address-family>ipv4</address-family></destination-address></fib-route></rpc>]]>]]>' "^<rpc-reply><route><address-family>ipv4</address-family><next-hop><next-hop-list>"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><fib-route xmlns="urn:ietf:params:xml:ns:yang:ietf-routing"><routing-instance-name>ipv4</routing-instance-name><destination-address><address-family>ipv4</address-family></destination-address></fib-route></rpc>]]>]]>' '^<rpc-reply><route xmlns="urn:ietf:params:xml:ns:yang:ietf-routing"><address-family>ipv4</address-family><next-hop><next-hop-list>'
|
||||||
|
|
||||||
new "netconf rpc without namespace (iterate kludge should work)"
|
#new "netconf rpc without namespace (iterate kludge should work)"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><fib-route><routing-instance-name>ipv4</routing-instance-name><destination-address><address-family>ipv4</address-family></destination-address></fib-route></rpc>]]>]]>" "^<rpc-reply><route><address-family>ipv4</address-family><next-hop><next-hop-list>"
|
#expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><fib-route><routing-instance-name>ipv4</routing-instance-name><destination-address><address-family>ipv4</address-family></destination-address></fib-route></rpc>]]>]]>" "^<rpc-reply><route><address-family>ipv4</address-family><next-hop><next-hop-list>"
|
||||||
|
|
||||||
new "netconf empty rpc"
|
new "netconf empty rpc"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><ex:empty/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><empty xmlns="urn:example:clixon"/></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf client-side rpc"
|
new "netconf client-side rpc"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><ex:client-rpc><request>example</request></ex:client-rpc></rpc>]]>]]>" "^<rpc-reply><result>ok</result></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><client-rpc xmlns="urn:example:clixon"><request>example</request></client-rpc></rpc>]]>]]>' '^<rpc-reply><result xmlns="urn:example:clixon">ok</result></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
if [ $BE -eq 0 ]; then
|
if [ $BE -eq 0 ]; then
|
||||||
exit # BE
|
exit # BE
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ fyang=$dir/order.yang
|
||||||
|
|
||||||
dbdir=$dir/order
|
dbdir=$dir/order
|
||||||
|
|
||||||
new "Set up $dbdir"
|
|
||||||
rm -rf $dbdir
|
rm -rf $dbdir
|
||||||
if [ ! -d $dbdir ]; then
|
if [ ! -d $dbdir ]; then
|
||||||
mkdir $dbdir
|
mkdir $dbdir
|
||||||
|
|
@ -84,30 +83,32 @@ module example{
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
rm -f $dbdir/candidate_db
|
||||||
|
# alt
|
||||||
cat <<EOF > $dbdir/running_db
|
cat <<EOF > $dbdir/running_db
|
||||||
<config>
|
<config>
|
||||||
<y0>d</y0>
|
<y0 xmlns="urn:example:clixon">d</y0>
|
||||||
<y1>d</y1>
|
<y1 xmlns="urn:example:clixon">d</y1>
|
||||||
<y2><k>d</k><a>bar</a></y2>
|
<y2 xmlns="urn:example:clixon"><k>d</k><a>bar</a></y2>
|
||||||
<y3><k>d</k><a>bar</a></y3>
|
<y3 xmlns="urn:example:clixon"><k>d</k><a>bar</a></y3>
|
||||||
<y0>b</y0>
|
<y0 xmlns="urn:example:clixon">b</y0>
|
||||||
<y1>b</y1>
|
<y1 xmlns="urn:example:clixon">b</y1>
|
||||||
<c><d>hej</d></c>
|
<c xmlns="urn:example:clixon"><d>hej</d></c>
|
||||||
<y0>c</y0>
|
<y0 xmlns="urn:example:clixon">c</y0>
|
||||||
<y1>c</y1>
|
<y1 xmlns="urn:example:clixon">c</y1>
|
||||||
<y2><k>a</k><a>bar</a></y2>
|
<y2 xmlns="urn:example:clixon"><k>a</k><a>bar</a></y2>
|
||||||
<y3><k>a</k><a>bar</a></y3>
|
<y3 xmlns="urn:example:clixon"><k>a</k><a>bar</a></y3>
|
||||||
<l>hopp</l>
|
<l xmlns="urn:example:clixon">hopp</l>
|
||||||
<y0>a</y0>
|
<y0 xmlns="urn:example:clixon">a</y0>
|
||||||
<y1>a</y1>
|
<y1 xmlns="urn:example:clixon">a</y1>
|
||||||
<y2><k>c</k><a>bar</a></y2>
|
<y2 xmlns="urn:example:clixon"><k>c</k><a>bar</a></y2>
|
||||||
<y3><k>c</k><a>bar</a></y3>
|
<y3 xmlns="urn:example:clixon"><k>c</k><a>bar</a></y3>
|
||||||
<y2><k>b</k><a>bar</a></y2>
|
<y2 xmlns="urn:example:clixon"><k>b</k><a>bar</a></y2>
|
||||||
<y3><k>b</k><a>bar</a></y3>
|
<y3 xmlns="urn:example:clixon"><k>b</k><a>bar</a></y3>
|
||||||
</config>
|
</config>
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
new "test params: -f $cfg -y $fyang"
|
new "test params: -s running -f $cfg -y $fyang"
|
||||||
|
|
||||||
if [ $BE -ne 0 ]; then
|
if [ $BE -ne 0 ]; then
|
||||||
new "kill old backend"
|
new "kill old backend"
|
||||||
|
|
@ -123,20 +124,20 @@ if [ $BE -ne 0 ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check as file
|
# Check as file
|
||||||
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: c,l,y0,y1,y2,y3; y1 and y3 sorted. Note this fails if CLICON_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 xmlns="urn:example:clixon"><d>hej</d></c><l xmlns="urn:example:clixon">hopp</l><y0 xmlns="urn:example:clixon">d</y0><y0 xmlns="urn:example:clixon">b</y0><y0 xmlns="urn:example:clixon">c</y0><y0 xmlns="urn:example:clixon">a</y0><y1 xmlns="urn:example:clixon">a</y1><y1 xmlns="urn:example:clixon">b</y1><y1 xmlns="urn:example:clixon">c</y1><y1 xmlns="urn:example:clixon">d</y1><y2 xmlns="urn:example:clixon"><k>d</k><a>bar</a></y2><y2 xmlns="urn:example:clixon"><k>a</k><a>bar</a></y2><y2 xmlns="urn:example:clixon"><k>c</k><a>bar</a></y2><y2 xmlns="urn:example:clixon"><k>b</k><a>bar</a></y2><y3 xmlns="urn:example:clixon"><k>a</k><a>bar</a></y3><y3 xmlns="urn:example:clixon"><k>b</k><a>bar</a></y3><y3 xmlns="urn:example:clixon"><k>c</k><a>bar</a></y3><y3 xmlns="urn:example:clixon"><k>d</k><a>bar</a></y3></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
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 xmlns="urn:example:clixon"><k>a</k><a>bar</a></y2></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
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=\"/y3[k='a']\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><y3><k>a</k><a>bar</a></y3></data></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y3[k='a']\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><y3 xmlns="urn:example:clixon"><k>a</k><a>bar</a></y3></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
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='b']\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><y2><k>b</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='b']\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><y2 xmlns="urn:example:clixon"><k>b</k><a>bar</a></y2></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
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=\"/y3[k='b']\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><y3><k>b</k><a>bar</a></y3></data></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y3[k='b']\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><y3 xmlns="urn:example:clixon"><k>b</k><a>bar</a></y3></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "delete candidate"
|
new "delete candidate"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><default-operation>none</default-operation><config operation="delete"/></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><default-operation>none</default-operation><config operation="delete"/></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
@ -144,33 +145,33 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></
|
||||||
# LEAF_LISTS
|
# LEAF_LISTS
|
||||||
|
|
||||||
new "add two entries to leaf-list user order"
|
new "add two entries to leaf-list user order"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><y0>c</y0><y0>b</y0></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><y0 xmlns="urn:example:clixon">c</y0><y0 xmlns="urn:example:clixon">b</y0></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "add one entry to leaf-list user order"
|
new "add one entry to leaf-list user order"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><y0>a</y0></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><y0 xmlns="urn:example:clixon">a</y0></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf commit"
|
new "netconf commit"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "add one entry to leaf-list user order after commit"
|
new "add one entry to leaf-list user order after commit"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><y0>0</y0></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><y0 xmlns="urn:example:clixon">0</y0></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf commit"
|
new "netconf commit"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "verify leaf-list user order in running (as entered)"
|
new "verify leaf-list user order in running (as entered)"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y0\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><y0>c</y0><y0>b</y0><y0>a</y0><y0>0</y0></data></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><running/></source><filter type="xpath" select="/y0"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><y0 xmlns="urn:example:clixon">c</y0><y0 xmlns="urn:example:clixon">b</y0><y0 xmlns="urn:example:clixon">a</y0><y0 xmlns="urn:example:clixon">0</y0></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
# LISTS
|
# LISTS
|
||||||
|
|
||||||
new "add two entries to list user order"
|
new "add two entries to list user order"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><y2><k>c</k><a>bar</a></y2><y2><k>b</k><a>foo</a></y2></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><y2 xmlns="urn:example:clixon"><k>c</k><a>bar</a></y2><y2 xmlns="urn:example:clixon"><k>b</k><a>foo</a></y2></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "add one entry to list user order"
|
new "add one entry to list user order"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><y2><k>a</k><a>fie</a></y2></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><y2 xmlns="urn:example:clixon"><k>a</k><a>fie</a></y2></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "verify list user order (as entered)"
|
new "verify list user order (as entered)"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/y2\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><y2><k>c</k><a>bar</a></y2><y2><k>b</k><a>foo</a></y2><y2><k>a</k><a>fie</a></y2></data></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/y2"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><y2 xmlns="urn:example:clixon"><k>c</k><a>bar</a></y2><y2 xmlns="urn:example:clixon"><k>b</k><a>foo</a></y2><y2 xmlns="urn:example:clixon"><k>a</k><a>fie</a></y2></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
if [ $BE -eq 0 ]; then
|
if [ $BE -eq 0 ]; then
|
||||||
exit # BE
|
exit # BE
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ sudo su -c "$clixon_restconf -f $cfg -y $fyang -D $DBG" -s /bin/sh www-data &
|
||||||
sleep $RCWAIT
|
sleep $RCWAIT
|
||||||
|
|
||||||
new "generate 'large' config with $number list entries"
|
new "generate 'large' config with $number list entries"
|
||||||
echo -n "<rpc><edit-config><target><candidate/></target><config><x>" > $fconfig
|
echo -n "<rpc><edit-config><target><candidate/></target><config><x xmlns=\"urn:example:clixon\">" > $fconfig
|
||||||
for (( i=0; i<$number; i++ )); do
|
for (( i=0; i<$number; i++ )); do
|
||||||
echo -n "<y><a>$i</a><b>$i</b></y>" >> $fconfig
|
echo -n "<y><a>$i</a><b>$i</b></y>" >> $fconfig
|
||||||
done
|
done
|
||||||
|
|
@ -111,7 +111,7 @@ new "netconf commit large config again"
|
||||||
expecteof "time -f %e $clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "time -f %e $clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf add small (1 entry) config"
|
new "netconf add small (1 entry) config"
|
||||||
expecteof "time -f %e $clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><x><y><a>x</a><b>y</b></y></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "time -f %e $clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><y><a>x</a><b>y</b></y></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf get $req small config"
|
new "netconf get $req small config"
|
||||||
time -p for (( i=0; i<$req; i++ )); do
|
time -p for (( i=0; i<$req; i++ )); do
|
||||||
|
|
@ -128,7 +128,7 @@ done
|
||||||
new "netconf add $req small config"
|
new "netconf add $req small config"
|
||||||
time -p for (( i=0; i<$req; i++ )); do
|
time -p for (( i=0; i<$req; i++ )); do
|
||||||
rnd=$(( ( RANDOM % $number ) ))
|
rnd=$(( ( RANDOM % $number ) ))
|
||||||
echo "<rpc><edit-config><target><candidate/></target><config><x><y><a>$rnd</a><b>$rnd</b></y></x></config></edit-config></rpc>]]>]]>"
|
echo "<rpc><edit-config><target><candidate/></target><config><x xmlns=\"urn:example:clixon\"><y><a>$rnd</a><b>$rnd</b></y></x></config></edit-config></rpc>]]>]]>"
|
||||||
done | $clixon_netconf -qf $cfg -y $fyang > /dev/null
|
done | $clixon_netconf -qf $cfg -y $fyang > /dev/null
|
||||||
|
|
||||||
new "netconf add $req restconf small config"
|
new "netconf add $req restconf small config"
|
||||||
|
|
@ -138,10 +138,10 @@ time -p for (( i=0; i<$req; i++ )); do
|
||||||
done
|
done
|
||||||
|
|
||||||
new "netconf get large config"
|
new "netconf get large config"
|
||||||
expecteof "time -f %e $clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><x><y><a>0</a><b>0</b></y><y><a>1</a><b>1</b>"
|
expecteof "time -f %e $clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" '^<rpc-reply><data><x xmlns="urn:example:clixon"><y><a>0</a><b>0</b></y><y><a>1</a><b>1</b>'
|
||||||
|
|
||||||
new "generate large leaf-list config"
|
new "generate large leaf-list config"
|
||||||
echo -n "<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><x>" > $fconfig
|
echo -n "<rpc><edit-config><target><candidate/></target><default-operation>replace</default-operation><config><x xmlns=\"urn:example:clixon\">" > $fconfig
|
||||||
for (( i=0; i<$number; i++ )); do
|
for (( i=0; i<$number; i++ )); do
|
||||||
echo -n "<c>$i</c>" >> $fconfig
|
echo -n "<c>$i</c>" >> $fconfig
|
||||||
done
|
done
|
||||||
|
|
@ -158,17 +158,17 @@ expecteof "time -f %e $clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc
|
||||||
new "netconf add $req small leaf-list config"
|
new "netconf add $req small leaf-list config"
|
||||||
time -p for (( i=0; i<$req; i++ )); do
|
time -p for (( i=0; i<$req; i++ )); do
|
||||||
rnd=$(( ( RANDOM % $number ) ))
|
rnd=$(( ( RANDOM % $number ) ))
|
||||||
echo "<rpc><edit-config><target><candidate/></target><config><x><c>$rnd</c></x></config></edit-config></rpc>]]>]]>"
|
echo "<rpc><edit-config><target><candidate/></target><config><x xmlns=\"urn:example:clixon\"><c>$rnd</c></x></config></edit-config></rpc>]]>]]>"
|
||||||
done | $clixon_netconf -qf $cfg -y $fyang > /dev/null
|
done | $clixon_netconf -qf $cfg -y $fyang > /dev/null
|
||||||
|
|
||||||
new "netconf add small leaf-list config"
|
new "netconf add small leaf-list config"
|
||||||
expecteof "time -f %e $clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><x><c>x</c></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "time -f %e $clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><c>x</c></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf commit small leaf-list config"
|
new "netconf commit small leaf-list config"
|
||||||
expecteof "time -f %e $clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "time -f %e $clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf get large leaf-list config"
|
new "netconf get large leaf-list config"
|
||||||
expecteof "time -f %e $clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><x><c>0</c><c>1</c>"
|
expecteof "time -f %e $clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" '^<rpc-reply><data><x xmlns="urn:example:clixon"><c>0</c><c>1</c>'
|
||||||
|
|
||||||
new "Kill restconf daemon"
|
new "Kill restconf daemon"
|
||||||
sudo pkill -u www-data -f "/www-data/clixon_restconf"
|
sudo pkill -u www-data -f "/www-data/clixon_restconf"
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ module example{
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# This is a fixed 'state' implemented in routing_backend. It is assumed to be always there
|
# This is a fixed 'state' implemented in routing_backend. It is assumed to be always there
|
||||||
state='{"state": {"op": "42"}}'
|
state='{"example:state": {"op": "42"}}'
|
||||||
|
|
||||||
new "test params: -f $cfg -y $fyang"
|
new "test params: -f $cfg -y $fyang"
|
||||||
if [ $BE -ne 0 ]; then
|
if [ $BE -ne 0 ]; then
|
||||||
|
|
@ -102,9 +102,6 @@ sleep $RCWAIT
|
||||||
|
|
||||||
new "restconf tests"
|
new "restconf tests"
|
||||||
|
|
||||||
new2 "restconf rpc using POST json without mandatory element"
|
|
||||||
expecteq "$(curl -s -X POST -d '{"input":{"wrongelement":"ipv4"}}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "unknown-element","error-info": {"bad-element": "wrongelement"},"error-severity": "error"}}}
'
|
|
||||||
|
|
||||||
new2 "restconf root discovery. RFC 8040 3.1 (xml+xrd)"
|
new2 "restconf root discovery. RFC 8040 3.1 (xml+xrd)"
|
||||||
expecteq "$(curl -s -X GET http://localhost/.well-known/host-meta)" "<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>
|
expecteq "$(curl -s -X GET http://localhost/.well-known/host-meta)" "<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>
|
||||||
<Link rel='restconf' href='/restconf'/>
|
<Link rel='restconf' href='/restconf'/>
|
||||||
|
|
@ -119,13 +116,14 @@ new2 "restconf get restconf resource. RFC 8040 3.3 (xml)"
|
||||||
expecteq "$(curl -s -H 'Accept: application/yang-data+xml' -G http://localhost/restconf)" '<restconf><data/><operations/><yang-library-version>2016-06-21</yang-library-version></restconf>
|
expecteq "$(curl -s -H 'Accept: application/yang-data+xml' -G http://localhost/restconf)" '<restconf><data/><operations/><yang-library-version>2016-06-21</yang-library-version></restconf>
|
||||||
'
|
'
|
||||||
|
|
||||||
|
# Should be alphabetically ordered
|
||||||
new2 "restconf get restconf/operations. RFC8040 3.3.2 (json)"
|
new2 "restconf get restconf/operations. RFC8040 3.3.2 (json)"
|
||||||
expecteq "$(curl -sG http://localhost/restconf/operations)" '{"operations": {"example:client-rpc": null,"ietf-routing:fib-route": null,"ietf-routing:route-count": null,"example:empty": null}}
|
expecteq "$(curl -sG http://localhost/restconf/operations)" '{"operations": {"example:empty": null,"example:client-rpc": null}{"ietf-routing:fib-route": null,"ietf-routing:route-count": null}}
|
||||||
'
|
'
|
||||||
|
|
||||||
new "restconf get restconf/operations. RFC8040 3.3.2 (xml)"
|
new "restconf get restconf/operations. RFC8040 3.3.2 (xml)"
|
||||||
ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/operations)
|
ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/operations)
|
||||||
expect='<operations><client-rpc xmlns="urn:example:clixon"/><fib-route xmlns="urn:ietf:params:xml:ns:yang:ietf-routing"/><route-count xmlns="urn:ietf:params:xml:ns:yang:ietf-routing"/><empty xmlns="urn:example:clixon"/></operations>'
|
expect='<operations><empty xmlns="urn:example:clixon"/><client-rpc xmlns="urn:example:clixon"/><fib-route xmlns="urn:ietf:params:xml:ns:yang:ietf-routing"/><route-count xmlns="urn:ietf:params:xml:ns:yang:ietf-routing"/></operations>'
|
||||||
match=`echo $ret | grep -EZo "$expect"`
|
match=`echo $ret | grep -EZo "$expect"`
|
||||||
if [ -z "$match" ]; then
|
if [ -z "$match" ]; then
|
||||||
err "$expect" "$ret"
|
err "$expect" "$ret"
|
||||||
|
|
@ -142,8 +140,8 @@ if [ -z "$match" ]; then
|
||||||
err "$expect" "$ret"
|
err "$expect" "$ret"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new2 "restconf schema resource, RFC 8040 sec 3.7 according to RFC 7895"
|
new2 "restconf schema resource, RFC 8040 sec 3.7 according to RFC 7895 (explicit resource)"
|
||||||
expecteq "$(curl -s -H 'Accept: application/yang-data+json' -G http://localhost/restconf/data/ietf-yang-library:modules-state/module=ietf-routing,2014-10-26/)" '{"module": [{"name": "ietf-routing","revision": "2014-10-26","namespace": "urn:ietf:params:xml:ns:yang:ietf-routing","conformance-type": "implement"}]}
|
expecteq "$(curl -s -H 'Accept: application/yang-data+json' -G http://localhost/restconf/data/ietf-yang-library:modules-state/module=ietf-routing,2014-10-26/)" '{"ietf-yang-library:module": [{"name": "ietf-routing","revision": "2014-10-26","namespace": "urn:ietf:params:xml:ns:yang:ietf-routing","conformance-type": "implement"}]}
|
||||||
'
|
'
|
||||||
|
|
||||||
new "restconf options. RFC 8040 4.1"
|
new "restconf options. RFC 8040 4.1"
|
||||||
|
|
@ -154,132 +152,133 @@ expectfn "curl -s -I http://localhost/restconf/data" 0 "HTTP/1.1 200 OK"
|
||||||
#Content-Type: application/yang-data+json"
|
#Content-Type: application/yang-data+json"
|
||||||
|
|
||||||
new "restconf empty rpc"
|
new "restconf empty rpc"
|
||||||
expecteq "$(curl -s -X POST -d {\"input\":null} http://localhost/restconf/operations/example:empty)" ""
|
expecteq "$(curl -s -X POST -d {\"example:input\":null} http://localhost/restconf/operations/example:empty)" ""
|
||||||
|
|
||||||
new2 "restconf empty rpc with extra args (should fail)"
|
new2 "restconf empty rpc with extra args (should fail)"
|
||||||
expecteq "$(curl -s -X POST -d {\"input\":{\"extra\":null}} http://localhost/restconf/operations/example:empty)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "unknown-element","error-info": {"bad-element": "extra"},"error-severity": "error"}}}
'
|
expecteq "$(curl -s -X POST -d {\"example:input\":{\"extra\":null}} http://localhost/restconf/operations/example:empty)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "unknown-element","error-info": {"bad-element": "extra"},"error-severity": "error"}}}
'
|
||||||
|
|
||||||
new2 "restconf get empty config + state json"
|
new2 "restconf get empty config + state json"
|
||||||
expecteq "$(curl -sSG http://localhost/restconf/data/state)" '{"state": {"op": "42"}}
|
expecteq "$(curl -sSG http://localhost/restconf/data/example:state)" '{"example:state": {"op": "42"}}
|
||||||
'
|
'
|
||||||
|
|
||||||
new2 "restconf get empty config + state json + module"
|
new2 "restconf get empty config + state json + module"
|
||||||
expecteq "$(curl -sSG http://localhost/restconf/data/example:state)" '{"state": {"op": "42"}}
|
expecteq "$(curl -sSG http://localhost/restconf/data/example:state)" '{"example:state": {"op": "42"}}
|
||||||
'
|
'
|
||||||
|
|
||||||
new2 "restconf get empty config + state json with wrong module name"
|
new2 "restconf get empty config + state json with wrong module name"
|
||||||
expecteq "$(curl -sSG http://localhost/restconf/data/badmodule:state)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "No yang node found: badmodule:state"}}}
'
|
expecteq "$(curl -sSG http://localhost/restconf/data/badmodule:state)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "No such yang module: badmodule"}}}
'
|
||||||
|
|
||||||
new "restconf get empty config + state xml"
|
new "restconf get empty config + state xml"
|
||||||
ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/data/state)
|
ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/data/example:state)
|
||||||
expect="<state><op>42</op></state>"
|
expect='<state xmlns="urn:example:clixon"><op>42</op></state>'
|
||||||
match=`echo $ret | grep -EZo "$expect"`
|
match=`echo $ret | grep -EZo "$expect"`
|
||||||
if [ -z "$match" ]; then
|
if [ -z "$match" ]; then
|
||||||
err "$expect" "$ret"
|
err "$expect" "$ret"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new2 "restconf get data/ json"
|
new2 "restconf get data/ json"
|
||||||
expecteq "$(curl -s -G http://localhost/restconf/data/state/op=42)" '{"op": "42"}
|
expecteq "$(curl -s -G http://localhost/restconf/data/example:state/op=42)" '{"example:op": "42"}
|
||||||
'
|
'
|
||||||
|
|
||||||
new "restconf get state operation eth0 xml"
|
new "restconf get state operation eth0 xml"
|
||||||
# Cant get shell macros to work, inline matching from lib.sh
|
# Cant get shell macros to work, inline matching from lib.sh
|
||||||
ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/data/state/op=42)
|
ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/data/example:state/op=42)
|
||||||
expect="<op>42</op>"
|
expect='<op xmlns="urn:example:clixon">42</op>'
|
||||||
match=`echo $ret | grep -EZo "$expect"`
|
match=`echo $ret | grep -EZo "$expect"`
|
||||||
if [ -z "$match" ]; then
|
if [ -z "$match" ]; then
|
||||||
err "$expect" "$ret"
|
err "$expect" "$ret"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new2 "restconf get state operation eth0 type json"
|
new2 "restconf get state operation eth0 type json"
|
||||||
expecteq "$(curl -s -G http://localhost/restconf/data/state/op=42)" '{"op": "42"}
|
expecteq "$(curl -s -G http://localhost/restconf/data/example:state/op=42)" '{"example:op": "42"}
|
||||||
'
|
'
|
||||||
|
|
||||||
new "restconf get state operation eth0 type xml"
|
new "restconf get state operation eth0 type xml"
|
||||||
# Cant get shell macros to work, inline matching from lib.sh
|
# Cant get shell macros to work, inline matching from lib.sh
|
||||||
ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/data/state/op=42)
|
ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/data/example:state/op=42)
|
||||||
expect="<op>42</op>"
|
expect='<op xmlns="urn:example:clixon">42</op>'
|
||||||
match=`echo $ret | grep -EZo "$expect"`
|
match=`echo $ret | grep -EZo "$expect"`
|
||||||
if [ -z "$match" ]; then
|
if [ -z "$match" ]; then
|
||||||
err "$expect" "$ret"
|
err "$expect" "$ret"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new2 "restconf GET datastore"
|
new2 "restconf GET datastore"
|
||||||
expecteq "$(curl -s -X GET http://localhost/restconf/data/state)" '{"state": {"op": "42"}}
|
expecteq "$(curl -s -X GET http://localhost/restconf/data/example:state)" '{"example:state": {"op": "42"}}
|
||||||
'
|
'
|
||||||
|
|
||||||
# Exact match
|
# Exact match
|
||||||
new "restconf Add subtree to datastore using POST"
|
new "restconf Add subtree to datastore using POST"
|
||||||
expectfn 'curl -s -i -X POST -H "Accept: application/yang-data+json" -d {"interfaces":{"interface":{"name":"eth/0/0","type":"ex:eth","enabled":true}}} http://localhost/restconf/data' 0 'HTTP/1.1 200 OK'
|
expectfn 'curl -s -i -X POST -H "Accept: application/yang-data+json" -d {"ietf-interfaces:interfaces":{"interface":{"name":"eth/0/0","type":"ex:eth","enabled":true}}} http://localhost/restconf/data' 0 'HTTP/1.1 200 OK'
|
||||||
|
|
||||||
new "restconf Re-add subtree which should give error"
|
new "restconf Re-add subtree which should give error"
|
||||||
expectfn 'curl -s -X POST -d {"interfaces":{"interface":{"name":"eth/0/0","type":"ex:eth","enabled":true}}} http://localhost/restconf/data' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "data-exists","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}}'
|
expectfn 'curl -s -X POST -d {"ietf-interfaces:interfaces":{"interface":{"name":"eth/0/0","type":"ex:eth","enabled":true}}} http://localhost/restconf/data' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "data-exists","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}}'
|
||||||
|
|
||||||
# XXX Cant get this to work
|
# XXX Cant get this to work
|
||||||
#expecteq "$(curl -s -X POST -d {\"interfaces\":{\"interface\":{\"name\":\"eth/0/0\",\"type\":\"ex:eth\",\"enabled\":true}}} http://localhost/restconf/data)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "data-exists","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}}'
|
#expecteq "$(curl -s -X POST -d {\"interfaces\":{\"interface\":{\"name\":\"eth/0/0\",\"type\":\"ex:eth\",\"enabled\":true}}} http://localhost/restconf/data)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "data-exists","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}}'
|
||||||
|
|
||||||
new "restconf Check interfaces eth/0/0 added"
|
new "restconf Check interfaces eth/0/0 added"
|
||||||
expectfn "curl -s -G http://localhost/restconf/data" 0 '{"interfaces": {"interface": \[{"name": "eth/0/0","type": "ex:eth","enabled": true}\]},"state": {"op": "42"}}
|
expectfn "curl -s -G http://localhost/restconf/data" 0 '"ietf-interfaces:interfaces": {"interface": \[{"name": "eth/0/0","type": "ex:eth","enabled": true}\]}'
|
||||||
'
|
|
||||||
|
|
||||||
new "restconf delete interfaces"
|
new "restconf delete interfaces"
|
||||||
expecteq $(curl -s -X DELETE http://localhost/restconf/data/interfaces) ""
|
expecteq $(curl -s -X DELETE http://localhost/restconf/data/ietf-interfaces:interfaces) ""
|
||||||
|
|
||||||
new "restconf Check empty config"
|
new "restconf Check empty config"
|
||||||
expectfn "curl -sG http://localhost/restconf/data/state" 0 "$state"
|
expectfn "curl -sG http://localhost/restconf/data/example:state" 0 "$state"
|
||||||
|
|
||||||
|
# XXX: gives <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
|
||||||
|
# <interface xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
|
||||||
new "restconf Add interfaces subtree eth/0/0 using POST"
|
new "restconf Add interfaces subtree eth/0/0 using POST"
|
||||||
expectfn 'curl -s -X POST -d {"interface":{"name":"eth/0/0","type":"ex:eth","enabled":true}} http://localhost/restconf/data/interfaces' 0 ""
|
expectfn 'curl -s -X POST -d {"ietf-interfaces:interface":{"name":"eth/0/0","type":"ex:eth","enabled":true}} http://localhost/restconf/data/ietf-interfaces:interfaces' 0 ""
|
||||||
# XXX cant get this to work
|
# XXX cant get this to work
|
||||||
#expecteq "$(curl -s -X POST -d '{"interface":{"name":"eth/0/0","type\":"ex:eth","enabled":true}}' http://localhost/restconf/data/interfaces)" ""
|
#expecteq "$(curl -s -X POST -d '{"interface":{"name":"eth/0/0","type\":"ex:eth","enabled":true}}' http://localhost/restconf/data/interfaces)" ""
|
||||||
|
|
||||||
new2 "restconf Check eth/0/0 added config"
|
new2 "restconf Check eth/0/0 added config"
|
||||||
expecteq "$(curl -s -G http://localhost/restconf/data/interfaces)" '{"interfaces": {"interface": [{"name": "eth/0/0","type": "ex:eth","enabled": true}]}}
|
expecteq "$(curl -s -G http://localhost/restconf/data/ietf-interfaces:interfaces)" '{"ietf-interfaces:interfaces": {"interface": [{"name": "eth/0/0","type": "ex:eth","enabled": true}]}}
|
||||||
'
|
'
|
||||||
|
|
||||||
new2 "restconf Check eth/0/0 added state"
|
new2 "restconf Check eth/0/0 added state"
|
||||||
expecteq "$(curl -s -G http://localhost/restconf/data/state)" '{"state": {"op": "42"}}
|
expecteq "$(curl -s -G http://localhost/restconf/data/example:state)" '{"example:state": {"op": "42"}}
|
||||||
'
|
'
|
||||||
|
|
||||||
new2 "restconf Re-post eth/0/0 which should generate error"
|
new2 "restconf Re-post eth/0/0 which should generate error"
|
||||||
expecteq "$(curl -s -X POST -d '{"interface":{"name":"eth/0/0","type":"ex:eth","enabled":true}}' http://localhost/restconf/data/interfaces)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "data-exists","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}}
'
|
expecteq "$(curl -s -X POST -d '{"ietf-interfaces:interface":{"name":"eth/0/0","type":"ex:eth","enabled":true}}' http://localhost/restconf/data/ietf-interfaces:interfaces)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "data-exists","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}}
'
|
||||||
|
|
||||||
new "Add leaf description using POST"
|
new "Add leaf description using POST"
|
||||||
expecteq "$(curl -s -X POST -d '{"description":"The-first-interface"}' http://localhost/restconf/data/interfaces/interface=eth%2f0%2f0)" ""
|
expecteq "$(curl -s -X POST -d '{"ietf-interfaces:description":"The-first-interface"}' http://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0)" ""
|
||||||
|
|
||||||
new "Add nothing using POST"
|
new "Add nothing using POST"
|
||||||
expectfn 'curl -s -X POST http://localhost/restconf/data/interfaces/interface=eth%2f0%2f0' 0 '"ietf-restconf:errors" : {"error": {"error-type": "rpc","error-tag": "malformed-message","error-severity": "error","error-message": " on line 1: syntax error at or before:'
|
expectfn 'curl -s -X POST http://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0' 0 '"ietf-restconf:errors" : {"error": {"error-type": "rpc","error-tag": "malformed-message","error-severity": "error","error-message": " on line 1: syntax error at or before:'
|
||||||
|
|
||||||
new2 "restconf Check description added"
|
new2 "restconf Check description added"
|
||||||
expecteq "$(curl -s -G http://localhost/restconf/data/interfaces)" '{"interfaces": {"interface": [{"name": "eth/0/0","description": "The-first-interface","type": "ex:eth","enabled": true}]}}
|
expecteq "$(curl -s -G http://localhost/restconf/data/ietf-interfaces:interfaces)" '{"ietf-interfaces:interfaces": {"interface": [{"name": "eth/0/0","description": "The-first-interface","type": "ex:eth","enabled": true}]}}
|
||||||
'
|
'
|
||||||
|
|
||||||
new "restconf delete eth/0/0"
|
new "restconf delete eth/0/0"
|
||||||
expecteq "$(curl -s -X DELETE http://localhost/restconf/data/interfaces/interface=eth%2f0%2f0)" ""
|
expecteq "$(curl -s -X DELETE http://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0)" ""
|
||||||
|
|
||||||
new "Check deleted eth/0/0"
|
new "Check deleted eth/0/0"
|
||||||
expectfn 'curl -s -G http://localhost/restconf/data' 0 $state
|
expectfn 'curl -s -G http://localhost/restconf/data' 0 $state
|
||||||
|
|
||||||
new2 "restconf Re-Delete eth/0/0 using none should generate error"
|
new2 "restconf Re-Delete eth/0/0 using none should generate error"
|
||||||
expecteq "$(curl -s -X DELETE http://localhost/restconf/data/interfaces/interface=eth%2f0%2f0)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "data-missing","error-severity": "error","error-message": "Data does not exist; cannot delete resource"}}}
'
|
expecteq "$(curl -s -X DELETE http://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "data-missing","error-severity": "error","error-message": "Data does not exist; cannot delete resource"}}}
'
|
||||||
|
|
||||||
new "restconf Add subtree eth/0/0 using PUT"
|
new "restconf Add subtree eth/0/0 using PUT"
|
||||||
expecteq "$(curl -s -X PUT -d '{"interface":{"name":"eth/0/0","type":"ex:eth","enabled":true}}' http://localhost/restconf/data/interfaces/interface=eth%2f0%2f0)" ""
|
expecteq "$(curl -s -X PUT -d '{"ietf-interfaces:interface":{"name":"eth/0/0","type":"ex:eth","enabled":true}}' http://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0)" ""
|
||||||
|
|
||||||
new2 "restconf get subtree"
|
new2 "restconf get subtree"
|
||||||
expecteq "$(curl -s -G http://localhost/restconf/data/interfaces)" '{"interfaces": {"interface": [{"name": "eth/0/0","type": "ex:eth","enabled": true}]}}
|
expecteq "$(curl -s -G http://localhost/restconf/data/ietf-interfaces:interfaces)" '{"ietf-interfaces:interfaces": {"interface": [{"name": "eth/0/0","type": "ex:eth","enabled": true}]}}
|
||||||
'
|
'
|
||||||
|
|
||||||
new2 "restconf rpc using POST json"
|
new2 "restconf rpc using POST json"
|
||||||
expecteq "$(curl -s -X POST -d '{"input":{"routing-instance-name":"ipv4","destination-address":{"address-family":"ipv6"}}}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"output": {"route": {"address-family": "ipv4","next-hop": {"next-hop-list": "2.3.4.5"},"source-protocol": "static"}}}
|
expecteq "$(curl -s -X POST -d '{"ietf-routing:input":{"routing-instance-name":"ipv4","destination-address":{"address-family":"ipv6"}}}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"ietf-routing:output": {"route": {"address-family": "ipv4","next-hop": {"next-hop-list": "2.3.4.5"},"source-protocol": "static"}}}
|
||||||
'
|
'
|
||||||
|
|
||||||
# Cant get this to work due to quoting
|
# Cant get this to work due to quoting
|
||||||
#new2 "restconf rpc using POST wrong JSON"
|
#new2 "restconf rpc using POST wrong JSON"
|
||||||
#expecteq "$(curl -s -X POST -d '{"input":{"routing-instance-name":ipv4}}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": " on line 1: syntax error at or before: i"}}}
'
|
#expecteq "$(curl -s -X POST -d '{"ietf-routing:input":{"routing-instance-name":ipv4}}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": " on line 1: syntax error at or before: i"}}}
'
|
||||||
|
|
||||||
new2 "restconf rpc using POST json without mandatory element"
|
new2 "restconf rpc using POST json without mandatory element"
|
||||||
expecteq "$(curl -s -X POST -d '{"input":{"wrongelement":"ipv4"}}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "unknown-element","error-info": {"bad-element": "wrongelement"},"error-severity": "error"}}}
'
|
expecteq "$(curl -s -X POST -d '{"ietf-routing:input":{"wrongelement":"ipv4"}}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "unknown-element","error-info": {"bad-element": "wrongelement"},"error-severity": "error"}}}
'
|
||||||
|
|
||||||
new2 "restconf rpc non-existing rpc without namespace"
|
new2 "restconf rpc non-existing rpc without namespace"
|
||||||
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/kalle)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "missing-element","error-info": {"bad-element": "kalle"},"error-severity": "error","error-message": "RPC not defined"}}}
'
|
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/kalle)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "missing-element","error-info": {"bad-element": "kalle"},"error-severity": "error","error-message": "RPC not defined"}}}
'
|
||||||
|
|
@ -291,29 +290,29 @@ new2 "restconf rpc missing name"
|
||||||
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "Operation name expected"}}}
'
|
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "Operation name expected"}}}
'
|
||||||
|
|
||||||
new2 "restconf rpc missing input"
|
new2 "restconf rpc missing input"
|
||||||
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "missing-element","error-info": {"bad-element": "routing-instance-name"},"error-severity": "error","error-message": "Mandatory variable"}}}
'
|
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"ietf-restconf:errors" : {"error": {"error-type": "rpc","error-tag": "malformed-message","error-severity": "error","error-message": "restconf RPC does not have input statement"}}}
'
|
||||||
|
|
||||||
new "restconf rpc using POST xml"
|
new "restconf rpc using POST xml"
|
||||||
ret=$(curl -s -X POST -H "Accept: application/yang-data+xml" -d '{"input":{"routing-instance-name":"ipv4"}}' http://localhost/restconf/operations/ietf-routing:fib-route)
|
ret=$(curl -s -X POST -H "Accept: application/yang-data+xml" -d '{"ietf-routing:input":{"routing-instance-name":"ipv4"}}' http://localhost/restconf/operations/ietf-routing:fib-route)
|
||||||
expect="<output><route><address-family>ipv4</address-family><next-hop><next-hop-list>2.3.4.5</next-hop-list></next-hop><source-protocol>static</source-protocol></route></output>"
|
expect='<output xmlns="urn:ietf:params:xml:ns:yang:ietf-routing"><route><address-family>ipv4</address-family><next-hop><next-hop-list>2.3.4.5</next-hop-list></next-hop><source-protocol>static</source-protocol></route></output>'
|
||||||
match=`echo $ret | grep -EZo "$expect"`
|
match=`echo $ret | grep -EZo "$expect"`
|
||||||
if [ -z "$match" ]; then
|
if [ -z "$match" ]; then
|
||||||
err "$expect" "$ret"
|
err "$expect" "$ret"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new2 "restconf rpc using wrong prefix"
|
new2 "restconf rpc using wrong prefix"
|
||||||
expecteq "$(curl -s -X POST -d '{"input":{"routing-instance-name":"ipv4"}}' http://localhost/restconf/operations/wrong:fib-route)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "yang module not found"}}}
'
|
expecteq "$(curl -s -X POST -d '{"wrong:input":{"routing-instance-name":"ipv4"}}' http://localhost/restconf/operations/wrong:fib-route)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "yang module not found"}}}
'
|
||||||
|
|
||||||
new "restconf local client rpc using POST xml"
|
new "restconf local client rpc using POST xml"
|
||||||
ret=$(curl -s -X POST -H "Accept: application/yang-data+xml" -d '{"input":{"request":"example"}}' http://localhost/restconf/operations/example:client-rpc)
|
ret=$(curl -s -X POST -H "Accept: application/yang-data+xml" -d '{"example:input":{"request":"example"}}' http://localhost/restconf/operations/example:client-rpc)
|
||||||
expect="<output><result>ok</result></output>"
|
expect='<output xmlns="urn:example:clixon"><result>ok</result></output>'
|
||||||
match=`echo $ret | grep -EZo "$expect"`
|
match=`echo $ret | grep -EZo "$expect"`
|
||||||
if [ -z "$match" ]; then
|
if [ -z "$match" ]; then
|
||||||
err "$expect" "$ret"
|
err "$expect" "$ret"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# XXX cant get -H to work
|
# XXX cant get -H to work
|
||||||
#expecteq 'curl -s -X POST -H "Accept: application/yang-data+xml" -d {"input":{"routing-instance-name":"ipv4"}} http://localhost/restconf/operations/ietf-routing:fib-route' '<output><route><address-family>ipv4</address-family><next-hop><next-hop-list>2.3.4.5</next-hop-list></next-hop></route></output>'
|
#expecteq 'curl -s -X POST -H "Accept: application/yang-data+xml" -d {"ietf-routing:input":{"routing-instance-name":"ipv4"}} http://localhost/restconf/operations/ietf-routing:fib-route' '<output><route><address-family>ipv4</address-family><next-hop><next-hop-list>2.3.4.5</next-hop-list></next-hop></route></output>'
|
||||||
|
|
||||||
# Cant get shell macros to work, inline matching from lib.sh
|
# Cant get shell macros to work, inline matching from lib.sh
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,73 +72,82 @@ sleep $RCWAIT
|
||||||
new "restconf tests"
|
new "restconf tests"
|
||||||
|
|
||||||
new "restconf POST initial tree"
|
new "restconf POST initial tree"
|
||||||
expectfn 'curl -s -X POST -d {"cont1":{"interface":{"name":"local0","type":"regular"}}} http://localhost/restconf/data' 0 ""
|
expectfn 'curl -s -X POST -d {"example:cont1":{"interface":{"name":"local0","type":"regular"}}} http://localhost/restconf/data' 0 ""
|
||||||
|
|
||||||
new "restconf GET datastore intial"
|
new "restconf GET datastore intial"
|
||||||
expectfn "curl -s -X GET http://localhost/restconf/data/cont1" 0 '{"cont1": {"interface": \[{"name": "local0","type": "regular"}\]}}'
|
expectfn "curl -s -X GET http://localhost/restconf/data/example:cont1" 0 '{"example:cont1": {"interface": \[{"name": "local0","type": "regular"}\]}}'
|
||||||
|
|
||||||
new "restconf GET interface"
|
new "restconf GET interface subtree"
|
||||||
expectfn "curl -s -X GET http://localhost/restconf/data/cont1/interface=local0" 0 '{"interface": \[{"name": "local0","type": "regular"}\]}'
|
expectfn "curl -s -X GET http://localhost/restconf/data/example:cont1/interface=local0" 0 '{"example:interface": \[{"name": "local0","type": "regular"}\]}'
|
||||||
|
|
||||||
|
new "restconf GET interface subtree xml"
|
||||||
|
ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/data/example:cont1/interface=local0)
|
||||||
|
expect='<interface xmlns="urn:example:clixon"><name>local0</name><type>regular</type></interface>'
|
||||||
|
match=`echo $ret | grep -EZo "$expect"`
|
||||||
|
if [ -z "$match" ]; then
|
||||||
|
err "$expect" "$ret"
|
||||||
|
fi
|
||||||
|
|
||||||
new "restconf GET if-type"
|
new "restconf GET if-type"
|
||||||
expectfn "curl -s -X GET http://localhost/restconf/data/cont1/interface=local0/type" 0 '{"type": "regular"}'
|
expectfn "curl -s -X GET http://localhost/restconf/data/example:cont1/interface=local0/type" 0 '{"example:type": "regular"}'
|
||||||
|
|
||||||
new "restconf POST interface without mandatory type"
|
new "restconf POST interface without mandatory type"
|
||||||
expectfn 'curl -s -X POST -d {"interface":{"name":"TEST"}} http://localhost/restconf/data/cont1' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "missing-element","error-info": {"bad-element": "type"},"error-severity": "error","error-message": "Mandatory variable"}}}
'
|
expectfn 'curl -s -X POST -d {"interface":{"name":"TEST"}} http://localhost/restconf/data/example:cont1' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "missing-element","error-info": {"bad-element": "type"},"error-severity": "error","error-message": "Mandatory variable"}}}
'
|
||||||
|
|
||||||
new "restconf POST interface"
|
new "restconf POST interface"
|
||||||
expectfn 'curl -s -X POST -d {"interface":{"name":"TEST","type":"eth0"}} http://localhost/restconf/data/cont1' 0 ""
|
expectfn 'curl -s -X POST -d {"example:interface":{"name":"TEST","type":"eth0"}} http://localhost/restconf/data/example:cont1' 0 ""
|
||||||
|
|
||||||
|
# XXX should it be example:interface?
|
||||||
new2 "restconf POST again"
|
new2 "restconf POST again"
|
||||||
expecteq "$(curl -s -X POST -d '{"interface":{"name":"TEST","type":"eth0"}}' http://localhost/restconf/data/cont1)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "data-exists","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}}
'
|
expecteq "$(curl -s -X POST -d '{"interface":{"name":"TEST","type":"eth0"}}' http://localhost/restconf/data/example:cont1)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "data-exists","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}}
'
|
||||||
|
|
||||||
new2 "restconf POST from top"
|
new2 "restconf POST from top"
|
||||||
expecteq "$(curl -s -X POST -d '{"cont1":{"interface":{"name":"TEST","type":"eth0"}}}' http://localhost/restconf/data)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "data-exists","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}}
'
|
expecteq "$(curl -s -X POST -d '{"example:cont1":{"interface":{"name":"TEST","type":"eth0"}}}' http://localhost/restconf/data)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "data-exists","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}}
'
|
||||||
|
|
||||||
new "restconf DELETE"
|
new "restconf DELETE"
|
||||||
expectfn 'curl -s -X DELETE http://localhost/restconf/data/cont1' 0 ""
|
expectfn 'curl -s -X DELETE http://localhost/restconf/data/example:cont1' 0 ""
|
||||||
|
|
||||||
new "restconf GET null datastore"
|
new "restconf GET null datastore"
|
||||||
expectfn "curl -s -X GET http://localhost/restconf/data/cont1" 0 'null'
|
expectfn "curl -s -X GET http://localhost/restconf/data/example:cont1" 0 'null'
|
||||||
|
|
||||||
new "restconf POST initial tree"
|
new "restconf POST initial tree"
|
||||||
expectfn 'curl -s -X POST -d {"cont1":{"interface":{"name":"local0","type":"regular"}}} http://localhost/restconf/data' 0 ""
|
expectfn 'curl -s -X POST -d {"example:cont1":{"interface":{"name":"local0","type":"regular"}}} http://localhost/restconf/data' 0 ""
|
||||||
|
|
||||||
new "restconf GET initial tree"
|
new "restconf GET initial tree"
|
||||||
expectfn "curl -s -X GET http://localhost/restconf/data/cont1" 0 '{"cont1": {"interface": \[{"name": "local0","type": "regular"}\]}}'
|
expectfn "curl -s -X GET http://localhost/restconf/data/example:cont1" 0 '{"example:cont1": {"interface": \[{"name": "local0","type": "regular"}\]}}'
|
||||||
|
|
||||||
new "restconf DELETE whole datastore"
|
new "restconf DELETE whole datastore"
|
||||||
expectfn 'curl -s -X DELETE http://localhost/restconf/data' 0 ""
|
expectfn 'curl -s -X DELETE http://localhost/restconf/data' 0 ""
|
||||||
|
|
||||||
new "restconf GET null datastore"
|
new "restconf GET null datastore"
|
||||||
expectfn "curl -s -X GET http://localhost/restconf/data/cont1" 0 'null'
|
expectfn "curl -s -X GET http://localhost/restconf/data/example:cont1" 0 'null'
|
||||||
|
|
||||||
new "restconf PUT initial datastore"
|
new "restconf PUT initial datastore"
|
||||||
expectfn 'curl -s -X PUT -d {"data":{"cont1":{"interface":{"name":"local0","type":"regular"}}}} http://localhost/restconf/data' 0 ""
|
expectfn 'curl -s -X PUT -d {"data":{"example:cont1":{"interface":{"name":"local0","type":"regular"}}}} http://localhost/restconf/data' 0 ""
|
||||||
|
|
||||||
new "restconf GET datastore"
|
new "restconf GET datastore"
|
||||||
expectfn "curl -s -X GET http://localhost/restconf/data/cont1" 0 '{"cont1": {"interface": \[{"name": "local0","type": "regular"}\]}}'
|
expectfn "curl -s -X GET http://localhost/restconf/data/example:cont1" 0 '{"example:cont1": {"interface": \[{"name": "local0","type": "regular"}\]}}'
|
||||||
|
|
||||||
new "restconf PUT replace datastore"
|
new "restconf PUT replace datastore"
|
||||||
expectfn 'curl -s -X PUT -d {"data":{"cont2":{"name":"foo"}}} http://localhost/restconf/data' 0 ""
|
expectfn 'curl -s -X PUT -d {"data":{"example:cont2":{"name":"foo"}}} http://localhost/restconf/data' 0 ""
|
||||||
|
|
||||||
new "restconf GET replaced datastore"
|
new "restconf GET replaced datastore"
|
||||||
expectfn "curl -s -X GET http://localhost/restconf/data/cont2" 0 '{"cont2": {"name": "foo"}}'
|
expectfn "curl -s -X GET http://localhost/restconf/data/example:cont2" 0 '{"example:cont2": {"name": "foo"}}'
|
||||||
|
|
||||||
new "restconf PUT initial datastore again"
|
new "restconf PUT initial datastore again"
|
||||||
expectfn 'curl -s -X PUT -d {"data":{"cont1":{"interface":{"name":"local0","type":"regular"}}}} http://localhost/restconf/data' 0 ""
|
expectfn 'curl -s -X PUT -d {"data":{"example:cont1":{"interface":{"name":"local0","type":"regular"}}}} http://localhost/restconf/data' 0 ""
|
||||||
|
|
||||||
new "restconf PUT change interface"
|
new "restconf PUT change interface"
|
||||||
expectfn 'curl -s -X PUT -d {"interface":{"name":"local0","type":"atm0"}} http://localhost/restconf/data/cont1/interface=local0' 0 ""
|
expectfn 'curl -s -X PUT -d {"interface":{"name":"local0","type":"atm0"}} http://localhost/restconf/data/example:cont1/interface=local0' 0 ""
|
||||||
|
|
||||||
new "restconf GET datastore atm"
|
new "restconf GET datastore atm"
|
||||||
expectfn "curl -s -X GET http://localhost/restconf/data/cont1" 0 '{"cont1": {"interface": \[{"name": "local0","type": "atm0"}\]}}'
|
expectfn "curl -s -X GET http://localhost/restconf/data/example:cont1" 0 '{"example:cont1": {"interface": \[{"name": "local0","type": "atm0"}\]}}'
|
||||||
|
|
||||||
new "restconf PUT add interface"
|
new "restconf PUT add interface"
|
||||||
expectfn 'curl -s -X PUT -d {"interface":{"name":"TEST","type":"eth0"}} http://localhost/restconf/data/cont1/interface=TEST' 0 ""
|
expectfn 'curl -s -X PUT -d {"interface":{"name":"TEST","type":"eth0"}} http://localhost/restconf/data/example:cont1/interface=TEST' 0 ""
|
||||||
|
|
||||||
new "restconf PUT change key error"
|
new "restconf PUT change key error"
|
||||||
expectfn 'curl -is -X PUT -d {"interface":{"name":"ALPHA","type":"eth0"}} http://localhost/restconf/data/cont1/interface=TEST' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "api-path keys do not match data keys"}}}'
|
expectfn 'curl -is -X PUT -d {"interface":{"name":"ALPHA","type":"eth0"}} http://localhost/restconf/data/example:cont1/interface=TEST' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "api-path keys do not match data keys"}}}'
|
||||||
|
|
||||||
new "Kill restconf daemon"
|
new "Kill restconf daemon"
|
||||||
sudo pkill -u www-data -f "/www-data/clixon_restconf"
|
sudo pkill -u www-data -f "/www-data/clixon_restconf"
|
||||||
|
|
|
||||||
|
|
@ -53,50 +53,70 @@ sleep $RCWAIT
|
||||||
new "rpc tests"
|
new "rpc tests"
|
||||||
|
|
||||||
# 1.First some positive tests vary media types
|
# 1.First some positive tests vary media types
|
||||||
#
|
# extra complex because pattern matching on return haders
|
||||||
|
new "restconf empty rpc"
|
||||||
|
ret=$(curl -is -X POST http://localhost/restconf/operations/example:empty)
|
||||||
|
expect="204 No Content"
|
||||||
|
match=`echo $ret | grep -EZo "$expect"`
|
||||||
|
if [ -z "$match" ]; then
|
||||||
|
err "$expect" "$ret"
|
||||||
|
fi
|
||||||
|
|
||||||
|
new "netconf empty rpc"
|
||||||
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><empty xmlns="urn:example:clixon"/></rpc>]]>]]>' '^<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new2 "restconf example rpc json/json default - no http media headers"
|
new2 "restconf example rpc json/json default - no http media headers"
|
||||||
expecteq "$(curl -s -X POST -d '{"input":{"x":"0"}}' http://localhost/restconf/operations/example:example)" '{"output": {"x": "0","y": "42"}}
|
expecteq "$(curl -s -X POST -d '{"example:input":{"x":0}}' http://localhost/restconf/operations/example:example)" '{"example:output": {"x": "0","y": "42"}}
|
||||||
'
|
'
|
||||||
|
|
||||||
new2 "restconf example rpc json/json change y default"
|
new2 "restconf example rpc json/json change y default"
|
||||||
expecteq "$(curl -s -X POST -d '{"input":{"x":"0","y":"99"}}' http://localhost/restconf/operations/example:example)" '{"output": {"x": "0","y": "99"}}
|
expecteq "$(curl -s -X POST -d '{"example:input":{"x":"0","y":"99"}}' http://localhost/restconf/operations/example:example)" '{"example:output": {"x": "0","y": "99"}}
|
||||||
'
|
'
|
||||||
|
|
||||||
new2 "restconf example rpc json/json"
|
new2 "restconf example rpc json/json"
|
||||||
# XXX example:input example:output
|
# XXX example:input example:output
|
||||||
expecteq "$(curl -s -X POST -H 'Content-Type: application/yang-data+json' -H 'Content-Type: application/yang-data+json' -d '{"input":{"x":"0"}}' http://localhost/restconf/operations/example:example)" '{"output": {"x": "0","y": "42"}}
|
expecteq "$(curl -s -X POST -H 'Content-Type: application/yang-data+json' -H 'Content-Type: application/yang-data+json' -d '{"example:input":{"x":"0"}}' http://localhost/restconf/operations/example:example)" '{"example:output": {"x": "0","y": "42"}}
|
||||||
'
|
'
|
||||||
|
|
||||||
new2 "restconf example rpc xml/json"
|
new2 "restconf example rpc xml/json"
|
||||||
expecteq "$(curl -s -X POST -H 'Content-Type: application/yang-data+xml' -H 'Content-Type: application/yang-data+json' -d '<input xmlns="urn:example:clixon"><x>0</x></input>' http://localhost/restconf/operations/example:example)" '{"output": {"x": "0","y": "42"}}
|
expecteq "$(curl -s -X POST -H 'Content-Type: application/yang-data+xml' -H 'Content-Type: application/yang-data+json' -d '<input xmlns="urn:example:clixon"><x>0</x></input>' http://localhost/restconf/operations/example:example)" '{"example:output": {"x": "0","y": "42"}}
|
||||||
'
|
'
|
||||||
|
|
||||||
new2 "restconf example rpc json/xml"
|
new2 "restconf example rpc json/xml"
|
||||||
# <output xmlns="rn:example:clixon"
|
expecteq "$(curl -s -X POST -H 'Content-Type: application/yang-data+json' -H 'Accept: application/yang-data+xml' -d '{"example:input":{"x":"0"}}' http://localhost/restconf/operations/example:example)" '<output xmlns="urn:example:clixon"><x>0</x><y>42</y></output>
|
||||||
expecteq "$(curl -s -X POST -H 'Content-Type: application/yang-data+json' -H 'Accept: application/yang-data+xml' -d '{"input":{"x":"0"}}' http://localhost/restconf/operations/example:example)" '<output><x>0</x><y>42</y></output>
|
|
||||||
'
|
'
|
||||||
|
|
||||||
new2 "restconf example rpc xml/xml"
|
new2 "restconf example rpc xml/xml"
|
||||||
# <output xmlns="rn:example:clixon"
|
expecteq "$(curl -s -X POST -H 'Content-Type: application/yang-data+xml' -H 'Accept: application/yang-data+xml' -d '<input xmlns="urn:example:clixon"><x>0</x></input>' http://localhost/restconf/operations/example:example)" '<output xmlns="urn:example:clixon"><x>0</x><y>42</y></output>
|
||||||
expecteq "$(curl -s -X POST -H 'Content-Type: application/yang-data+xml' -H 'Accept: application/yang-data+xml' -d '<input xmlns="urn:example:clixon"><x>0</x></input>' http://localhost/restconf/operations/example:example)" '<output><x>0</x><y>42</y></output>
|
|
||||||
'
|
'
|
||||||
|
|
||||||
new "netconf example rpc"
|
new "netconf example rpc"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><example><x>0</x></example></rpc>]]>]]>' '^<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><x>0</x><y>42</y></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><example xmlns="urn:example:clixon"><x>0</x></example></rpc>]]>]]>' '^<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><x xmlns="urn:example:clixon">0</x><y xmlns="urn:example:clixon">42</y></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
# 2. Then error cases
|
# 2. Then error cases
|
||||||
#
|
#
|
||||||
|
new "restconf empy rpc with null input"
|
||||||
|
ret=$(curl -is -X POST -d '{"example:input":null}' http://localhost/restconf/operations/example:empty)
|
||||||
|
expect="204 No Content"
|
||||||
|
match=`echo $ret | grep -EZo "$expect"`
|
||||||
|
if [ -z "$match" ]; then
|
||||||
|
err "$expect" "$ret"
|
||||||
|
fi
|
||||||
|
|
||||||
|
new2 "restconf empy rpc with input x"
|
||||||
|
expecteq "$(curl -s -X POST -d '{"example:input":{"x":0}}' http://localhost/restconf/operations/example:empty)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "unknown-element","error-info": {"bad-element": "x"},"error-severity": "error"}}}
'
|
||||||
|
|
||||||
new2 "restconf omit mandatory"
|
new2 "restconf omit mandatory"
|
||||||
expecteq "$(curl -s -X POST -d '{"input":null}' http://localhost/restconf/operations/example:example)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "missing-element","error-info": {"bad-element": "x"},"error-severity": "error","error-message": "Mandatory variable"}}}
'
|
expecteq "$(curl -s -X POST -d '{"example:input":null}' http://localhost/restconf/operations/example:example)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "missing-element","error-info": {"bad-element": "x"},"error-severity": "error","error-message": "Mandatory variable"}}}
'
|
||||||
|
|
||||||
new2 "restconf add extra"
|
new2 "restconf add extra"
|
||||||
expecteq "$(curl -s -X POST -d '{"input":{"x":"0","extra":"0"}}' http://localhost/restconf/operations/example:example)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "unknown-element","error-info": {"bad-element": "extra"},"error-severity": "error"}}}
'
|
expecteq "$(curl -s -X POST -d '{"example:input":{"x":"0","extra":"0"}}' http://localhost/restconf/operations/example:example)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "unknown-element","error-info": {"bad-element": "extra"},"error-severity": "error"}}}
'
|
||||||
|
|
||||||
new2 "restconf wrong method"
|
new2 "restconf wrong method"
|
||||||
expecteq "$(curl -s -X POST -d '{"input":{"x":"0"}}' http://localhost/restconf/operations/example:wrong)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "missing-element","error-info": {"bad-element": "wrong"},"error-severity": "error","error-message": "RPC not defined"}}}
'
|
expecteq "$(curl -s -X POST -d '{"example:input":{"x":"0"}}' http://localhost/restconf/operations/example:wrong)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "missing-element","error-info": {"bad-element": "wrong"},"error-severity": "error","error-message": "RPC not defined"}}}
'
|
||||||
|
|
||||||
new2 "restconf edit-config missing mandatory"
|
new2 "restconf edit-config missing mandatory"
|
||||||
expecteq "$(curl -s -X POST -d '{"input":null}' http://localhost/restconf/operations/ietf-netconf:edit-config)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "yang module not found"}}}
'
|
expecteq "$(curl -s -X POST -d '{"example:input":null}' http://localhost/restconf/operations/ietf-netconf:edit-config)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "yang module not found"}}}
'
|
||||||
|
|
||||||
new "netconf kill-session missing session-id mandatory"
|
new "netconf kill-session missing session-id mandatory"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><kill-session/></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>missing-element</error-tag><error-info><bad-element>session-id</bad-element></error-info><error-severity>error</error-severity><error-message>Mandatory variable</error-message></rpc-error></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><kill-session/></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>missing-element</error-tag><error-info><bad-element>session-id</bad-element></error-info><error-severity>error</error-severity><error-message>Mandatory variable</error-message></rpc-error></rpc-reply>]]>]]>$'
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ run(){
|
||||||
dbdir=$dir/db
|
dbdir=$dir/db
|
||||||
cat <<EOF > $dbdir
|
cat <<EOF > $dbdir
|
||||||
<config>
|
<config>
|
||||||
<interfaces>
|
<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
|
||||||
<interface>
|
<interface>
|
||||||
<name>run</name>
|
<name>run</name>
|
||||||
<type>ex:eth</type>
|
<type>ex:eth</type>
|
||||||
|
|
@ -53,7 +53,7 @@ EOF
|
||||||
|
|
||||||
cat <<EOF > $dbdir
|
cat <<EOF > $dbdir
|
||||||
<config>
|
<config>
|
||||||
<interfaces>
|
<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
|
||||||
<interface>
|
<interface>
|
||||||
<name>startup</name>
|
<name>startup</name>
|
||||||
<type>ex:eth</type>
|
<type>ex:eth</type>
|
||||||
|
|
@ -65,7 +65,7 @@ EOF
|
||||||
|
|
||||||
cat <<EOF > $dir/config
|
cat <<EOF > $dir/config
|
||||||
<config>
|
<config>
|
||||||
<interfaces>
|
<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
|
||||||
<interface>
|
<interface>
|
||||||
<name>extra</name>
|
<name>extra</name>
|
||||||
<type>ex:eth</type>
|
<type>ex:eth</type>
|
||||||
|
|
@ -104,8 +104,8 @@ EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
run init '<data/>'
|
run init '<data/>'
|
||||||
run none '<data><interfaces><interface><name>run</name><type>ex:eth</type><enabled>true</enabled></interface></interfaces></data>'
|
run none '<data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>run</name><type>ex:eth</type><enabled>true</enabled></interface></interfaces></data>'
|
||||||
run running '<data><interfaces><interface><name>extra</name><type>ex:eth</type><enabled>true</enabled></interface><interface><name>lo</name><type>ex:loopback</type><enabled>true</enabled></interface><interface><name>run</name><type>ex:eth</type><enabled>true</enabled></interface></interfaces></data>'
|
run running '<data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>extra</name><type>ex:eth</type><enabled>true</enabled></interface><interface><name>lo</name><type>ex:loopback</type><enabled>true</enabled></interface><interface><name>run</name><type>ex:eth</type><enabled>true</enabled></interface></interfaces></data>'
|
||||||
run startup '<data><interfaces><interface><name>extra</name><type>ex:eth</type><enabled>true</enabled></interface><interface><name>lo</name><type>ex:loopback</type><enabled>true</enabled></interface><interface><name>startup</name><type>ex:eth</type><enabled>true</enabled></interface></interfaces></data>'
|
run startup '<data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>extra</name><type>ex:eth</type><enabled>true</enabled></interface><interface><name>lo</name><type>ex:loopback</type><enabled>true</enabled></interface><interface><name>startup</name><type>ex:eth</type><enabled>true</enabled></interface></interfaces></data>'
|
||||||
|
|
||||||
rm -rf $dir
|
rm -rf $dir
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ EOF
|
||||||
# using reportingEntity (rfc5277) not reporting-entity (rfc8040)
|
# using reportingEntity (rfc5277) not reporting-entity (rfc8040)
|
||||||
cat <<EOF > $fyang
|
cat <<EOF > $fyang
|
||||||
module example {
|
module example {
|
||||||
namespace "http://example.com/event/1.0";
|
namespace "urn:example:clixon";
|
||||||
prefix ex;
|
prefix ex;
|
||||||
organization "Example, Inc.";
|
organization "Example, Inc.";
|
||||||
contact "support at example.com";
|
contact "support at example.com";
|
||||||
|
|
@ -130,35 +130,35 @@ sleep $RCWAIT
|
||||||
new "1. Netconf RFC5277 stream testing"
|
new "1. Netconf RFC5277 stream testing"
|
||||||
# 1.1 Stream discovery
|
# 1.1 Stream discovery
|
||||||
new "netconf event stream discovery RFC5277 Sec 3.2.5"
|
new "netconf event stream discovery RFC5277 Sec 3.2.5"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get><filter type="xpath" select="netconf/streams" xmlns="urn:ietf:params:xml:ns:netmod:notification"/></get></rpc>]]>]]>' '<rpc-reply><data><netconf><streams><stream><name>EXAMPLE</name><description>Example event stream</description><replay-support>true</replay-support></stream></streams></netconf></data></rpc-reply>]]>]]>'
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get><filter type="xpath" select="netconf/streams" xmlns="urn:ietf:params:xml:ns:netmod:notification"/></get></rpc>]]>]]>' '<rpc-reply><data><netconf xmlns="urn:ietf:params:xml:ns:netmod:notification"><streams><stream><name>EXAMPLE</name><description>Example event stream</description><replay-support>true</replay-support></stream></streams></netconf></data></rpc-reply>]]>]]>'
|
||||||
|
|
||||||
new "netconf event stream discovery RFC8040 Sec 6.2"
|
new "netconf event stream discovery RFC8040 Sec 6.2"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get><filter type="xpath" select="restconf-state/streams" xmlns="urn:ietf:params:xml:ns:netmod:notification"/></get></rpc>]]>]]>' '<rpc-reply><data><restconf-state><streams><stream><name>EXAMPLE</name><description>Example event stream</description><replay-support>true</replay-support><access><encoding>xml</encoding><location>https://localhost/streams/EXAMPLE</location></access></stream></streams></restconf-state></data></rpc-reply>]]>]]>'
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get><filter type="xpath" select="restconf-state/streams"/></get></rpc>]]>]]>' '<rpc-reply><data><restconf-state xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf-monitoring"><streams><stream><name>EXAMPLE</name><description>Example event stream</description><replay-support>true</replay-support><access><encoding>xml</encoding><location>https://localhost/streams/EXAMPLE</location></access></stream></streams></restconf-state></data></rpc-reply>]]>]]>'
|
||||||
|
|
||||||
#
|
#
|
||||||
# 1.2 Netconf stream subscription
|
# 1.2 Netconf stream subscription
|
||||||
new "netconf EXAMPLE subscription"
|
new "netconf EXAMPLE subscription"
|
||||||
expectwait "$clixon_netconf -qf $cfg -y $fyang" '<rpc><create-subscription><stream>EXAMPLE</stream></create-subscription></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]><notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>20' $NCWAIT
|
expectwait "$clixon_netconf -qf $cfg -y $fyang" '<rpc><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"><stream>EXAMPLE</stream></create-subscription></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]><notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>20' $NCWAIT
|
||||||
|
|
||||||
new "netconf subscription with empty startTime"
|
new "netconf subscription with empty startTime"
|
||||||
expectwait "$clixon_netconf -qf $cfg -y $fyang" '<rpc><create-subscription><stream>EXAMPLE</stream><startTime/></create-subscription></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]><notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>20' $NCWAIT
|
expectwait "$clixon_netconf -qf $cfg -y $fyang" '<rpc><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"><stream>EXAMPLE</stream><startTime/></create-subscription></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]><notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>20' $NCWAIT
|
||||||
|
|
||||||
new "netconf EXAMPLE subscription with simple filter"
|
new "netconf EXAMPLE subscription with simple filter"
|
||||||
expectwait "$clixon_netconf -qf $cfg -y $fyang" "<rpc><create-subscription><stream>EXAMPLE</stream><filter type=\"xpath\" select=\"event\"/></create-subscription></rpc>]]>]]>" '^<rpc-reply><ok/></rpc-reply>]]>]]><notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>20' $NCWAIT
|
expectwait "$clixon_netconf -qf $cfg -y $fyang" '<rpc><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"><stream>EXAMPLE</stream><filter type="xpath" select="event"/></create-subscription></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]><notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>20' $NCWAIT
|
||||||
|
|
||||||
new "netconf EXAMPLE subscription with filter classifier"
|
new "netconf EXAMPLE subscription with filter classifier"
|
||||||
expectwait "$clixon_netconf -qf $cfg -y $fyang" "<rpc><create-subscription><stream>EXAMPLE</stream><filter type=\"xpath\" select=\"event[event-class='fault']\"/></create-subscription></rpc>]]>]]>" '^<rpc-reply><ok/></rpc-reply>]]>]]><notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>20' $NCWAIT
|
expectwait "$clixon_netconf -qf $cfg -y $fyang" "<rpc><create-subscription xmlns=\"urn:ietf:params:xml:ns:netmod:notification\"><stream>EXAMPLE</stream><filter type=\"xpath\" select=\"event[event-class='fault']\"/></create-subscription></rpc>]]>]]>" '^<rpc-reply><ok/></rpc-reply>]]>]]><notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>20' $NCWAIT
|
||||||
|
|
||||||
new "netconf NONEXIST subscription"
|
new "netconf NONEXIST subscription"
|
||||||
expectwait "$clixon_netconf -qf $cfg -y $fyang" '<rpc><create-subscription><stream>NONEXIST</stream></create-subscription></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>invalid-value</error-tag><error-severity>error</error-severity><error-message>No such stream</error-message></rpc-error></rpc-reply>]]>]]>$' $NCWAIT
|
expectwait "$clixon_netconf -qf $cfg -y $fyang" '<rpc><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"><stream>NONEXIST</stream></create-subscription></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>invalid-value</error-tag><error-severity>error</error-severity><error-message>No such stream</error-message></rpc-error></rpc-reply>]]>]]>$' $NCWAIT
|
||||||
|
|
||||||
new "netconf EXAMPLE subscription with wrong date"
|
new "netconf EXAMPLE subscription with wrong date"
|
||||||
expectwait "$clixon_netconf -qf $cfg -y $fyang" '<rpc><create-subscription><stream>EXAMPLE</stream><startTime>kallekaka</startTime></create-subscription></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>startTime</bad-element></error-info><error-severity>error</error-severity><error-message>Invalid time: kallekaka</error-message></rpc-error></rpc-reply>]]>]]>$' 0
|
expectwait "$clixon_netconf -qf $cfg -y $fyang" '<rpc><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"><stream>EXAMPLE</stream><startTime>kallekaka</startTime></create-subscription></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>startTime</bad-element></error-info><error-severity>error</error-severity><error-message>Invalid time: kallekaka</error-message></rpc-error></rpc-reply>]]>]]>$' 0
|
||||||
|
|
||||||
#new "netconf EXAMPLE subscription with replay"
|
#new "netconf EXAMPLE subscription with replay"
|
||||||
#NOW=$(date +"%Y-%m-%dT%H:%M:%S")
|
#NOW=$(date +"%Y-%m-%dT%H:%M:%S")
|
||||||
#sleep 10
|
#sleep 10
|
||||||
#expectwait "$clixon_netconf -qf $cfg -y $fyang" "<rpc><create-subscription><stream>EXAMPLE</stream><startTime>$NOW</startTime></create-subscription></rpc>]]>]]>" '^<rpc-reply><ok/></rpc-reply>]]>]]><notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>20' 10
|
#expectwait "$clixon_netconf -qf $cfg -y $fyang" "<rpc><create-subscription xmlns=\"urn:ietf:params:xml:ns:netmod:notification\"><stream>EXAMPLE</stream><startTime>$NOW</startTime></create-subscription></rpc>]]>]]>" '^<rpc-reply><ok/></rpc-reply>]]>]]><notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>20' 10
|
||||||
sleep 2
|
sleep 2
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
@ -166,11 +166,11 @@ sleep 2
|
||||||
new "2. Restconf RFC8040 stream testing"
|
new "2. Restconf RFC8040 stream testing"
|
||||||
# 2.1 Stream discovery
|
# 2.1 Stream discovery
|
||||||
new "restconf event stream discovery RFC8040 Sec 6.2"
|
new "restconf event stream discovery RFC8040 Sec 6.2"
|
||||||
expectfn "curl -s -X GET http://localhost/restconf/data/ietf-restconf-monitoring:restconf-state/streams" 0 '{"streams": {"stream": \[{"name": "EXAMPLE","description": "Example event stream","replay-support": true,"access": \[{"encoding": "xml","location": "https://localhost/streams/EXAMPLE"}\]}\]}'
|
expectfn "curl -s -X GET http://localhost/restconf/data/ietf-restconf-monitoring:restconf-state/streams" 0 '{"ietf-restconf-monitoring:streams": {"stream": \[{"name": "EXAMPLE","description": "Example event stream","replay-support": true,"access": \[{"encoding": "xml","location": "https://localhost/streams/EXAMPLE"}\]}\]}'
|
||||||
|
|
||||||
sleep 2
|
sleep 2
|
||||||
new "restconf subscribe RFC8040 Sec 6.3, get location"
|
new "restconf subscribe RFC8040 Sec 6.3, get location"
|
||||||
expectfn "curl -s -X GET http://localhost/restconf/data/ietf-restconf-monitoring:restconf-state/streams/stream=EXAMPLE/access=xml/location" 0 '{"location": "https://localhost/streams/EXAMPLE"}'
|
expectfn "curl -s -X GET http://localhost/restconf/data/ietf-restconf-monitoring:restconf-state/streams/stream=EXAMPLE/access=xml/location" 0 '{"ietf-restconf-monitoring:location": "https://localhost/streams/EXAMPLE"}'
|
||||||
|
|
||||||
sleep 2
|
sleep 2
|
||||||
# Restconf stream subscription RFC8040 Sec 6.3
|
# Restconf stream subscription RFC8040 Sec 6.3
|
||||||
|
|
@ -246,13 +246,12 @@ if [ $nr -lt 9 -o $nr -gt 14 ]; then
|
||||||
err 10 "$nr"
|
err 10 "$nr"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
# Try parallell
|
# Try parallell
|
||||||
# start background job
|
# start background job
|
||||||
curl -s -X GET -H "Accept: text/event-stream" -H "Cache-Control: no-cache" -H "Connection: keep-alive" "http://localhost/streams/EXAMPLE" > /dev/null &
|
curl -s -X GET -H "Accept: text/event-stream" -H "Cache-Control: no-cache" -H "Connection: keep-alive" "http://localhost/streams/EXAMPLE" > /dev/null &
|
||||||
PID=$!
|
PID=$!
|
||||||
|
|
||||||
new "Start subscription in parallell"
|
new "Start subscriptions in parallell"
|
||||||
ret=$($UTIL -u http://localhost/streams/EXAMPLE -t 8)
|
ret=$($UTIL -u http://localhost/streams/EXAMPLE -t 8)
|
||||||
expect="data: <notification xmlns=\"urn:ietf:params:xml:ns:netconf:notification:1.0\"><eventTime>${DATE}T[0-9:.]*</eventTime><event><event-class>fault</event-class><reportingEntity><card>Ethernet0</card></reportingEntity><severity>major</severity></event>"
|
expect="data: <notification xmlns=\"urn:ietf:params:xml:ns:netconf:notification:1.0\"><eventTime>${DATE}T[0-9:.]*</eventTime><event><event-class>fault</event-class><reportingEntity><card>Ethernet0</card></reportingEntity><severity>major</severity></event>"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -214,7 +214,7 @@ new "cli set transitive string error"
|
||||||
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set c talle 9xx" 255 "^$"
|
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set c talle 9xx" 255 "^$"
|
||||||
|
|
||||||
new "netconf set transitive string error"
|
new "netconf set transitive string error"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><c><talle>9xx</talle></c></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><c xmlns="urn:example:clixon"><talle>9xx</talle></c></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>"
|
||||||
|
|
||||||
new "netconf validate should fail"
|
new "netconf validate should fail"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>talle</bad-element></error-info><error-severity>error</error-severity><error-message>regexp match fail: "9xx" does not match \[a-z\]\[0-9\]\*</error-message></rpc-error></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>talle</bad-element></error-info><error-severity>error</error-severity><error-message>regexp match fail: "9xx" does not match \[a-z\]\[0-9\]\*</error-message></rpc-error></rpc-reply>]]>]]>$'
|
||||||
|
|
@ -241,7 +241,7 @@ new "cli set transitive union error int"
|
||||||
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set c ulle 55" 255 ""
|
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set c ulle 55" 255 ""
|
||||||
|
|
||||||
new "netconf set transitive union error int"
|
new "netconf set transitive union error int"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><c><ulle>55</ulle></c></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><c xmlns="urn:example:clixon"><ulle>55</ulle></c></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>"
|
||||||
|
|
||||||
new "netconf validate should fail"
|
new "netconf validate should fail"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>ulle</bad-element></error-info><error-severity>error</error-severity><error-message>'55' does not match enumeration</error-message></rpc-error></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>ulle</bad-element></error-info><error-severity>error</error-severity><error-message>'55' does not match enumeration</error-message></rpc-error></rpc-reply>]]>]]>$"
|
||||||
|
|
@ -276,7 +276,7 @@ new "netconf validate ok"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf set ab wrong"
|
new "netconf set ab wrong"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><list><ip>a.b& c.d</ip></list></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><list xmlns="urn:example:clixon"><ip>a.b& c.d</ip></list></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf validate"
|
new "netconf validate"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error>"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error>"
|
||||||
|
|
@ -298,7 +298,7 @@ expectfn "$clixon_cli -1f $cfg -l o -y $fyang set mbits create" 0 "^$"
|
||||||
#expectfn "$clixon_cli -1f $cfg -l o -y $fyang set mbits \"create read\"" 0 "^$"
|
#expectfn "$clixon_cli -1f $cfg -l o -y $fyang set mbits \"create read\"" 0 "^$"
|
||||||
|
|
||||||
new "netconf bits two values"
|
new "netconf bits two values"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><mbits>create read</mbits></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><mbits xmlns="urn:example:clixon">create read</mbits></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "cli bits validate"
|
new "cli bits validate"
|
||||||
expectfn "$clixon_cli -1f $cfg -l o -y $fyang validate" 0 "^$"
|
expectfn "$clixon_cli -1f $cfg -l o -y $fyang validate" 0 "^$"
|
||||||
|
|
|
||||||
|
|
@ -106,16 +106,16 @@ if [ $BE -ne 0 ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new "when: add static route"
|
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>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><whenex xmlns="urn:example:clixon"><type>static</type><name>r1</name><static-routes/></whenex></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "when: validate ok"
|
new "when: validate ok"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
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"
|
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>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><whenex xmlns="urn:example:clixon"><type>direct</type><name>r2</name><static-routes/></whenex></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "when get config"
|
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>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" '^<rpc-reply><data><whenex xmlns="urn:example:clixon"><type>direct</type><name>r2</name><static-routes/></whenex><whenex xmlns="urn:example:clixon"><type>static</type><name>r1</name><static-routes/></whenex></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "when: validate fail"
|
new "when: validate fail"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>when xpath validation failed</error-message></rpc-error></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>when xpath validation failed</error-message></rpc-error></rpc-reply>]]>]]>$"
|
||||||
|
|
@ -124,19 +124,19 @@ new "when: discard-changes"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "must: add interface"
|
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>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><interface xmlns="urn:example:clixon"><ifType>ethernet</ifType><ifMTU>1500</ifMTU></interface></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "must: validate ok"
|
new "must: validate ok"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
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"
|
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>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><interface xmlns="urn:example:clixon"><ifType>atm</ifType><ifMTU>32</ifMTU></interface></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "must: atm validate fail"
|
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-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>An ATM MTU must be 64 .. 17966</error-message></rpc-error></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><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"
|
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>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><interface xmlns="urn:example:clixon"><ifType>ethernet</ifType><ifMTU>989</ifMTU></interface></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "must: eth validate fail"
|
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-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>An Ethernet MTU must be 1500</error-message></rpc-error></rpc-reply>]]>]]>"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>An Ethernet MTU must be 1500</error-message></rpc-error></rpc-reply>]]>]]>"
|
||||||
|
|
|
||||||
|
|
@ -160,13 +160,13 @@ new "cli defined extension"
|
||||||
expectfn "$clixon_cli -1f $cfg -y $fyang show version" 0 "3."
|
expectfn "$clixon_cli -1f $cfg -y $fyang show version" 0 "3."
|
||||||
|
|
||||||
new "empty values in leaf-list"
|
new "empty values in leaf-list"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><x><f><e>a</e></f></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><f><e>a</e></f></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "empty values in leaf-list2"
|
new "empty values in leaf-list2"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><x><f><e/></f></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><f><e/></f></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf get config"
|
new "netconf get config"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><x><f><e/><e>a</e></f></x></data></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" '^<rpc-reply><data><x xmlns="urn:example:clixon"><f><e/><e>a</e></f></x></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "netconf discard-changes"
|
new "netconf discard-changes"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
@ -182,7 +182,7 @@ new "netconf schema resource, RFC 7895"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get><filter type="xpath" select="modules-state/module" xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library"/></get></rpc>]]>]]>' '<module><name>ietf-yang-types</name><revision>2013-07-15</revision><namespace>urn:ietf:params:xml:ns:yang:ietf-yang-types</namespace><conformance-type>implement</conformance-type></module>'
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get><filter type="xpath" select="modules-state/module" xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library"/></get></rpc>]]>]]>' '<module><name>ietf-yang-types</name><revision>2013-07-15</revision><namespace>urn:ietf:params:xml:ns:yang:ietf-yang-types</namespace><conformance-type>implement</conformance-type></module>'
|
||||||
|
|
||||||
new "netconf edit config"
|
new "netconf edit config"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><x><y><a>1</a><b>2</b><c>5</c><val>one</val></y><d/></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><y><a>1</a><b>2</b><c>5</c><val>one</val></y><d/></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf commit"
|
new "netconf commit"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
@ -192,33 +192,34 @@ new "netconf commit 2nd"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf get config xpath"
|
new "netconf get config xpath"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/x/y[a=1][b=2][c=5]\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><x><y><a>1</a><b>2</b><c>5</c><val>one</val></y></x></data></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/x/y[a=1][b=2][c=5]\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><x xmlns="urn:example:clixon"><y><a>1</a><b>2</b><c>5</c><val>one</val></y></x></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "netconf edit leaf-list"
|
new "netconf edit leaf-list"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<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 $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><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 $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 xmlns="urn:example:clixon"><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 $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 xmlns=\"urn:example:clixon\"><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 $cfg -y $fyang" 0 "<rpc><get><filter type=\"xpath\" select=\"/\"/></get></rpc>]]>]]>" "^<rpc-reply><data><x><y><a>1</a><b>2</b><c>5</c><val>one</val></y><d/></x>"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get><filter type=\"xpath\" select=\"/\"/></get></rpc>]]>]]>" '^<rpc-reply><data><x xmlns="urn:example:clixon"><y><a>1</a><b>2</b><c>5</c><val>one</val></y><d/></x>'
|
||||||
|
|
||||||
new "cli set leaf-list"
|
new "cli set leaf-list"
|
||||||
expectfn "$clixon_cli -1f $cfg -y $fyang set x f e foo" 0 ""
|
expectfn "$clixon_cli -1f $cfg -y $fyang set x f e foo" 0 ""
|
||||||
|
|
||||||
new "cli show leaf-list"
|
new "cli show leaf-list"
|
||||||
expectfn "$clixon_cli -1f $cfg -y $fyang show xpath /x/f/e" 0 "<e>foo</e>"
|
expectfn "$clixon_cli -1f $cfg -y $fyang show xpath /x/f/e" 0 "<e>foo</e>"
|
||||||
|
|
||||||
new "netconf set state data (not allowed)"
|
new "netconf set state data (not allowed)"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><state><op>42</op></state></config></edit-config></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-type>protocol</error-type><error-tag>invalid-value"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><state xmlns="urn:example:clixon"><op>42</op></state></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>protocol</error-type><error-tag>invalid-value</error-tag><error-severity>error</error-severity><error-message>State data not allowed</error-message></rpc-error></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "netconf set presence and not present"
|
new "netconf set presence and not present"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><x><nopresence/><presence/></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><nopresence/><presence/></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf get presence only"
|
new "netconf get presence only"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<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 $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/x/presence"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><x xmlns="urn:example:clixon"><presence/></x></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "netconf get presence only"
|
new "netconf get presence only"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/x/nopresence"/></get-config></rpc>]]>]]>' "^<rpc-reply><data/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/x/nopresence"/></get-config></rpc>]]>]]>' "^<rpc-reply><data/></rpc-reply>]]>]]>$"
|
||||||
|
|
@ -227,7 +228,7 @@ new "netconf discard-changes"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf anyxml"
|
new "netconf anyxml"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<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>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><any><foo><bar a="nisse"/></foo></any></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf validate anyxml"
|
new "netconf validate anyxml"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
@ -237,28 +238,28 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><can
|
||||||
|
|
||||||
# Check 3-keys
|
# Check 3-keys
|
||||||
new "netconf add one 3-key entry"
|
new "netconf add one 3-key entry"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><x><y><a>1</a><b>1</b><c>1</c><val>one</val></y></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><y><a>1</a><b>1</b><c>1</c><val>one</val></y></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf check add one 3-key"
|
new "netconf check add one 3-key"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '<rpc-reply><data><x><y><a>1</a><b>1</b><c>1</c><val>one</val></y></x></data></rpc-reply>]]>]]>'
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '<rpc-reply><data><x xmlns="urn:example:clixon"><y><a>1</a><b>1</b><c>1</c><val>one</val></y></x></data></rpc-reply>]]>]]>'
|
||||||
|
|
||||||
new "netconf add another (with same 1st key)"
|
new "netconf add another (with same 1st key)"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><x><y><a>1</a><b>2</b><c>1</c><val>two</val></y></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><y><a>1</a><b>2</b><c>1</c><val>two</val></y></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf check add another"
|
new "netconf check add another"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '<rpc-reply><data><x><y><a>1</a><b>1</b><c>1</c><val>one</val></y><y><a>1</a><b>2</b><c>1</c><val>two</val></y></x></data></rpc-reply>]]>]]>'
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '<rpc-reply><data><x xmlns="urn:example:clixon"><y><a>1</a><b>1</b><c>1</c><val>one</val></y><y><a>1</a><b>2</b><c>1</c><val>two</val></y></x></data></rpc-reply>]]>]]>'
|
||||||
|
|
||||||
new "netconf replace first"
|
new "netconf replace first"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><x><y><a>1</a><b>1</b><c>1</c><val>replace</val></y></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><y><a>1</a><b>1</b><c>1</c><val>replace</val></y></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf check replace"
|
new "netconf check replace"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '<rpc-reply><data><x><y><a>1</a><b>1</b><c>1</c><val>replace</val></y><y><a>1</a><b>2</b><c>1</c><val>two</val></y></x></data></rpc-reply>]]>]]>'
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '<rpc-reply><data><x xmlns="urn:example:clixon"><y><a>1</a><b>1</b><c>1</c><val>replace</val></y><y><a>1</a><b>2</b><c>1</c><val>two</val></y></x></data></rpc-reply>]]>]]>'
|
||||||
|
|
||||||
new "netconf delete first"
|
new "netconf delete first"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><x><y operation="remove"><a>1</a><b>1</b><c>1</c></y></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><y operation="remove"><a>1</a><b>1</b><c>1</c></y></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf check delete"
|
new "netconf check delete"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '<rpc-reply><data><x><y><a>1</a><b>2</b><c>1</c><val>two</val></y></x></data></rpc-reply>]]>]]>'
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '<rpc-reply><data><x xmlns="urn:example:clixon"><y><a>1</a><b>2</b><c>1</c><val>two</val></y></x></data></rpc-reply>]]>]]>'
|
||||||
|
|
||||||
# clear db for next test
|
# clear db for next test
|
||||||
new "netconf delete candidate"
|
new "netconf delete candidate"
|
||||||
|
|
@ -268,10 +269,10 @@ new "netconf commit empty candidate"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconfig config submodule"
|
new "netconfig config submodule"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><mylist><x>a</x><subm-container><subm-leaf>foo</subm-leaf></subm-container></mylist></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><mylist xmlns="urn:example:clixon"><x>a</x><subm-container><subm-leaf>foo</subm-leaf></subm-container></mylist></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf submodule get config"
|
new "netconf submodule get config"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><mylist><x>a</x><subm-container><subm-leaf>foo</subm-leaf></subm-container></mylist></data></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply><data><mylist xmlns="urn:example:clixon"><x>a</x><subm-container><subm-leaf>foo</subm-leaf></subm-container></mylist></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "netconf submodule validate"
|
new "netconf submodule validate"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ cat <<EOF > $fyang1
|
||||||
module $APPNAME{
|
module $APPNAME{
|
||||||
prefix ex;
|
prefix ex;
|
||||||
revision 2018-12-02;
|
revision 2018-12-02;
|
||||||
namespace "urn:example:example";
|
namespace "urn:example:clixon";
|
||||||
leaf newex{
|
leaf newex{
|
||||||
type string;
|
type string;
|
||||||
}
|
}
|
||||||
|
|
@ -32,7 +32,7 @@ cat <<EOF > $fyang2
|
||||||
module $APPNAME{
|
module $APPNAME{
|
||||||
prefix ex;
|
prefix ex;
|
||||||
revision 2018-01-01;
|
revision 2018-01-01;
|
||||||
namespace "urn:example:example";
|
namespace "urn:example:clixon";
|
||||||
leaf oldex{
|
leaf oldex{
|
||||||
type string;
|
type string;
|
||||||
}
|
}
|
||||||
|
|
@ -44,7 +44,7 @@ cat <<EOF > $fyang3
|
||||||
module other{
|
module other{
|
||||||
prefix oth;
|
prefix oth;
|
||||||
revision 2018-01-01;
|
revision 2018-01-01;
|
||||||
namespace "urn:example:example2";
|
namespace "urn:example:clixon2";
|
||||||
leaf other{
|
leaf other{
|
||||||
type string;
|
type string;
|
||||||
}
|
}
|
||||||
|
|
@ -85,13 +85,13 @@ if [ $BE -ne 0 ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new "1. Set newex"
|
new "1. Set newex"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><newex>str</newex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><newex xmlns="urn:example:clixon">str</newex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "Set oldex should fail (since oldex is in old revision and only the new is loaded)"
|
new "Set oldex should fail (since oldex is in old revision and only the new is loaded)"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><oldex>str</oldex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>Validation failed</error-message></rpc-error></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><oldex xmlns="urn:example:clixon">str</oldex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>oldex</bad-element></error-info><error-severity>error</error-severity><error-message>Unassigned yang spec</error-message></rpc-error></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "Set other should fail"
|
new "Set other should fail"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other>str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>Validation failed</error-message></rpc-error></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other xmlns="urn:example:clixon2">str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>other</bad-element></error-info><error-severity>error</error-severity><error-message>Unassigned yang spec</error-message></rpc-error></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
if [ $BE -eq 0 ]; then
|
if [ $BE -eq 0 ]; then
|
||||||
exit # BE
|
exit # BE
|
||||||
|
|
@ -137,13 +137,13 @@ if [ $? -ne 0 ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new "Set oldex"
|
new "Set oldex"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><oldex>str</oldex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><oldex xmlns="urn:example:clixon">str</oldex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "Set newex should fail"
|
new "Set newex should fail"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><newex>str</newex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>Validation failed</error-message></rpc-error></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><newex xmlns="urn:example:clixon">str</newex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>newex</bad-element></error-info><error-severity>error</error-severity><error-message>Unassigned yang spec</error-message></rpc-error></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "Set other should fail"
|
new "Set other should fail"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other>str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>Validation failed</error-message></rpc-error></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other xmlns="urn:example:clixon2">str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>other</bad-element></error-info><error-severity>error</error-severity><error-message>Unassigned yang spec</error-message></rpc-error></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "Kill backend"
|
new "Kill backend"
|
||||||
# Check if premature kill
|
# Check if premature kill
|
||||||
|
|
@ -181,13 +181,13 @@ if [ $? -ne 0 ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new "Set newex"
|
new "Set newex"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><newex>str</newex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><newex xmlns="urn:example:clixon">str</newex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "Set oldex should fail"
|
new "Set oldex should fail"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><oldex>str</oldex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><oldex xmlns="urn:example:clixon">str</oldex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>oldex</bad-element></error-info><error-severity>error</error-severity><error-message>Unassigned yang spec</error-message></rpc-error></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "Set other should fail"
|
new "Set other should fail"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other>str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other xmlns="urn:example:clixon2">str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>other</bad-element></error-info><error-severity>error</error-severity><error-message>Unassigned yang spec</error-message></rpc-error></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "Kill backend"
|
new "Kill backend"
|
||||||
# Check if premature kill
|
# Check if premature kill
|
||||||
|
|
@ -226,13 +226,13 @@ if [ $? -ne 0 ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new "Set oldex"
|
new "Set oldex"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><oldex>str</oldex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><oldex xmlns="urn:example:clixon">str</oldex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "Set newex should fail"
|
new "Set newex should fail"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><newex>str</newex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><newex xmlns="urn:example:clixon">str</newex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>newex</bad-element></error-info><error-severity>error</error-severity><error-message>Unassigned yang spec</error-message></rpc-error></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "Set other should fail"
|
new "Set other should fail"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other>str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other xmlns="urn:example:clixon2">str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>other</bad-element></error-info><error-severity>error</error-severity><error-message>Unassigned yang spec</error-message></rpc-error></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "Kill backend"
|
new "Kill backend"
|
||||||
# Check if premature kill
|
# Check if premature kill
|
||||||
|
|
@ -270,13 +270,13 @@ if [ $? -ne 0 ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new "Set newex"
|
new "Set newex"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><newex>str</newex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><newex xmlns="urn:example:clixon">str</newex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "Set oldex should fail"
|
new "Set oldex should fail"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><oldex>str</oldex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><oldex xmlns="urn:example:clixon">str</oldex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>oldex</bad-element></error-info><error-severity>error</error-severity><error-message>Unassigned yang spec</error-message></rpc-error></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "Set other"
|
new "Set other"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other>str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other xmlns="urn:example:clixon2">str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "Kill backend"
|
new "Kill backend"
|
||||||
# Check if premature kill
|
# Check if premature kill
|
||||||
|
|
@ -315,13 +315,13 @@ if [ $? -ne 0 ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new "Set oldex"
|
new "Set oldex"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><oldex>str</oldex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><oldex xmlns="urn:example:clixon">str</oldex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "Set newex should fail"
|
new "Set newex should fail"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><newex>str</newex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><newex xmlns="urn:example:clixon">str</newex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>newex</bad-element></error-info><error-severity>error</error-severity><error-message>Unassigned yang spec</error-message></rpc-error></rpc-reply>]]>]]>'
|
||||||
|
|
||||||
new "Set other"
|
new "Set other"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other>str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other xmlns="urn:example:clixon2">str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "Kill backend"
|
new "Kill backend"
|
||||||
# Check if premature kill
|
# Check if premature kill
|
||||||
|
|
@ -362,13 +362,13 @@ if [ $? -ne 0 ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new "Set oldex"
|
new "Set oldex"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><oldex>str</oldex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><oldex xmlns="urn:example:clixon">str</oldex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "Set newex should fail"
|
new "Set newex should fail"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><newex>str</newex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><newex xmlns="urn:example:clixon">str</newex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>newex</bad-element></error-info><error-severity>error</error-severity><error-message>Unassigned yang spec</error-message></rpc-error></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "Set other"
|
new "Set other"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other>str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other xmlns="urn:example:clixon2">str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "Kill backend"
|
new "Kill backend"
|
||||||
# Check if premature kill
|
# Check if premature kill
|
||||||
|
|
@ -408,13 +408,13 @@ if [ $? -ne 0 ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new "Set oldex"
|
new "Set oldex"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><oldex>str</oldex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><oldex xmlns="urn:example:clixon">str</oldex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "Set newex should fail"
|
new "Set newex should fail"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><newex>str</newex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><newex xmlns="urn:example:clixon">str</newex></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>newex</bad-element></error-info><error-severity>error</error-severity><error-message>Unassigned yang spec</error-message></rpc-error></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "Set other should fail"
|
new "Set other should fail"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other>str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><other xmlns="urn:example:clixon2">str</other></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>other</bad-element></error-info><error-severity>error</error-severity><error-message>Unassigned yang spec</error-message></rpc-error></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "Kill backend"
|
new "Kill backend"
|
||||||
# Check if premature kill
|
# Check if premature kill
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,15 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Yang specifics: multi-keys and empty type
|
|
||||||
APPNAME=example
|
APPNAME=example
|
||||||
# include err() and new() functions and creates $dir
|
# test two modules example1 and example2 with overlapping statements x.
|
||||||
|
# x is leaf in example1 and list on example2.
|
||||||
|
# Test netconf and restconf
|
||||||
|
# BTW, this is not supported in generated CLI
|
||||||
|
|
||||||
. ./lib.sh
|
. ./lib.sh
|
||||||
|
|
||||||
cfg=$dir/conf_yang.xml
|
cfg=$dir/conf_yang.xml
|
||||||
fyang=$dir/example.yang
|
fyang1=$dir/example1.yang
|
||||||
fyang2=$dir/example2.yang
|
fyang2=$dir/example2.yang
|
||||||
|
|
||||||
# <CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
|
# <CLICON_YANG_DIR>/usr/local/share/$APPNAME/yang</CLICON_YANG_DIR>
|
||||||
|
|
@ -18,17 +22,35 @@ cat <<EOF > $cfg
|
||||||
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
|
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
|
||||||
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
|
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
|
||||||
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
|
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
|
||||||
|
<CLICON_RESTCONF_PRETTY>false</CLICON_RESTCONF_PRETTY>
|
||||||
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
|
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
|
||||||
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
|
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
|
||||||
<CLICON_CLI_GENMODEL_COMPLETION>1</CLICON_CLI_GENMODEL_COMPLETION>
|
<CLICON_CLI_GENMODEL_COMPLETION>1</CLICON_CLI_GENMODEL_COMPLETION>
|
||||||
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
|
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
|
||||||
<CLICON_XMLDB_PLUGIN>/usr/local/lib/xmldb/text.so</CLICON_XMLDB_PLUGIN>
|
<CLICON_XMLDB_PLUGIN>/usr/local/lib/xmldb/text.so</CLICON_XMLDB_PLUGIN>
|
||||||
|
<CLICON_XML_NS_STRICT>true</CLICON_XML_NS_STRICT> <!-- Must be strict -->
|
||||||
<CLICON_MODULE_LIBRARY_RFC7895>true</CLICON_MODULE_LIBRARY_RFC7895>
|
<CLICON_MODULE_LIBRARY_RFC7895>true</CLICON_MODULE_LIBRARY_RFC7895>
|
||||||
</config>
|
</config>
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
|
||||||
|
cat <<EOF > $fyang1
|
||||||
|
module example1{
|
||||||
|
yang-version 1.1;
|
||||||
|
prefix ex1;
|
||||||
|
namespace "urn:example:clixon1";
|
||||||
|
import ietf-routing {
|
||||||
|
description "defines fib-route";
|
||||||
|
prefix rt;
|
||||||
|
}
|
||||||
|
leaf x{
|
||||||
|
type int32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
# For testing namespaces -
|
# For testing namespaces -
|
||||||
# x.y is different type. Here it is string whereas in fyang it is list.
|
# x.y is different type. Here it is string whereas in fyang1 it is list.
|
||||||
#
|
#
|
||||||
cat <<EOF > $fyang2
|
cat <<EOF > $fyang2
|
||||||
module example2{
|
module example2{
|
||||||
|
|
@ -43,37 +65,6 @@ module example2{
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
cat <<EOF > $fyang
|
|
||||||
module example{
|
|
||||||
yang-version 1.1;
|
|
||||||
prefix ex;
|
|
||||||
namespace "urn:example:clixon";
|
|
||||||
import ietf-routing {
|
|
||||||
description "defines fib-route";
|
|
||||||
prefix rt;
|
|
||||||
}
|
|
||||||
leaf x{
|
|
||||||
type int32;
|
|
||||||
}
|
|
||||||
rpc client-rpc {
|
|
||||||
description "Example local client-side RPC that is processed by the
|
|
||||||
the netconf/restconf and not sent to the backend.
|
|
||||||
This is a clixon implementation detail: some rpc:s
|
|
||||||
are better processed by the client for API or perf reasons";
|
|
||||||
input {
|
|
||||||
leaf request {
|
|
||||||
type string;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
output {
|
|
||||||
leaf result{
|
|
||||||
type string;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
new "test params: -f $cfg"
|
new "test params: -f $cfg"
|
||||||
|
|
||||||
if [ $BE -ne 0 ]; then
|
if [ $BE -ne 0 ]; then
|
||||||
|
|
@ -91,36 +82,57 @@ if [ $BE -ne 0 ]; then
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
new "kill old restconf daemon"
|
||||||
|
sudo pkill -u www-data clixon_restconf
|
||||||
|
|
||||||
|
new "start restconf daemon"
|
||||||
|
sudo su -c "$clixon_restconf -f $cfg -D $DBG" -s /bin/sh www-data &
|
||||||
|
|
||||||
new "netconf xmlns module ex"
|
new "netconf set x in example1"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon">42</x></config></edit-config></rpc>]]>]]>' '^<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><ok/></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon1">42</x></config></edit-config></rpc>]]>]]>' '^<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "netconf get config XXX xmlfn in return"
|
new "netconf get config example1"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><x>42</x></data></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" '^<rpc-reply><data><x xmlns="urn:example:clixon1">42</x></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "netconf xmlns module ex2"
|
new "netconf set x in example2"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon2"><y>99</y></x></config></edit-config></rpc>]]>]]>' '^<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><ok/></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon2"><y>99</y></x></config></edit-config></rpc>]]>]]>' '^<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "netconf get config XXX xmlns"
|
new "netconf get config example1 and example2"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><x>42</x><x><y>99</y></x></data></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" '^<rpc-reply><data><x xmlns="urn:example:clixon1">42</x><x xmlns="urn:example:clixon2"><y>99</y></x></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "netconf discard-changes"
|
new "netconf discard-changes"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg -y $fyang1" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf xmlns:ex"
|
new "restconf set x in example1"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:ex="urn:example:clixon"><edit-config><target><candidate/></target><config><ex:x>4422</ex:x></config></edit-config></rpc>]]>]]>' '^<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:ex="urn:example:clixon"><ok/></rpc-reply>]]>]]>$'
|
expecteq "$(curl -s -X POST -d '{"example1:x":42}' http://localhost/restconf/data)" ''
|
||||||
|
|
||||||
new "netconf get config XXX xmlns:ex"
|
new2 "restconf get config example1"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><x>4422</x></data></rpc-reply>]]>]]>$"
|
expecteq "$(curl -s -X GET http://localhost/restconf/data/example1:x)" '{"example1:x": 42}
|
||||||
|
'
|
||||||
|
|
||||||
new "netconf xmlns:ex2"
|
new "restconf set x in example2"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:ex2="urn:example:clixon2"><edit-config><target><candidate/></target><config><ex2:x><ex2:y>9999</ex2:y></ex2:x></config></edit-config></rpc>]]>]]>' '^<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:ex2="urn:example:clixon2"><ok/></rpc-reply>]]>]]>$'
|
expecteq "$(curl -s -X POST -d '{"example2:x":{"y":99}}' http://localhost/restconf/data)" ''
|
||||||
|
|
||||||
new "netconf get config XXX xmlns:ex2"
|
# XXX GET ../example1:x is translated to select=/x which gets both example1&2
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><x>4422</x><x><y>9999</y></x></data></rpc-reply>]]>]]>$"
|
#new "restconf get config example1"
|
||||||
|
#expecteq "$(curl -s -X GET http://localhost/restconf/data/example1:x)" '{"example1:x": 42}
|
||||||
|
#
'
|
||||||
|
|
||||||
# rpc
|
# XXX GET ../example2:x is translated to select=/x which gets both example1&2
|
||||||
|
#new "restconf get config example2"
|
||||||
|
#expecteq "$(curl -s -X GET http://localhost/restconf/data/example2:x)" '{"example2:x": {"y":42}}
|
||||||
|
#
'
|
||||||
|
|
||||||
|
new "restconf get config example1 and example2"
|
||||||
|
ret=$(curl -s -X GET http://localhost/restconf/data)
|
||||||
|
expect='"example1:x": 42,"example2:x": {"y": 99}'
|
||||||
|
match=`echo $ret | grep -EZo "$expect"`
|
||||||
|
if [ -z "$match" ]; then
|
||||||
|
err "$expect" "$ret"
|
||||||
|
fi
|
||||||
|
|
||||||
|
new "Kill restconf daemon"
|
||||||
|
sudo pkill -u www-data -f "/www-data/clixon_restconf"
|
||||||
|
|
||||||
if [ $BE -eq 0 ]; then
|
if [ $BE -eq 0 ]; then
|
||||||
exit # BE
|
exit # BE
|
||||||
|
|
|
||||||
|
|
@ -353,14 +353,19 @@ module clixon-config {
|
||||||
Only works for Yang specified XML.
|
Only works for Yang specified XML.
|
||||||
If not set, all lists accessed via linear search.";
|
If not set, all lists accessed via linear search.";
|
||||||
}
|
}
|
||||||
leaf CLICON_XML_NS_ITERATE {
|
leaf CLICON_XML_NS_STRICT {
|
||||||
type boolean;
|
type boolean;
|
||||||
default true;
|
default true;
|
||||||
description
|
description
|
||||||
"If set, iterate through modules to find the matching datanode
|
"If not set, make non-strict laze namespace checks, by iterating
|
||||||
|
through modules to find the matching datanode
|
||||||
or rpc if no xmlns attribute specifies namespace.
|
or rpc if no xmlns attribute specifies namespace.
|
||||||
This is loose semantics of finding namespaces.
|
This is lazy semantics of finding namespaces, which means you
|
||||||
And it is wrong, but is the way Clixon originally was written.";
|
do not need to explicitly give the namespace if the symbol exists
|
||||||
|
in some loaded module.
|
||||||
|
Example: <x/> is enough, instead of <x xmlns='urn:example:clixon'/>
|
||||||
|
But it is wrong, but is the way Clixon originally was written.
|
||||||
|
Strict semantics is the default.";
|
||||||
}
|
}
|
||||||
leaf CLICON_USE_STARTUP_CONFIG {
|
leaf CLICON_USE_STARTUP_CONFIG {
|
||||||
type int32;
|
type int32;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
module ietf-netconf-notification {
|
module ietf-netconf-notification {
|
||||||
namespace "urn:ietf:params:xml:ns:netconf:notification:1:0";
|
/* namespace "urn:ietf:params:xml:ns:netconf:notification:1.0";*/
|
||||||
|
namespace "urn:ietf:params:xml:ns:netmod:notification";
|
||||||
prefix "rcmon";
|
prefix "rcmon";
|
||||||
|
|
||||||
import ietf-yang-types { prefix yang; }
|
import ietf-yang-types { prefix yang; }
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue