* More precise Yang validation and better error messages
* For Example, adding bad-, missing-, or unknown-element error messages, etc instead of operation-failed * 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. * Added example_rpc RPC to example backend * Renamed xml_namespace[_set]() to xml_prefix[_set]() * Some restconf error messages contained "rpc-reply" or "rpc-error" which have now been removed. * Netconf/Restconf RPC extra input arguments are ignored (https://github.com/clicon/clixon/issues/47)
This commit is contained in:
parent
03e618b1e5
commit
f872c7e295
45 changed files with 807 additions and 405 deletions
13
CHANGELOG.md
13
CHANGELOG.md
|
|
@ -6,7 +6,6 @@
|
|||
* [Roadmap](ROADMAP.md) (Uncommitted and unprioritized)
|
||||
|
||||
### Major New features
|
||||
|
||||
* NACM extension (RFC8341)
|
||||
* NACM module support (RFC8341 A1+A2)
|
||||
* Recovery user "_nacm_recovery" added.
|
||||
|
|
@ -20,6 +19,8 @@
|
|||
* Support of submodule, include and belongs-to.
|
||||
* Openconfig yang specs parsed: https://github.com/openconfig/public
|
||||
* Improved "unknown" handling
|
||||
* More precise Yang validation and better error messages
|
||||
* For Example, adding bad-, missing-, or unknown-element error messages, etc instead of operation-failed
|
||||
* Yang load file configure options changed
|
||||
* `CLICON_YANG_DIR` is changed from a single directory to a path of directories
|
||||
* Note CLIXON_DATADIR (=/usr/local/share/clixon) need to be in the list
|
||||
|
|
@ -27,18 +28,20 @@
|
|||
* 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)
|
||||
* 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.
|
||||
* Yang parser is stricter (see above) which may break parsing of existing yang specs.
|
||||
* XML namespace handling is corrected (see above)
|
||||
* For backward compatibility set config option CLICON_XML_NS_ITERATE
|
||||
|
|
@ -49,6 +52,8 @@
|
|||
* For backward compatibility, define CLICON_CLI_MODEL_TREENAME_PATCH in clixon_custom.h
|
||||
|
||||
### Minor changes
|
||||
* Added example_rpc RPC to example backend
|
||||
* Renamed xml_namespace[_set]() to xml_prefix[_set]()
|
||||
* Changed all make tags --> make TAGS
|
||||
* Keyvalue datastore removed (it has been disabled since 3.3.3)
|
||||
* Removed return value ymodp from yang parse functions (eg yang_parse()).
|
||||
|
|
@ -60,7 +65,9 @@
|
|||
* <!DOCTYPE (ie DTD) is not supported.
|
||||
|
||||
### Corrected Bugs
|
||||
* Some restconf error messages contained "rpc-reply" or "rpc-error" which have now been removed.
|
||||
* getopt return value changed from char to int (https://github.com/clicon/clixon/issues/58)
|
||||
* Netconf/Restconf RPC extra input arguments are ignored (https://github.com/clicon/clixon/issues/47)
|
||||
|
||||
### Known issues
|
||||
* debug rpc added in example application (should be in clixon-config).
|
||||
|
|
|
|||
|
|
@ -125,8 +125,9 @@ However, the following YANG syntax modules are not implemented:
|
|||
- belongs-to
|
||||
|
||||
Restrictions on Yang types are as follows:
|
||||
- The range statement does not support multiple values (RFC7895 sec 9.2.4)
|
||||
- The range statement does not support multiple values (RFC7950 9.2.4)
|
||||
- Submodules cannot re-use a prefix in an import statement that is already used for another imported module in the module that the submodule belongs to. (see https://github.com/clicon/clixon/issues/60)
|
||||
- default values on leaf-lists (RFC7950 7.7.2)
|
||||
|
||||
Netconf
|
||||
=======
|
||||
|
|
|
|||
20
ROADMAP.md
20
ROADMAP.md
|
|
@ -1,36 +1,34 @@
|
|||
# Clixon roadmap
|
||||
|
||||
In prio order
|
||||
|
||||
High prio
|
||||
## High prio
|
||||
- NACM (RFC 8341)
|
||||
- Module rules
|
||||
- Module rules (done)
|
||||
- Data node rules (read/create/delete/update/execute)
|
||||
- Special handling of the initial startup transaction to avoid exit at startup
|
||||
- Possibly - draft-wu-netconf-restconf-factory-restore-03
|
||||
- Handle revisions to data model.
|
||||
- Possibly draft-wang-netmod-module-revision-management-01
|
||||
- XML [Namespace handling](https://github.com/clicon/clixon/issues/49)
|
||||
|
||||
Medium prio:
|
||||
- Input validation on custom RPCs/
|
||||
## Medium prio:
|
||||
- Input validation on custom RPCs/ (done)
|
||||
- [Sanity checks](https://github.com/clicon/clixon/issues/47)
|
||||
- Support for XML regex's.
|
||||
- Currently Posix extended regular expressions
|
||||
- Support a plugin callback that is invoked when copy-config is called.
|
||||
- Preserve CLI command history across sessions. The up/down arrows
|
||||
|
||||
Low prio:
|
||||
## Low prio:
|
||||
- Provide a client library to access netconf APIs provided by system services.
|
||||
- Netconf backend (Clixon acts as netconf controller)
|
||||
- Support for restconf call-home (RFC 8071)
|
||||
- Support for restconf PATCH method
|
||||
|
||||
Not prioritized:
|
||||
- XML [Namespace handling](https://github.com/clicon/clixon/issues/49)
|
||||
- Support for restconf PATCH method
|
||||
- NETCONF
|
||||
- Support for additional Netconf [edit-config modes](https://github.com/clicon/clixon/issues/53)
|
||||
- Netconf [framing](https://github.com/clicon/clixon/issues/50)
|
||||
- [Child ordering](https://github.com/clicon/clixon/issues/22)
|
||||
- Netconf backend (Clixon acts as netconf controller)
|
||||
- Restconf
|
||||
- Query parameters
|
||||
- Streams (netconf and restconf)
|
||||
|
|
@ -38,7 +36,7 @@ Not prioritized:
|
|||
- Jenkins CI/CD and webhooks
|
||||
- YANG
|
||||
- RFC 6022 [NETCONF monitoring](https://github.com/clicon/clixon/issues/39)
|
||||
- Deviation, belongs-to, min/max-elements, action, unique
|
||||
- Deviation, min/max-elements, action, unique
|
||||
- Containers
|
||||
- [Docker improvements](https://github.com/clicon/clixon/issues/44)
|
||||
- Kubernetes Helm chart definition
|
||||
|
|
|
|||
|
|
@ -468,12 +468,12 @@ from_client_edit_config(clicon_handle h,
|
|||
}
|
||||
}
|
||||
if ((xc = xpath_first(xn, "config")) == NULL){
|
||||
if (netconf_missing_element(cbret, "protocol", "<bad-element>config</bad-element>", NULL) < 0)
|
||||
if (netconf_missing_element(cbret, "protocol", "config", NULL) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
else{
|
||||
/* <config> yang spec may be set to anyxml by ingress yang check,...*/
|
||||
/* <config> yang spec may be set to anyxmly by ingress yang check,...*/
|
||||
if (xml_spec(xc) != NULL)
|
||||
xml_spec_set(xc, NULL);
|
||||
/* Populate XML with Yang spec (why not do this in parser?)
|
||||
|
|
@ -530,7 +530,7 @@ from_client_lock(clicon_handle h,
|
|||
cbuf *cbx = NULL; /* Assist cbuf */
|
||||
|
||||
if ((db = netconf_db_find(xe, "target")) == NULL){
|
||||
if (netconf_missing_element(cbret, "protocol", "<bad-element>target</bad-element>", NULL) < 0)
|
||||
if (netconf_missing_element(cbret, "protocol", "target", NULL) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -589,7 +589,7 @@ from_client_unlock(clicon_handle h,
|
|||
cbuf *cbx = NULL; /* Assist cbuf */
|
||||
|
||||
if ((db = netconf_db_find(xe, "target")) == NULL){
|
||||
if (netconf_missing_element(cbret, "protocol", "<bad-element>target</bad-element>", NULL) < 0)
|
||||
if (netconf_missing_element(cbret, "protocol", "target", NULL) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -651,7 +651,7 @@ from_client_kill_session(clicon_handle h,
|
|||
|
||||
if ((x = xml_find(xe, "session-id")) == NULL ||
|
||||
(str = xml_find_value(x, "body")) == NULL){
|
||||
if (netconf_missing_element(cbret, "protocol", "<bad-element>session-id</bad-element>", NULL) < 0)
|
||||
if (netconf_missing_element(cbret, "protocol", "session-id", NULL) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -709,7 +709,7 @@ from_client_copy_config(clicon_handle h,
|
|||
cbuf *cbx = NULL; /* Assist cbuf */
|
||||
|
||||
if ((source = netconf_db_find(xe, "source")) == NULL){
|
||||
if (netconf_missing_element(cbret, "protocol", "<bad-element>source</bad-element>", NULL) < 0)
|
||||
if (netconf_missing_element(cbret, "protocol", "source", NULL) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -724,7 +724,7 @@ from_client_copy_config(clicon_handle h,
|
|||
goto ok;
|
||||
}
|
||||
if ((target = netconf_db_find(xe, "target")) == NULL){
|
||||
if (netconf_missing_element(cbret, "protocol", "<bad-element>target</bad-element>", NULL) < 0)
|
||||
if (netconf_missing_element(cbret, "protocol", "target", NULL) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -777,7 +777,7 @@ from_client_delete_config(clicon_handle h,
|
|||
|
||||
if ((target = netconf_db_find(xe, "target")) == NULL||
|
||||
strcmp(target, "running")==0){
|
||||
if (netconf_missing_element(cbret, "protocol", "<bad-element>target</bad-element>", NULL) < 0)
|
||||
if (netconf_missing_element(cbret, "protocol", "target", NULL) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -856,7 +856,7 @@ from_client_create_subscription(clicon_handle h,
|
|||
if ((x = xpath_first(xe, "//stopTime")) != NULL){
|
||||
if ((stoptime = xml_find_value(x, "body")) != NULL &&
|
||||
str2time(stoptime, &stop) < 0){
|
||||
if (netconf_bad_element(cbret, "application", "<bad-element>stopTime</bad-element>", "Expected timestamp") < 0)
|
||||
if (netconf_bad_element(cbret, "application", "stopTime", "Expected timestamp") < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -864,7 +864,7 @@ from_client_create_subscription(clicon_handle h,
|
|||
if ((x = xpath_first(xe, "//startTime")) != NULL){
|
||||
if ((starttime = xml_find_value(x, "body")) != NULL &&
|
||||
str2time(starttime, &start) < 0){
|
||||
if (netconf_bad_element(cbret, "application", "<bad-element>startTime</bad-element>", "Expected timestamp") < 0)
|
||||
if (netconf_bad_element(cbret, "application", "startTime", "Expected timestamp") < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -925,7 +925,7 @@ from_client_debug(clicon_handle h,
|
|||
char *valstr;
|
||||
|
||||
if ((valstr = xml_find_body(xe, "level")) == NULL){
|
||||
if (netconf_missing_element(cbret, "application", "<bad-element>level</bad-element>", NULL) < 0)
|
||||
if (netconf_missing_element(cbret, "application", "level", NULL) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -993,13 +993,10 @@ from_client_msg(clicon_handle h,
|
|||
/* Populate incoming XML tree with yang */
|
||||
if (xml_spec_populate_rpc(h, x, yspec) < 0)
|
||||
goto done;
|
||||
if ((ret = xml_yang_validate_rpc(x)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
if (netconf_operation_failed(cbret, "application", "Validation failed")< 0)
|
||||
if ((ret = xml_yang_validate_rpc(x, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto reply;
|
||||
}
|
||||
xe = NULL;
|
||||
username = xml_find_value(x, "username");
|
||||
while ((xe = xml_child_each(x, xe, CX_ELMNT)) != NULL) {
|
||||
|
|
@ -1059,7 +1056,7 @@ from_client_msg(clicon_handle h,
|
|||
}
|
||||
else if (strcmp(rpc, "validate") == 0){
|
||||
if ((db = netconf_db_find(xe, "source")) == NULL){
|
||||
if (netconf_missing_element(cbret, "protocol", "<bad-element>source</bad-element>", NULL) < 0)
|
||||
if (netconf_missing_element(cbret, "protocol", "source", NULL) < 0)
|
||||
goto done;
|
||||
goto reply;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,67 +81,85 @@
|
|||
* are if code comes via XML/NETCONF.
|
||||
* @param[in] yspec Yang spec
|
||||
* @param[in] td Transaction data
|
||||
* @param[out] cbret Cligen buffer containing netconf error (if retval == 0)
|
||||
* @retval -1 Error
|
||||
* @retval 0 Validation failed (with cbret set)
|
||||
* @retval 1 Validation OK
|
||||
*/
|
||||
static int
|
||||
generic_validate(yang_spec *yspec,
|
||||
transaction_data_t *td)
|
||||
transaction_data_t *td,
|
||||
cbuf *cbret)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *x1;
|
||||
cxobj *x2;
|
||||
yang_stmt *ys;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
/* All entries */
|
||||
if (xml_apply(td->td_target, CX_ELMNT,
|
||||
(xml_applyfn_t*)xml_yang_validate_all, NULL) < 0)
|
||||
if ((ret = xml_yang_validate_all_top(td->td_target, cbret)) < 0)
|
||||
goto done;
|
||||
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
/* changed entries */
|
||||
for (i=0; i<td->td_clen; i++){
|
||||
x1 = td->td_scvec[i]; /* source changed */
|
||||
x2 = td->td_tcvec[i]; /* target changed */
|
||||
if (xml_yang_validate_add(x2, NULL) < 0)
|
||||
/* Should this be recursive? */
|
||||
if ((ret = xml_yang_validate_add(x2, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
}
|
||||
/* deleted entries */
|
||||
for (i=0; i<td->td_dlen; i++){
|
||||
x1 = td->td_dvec[i];
|
||||
ys = xml_spec(x1);
|
||||
if (ys && yang_mandatory(ys)){
|
||||
clicon_err(OE_CFG, 0,"Removed mandatory variable: %s",
|
||||
xml_name(x1));
|
||||
if (netconf_missing_element(cbret, "protocol", xml_name(x1), "Removed mandatory variable") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
/* added entries */
|
||||
for (i=0; i<td->td_alen; i++){
|
||||
x2 = td->td_avec[i];
|
||||
if (xml_apply0(x2, CX_ELMNT,
|
||||
(xml_applyfn_t*)xml_yang_validate_add, NULL) < 0)
|
||||
if ((ret = xml_yang_validate_add(x2, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
}
|
||||
retval = 0;
|
||||
// ok:
|
||||
retval = 1;
|
||||
done:
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Common code of candidate_validate and candidate_commit
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] candidate The candidate database. The wanted backend state
|
||||
* @retval 0 OK
|
||||
* @retval -1 Fatal error or validation fail
|
||||
* @retval -1 Error - or validation failed (but cbret not set)
|
||||
* @retval 0 Validation failed (with cbret set)
|
||||
* @retval 1 Validation OK
|
||||
* @note Need to differentiate between error and validation fail
|
||||
* (only done for generic_validate)
|
||||
*/
|
||||
static int
|
||||
validate_common(clicon_handle h,
|
||||
char *candidate,
|
||||
transaction_data_t *td)
|
||||
transaction_data_t *td,
|
||||
cbuf *cbret)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_spec *yspec;
|
||||
int i;
|
||||
cxobj *xn;
|
||||
int ret;
|
||||
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||
|
|
@ -193,9 +211,12 @@ validate_common(clicon_handle h,
|
|||
if (plugin_transaction_begin(h, td) < 0)
|
||||
goto done;
|
||||
|
||||
/* 5. Make generic validation on all new or changed data. */
|
||||
if (generic_validate(yspec, td) < 0)
|
||||
/* 5. Make generic validation on all new or changed data.
|
||||
Note this is only call that uses 3-values */
|
||||
if ((ret = generic_validate(yspec, td, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
|
||||
/* 6. Call plugin transaction validate callbacks */
|
||||
if (plugin_transaction_validate(h, td) < 0)
|
||||
|
|
@ -204,9 +225,12 @@ validate_common(clicon_handle h,
|
|||
/* 7. Call plugin transaction complete callbacks */
|
||||
if (plugin_transaction_complete(h, td) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
retval = 1;
|
||||
done:
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Do a diff between candidate and running, then start a commit transaction
|
||||
|
|
@ -216,24 +240,30 @@ validate_common(clicon_handle h,
|
|||
* do something more drastic?
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] candidate A candidate database, not necessarily "candidate"
|
||||
* @retval 0 OK
|
||||
* @retval -1 Fatal error or validation fail
|
||||
* @retval -1 Error - or validation failed (but cbret not set)
|
||||
* @retval 0 Validation failed (with cbret set)
|
||||
* @retval 1 Validation OK
|
||||
* @note Need to differentiate between error and validation fail
|
||||
* (only done for validate_common)
|
||||
*/
|
||||
int
|
||||
candidate_commit(clicon_handle h,
|
||||
char *candidate)
|
||||
char *candidate,
|
||||
cbuf *cbret)
|
||||
{
|
||||
int retval = -1;
|
||||
transaction_data_t *td = NULL;
|
||||
int ret;
|
||||
|
||||
/* 1. Start transaction */
|
||||
if ((td = transaction_new()) == NULL)
|
||||
goto done;
|
||||
|
||||
/* Common steps (with validate) */
|
||||
if (validate_common(h, candidate, td) < 0)
|
||||
/* Common steps (with validate). Note this is only call that uses 3-values */
|
||||
if ((ret = validate_common(h, candidate, td, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
|
||||
/* 7. Call plugin transaction commit callbacks */
|
||||
if (plugin_transaction_commit(h, td) < 0)
|
||||
|
|
@ -252,21 +282,23 @@ candidate_commit(clicon_handle h,
|
|||
/* 9. Call plugin transaction end callbacks */
|
||||
plugin_transaction_end(h, td);
|
||||
|
||||
|
||||
/* 8. Copy running back to candidate in case end functions updated running */
|
||||
if (xmldb_copy(h, "running", candidate) < 0){
|
||||
/* ignore errors or signal major setback ? */
|
||||
clicon_log(LOG_NOTICE, "Error in rollback, trying to continue");
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
retval = 1;
|
||||
done:
|
||||
/* In case of failure, call plugin transaction termination callbacks */
|
||||
if (retval < 0 && td)
|
||||
/* In case of failure (or error), call plugin transaction termination callbacks */
|
||||
if (retval < 1 && td)
|
||||
plugin_transaction_abort(h, td);
|
||||
if (td)
|
||||
transaction_free(td);
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Commit changes from candidate to running
|
||||
|
|
@ -283,6 +315,7 @@ from_client_commit(clicon_handle h,
|
|||
int retval = -1;
|
||||
int piddb;
|
||||
cbuf *cbx = NULL; /* Assist cbuf */
|
||||
int ret;
|
||||
|
||||
/* Check if target locked by other client */
|
||||
piddb = xmldb_islocked(h, "running");
|
||||
|
|
@ -296,9 +329,10 @@ from_client_commit(clicon_handle h,
|
|||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
if (candidate_commit(h, "candidate") < 0){ /* Assume validation fail, nofatal */
|
||||
if ((ret = candidate_commit(h, "candidate", cbret)) < 0){ /* Assume validation fail, nofatal */
|
||||
clicon_debug(1, "Commit candidate failed");
|
||||
if (netconf_invalid_value(cbret, "protocol", clicon_err_reason)< 0)
|
||||
if (ret < 0)
|
||||
if (netconf_operation_failed(cbret, "application", clicon_err_reason)< 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -367,6 +401,7 @@ from_client_validate(clicon_handle h,
|
|||
{
|
||||
int retval = -1;
|
||||
transaction_data_t *td = NULL;
|
||||
int ret;
|
||||
|
||||
if (strcmp(db, "candidate") != 0 && strcmp(db, "tmp") != 0){
|
||||
if (netconf_invalid_value(cbret, "protocol", "No such database")< 0)
|
||||
|
|
@ -379,11 +414,12 @@ from_client_validate(clicon_handle h,
|
|||
if ((td = transaction_new()) == NULL)
|
||||
goto done;
|
||||
/* Common steps (with commit) */
|
||||
if (validate_common(h, db, td) < 0){
|
||||
if ((ret = validate_common(h, db, td, cbret)) < 1){
|
||||
clicon_debug(1, "Validate %s failed", db);
|
||||
/* XXX: candidate_validate should have proper error handling */
|
||||
if (ret < 0){
|
||||
if (netconf_operation_failed(cbret, "application", clicon_err_reason)< 0)
|
||||
goto done;
|
||||
}
|
||||
goto ok;
|
||||
}
|
||||
/* Optionally write (potentially modified) tree back to candidate */
|
||||
|
|
|
|||
|
|
@ -43,6 +43,6 @@
|
|||
int from_client_validate(clicon_handle h, char *db, cbuf *cbret);
|
||||
int from_client_commit(clicon_handle h, int pid, cbuf *cbret);
|
||||
int from_client_discard_changes(clicon_handle h, int pid, cbuf *cbret);
|
||||
int candidate_commit(clicon_handle h, char *db);
|
||||
int candidate_commit(clicon_handle h, char *db, cbuf *cbret);
|
||||
|
||||
#endif /* _BACKEND_COMMIT_H_ */
|
||||
|
|
|
|||
|
|
@ -386,6 +386,7 @@ startup_mode_running(clicon_handle h,
|
|||
char *extraxml_file)
|
||||
{
|
||||
int retval = -1;
|
||||
cbuf *cbret = NULL;
|
||||
|
||||
/* Stash original running to candidate for later commit */
|
||||
if (xmldb_copy(h, "running", "candidate") < 0)
|
||||
|
|
@ -405,15 +406,20 @@ startup_mode_running(clicon_handle h,
|
|||
/* Clear running db */
|
||||
if (db_reset(h, "running") < 0)
|
||||
goto done;
|
||||
if ((cbret = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
/* Commit original running. Assume -1 is validate fail */
|
||||
if (candidate_commit(h, "candidate") < 0){
|
||||
if (candidate_commit(h, "candidate", cbret) < 1){
|
||||
/* (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
|
||||
*/
|
||||
clicon_log(LOG_NOTICE, "%s: Commit of saved running failed, exiting.", __FUNCTION__);
|
||||
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;
|
||||
|
|
@ -424,6 +430,8 @@ startup_mode_running(clicon_handle h,
|
|||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
if (cbret)
|
||||
cbuf_free(cbret);
|
||||
if (xmldb_delete(h, "tmp") < 0)
|
||||
goto done;
|
||||
return retval;
|
||||
|
|
@ -455,6 +463,7 @@ startup_mode_startup(clicon_handle h,
|
|||
char *extraxml_file)
|
||||
{
|
||||
int retval = -1;
|
||||
cbuf *cbret = NULL;
|
||||
|
||||
/* Stash original running to backup */
|
||||
if (xmldb_copy(h, "running", "backup") < 0)
|
||||
|
|
@ -478,13 +487,19 @@ startup_mode_startup(clicon_handle h,
|
|||
/* Clear running db */
|
||||
if (db_reset(h, "running") < 0)
|
||||
goto done;
|
||||
/* Create return buffer (not used) */
|
||||
if ((cbret = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
/* Commit startup */
|
||||
if (candidate_commit(h, "startup") < 0){ /* diff */
|
||||
if (candidate_commit(h, "startup", cbret) < 1){ /* diff */
|
||||
/* We cannot differentiate between fatal errors and validation
|
||||
* failures
|
||||
* In both cases we copy back the original running and quit
|
||||
*/
|
||||
clicon_log(LOG_NOTICE, "%s: Commit of startup failed, exiting.", __FUNCTION__);
|
||||
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;
|
||||
|
|
@ -494,6 +509,8 @@ startup_mode_startup(clicon_handle h,
|
|||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
if (cbret)
|
||||
cbuf_free(cbret);
|
||||
if (xmldb_delete(h, "backup") < 0)
|
||||
goto done;
|
||||
if (xmldb_delete(h, "tmp") < 0)
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ static int
|
|||
process_incoming_packet(clicon_handle h,
|
||||
cbuf *cb)
|
||||
{
|
||||
int retval = -1;
|
||||
char *str;
|
||||
char *str0;
|
||||
cxobj *xreq = NULL; /* Request (in) */
|
||||
|
|
@ -92,6 +93,7 @@ process_incoming_packet(clicon_handle h,
|
|||
cxobj *xrpc;
|
||||
cxobj *xc;
|
||||
yang_spec *yspec;
|
||||
int ret;
|
||||
|
||||
clicon_debug(1, "RECV");
|
||||
clicon_debug(2, "%s: RCV: \"%s\"", __FUNCTION__, cbuf_get(cb));
|
||||
|
|
@ -115,15 +117,12 @@ process_incoming_packet(clicon_handle h,
|
|||
}
|
||||
free(str0);
|
||||
if ((xrpc=xpath_first(xreq, "//rpc")) != NULL){
|
||||
int ret;
|
||||
isrpc++;
|
||||
if ((ret = xml_yang_validate_rpc(xrpc)) < 0)
|
||||
if ((ret = xml_yang_validate_rpc(xrpc, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
if (netconf_operation_failed(cbret, "application", "Validation failed")< 0)
|
||||
goto done;
|
||||
netconf_output(1, cbret, "rpc-error");
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -168,6 +167,8 @@ process_incoming_packet(clicon_handle h,
|
|||
}
|
||||
}
|
||||
}
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
if (xreq)
|
||||
xml_free(xreq);
|
||||
|
|
@ -175,7 +176,7 @@ process_incoming_packet(clicon_handle h,
|
|||
xml_free(xret);
|
||||
if (cbret)
|
||||
cbuf_free(cbret);
|
||||
return 0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Get netconf message: detect end-of-msg
|
||||
|
|
@ -229,7 +230,7 @@ netconf_input_cb(int s,
|
|||
/* Remove trailer */
|
||||
*(((char*)cbuf_get(cb)) + cbuf_len(cb) - strlen("]]>]]>")) = '\0';
|
||||
if (process_incoming_packet(h, cb) < 0)
|
||||
goto done;
|
||||
; //goto done; // ignore errors
|
||||
if (cc_closed)
|
||||
break;
|
||||
cbuf_reset(cb);
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@
|
|||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <syslog.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/param.h>
|
||||
|
|
@ -882,6 +883,10 @@ netconf_application_rpc(clicon_handle h,
|
|||
clicon_err(OE_UNIX, 0, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if ((cbret = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, 0, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
/* Find yang rpc statement, return yang rpc statement if found
|
||||
Check application RPC */
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
|
|
@ -917,15 +922,18 @@ netconf_application_rpc(clicon_handle h,
|
|||
xml_spec_set(xn, yinput); /* needed for xml_spec_populate */
|
||||
if (xml_apply(xn, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
||||
goto done;
|
||||
if (xml_apply(xn, CX_ELMNT,
|
||||
(xml_applyfn_t*)xml_yang_validate_all, NULL) < 0)
|
||||
goto done;
|
||||
if (xml_yang_validate_add(xn, NULL) < 0)
|
||||
if ((ret = xml_yang_validate_all_top(xn, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
netconf_output(1, cbret, "rpc-error");
|
||||
goto ok;
|
||||
}
|
||||
if ((cbret = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, 0, "cbuf_new");
|
||||
if ((ret = xml_yang_validate_add(xn, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
netconf_output(1, cbret, "rpc-error");
|
||||
goto ok;
|
||||
}
|
||||
}
|
||||
/* Look for local (client-side) netconf plugins. */
|
||||
if ((ret = rpc_callback_call(h, xn, cbret, NULL)) < 0)
|
||||
|
|
@ -943,11 +951,18 @@ netconf_application_rpc(clicon_handle h,
|
|||
xml_spec_set(xoutput, youtput); /* needed for xml_spec_populate */
|
||||
if (xml_apply(xoutput, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
||||
goto done;
|
||||
if (xml_apply(xoutput, CX_ELMNT,
|
||||
(xml_applyfn_t*)xml_yang_validate_all, NULL) < 0)
|
||||
if ((ret = xml_yang_validate_all_top(xoutput, cbret)) < 0)
|
||||
goto done;
|
||||
if (xml_yang_validate_add(xoutput, NULL) < 0)
|
||||
if (ret == 0){
|
||||
clicon_log(LOG_WARNING, "Errors in output netconf %s", cbuf_get(cbret));
|
||||
goto ok;
|
||||
}
|
||||
if ((ret = xml_yang_validate_add(xoutput, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
clicon_log(LOG_WARNING, "Errors in output netconf %s", cbuf_get(cbret));
|
||||
goto ok;
|
||||
}
|
||||
}
|
||||
retval = 1; /* handled by callback */
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -71,10 +71,11 @@ static const map_str2int netconf_restconf_map[] = {
|
|||
{"missing-attribute", 400},
|
||||
{"bad-attribute", 400},
|
||||
{"unknown-attribute", 400},
|
||||
{"missing-element", 400},
|
||||
{"bad-element", 400},
|
||||
{"unknown-element", 400},
|
||||
{"unknown-namespace", 400},
|
||||
{"access-denied", 401},
|
||||
{"access-denied", 401}, /* or 403 */
|
||||
{"access-denied", 403},
|
||||
{"lock-denied", 409},
|
||||
{"resource-denied", 409},
|
||||
|
|
@ -436,7 +437,8 @@ api_return_err(clicon_handle h,
|
|||
goto ok;
|
||||
}
|
||||
tagstr = xml_body(xtag);
|
||||
code = restconf_err2code(tagstr);
|
||||
if ((code = restconf_err2code(tagstr)) < 0)
|
||||
code = 500; /* internal server error */
|
||||
if ((reason_phrase = restconf_code2reason(code)) == NULL)
|
||||
reason_phrase="";
|
||||
if (xml_name_set(xerr, "error") < 0)
|
||||
|
|
@ -448,6 +450,7 @@ api_return_err(clicon_handle h,
|
|||
else
|
||||
if (xml2json_cbuf(cb, xerr, pretty) < 0)
|
||||
goto done;
|
||||
FCGX_SetExitStatus(code, r->out); /* Created */
|
||||
FCGX_FPrintF(r->out, "Status: %d %s\r\n", code, reason_phrase);
|
||||
FCGX_FPrintF(r->out, "Content-Type: application/yang-data+%s\r\n\r\n",
|
||||
use_xml?"xml":"json");
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ api_data_get2(clicon_handle h,
|
|||
yang_spec *yspec;
|
||||
cxobj *xret = NULL;
|
||||
cxobj *xerr = NULL; /* malloced */
|
||||
cxobj *xe;
|
||||
cxobj *xe = NULL;
|
||||
cxobj **xvec = NULL;
|
||||
size_t xlen;
|
||||
int i;
|
||||
|
|
@ -206,7 +206,8 @@ api_data_get2(clicon_handle h,
|
|||
if (api_path2xpath_cvv(yspec, pcvec, pi, cbpath) < 0){
|
||||
if (netconf_operation_failed_xml(&xerr, "protocol", clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -215,7 +216,8 @@ api_data_get2(clicon_handle h,
|
|||
if (clicon_rpc_get(h, path, &xret) < 0){
|
||||
if (netconf_operation_failed_xml(&xerr, "protocol", clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -434,7 +436,8 @@ api_data_post(clicon_handle h,
|
|||
if (xml_parse_string(data, NULL, &xdata) < 0){
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -442,7 +445,8 @@ api_data_post(clicon_handle h,
|
|||
else if (json_parse_str(data, &xdata) < 0){
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -452,7 +456,8 @@ api_data_post(clicon_handle h,
|
|||
if (xml_child_nr(xdata) != 1){
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -662,7 +667,8 @@ api_data_put(clicon_handle h,
|
|||
if (xml_parse_string(data, NULL, &xdata) < 0){
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -670,7 +676,8 @@ api_data_put(clicon_handle h,
|
|||
else if (json_parse_str(data, &xdata) < 0){
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -680,7 +687,8 @@ api_data_put(clicon_handle h,
|
|||
if (xml_child_nr(xdata) != 1){
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -705,7 +713,8 @@ api_data_put(clicon_handle h,
|
|||
if (strcmp(xml_name(x), xml_name(xbot))){
|
||||
if (netconf_operation_failed_xml(&xerr, "protocol", "Not same symbol in api-path as data") < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -714,7 +723,8 @@ api_data_put(clicon_handle h,
|
|||
if (match_list_keys((yang_stmt*)y, x, xbot) < 0){
|
||||
if (netconf_operation_failed_xml(&xerr, "protocol", "api-path keys do not match data keys") < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -1054,7 +1064,6 @@ api_operations_post(clicon_handle h,
|
|||
cxobj *xdata = NULL;
|
||||
cxobj *xret = NULL;
|
||||
cxobj *xerr = NULL; /* malloced must be freed */
|
||||
cxobj *xer; /* non-malloced error */
|
||||
cbuf *cbx = NULL;
|
||||
cxobj *xtop = NULL; /* xpath root */
|
||||
cxobj *xbot = NULL;
|
||||
|
|
@ -1076,12 +1085,17 @@ api_operations_post(clicon_handle h,
|
|||
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||
goto done;
|
||||
}
|
||||
if ((cbret = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, 0, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
for (i=0; i<pi; i++)
|
||||
oppath = index(oppath+1, '/');
|
||||
if (oppath == NULL || strcmp(oppath,"/")==0){
|
||||
if (netconf_operation_failed_xml(&xerr, "protocol", "Operation name expected") < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -1098,21 +1112,24 @@ api_operations_post(clicon_handle h,
|
|||
if ((ys = yang_find((yang_node*)yspec, Y_MODULE, prefix)) == NULL){
|
||||
if (netconf_operation_failed_xml(&xerr, "protocol", "yang module not found") < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
if ((yrpc = yang_find((yang_node*)ys, Y_RPC, id)) == NULL){
|
||||
if (netconf_operation_failed_xml(&xerr, "protocol", "yang node not found") < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
if (yrpc == NULL){
|
||||
if (netconf_operation_failed_xml(&xerr, "protocol", "yang node not found") < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -1142,7 +1159,8 @@ api_operations_post(clicon_handle h,
|
|||
if (xml_parse_string(data, NULL, &xdata) < 0){
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -1150,7 +1168,8 @@ api_operations_post(clicon_handle h,
|
|||
else if (json_parse_str(data, &xdata) < 0){
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -1160,10 +1179,13 @@ api_operations_post(clicon_handle h,
|
|||
xml_name_set(xdata, "input");
|
||||
xml_spec_set(xdata, yinput); /* needed for xml_spec_populate */
|
||||
if (yinput){
|
||||
if (xml_yang_validate_add(xdata, NULL) < 0){
|
||||
if (netconf_operation_failed_xml(&xerr, "protocol", clicon_err_reason) < 0)
|
||||
if ((ret = xml_yang_validate_add(xdata, cbret)) < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
if (ret == 0){ /* validation failed */
|
||||
if (xml_parse_string(cbuf_get(cbret), yspec, &xerr) < 0)
|
||||
goto done;
|
||||
if ((xe=xpath_first(xerr, "rpc-reply/rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -1182,23 +1204,31 @@ api_operations_post(clicon_handle h,
|
|||
/* XXX yinput <-> h ?*/
|
||||
if (xml_apply(xbot, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
||||
goto done;
|
||||
if (xml_apply(xbot, CX_ELMNT,
|
||||
(xml_applyfn_t*)xml_yang_validate_all, NULL) < 0)
|
||||
if ((ret = xml_yang_validate_all(xbot, cbret)) < 0)
|
||||
goto done;
|
||||
if (xml_yang_validate_add(xbot, NULL) < 0){
|
||||
if (netconf_operation_failed_xml(&xerr, "protocol", clicon_err_reason) < 0)
|
||||
if (ret == 0){ /* validation failed */
|
||||
clicon_debug(1, "%s err: %s", __FUNCTION__, cbuf_get(cbret));
|
||||
if (xml_parse_string(cbuf_get(cbret), yspec, &xerr) < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
if ((xe=xpath_first(xerr, "rpc-reply/rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
if ((ret = xml_yang_validate_add(xbot, cbret)) < 0){
|
||||
if (xml_parse_string(cbuf_get(cbret), yspec, &xerr) < 0)
|
||||
goto done;
|
||||
if ((xe=xpath_first(xerr, "rpc-reply/rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((cbret = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, 0, "cbuf_new");
|
||||
if (xml_apply0(xbot, CX_ELMNT, xml_default, NULL) < 0)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
xe = NULL;
|
||||
while ((xe = xml_child_each(xtop, xe, CX_ELMNT)) != NULL) {
|
||||
/* Look for local (client-side) restconf plugins. */
|
||||
|
|
@ -1208,8 +1238,8 @@ api_operations_post(clicon_handle h,
|
|||
if (xml_parse_string(cbuf_get(cbret), NULL, &xret) < 0)
|
||||
goto done;
|
||||
/* Local error: return it and quit */
|
||||
if ((xer = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
if (api_return_err(h, r, xer, pretty, use_xml) < 0)
|
||||
if ((xe = xpath_first(xret, "rpc-reply/rpc-error")) != NULL){
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -1219,8 +1249,8 @@ api_operations_post(clicon_handle h,
|
|||
if (ret == 0){ /* Send to backend */
|
||||
if (clicon_rpc_netconf_xml(h, xtop, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xer = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
if (api_return_err(h, r, xer, pretty, use_xml) < 0)
|
||||
if ((xe = xpath_first(xret, "rpc-reply/rpc-error")) != NULL){
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -1240,18 +1270,31 @@ api_operations_post(clicon_handle h,
|
|||
goto done;
|
||||
if ((xoutput=xpath_first(xret, "/")) != NULL){
|
||||
xml_name_set(xoutput, "output");
|
||||
#if 0
|
||||
clicon_debug(1, "%s xoutput:%s", __FUNCTION__, cbuf_get(cbx));
|
||||
#endif
|
||||
cbuf_reset(cbx);
|
||||
xml_spec_set(xoutput, youtput); /* needed for xml_spec_populate */
|
||||
if (xml_apply(xoutput, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
||||
goto done;
|
||||
if (xml_apply(xoutput, CX_ELMNT,
|
||||
(xml_applyfn_t*)xml_yang_validate_all, NULL) < 0)
|
||||
if ((ret = xml_yang_validate_all(xoutput, cbret)) < 0)
|
||||
goto done;
|
||||
if (xml_yang_validate_add(xoutput, NULL) < 0)
|
||||
if (ret == 0){ /* validation failed */
|
||||
clicon_debug(1, "%s output validation failed", __FUNCTION__);
|
||||
if (xml_parse_string(cbuf_get(cbret), yspec, &xerr) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xret, "rpc-reply/rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
if ((ret = xml_yang_validate_add(xoutput, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){ /* validation failed */
|
||||
if (xml_parse_string(cbuf_get(cbret), yspec, &xerr) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xret, "rpc-reply/rpc-error")) != NULL)
|
||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
}
|
||||
/* Sanity check of outgoing XML */
|
||||
FCGX_SetExitStatus(200, r->out); /* OK */
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ fib_route(clicon_handle h, /* Clicon handle */
|
|||
cprintf(cbret, "<rpc-reply><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></rpc-reply>");
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -157,7 +158,7 @@ route_count(clicon_handle h,
|
|||
* in [RFC6241].
|
||||
*/
|
||||
static int
|
||||
empty(clicon_handle h, /* Clicon handle */
|
||||
empty_rpc(clicon_handle h, /* Clicon handle */
|
||||
cxobj *xe, /* Request: <rpc><xn></rpc> */
|
||||
cbuf *cbret, /* Reply eg <rpc-reply>... */
|
||||
void *arg, /* client_entry */
|
||||
|
|
@ -167,6 +168,31 @@ empty(clicon_handle h, /* Clicon handle */
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*! More elaborate example RPC for testing
|
||||
* The RPC returns the incoming parameters
|
||||
*/
|
||||
static int
|
||||
example_rpc(clicon_handle h, /* Clicon handle */
|
||||
cxobj *xe, /* Request: <rpc><xn></rpc> */
|
||||
cbuf *cbret, /* Reply eg <rpc-reply>... */
|
||||
void *arg, /* client_entry */
|
||||
void *regarg) /* Argument given at register */
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *x = NULL;
|
||||
|
||||
cprintf(cbret, "<rpc-reply>");
|
||||
while ((x = xml_child_each(xe, x, CX_ELMNT)) != NULL) {
|
||||
if (clicon_xml2cbuf(cbret, x, 0, 0) < 0)
|
||||
goto done;
|
||||
}
|
||||
cprintf(cbret, "</rpc-reply>");
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*! Called to get state data from plugin
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] xpath String with XPATH syntax. or NULL for all
|
||||
|
|
@ -315,22 +341,31 @@ clixon_plugin_init(clicon_handle h)
|
|||
if (example_stream_timer_setup(h) < 0)
|
||||
goto done;
|
||||
|
||||
/* Register callback for routing rpc calls */
|
||||
/* Register callback for routing rpc calls
|
||||
*/
|
||||
|
||||
if (rpc_callback_register(h, fib_route,
|
||||
NULL,
|
||||
"fib-route"/* Xml tag when callback is made */
|
||||
) < 0)
|
||||
goto done;
|
||||
/* From ietf-routing.yang */
|
||||
if (rpc_callback_register(h, route_count,
|
||||
NULL,
|
||||
"route-count"/* Xml tag when callback is made */
|
||||
) < 0)
|
||||
goto done;
|
||||
if (rpc_callback_register(h, empty,
|
||||
/* From example.yang (clicon) */
|
||||
if (rpc_callback_register(h, empty_rpc,
|
||||
NULL,
|
||||
"empty"/* Xml tag when callback is made */
|
||||
) < 0)
|
||||
goto done;
|
||||
if (rpc_callback_register(h, example_rpc,
|
||||
NULL,
|
||||
"example"/* Xml tag when callback is made */
|
||||
) < 0)
|
||||
goto done;
|
||||
|
||||
/* Return plugin API */
|
||||
return &api;
|
||||
|
|
|
|||
|
|
@ -46,9 +46,9 @@ int netconf_too_big(cbuf *cb, char *type, char *message);
|
|||
int netconf_missing_attribute(cbuf *cb, char *type, char *info, char *message);
|
||||
int netconf_bad_attribute(cbuf *cb, char *type, char *info, char *message);
|
||||
int netconf_unknown_attribute(cbuf *cb, char *type, char *info, char *message);
|
||||
int netconf_missing_element(cbuf *cb, char *type, char *info, char *message);
|
||||
int netconf_bad_element(cbuf *cb, char *type, char *info, char *message);
|
||||
int netconf_unknown_element(cbuf *cb, char *type, char *info, char *message);
|
||||
int netconf_missing_element(cbuf *cb, char *type, char *element, char *message);
|
||||
int netconf_bad_element(cbuf *cb, char *type, char *info, char *element);
|
||||
int netconf_unknown_element(cbuf *cb, char *type, char *element, char *message);
|
||||
int netconf_unknown_namespace(cbuf *cb, char *type, char *info, char *message);
|
||||
int netconf_access_denied(cbuf *cb, char *type, char *message);
|
||||
int netconf_access_denied_xml(cxobj **xret, char *type, char *message);
|
||||
|
|
|
|||
|
|
@ -99,8 +99,8 @@ extern int _CLICON_XML_NS_ITERATE;
|
|||
char *xml_type2str(enum cxobj_type type);
|
||||
char *xml_name(cxobj *xn);
|
||||
int xml_name_set(cxobj *xn, char *name);
|
||||
char *xml_namespace(cxobj *xn);
|
||||
int xml_namespace_set(cxobj *xn, char *name);
|
||||
char *xml_prefix(cxobj *xn);
|
||||
int xml_prefix_set(cxobj *xn, char *name);
|
||||
int xml2ns(cxobj *x, char *localname, char **namespace);
|
||||
cxobj *xml_parent(cxobj *xn);
|
||||
int xml_parent_set(cxobj *xn, cxobj *parent);
|
||||
|
|
|
|||
|
|
@ -43,9 +43,10 @@
|
|||
*/
|
||||
int xml2txt(FILE *f, cxobj *x, int level);
|
||||
int xml2cli(FILE *f, cxobj *x, char *prepend, enum genmodel_type gt);
|
||||
int xml_yang_validate_rpc(cxobj *xrpc);
|
||||
int xml_yang_validate_add(cxobj *xt, void *arg);
|
||||
int xml_yang_validate_all(cxobj *xt, void *arg);
|
||||
int xml_yang_validate_rpc(cxobj *xrpc, 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_top(cxobj *xt, cbuf *cbret);
|
||||
int xml2cvec(cxobj *xt, yang_stmt *ys, cvec **cvv0);
|
||||
int cvec2xml_1(cvec *cvv, char *toptag, cxobj *xp, cxobj **xt0);
|
||||
int xml_diff(yang_spec *yspec, cxobj *xt1, cxobj *xt2,
|
||||
|
|
|
|||
|
|
@ -315,7 +315,7 @@ xml2json1_cbuf(cbuf *cb,
|
|||
* Harder if x has a prefix, then that should also be translated to associated
|
||||
* module name
|
||||
*/
|
||||
prefix = xml_namespace(x);
|
||||
prefix = xml_prefix(x);
|
||||
if (xml2ns(x, prefix, &namespace) < 0)
|
||||
goto done;
|
||||
if ((ys = xml_spec(x)) != NULL) /* yang spec associated with x */
|
||||
|
|
|
|||
|
|
@ -80,8 +80,8 @@ netconf_in_use(cbuf *cb,
|
|||
char *encstr = NULL;
|
||||
|
||||
if (cprintf(cb, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>in-use</error-tag>"
|
||||
"<error-type>%s</error-type>"
|
||||
"<error-tag>in-use</error-tag>"
|
||||
"<error-severity>error</error-severity>",
|
||||
type) <0)
|
||||
goto err;
|
||||
|
|
@ -119,8 +119,8 @@ netconf_invalid_value(cbuf *cb,
|
|||
char *encstr = NULL;
|
||||
|
||||
if (cprintf(cb, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>invalid-value</error-tag>"
|
||||
"<error-type>%s</error-type>"
|
||||
"<error-tag>invalid-value</error-tag>"
|
||||
"<error-severity>error</error-severity>",
|
||||
type) <0)
|
||||
goto err;
|
||||
|
|
@ -159,8 +159,8 @@ netconf_too_big(cbuf *cb,
|
|||
char *encstr = NULL;
|
||||
|
||||
if (cprintf(cb, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>too-big</error-tag>"
|
||||
"<error-type>%s</error-type>"
|
||||
"<error-tag>too-big</error-tag>"
|
||||
"<error-severity>error</error-severity>",
|
||||
type) <0)
|
||||
goto err;
|
||||
|
|
@ -200,8 +200,8 @@ netconf_missing_attribute(cbuf *cb,
|
|||
char *encstr = NULL;
|
||||
|
||||
if (cprintf(cb, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>missing-attribute</error-tag>"
|
||||
"<error-type>%s</error-type>"
|
||||
"<error-tag>missing-attribute</error-tag>"
|
||||
"<error-info>%s</error-info>"
|
||||
"<error-severity>error</error-severity>",
|
||||
type, info) <0)
|
||||
|
|
@ -241,8 +241,8 @@ netconf_bad_attribute(cbuf *cb,
|
|||
char *encstr = NULL;
|
||||
|
||||
if (cprintf(cb, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>bad-attribute</error-tag>"
|
||||
"<error-type>%s</error-type>"
|
||||
"<error-tag>bad-attribute</error-tag>"
|
||||
"<error-info>%s</error-info>"
|
||||
"<error-severity>error</error-severity>",
|
||||
type, info) <0)
|
||||
|
|
@ -283,8 +283,8 @@ netconf_unknown_attribute(cbuf *cb,
|
|||
char *encstr = NULL;
|
||||
|
||||
if (cprintf(cb, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>unknown-attribute</error-tag>"
|
||||
"<error-type>%s</error-type>"
|
||||
"<error-tag>unknown-attribute</error-tag>"
|
||||
"<error-info>%s</error-info>"
|
||||
"<error-severity>error</error-severity>",
|
||||
type, info) <0)
|
||||
|
|
@ -318,18 +318,18 @@ netconf_unknown_attribute(cbuf *cb,
|
|||
int
|
||||
netconf_missing_element(cbuf *cb,
|
||||
char *type,
|
||||
char *info,
|
||||
char *element,
|
||||
char *message)
|
||||
{
|
||||
int retval = -1;
|
||||
char *encstr = NULL;
|
||||
|
||||
if (cprintf(cb, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>missing-element</error-tag>"
|
||||
"<error-type>%s</error-type>"
|
||||
"<error-info>%s</error-info>"
|
||||
"<error-tag>missing-element</error-tag>"
|
||||
"<error-info><bad-element>%s</bad-element></error-info>"
|
||||
"<error-severity>error</error-severity>",
|
||||
type, info) <0)
|
||||
type, element) <0)
|
||||
goto err;
|
||||
if (message){
|
||||
if (xml_chardata_encode(&encstr, "%s", message) < 0)
|
||||
|
|
@ -355,24 +355,24 @@ netconf_missing_element(cbuf *cb,
|
|||
* pattern mismatch.
|
||||
* @param[out] cb CLIgen buf. Error XML is written in this buffer
|
||||
* @param[in] type Error type: "application" or "protocol"
|
||||
* @param[in] info bad-element xml
|
||||
* @param[in] elemnt Bad element name
|
||||
* @param[in] message Error message
|
||||
*/
|
||||
int
|
||||
netconf_bad_element(cbuf *cb,
|
||||
char *type,
|
||||
char *info,
|
||||
char *element,
|
||||
char *message)
|
||||
{
|
||||
int retval = -1;
|
||||
char *encstr = NULL;
|
||||
|
||||
if (cprintf(cb, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>bad-element</error-tag>"
|
||||
"<error-type>%s</error-type>"
|
||||
"<error-info>%s</error-info>"
|
||||
"<error-tag>bad-element</error-tag>"
|
||||
"<error-info><bad-element>%s</bad-element></error-info>"
|
||||
"<error-severity>error</error-severity>",
|
||||
type, info) <0)
|
||||
type, element) <0)
|
||||
goto err;
|
||||
if (message){
|
||||
if (xml_chardata_encode(&encstr, "%s", message) < 0)
|
||||
|
|
@ -397,24 +397,24 @@ netconf_bad_element(cbuf *cb,
|
|||
* An unexpected element is present.
|
||||
* @param[out] cb CLIgen buf. Error XML is written in this buffer
|
||||
* @param[in] type Error type: "application" or "protocol"
|
||||
* @param[in] info bad-element xml
|
||||
* @param[in] element Bad element name
|
||||
* @param[in] message Error message
|
||||
*/
|
||||
int
|
||||
netconf_unknown_element(cbuf *cb,
|
||||
char *type,
|
||||
char *info,
|
||||
char *element,
|
||||
char *message)
|
||||
{
|
||||
int retval = -1;
|
||||
char *encstr = NULL;
|
||||
|
||||
if (cprintf(cb, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>unknown-element</error-tag>"
|
||||
"<error-type>%s</error-type>"
|
||||
"<error-info>%s</error-info>"
|
||||
"<error-tag>unknown-element</error-tag>"
|
||||
"<error-info><bad-element>%s</bad-element></error-info>"
|
||||
"<error-severity>error</error-severity>",
|
||||
type, info) <0)
|
||||
type, element) <0)
|
||||
goto err;
|
||||
if (message){
|
||||
if (xml_chardata_encode(&encstr, "%s", message) < 0)
|
||||
|
|
@ -452,8 +452,8 @@ netconf_unknown_namespace(cbuf *cb,
|
|||
char *encstr = NULL;
|
||||
|
||||
if (cprintf(cb, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>unknown-namespace</error-tag>"
|
||||
"<error-type>%s</error-type>"
|
||||
"<error-tag>unknown-namespace</error-tag>"
|
||||
"<error-info>%s</error-info>"
|
||||
"<error-severity>error</error-severity>",
|
||||
type, info) <0)
|
||||
|
|
@ -478,7 +478,8 @@ netconf_unknown_namespace(cbuf *cb,
|
|||
|
||||
/*! Create Netconf access-denied error XML tree according to RFC 6241 App A
|
||||
*
|
||||
* An expected element is missing.
|
||||
* Access to the requested protocol operation or data model is denied because
|
||||
* authorization failed.
|
||||
* @param[out] cb CLIgen buf. Error XML is written in this buffer
|
||||
* @param[in] type Error type: "application" or "protocol"
|
||||
* @param[in] message Error message
|
||||
|
|
@ -492,8 +493,8 @@ netconf_access_denied(cbuf *cb,
|
|||
char *encstr = NULL;
|
||||
|
||||
if (cprintf(cb, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>access-denied</error-tag>"
|
||||
"<error-type>%s</error-type>"
|
||||
"<error-tag>access-denied</error-tag>"
|
||||
"<error-severity>error</error-severity>",
|
||||
type) <0)
|
||||
goto err;
|
||||
|
|
@ -517,7 +518,8 @@ netconf_access_denied(cbuf *cb,
|
|||
|
||||
/*! Create Netconf access-denied error XML tree according to RFC 6241 App A
|
||||
*
|
||||
* An expected element is missing.
|
||||
* Access to the requested protocol operation or data model is denied because
|
||||
* authorization failed.
|
||||
* @param[out] xret Error XML tree
|
||||
* @param[in] type Error type: "application" or "protocol"
|
||||
* @param[in] message Error message
|
||||
|
|
@ -538,8 +540,8 @@ netconf_access_denied_xml(cxobj **xret,
|
|||
goto done;
|
||||
if ((xerr = xml_new("rpc-error", *xret, NULL)) == NULL)
|
||||
goto done;
|
||||
if (xml_parse_va(&xerr, NULL, "<error-tag>access-denied</error-tag>"
|
||||
"<error-type>%s</error-type>"
|
||||
if (xml_parse_va(&xerr, NULL, "<error-type>%s</error-type>"
|
||||
"<error-tag>access-denied</error-tag>"
|
||||
"<error-severity>error</error-severity>", type) < 0)
|
||||
goto done;
|
||||
if (message && xml_parse_va(&xerr, NULL, "<error-message>%s</error-message>",
|
||||
|
|
@ -567,8 +569,8 @@ netconf_lock_denied(cbuf *cb,
|
|||
char *encstr = NULL;
|
||||
|
||||
if (cprintf(cb, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>lock-denied</error-tag>"
|
||||
"<error-type>protocol</error-type>"
|
||||
"<error-tag>lock-denied</error-tag>"
|
||||
"<error-info>%s</error-info>"
|
||||
"<error-severity>error</error-severity>",
|
||||
info) <0)
|
||||
|
|
@ -593,7 +595,7 @@ netconf_lock_denied(cbuf *cb,
|
|||
|
||||
/*! Create Netconf resource-denied error XML tree according to RFC 6241 App A
|
||||
*
|
||||
* An expected element is missing.
|
||||
* Request could not be completed because of insufficient resources.
|
||||
* @param[out] cb CLIgen buf. Error XML is written in this buffer
|
||||
* @param[in] type Error type: "transport, "rpc", "application", "protocol"
|
||||
* @param[in] message Error message
|
||||
|
|
@ -607,8 +609,8 @@ netconf_resource_denied(cbuf *cb,
|
|||
char *encstr = NULL;
|
||||
|
||||
if (cprintf(cb, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>resource-denied</error-tag>"
|
||||
"<error-type>%s</error-type>"
|
||||
"<error-tag>resource-denied</error-tag>"
|
||||
"<error-severity>error</error-severity>",
|
||||
type) <0)
|
||||
goto err;
|
||||
|
|
@ -647,8 +649,8 @@ netconf_rollback_failed(cbuf *cb,
|
|||
char *encstr = NULL;
|
||||
|
||||
if (cprintf(cb, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>rollback-failed</error-tag>"
|
||||
"<error-type>%s</error-type>"
|
||||
"<error-tag>rollback-failed</error-tag>"
|
||||
"<error-severity>error</error-severity>",
|
||||
type) <0)
|
||||
goto err;
|
||||
|
|
@ -686,8 +688,8 @@ netconf_data_exists(cbuf *cb,
|
|||
char *encstr = NULL;
|
||||
|
||||
if (cprintf(cb, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>data-exists</error-tag>"
|
||||
"<error-type>application</error-type>"
|
||||
"<error-tag>data-exists</error-tag>"
|
||||
"<error-severity>error</error-severity>") <0)
|
||||
goto err;
|
||||
if (message){
|
||||
|
|
@ -724,8 +726,8 @@ netconf_data_missing(cbuf *cb,
|
|||
char *encstr = NULL;
|
||||
|
||||
if (cprintf(cb, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>data-missing</error-tag>"
|
||||
"<error-type>application</error-type>"
|
||||
"<error-tag>data-missing</error-tag>"
|
||||
"<error-severity>error</error-severity>") <0)
|
||||
goto err;
|
||||
if (message){
|
||||
|
|
@ -763,8 +765,8 @@ netconf_operation_not_supported(cbuf *cb,
|
|||
char *encstr = NULL;
|
||||
|
||||
if (cprintf(cb, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>operation-not-supported</error-tag>"
|
||||
"<error-type>%s</error-type>"
|
||||
"<error-tag>operation-not-supported</error-tag>"
|
||||
"<error-severity>error</error-severity>",
|
||||
type) <0)
|
||||
goto err;
|
||||
|
|
@ -803,8 +805,8 @@ netconf_operation_failed(cbuf *cb,
|
|||
char *encstr = NULL;
|
||||
|
||||
if (cprintf(cb, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>operation-failed</error-tag>"
|
||||
"<error-type>%s</error-type>"
|
||||
"<error-tag>operation-failed</error-tag>"
|
||||
"<error-severity>error</error-severity>",
|
||||
type) <0)
|
||||
goto err;
|
||||
|
|
@ -850,8 +852,8 @@ netconf_operation_failed_xml(cxobj **xret,
|
|||
goto done;
|
||||
if ((xerr = xml_new("rpc-error", *xret, NULL)) == NULL)
|
||||
goto done;
|
||||
if (xml_parse_va(&xerr, NULL, "<error-tag>operation-failed</error-tag>"
|
||||
"<error-type>%s</error-type>"
|
||||
if (xml_parse_va(&xerr, NULL, "<error-type>%s</error-type>"
|
||||
"<error-tag>operation-failed</error-tag>"
|
||||
"<error-severity>error</error-severity>", type) < 0)
|
||||
goto done;
|
||||
if (message && xml_parse_va(&xerr, NULL, "<error-message>%s</error-message>",
|
||||
|
|
@ -879,8 +881,8 @@ netconf_malformed_message(cbuf *cb,
|
|||
char *encstr = NULL;
|
||||
|
||||
if (cprintf(cb, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>malformed-message</error-tag>"
|
||||
"<error-type>rpc</error-type>"
|
||||
"<error-tag>malformed-message</error-tag>"
|
||||
"<error-severity>error</error-severity>") <0)
|
||||
goto err;
|
||||
if (message){
|
||||
|
|
@ -925,8 +927,8 @@ netconf_malformed_message_xml(cxobj **xret,
|
|||
goto done;
|
||||
if ((xerr = xml_new("rpc-error", *xret, NULL)) == NULL)
|
||||
goto done;
|
||||
if (xml_parse_va(&xerr, NULL, "<error-tag>malformed-message</error-tag>"
|
||||
"<error-type>rpc</error-type>"
|
||||
if (xml_parse_va(&xerr, NULL, "<error-type>rpc</error-type>"
|
||||
"<error-tag>malformed-message</error-tag>"
|
||||
"<error-severity>error</error-severity>") < 0)
|
||||
goto done;
|
||||
if (message && xml_parse_va(&xerr, NULL, "<error-message>%s</error-message>",
|
||||
|
|
@ -990,7 +992,6 @@ netconf_module_load(clicon_handle h)
|
|||
clicon_err(OE_CFG, ENOENT, "Clicon configuration not loaded");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Enable features (hardcoded here) */
|
||||
if (xml_parse_string("<CLICON_FEATURE>ietf-netconf:candidate</CLICON_FEATURE>", yspec, &xc) < 0)
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -136,6 +136,8 @@ parse_configfile(clicon_handle h,
|
|||
char *name;
|
||||
char *body;
|
||||
clicon_hash_t *copt = clicon_options(h);
|
||||
cbuf *cbret = NULL;
|
||||
int ret;
|
||||
|
||||
if (filename == NULL || !strlen(filename)){
|
||||
clicon_err(OE_UNIX, 0, "Not specified");
|
||||
|
|
@ -167,8 +169,16 @@ parse_configfile(clicon_handle h,
|
|||
}
|
||||
if (xml_apply0(xc, CX_ELMNT, xml_default, yspec) < 0)
|
||||
goto done;
|
||||
if (xml_apply0(xc, CX_ELMNT, xml_yang_validate_add, NULL) < 0)
|
||||
if ((cbret = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if ((ret = xml_yang_validate_add(xc, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
clicon_err(OE_CFG, 0, "Config file validation: %s", cbuf_get(cbret));
|
||||
goto done;
|
||||
}
|
||||
while ((x = xml_child_each(xc, x, CX_ELMNT)) != NULL) {
|
||||
name = xml_name(x);
|
||||
body = xml_body(x);
|
||||
|
|
|
|||
|
|
@ -444,7 +444,7 @@ clicon_rpc_delete_config(clicon_handle h,
|
|||
char *username;
|
||||
|
||||
username = clicon_username_get(h);
|
||||
if ((msg = clicon_msg_encode("<rpc username=\"%s\"><delete-config><target><%s/></target></delete-config></rpc>",
|
||||
if ((msg = clicon_msg_encode("<rpc username=\"%s\"><edit-config><target><%s/></target><default-operation>none</default-operation><config operation=\"delete\"/></edit-config></rpc>",
|
||||
username?username:"", db)) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
|
|
|
|||
|
|
@ -196,10 +196,9 @@ xml_name_set(cxobj *xn,
|
|||
/*! Get namespace of xnode
|
||||
* @param[in] xn xml node
|
||||
* @retval namespace of xml node
|
||||
* XXX change to xml_localname
|
||||
*/
|
||||
char*
|
||||
xml_namespace(cxobj *xn)
|
||||
xml_prefix(cxobj *xn)
|
||||
{
|
||||
return xn->x_prefix;
|
||||
}
|
||||
|
|
@ -209,10 +208,9 @@ xml_namespace(cxobj *xn)
|
|||
* @param[in] localname new namespace, null-terminated string, copied by function
|
||||
* @retval -1 on error with clicon-err set
|
||||
* @retval 0 OK
|
||||
* XXX change to xml_localname_set
|
||||
*/
|
||||
int
|
||||
xml_namespace_set(cxobj *xn,
|
||||
xml_prefix_set(cxobj *xn,
|
||||
char *localname)
|
||||
{
|
||||
if (xn->x_prefix){
|
||||
|
|
@ -288,7 +286,7 @@ xmlns_check(cxobj *xn,
|
|||
char *xns;
|
||||
|
||||
while ((x = xml_child_each(xn, x, CX_ATTR)) != NULL)
|
||||
if ((xns = xml_namespace(x)) && strcmp(xns, "xmlns")==0 &&
|
||||
if ((xns = xml_prefix(x)) && strcmp(xns, "xmlns")==0 &&
|
||||
strcmp(xml_name(x), nsn) == 0)
|
||||
return xml_value(x);
|
||||
return NULL;
|
||||
|
|
@ -311,7 +309,7 @@ xml_localname_check(cxobj *xn,
|
|||
yang_stmt *ys = xml_spec(xn);
|
||||
|
||||
/* No namespace name - comply */
|
||||
if ((nsn = xml_namespace(xn)) == NULL)
|
||||
if ((nsn = xml_prefix(xn)) == NULL)
|
||||
return 0;
|
||||
/* Check if NSN defined in same node */
|
||||
if (xmlns_check(xn, nsn) != NULL)
|
||||
|
|
@ -965,7 +963,7 @@ xml_find_type_value(cxobj *xt,
|
|||
char *xprefix; /* xprefix */
|
||||
|
||||
while ((x = xml_child_each(xt, x, type)) != NULL) {
|
||||
xprefix = xml_namespace(x);
|
||||
xprefix = xml_prefix(x);
|
||||
if (prefix)
|
||||
pmatch = xprefix?strcmp(prefix,xprefix)==0:0;
|
||||
else
|
||||
|
|
@ -1121,7 +1119,7 @@ clicon_xml2file(FILE *f,
|
|||
if (x == NULL)
|
||||
goto ok;
|
||||
name = xml_name(x);
|
||||
namespace = xml_namespace(x);
|
||||
namespace = xml_prefix(x);
|
||||
switch(xml_type(x)){
|
||||
case CX_BODY:
|
||||
if ((val = xml_value(x)) == NULL) /* incomplete tree */
|
||||
|
|
@ -1246,7 +1244,7 @@ clicon_xml2cbuf(cbuf *cb,
|
|||
char *val;
|
||||
|
||||
name = xml_name(x);
|
||||
namespace = xml_namespace(x);
|
||||
namespace = xml_prefix(x);
|
||||
switch(xml_type(x)){
|
||||
case CX_BODY:
|
||||
if ((val = xml_value(x)) == NULL) /* incomplete tree */
|
||||
|
|
@ -1333,10 +1331,10 @@ xmltree2cbuf(cbuf *cb,
|
|||
cprintf(cb, " ");
|
||||
if (xml_type(x) != CX_BODY)
|
||||
cprintf(cb, "%s", xml_type2str(xml_type(x)));
|
||||
if (xml_namespace(x)==NULL)
|
||||
if (xml_prefix(x)==NULL)
|
||||
cprintf(cb, " %s", xml_name(x));
|
||||
else
|
||||
cprintf(cb, " %s:%s", xml_namespace(x), xml_name(x));
|
||||
cprintf(cb, " %s:%s", xml_prefix(x), xml_name(x));
|
||||
if (xml_value(x))
|
||||
cprintf(cb, " value:\"%s\"", xml_value(x));
|
||||
if (x->x_flags)
|
||||
|
|
@ -1612,8 +1610,8 @@ xml_copy_one(cxobj *x0,
|
|||
if ((s = xml_name(x0))) /* malloced string */
|
||||
if ((xml_name_set(x1, s)) < 0)
|
||||
return -1;
|
||||
if ((s = xml_namespace(x0))) /* malloced string */
|
||||
if ((xml_namespace_set(x1, s)) < 0)
|
||||
if ((s = xml_prefix(x0))) /* malloced string */
|
||||
if ((xml_prefix_set(x1, s)) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@
|
|||
#include "clixon_xpath.h"
|
||||
#include "clixon_log.h"
|
||||
#include "clixon_err.h"
|
||||
#include "clixon_netconf_lib.h"
|
||||
#include "clixon_xml_sort.h"
|
||||
#include "clixon_xml_map.h"
|
||||
|
||||
|
|
@ -230,10 +231,15 @@ xml2cli(FILE *f,
|
|||
/*! Validate xml node of type leafref, ensure the value is one of that path's reference
|
||||
* @param[in] xt XML leaf node of type leafref
|
||||
* @param[in] ytype Yang type statement belonging to the XML node
|
||||
* @param[out] cbret Error buffer
|
||||
* @retval 1 Validation OK
|
||||
* @retval 0 Validation failed
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
validate_leafref(cxobj *xt,
|
||||
yang_stmt *ytype)
|
||||
yang_stmt *ytype,
|
||||
cbuf *cbret)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt *ypath;
|
||||
|
|
@ -247,8 +253,9 @@ validate_leafref(cxobj *xt,
|
|||
if ((leafrefbody = xml_body(xt)) == NULL)
|
||||
goto ok;
|
||||
if ((ypath = yang_find((yang_node*)ytype, Y_PATH, NULL)) == NULL){
|
||||
clicon_err(OE_DB, 0, "Leafref %s requires path statement", ytype->ys_argument);
|
||||
if (netconf_missing_element(cbret, "application", ytype->ys_argument, "Leafref requires path statement") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
if (xpath_vec(xt, "%s", &xvec, &xlen, ypath->ys_argument) < 0)
|
||||
goto done;
|
||||
|
|
@ -260,9 +267,9 @@ validate_leafref(cxobj *xt,
|
|||
break;
|
||||
}
|
||||
if (i==xlen){
|
||||
clicon_err(OE_DB, 0, "Leafref validation failed, no such leaf: %s",
|
||||
leafrefbody);
|
||||
if (netconf_bad_element(cbret, "application", leafrefbody, "Leafref validation failed: No such leaf") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
ok:
|
||||
retval = 0;
|
||||
|
|
@ -270,6 +277,9 @@ validate_leafref(cxobj *xt,
|
|||
if (xvec)
|
||||
free(xvec);
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Validate xml node of type identityref, ensure value is a defined identity
|
||||
|
|
@ -285,14 +295,18 @@ validate_leafref(cxobj *xt,
|
|||
* @param[in] xt XML leaf node of type identityref
|
||||
* @param[in] ys Yang spec of leaf
|
||||
* @param[in] ytype Yang type field of type identityref
|
||||
* @param[out] cbret Error buffer
|
||||
* @retval 1 Validation OK
|
||||
* @retval 0 Validation failed
|
||||
* @retval -1 Error
|
||||
* @see ys_populate_identity where the derived types are set
|
||||
* @see RFC7950 Sec 9.10.2:
|
||||
|
||||
*/
|
||||
static int
|
||||
validate_identityref(cxobj *xt,
|
||||
yang_stmt *ys,
|
||||
yang_stmt *ytype)
|
||||
yang_stmt *ytype,
|
||||
cbuf *cbret)
|
||||
{
|
||||
int retval = -1;
|
||||
char *node;
|
||||
|
|
@ -305,37 +319,46 @@ validate_identityref(cxobj *xt,
|
|||
* Always add default prefix because derived identifiers are stored with
|
||||
* prefixes in the base identifiers derived-list.
|
||||
*/
|
||||
if ((node = xml_body(xt)) == NULL)
|
||||
return 0;
|
||||
if (strchr(node, ':') == NULL){
|
||||
prefix = yang_find_myprefix(ys);
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if ((node = xml_body(xt)) == NULL)
|
||||
return 0;
|
||||
if (strchr(node, ':') == NULL){
|
||||
prefix = yang_find_myprefix(ys);
|
||||
cprintf(cb, "%s:%s", prefix, node);
|
||||
node = cbuf_get(cb);
|
||||
}
|
||||
/* This is the type's base reference */
|
||||
if ((ybaseref = yang_find((yang_node*)ytype, Y_BASE, NULL)) == NULL){
|
||||
clicon_err(OE_DB, 0, "Identityref validation failed, no base");
|
||||
if (netconf_missing_element(cbret, "application", ytype->ys_argument, "Identityref validation failed, no base") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
/* This is the actual base identity */
|
||||
if ((ybaseid = yang_find_identity(ybaseref, ybaseref->ys_argument)) == NULL){
|
||||
clicon_err(OE_DB, 0, "Identityref validation failed, no base identity");
|
||||
if (netconf_missing_element(cbret, "application", ybaseref->ys_argument, "Identityref validation failed, no base identity") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
/* Here check if node is in the derived node list of the base identity */
|
||||
if (cvec_find(ybaseid->ys_cvec, node) == NULL){
|
||||
clicon_err(OE_DB, 0, "Identityref validation failed, %s not derived from %s", node, ybaseid->ys_argument);
|
||||
cbuf_reset(cb);
|
||||
cprintf(cb, "Identityref validation failed, %s not derived from %s",
|
||||
node, ybaseid->ys_argument);
|
||||
if (netconf_operation_failed(cbret, "application", cbuf_get(cb)) < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
retval = 0;
|
||||
retval = 1;
|
||||
done:
|
||||
if (cb)
|
||||
cbuf_free(cb);
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Validate an RPC node
|
||||
|
|
@ -377,24 +400,33 @@ validate_identityref(cxobj *xt,
|
|||
* the same order as they are defined within the "output" statement.
|
||||
*/
|
||||
int
|
||||
xml_yang_validate_rpc(cxobj *xrpc)
|
||||
xml_yang_validate_rpc(cxobj *xrpc,
|
||||
cbuf *cbret)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt *yn=NULL; /* rpc name */
|
||||
cxobj *xn; /* rpc name */
|
||||
yang_stmt *yi=NULL; /* input name */
|
||||
cxobj *xi; /* input name */
|
||||
int ret;
|
||||
|
||||
assert(strcmp(xml_name(xrpc), "rpc")==0);
|
||||
if (strcmp(xml_name(xrpc), "rpc")){
|
||||
clicon_err(OE_XML, EINVAL, "Expected RPC");
|
||||
goto done;
|
||||
}
|
||||
xn = NULL;
|
||||
/* xn is name of rpc, ie <rcp><xn/></rpc> */
|
||||
while ((xn = xml_child_each(xrpc, xn, CX_ELMNT)) != NULL) {
|
||||
if ((yn = xml_spec(xn)) == NULL)
|
||||
goto fail;
|
||||
xi = NULL;
|
||||
while ((xi = xml_child_each(xn, xi, CX_ELMNT)) != NULL) {
|
||||
if ((yi = xml_spec(xi)) == NULL)
|
||||
if ((ret = xml_yang_validate_all(xn, cbret)) < 0)
|
||||
goto fail;
|
||||
}
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
if ((ret = xml_yang_validate_add(xn, cbret)) < 0)
|
||||
goto fail;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
if (xml_apply0(xn, CX_ELMNT, xml_default, NULL) < 0)
|
||||
goto done;
|
||||
}
|
||||
// ok: /* pass validation */
|
||||
retval = 1;
|
||||
|
|
@ -409,13 +441,23 @@ xml_yang_validate_rpc(cxobj *xrpc)
|
|||
* 1. Check if mandatory leafs present as subs.
|
||||
* 2. Check leaf values, eg int ranges and string regexps.
|
||||
* @param[in] xt XML node to be validated
|
||||
* @retval 0 Valid OK
|
||||
* @retval -1 Validation failed
|
||||
* @param[out] cbret Error buffer
|
||||
* @retval 1 Validation OK
|
||||
* @retval 0 Validation failed
|
||||
* @retval -1 Error
|
||||
* @code
|
||||
* cxobj *x;
|
||||
* cbuf *cbret = cbuf_new();
|
||||
* if ((ret = xml_yang_validate_add(x, cbret)) < 0)
|
||||
* err;
|
||||
* if (ret == 0)
|
||||
* fail;
|
||||
* @endcode
|
||||
* @see xml_yang_validate_all
|
||||
*/
|
||||
int
|
||||
xml_yang_validate_add(cxobj *xt,
|
||||
void *arg)
|
||||
cbuf *cbret)
|
||||
{
|
||||
int retval = -1;
|
||||
cg_var *cv = NULL;
|
||||
|
|
@ -424,11 +466,14 @@ xml_yang_validate_add(cxobj *xt,
|
|||
int i;
|
||||
yang_stmt *ys;
|
||||
char *body;
|
||||
int ret;
|
||||
cxobj *x;
|
||||
|
||||
/* if not given by argument (overide) use default link
|
||||
and !Node has a config sub-statement and it is false */
|
||||
if ((ys = xml_spec(xt)) != NULL && yang_config(ys) != 0){
|
||||
switch (ys->ys_keyword){
|
||||
case Y_RPC:
|
||||
case Y_INPUT:
|
||||
case Y_LIST:
|
||||
/* fall thru */
|
||||
|
|
@ -440,9 +485,9 @@ xml_yang_validate_add(cxobj *xt,
|
|||
if (yang_config(yc)==0)
|
||||
continue;
|
||||
if (yang_mandatory(yc) && xml_find(xt, yc->ys_argument)==NULL){
|
||||
clicon_err(OE_CFG, 0,"Missing mandatory variable: %s",
|
||||
yc->ys_argument);
|
||||
if (netconf_missing_element(cbret, "application", yc->ys_argument, "Mandatory variable") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -463,12 +508,11 @@ xml_yang_validate_add(cxobj *xt,
|
|||
goto done;
|
||||
}
|
||||
if ((ys_cv_validate(cv, ys, &reason)) != 1){
|
||||
clicon_err(OE_DB, 0,
|
||||
"validation of %s failed %s",
|
||||
ys->ys_argument, reason?reason:"");
|
||||
if (netconf_bad_element(cbret, "application", ys->ys_argument, reason) < 0)
|
||||
goto done;
|
||||
if (reason)
|
||||
free(reason);
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -476,28 +520,43 @@ xml_yang_validate_add(cxobj *xt,
|
|||
break;
|
||||
}
|
||||
}
|
||||
retval = 0;
|
||||
x = NULL;
|
||||
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
|
||||
if ((ret = xml_yang_validate_add(x, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
}
|
||||
retval = 1;
|
||||
done:
|
||||
if (cv)
|
||||
cv_free(cv);
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Validate a single XML node with yang specification for all (not only added) entries
|
||||
* 1. Check leafrefs. Eg you delete a leaf and a leafref references it.
|
||||
* @param[in] xt XML node to be validated
|
||||
* @param[in] arg Not used
|
||||
* @retval -1 Validation failed
|
||||
* @retval 0 Validation OK
|
||||
* @param[out] cbret Error buffer
|
||||
* @retval 1 Validation OK
|
||||
* @retval 0 Validation failed
|
||||
* @retval -1 Error
|
||||
* @see xml_yang_validate_add
|
||||
* @code
|
||||
* if (xml_apply(x, CX_ELMNT, (xml_applyfn_t*)xml_yang_validate_all, 0) < 0)
|
||||
* cxobj *x;
|
||||
* cbuf *cbret = cbuf_new();
|
||||
* if ((ret = xml_yang_validate_all(x, cbret)) < 0)
|
||||
* err;
|
||||
* if (ret == 0)
|
||||
* fail;
|
||||
* @endcode
|
||||
*/
|
||||
int
|
||||
xml_yang_validate_all(cxobj *xt,
|
||||
void *arg)
|
||||
cbuf *cbret)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt *ys; /* yang node */
|
||||
|
|
@ -505,13 +564,24 @@ xml_yang_validate_all(cxobj *xt,
|
|||
yang_stmt *ye; /* yang must error-message */
|
||||
char *xpath;
|
||||
int nr;
|
||||
int ret;
|
||||
cxobj *x;
|
||||
|
||||
/* if not given by argument (overide) use default link
|
||||
and !Node has a config sub-statement and it is false */
|
||||
if ((ys = xml_spec(xt)) != NULL &&
|
||||
yang_config(ys) != 0){
|
||||
ys=xml_spec(xt);
|
||||
if (ys==NULL){
|
||||
if (netconf_unknown_element(cbret, "application", xml_name(xt), NULL) < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
if (ys != NULL && yang_config(ys) != 0){
|
||||
/* Node-specific validation */
|
||||
switch (ys->ys_keyword){
|
||||
case Y_ANYXML:
|
||||
case Y_ANYDATA:
|
||||
goto ok;
|
||||
break;
|
||||
case Y_LEAF:
|
||||
/* fall thru */
|
||||
case Y_LEAF_LIST:
|
||||
|
|
@ -520,11 +590,11 @@ xml_yang_validate_all(cxobj *xt,
|
|||
*/
|
||||
if ((yc = yang_find((yang_node*)ys, Y_TYPE, NULL)) != NULL){
|
||||
if (strcmp(yc->ys_argument, "leafref") == 0){
|
||||
if (validate_leafref(xt, yc) < 0)
|
||||
if (validate_leafref(xt, yc, cbret) < 0)
|
||||
goto done;
|
||||
}
|
||||
else if (strcmp(yc->ys_argument, "identityref") == 0){
|
||||
if (validate_identityref(xt, ys, yc) < 0)
|
||||
if (validate_identityref(xt, ys, yc, cbret) < 0)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
|
@ -568,11 +638,11 @@ xml_yang_validate_all(cxobj *xt,
|
|||
if ((nr = xpath_vec_bool(xt, "%s", xpath)) < 0)
|
||||
goto done;
|
||||
if (!nr){
|
||||
if ((ye = yang_find((yang_node*)yc, Y_ERROR_MESSAGE, NULL)) != NULL)
|
||||
clicon_err(OE_DB, 0, "%s", ye->ys_argument);
|
||||
else
|
||||
clicon_err(OE_DB, 0, "xpath %s validation failed", xml_name(xt));
|
||||
ye = yang_find((yang_node*)yc, Y_ERROR_MESSAGE, NULL);
|
||||
if (netconf_operation_failed(cbret, "application",
|
||||
ye?ye->ys_argument:"must xpath validation failed") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
/* "when" sub-node RFC 7950 Sec 7.21.5. Can only be one. */
|
||||
|
|
@ -581,14 +651,42 @@ xml_yang_validate_all(cxobj *xt,
|
|||
if ((nr = xpath_vec_bool(xt, "%s", xpath)) < 0)
|
||||
goto done;
|
||||
if (!nr){
|
||||
clicon_err(OE_DB, 0, "xpath %s validation failed", xml_name(xt));
|
||||
if (netconf_operation_failed(cbret, "application",
|
||||
"when xpath validation failed") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
retval = 0;
|
||||
x = NULL;
|
||||
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
|
||||
if ((ret = xml_yang_validate_all(x, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
}
|
||||
ok:
|
||||
retval = 1;
|
||||
done:
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
int
|
||||
xml_yang_validate_all_top(cxobj *xt,
|
||||
cbuf *cbret)
|
||||
{
|
||||
int ret;
|
||||
cxobj *x;
|
||||
|
||||
x = NULL;
|
||||
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
|
||||
if ((ret = xml_yang_validate_all(x, cbret)) < 1)
|
||||
return ret;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*! Translate a single xml node to a cligen variable vector. Note not recursive
|
||||
|
|
@ -1310,6 +1408,11 @@ xml_tree_prune_flagged(cxobj *xt,
|
|||
|
||||
/*! Add default values (if not set)
|
||||
* @param[in] xt XML tree with some node marked
|
||||
* @param[in] arg Ignored
|
||||
* Typically called in a recursive apply function:
|
||||
* @code
|
||||
* xml_apply(xt, CX_ELMNT, xml_default, NULL);
|
||||
* @endcode
|
||||
*/
|
||||
int
|
||||
xml_default(cxobj *xt,
|
||||
|
|
@ -1328,7 +1431,8 @@ xml_default(cxobj *xt,
|
|||
goto done;
|
||||
}
|
||||
/* Check leaf defaults */
|
||||
if (ys->ys_keyword == Y_CONTAINER || ys->ys_keyword == Y_LIST){
|
||||
if (ys->ys_keyword == Y_CONTAINER || ys->ys_keyword == Y_LIST ||
|
||||
ys->ys_keyword == Y_INPUT){
|
||||
for (i=0; i<ys->ys_len; i++){
|
||||
y = ys->ys_stmt[i];
|
||||
if (y->ys_keyword != Y_LEAF)
|
||||
|
|
@ -1493,9 +1597,9 @@ xml_spec_populate_rpc(clicon_handle h,
|
|||
yang_stmt *y=NULL; /* yang node */
|
||||
yang_stmt *ymod=NULL; /* yang module */
|
||||
yang_stmt *yi = NULL; /* input */
|
||||
yang_stmt *ya = NULL; /* arg */
|
||||
// yang_stmt *ya = NULL; /* arg */
|
||||
cxobj *x;
|
||||
cxobj *xi;
|
||||
// cxobj *xi;
|
||||
int i;
|
||||
|
||||
if ((strcmp(xml_name(xrpc), "rpc"))!=0){
|
||||
|
|
@ -1521,11 +1625,18 @@ xml_spec_populate_rpc(clicon_handle h,
|
|||
if (y){
|
||||
xml_spec_set(x, y);
|
||||
if ((yi = yang_find((yang_node*)y, Y_INPUT, NULL)) != NULL){
|
||||
/* kludge rpc -> input */
|
||||
xml_spec_set(x, yi);
|
||||
#if 1
|
||||
if (xml_apply(x, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
||||
goto done;
|
||||
#else
|
||||
xi = NULL;
|
||||
while ((xi = xml_child_each(x, xi, CX_ELMNT)) != NULL) {
|
||||
if ((ya = yang_find_datanode((yang_node*)yi, xml_name(xi))) != NULL)
|
||||
xml_spec_set(xi, ya);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ xml_parse_prefixed_name(struct xml_parse_yacc_arg *ya,
|
|||
goto done;
|
||||
if ((x = xml_new(name, xp, y)) == NULL)
|
||||
goto done;
|
||||
if (xml_namespace_set(x, prefix) < 0)
|
||||
if (xml_prefix_set(x, prefix) < 0)
|
||||
goto done;
|
||||
ya->ya_xelement = x;
|
||||
retval = 0;
|
||||
|
|
@ -223,9 +223,9 @@ xml_parse_bslash1(struct xml_parse_yacc_arg *ya,
|
|||
xml_name(x), name);
|
||||
goto done;
|
||||
}
|
||||
if (xml_namespace(x)!=NULL){
|
||||
if (xml_prefix(x)!=NULL){
|
||||
clicon_err(OE_XML, 0, "XML parse sanity check failed: %s:%s vs %s",
|
||||
xml_namespace(x), xml_name(x), name);
|
||||
xml_prefix(x), xml_name(x), name);
|
||||
goto done;
|
||||
}
|
||||
/* Strip pretty-print. Ad-hoc algorithm
|
||||
|
|
@ -263,16 +263,16 @@ xml_parse_bslash2(struct xml_parse_yacc_arg *ya,
|
|||
|
||||
if (strcmp(xml_name(x), name)){
|
||||
clicon_err(OE_XML, 0, "Sanity check failed: %s:%s vs %s:%s",
|
||||
xml_namespace(x),
|
||||
xml_prefix(x),
|
||||
xml_name(x),
|
||||
namespace,
|
||||
name);
|
||||
goto done;
|
||||
}
|
||||
if (xml_namespace(x)==NULL ||
|
||||
strcmp(xml_namespace(x), namespace)){
|
||||
if (xml_prefix(x)==NULL ||
|
||||
strcmp(xml_prefix(x), namespace)){
|
||||
clicon_err(OE_XML, 0, "Sanity check failed: %s:%s vs %s:%s",
|
||||
xml_namespace(x),
|
||||
xml_prefix(x),
|
||||
xml_name(x),
|
||||
namespace,
|
||||
name);
|
||||
|
|
@ -324,7 +324,7 @@ xml_parse_attr(struct xml_parse_yacc_arg *ya,
|
|||
if ((xa = xml_new(name, ya->ya_xelement, NULL)) == NULL)
|
||||
goto done;
|
||||
xml_type_set(xa, CX_ATTR);
|
||||
if (prefix && xml_namespace_set(xa, prefix) < 0)
|
||||
if (prefix && xml_prefix_set(xa, prefix) < 0)
|
||||
goto done;
|
||||
if (xml_value_set(xa, attval) < 0)
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -118,6 +118,9 @@ xml_child_spec(char *name,
|
|||
}
|
||||
else
|
||||
y = NULL;
|
||||
/* kludge rpc -> input */
|
||||
if (y && y->ys_keyword == Y_RPC && yang_find((yang_node*)y, Y_INPUT, NULL))
|
||||
y = yang_find((yang_node*)y, Y_INPUT, NULL);
|
||||
*yresult = y;
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
|
|||
|
|
@ -862,7 +862,7 @@ ys_module_by_xml(yang_spec *ysp,
|
|||
|
||||
if (ymodp)
|
||||
*ymodp = NULL;
|
||||
prefix = xml_namespace(xt);
|
||||
prefix = xml_prefix(xt);
|
||||
if (prefix){
|
||||
/* Get namespace for prefix */
|
||||
if (xml2ns(xt, prefix, &namespace) < 0)
|
||||
|
|
|
|||
|
|
@ -13,8 +13,10 @@ APPNAME=example
|
|||
. ./lib.sh
|
||||
cfg=$dir/conf_yang.xml
|
||||
|
||||
# Use yang in example
|
||||
|
||||
cat <<EOF > $cfg
|
||||
<config xmlns="http://clicon.org">
|
||||
<config xmlns="urn:example:clixon">
|
||||
<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>
|
||||
|
|
@ -115,7 +117,7 @@ expectfn "$clixon_cli -1 -f $cfg -l o debug level 0" 0 "^$"
|
|||
new "cli rpc"
|
||||
expectfn "$clixon_cli -1 -f $cfg -l o rpc ipv4" 0 "<address-family>ipv4</address-family>" "<next-hop-list>2.3.4.5</next-hop-list>"
|
||||
|
||||
if [ $BE -ne 0 ]; then
|
||||
if [ $BE -eq 0 ]; then
|
||||
exit # BE
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -96,8 +96,7 @@ 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>]]>]]>$"
|
||||
|
||||
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-tag>operation-failed</error-tag><error-type>application</error-type><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><A>foo</A></config></edit-config></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-tag>operation-failed</error-tag><error-type>protocol</error-type><error-severity>error</error-severity><error-message>XML node config/A has no corresponding yang specification (Invalid XML or wrong Yang spec?'
|
||||
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>]]>]]>$'
|
||||
|
||||
# This test has been broken up into all different modules instead of one large
|
||||
# reply since the modules change so often
|
||||
|
|
@ -162,7 +161,7 @@ if [ -z "$match" ]; then
|
|||
err "$expect" "$ret"
|
||||
fi
|
||||
|
||||
if [ $BE -ne 0 ]; then
|
||||
if [ $BE -eq 0 ]; then
|
||||
exit # BE
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ 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>]]>]]>$"
|
||||
|
||||
new "netconf validate"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-tag>operation-failed</error-tag><error-type>application</error-type><error-severity>error</error-severity><error-message>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>]]>]]>$"
|
||||
|
||||
new "cli set crypto to mc:aes"
|
||||
expectfn "$clixon_cli -1 -f $cfg -y $fyang -l o set crypto mc:aes" 0 "^$"
|
||||
|
|
@ -182,7 +182,7 @@ expectfn "$clixon_cli -1 -f $cfg -y $fyang -l o set crypto des:des3" 0 "^$"
|
|||
new "cli validate"
|
||||
expectfn "$clixon_cli -1 -f $cfg -y $fyang -l o validate" 0 "^$"
|
||||
|
||||
if [ $BE -ne 0 ]; then
|
||||
if [ $BE -eq 0 ]; then
|
||||
exit # BE
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -105,8 +105,8 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></s
|
|||
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>]]>]]>$"
|
||||
|
||||
new "leafref validate XXX shouldnt really be operation-failed, more work in validate code"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-tag>operation-failed</error-tag>"
|
||||
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>]]>]]>$'
|
||||
|
||||
new "leafref discard-changes"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
|
@ -126,7 +126,7 @@ 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>"
|
||||
|
||||
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-tag>operation-failed</error-tag>"
|
||||
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>]]>]]>$'
|
||||
|
||||
new "leafref discard-changes"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
|
@ -143,7 +143,7 @@ expectfn "$clixon_cli -1f $cfg -y $fyang -l o set sender a" 0 "^$"
|
|||
new "cli sender template"
|
||||
expectfn "$clixon_cli -1f $cfg -y $fyang -l o set sender b template a" 0 "^$"
|
||||
|
||||
if [ $BE -ne 0 ]; then
|
||||
if [ $BE -eq 0 ]; then
|
||||
exit # BE
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ 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>]]>]]>$"
|
||||
fi # NYI
|
||||
|
||||
if [ $BE -ne 0 ]; then
|
||||
if [ $BE -eq 0 ]; then
|
||||
exit # BE
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -141,10 +141,10 @@ new "commit it"
|
|||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
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-tag": "access-denied","error-type": "protocol","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"}}}
'
|
||||
|
||||
new2 "auth get (wrong passwd: access denied)"
|
||||
expecteq "$(curl -u andy:foo -sS -X GET http://localhost/restconf/data)" '{"ietf-restconf:errors" : {"error": {"error-tag": "access-denied","error-type": "protocol","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)"
|
||||
expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/x)" '{"x": 0}
|
||||
|
|
@ -164,21 +164,21 @@ expecteq "$(curl -u wilma:bar -sS -X GET http://localhost/restconf/data/x)" '{"x
|
|||
'
|
||||
|
||||
new2 "guest get nacm"
|
||||
expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/x)" '{"ietf-restconf:errors" : {"error": {"error-tag": "access-denied","error-type": "protocol","error-severity": "error","error-message": "access denied"}}}
'
|
||||
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"}}}
'
|
||||
|
||||
new "admin edit nacm"
|
||||
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"x": 1}' http://localhost/restconf/data/x)" ""
|
||||
|
||||
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-tag": "access-denied","error-type": "protocol","error-severity": "error","error-message": "default deny"}}}
'
|
||||
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"}}}
'
|
||||
|
||||
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-tag": "access-denied","error-type": "protocol","error-severity": "error","error-message": "access denied"}}}
'
|
||||
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"}}}
'
|
||||
|
||||
new "Kill restconf daemon"
|
||||
sudo pkill -u www-data -f "/www-data/clixon_restconf"
|
||||
|
||||
if [ $BE -ne 0 ]; then
|
||||
if [ $BE -eq 0 ]; then
|
||||
exit # BE
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -170,10 +170,10 @@ new "Set x to 0"
|
|||
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"x": 0}' http://localhost/restconf/data/x)" ""
|
||||
|
||||
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-tag": "access-denied","error-type": "protocol","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"}}}
'
|
||||
|
||||
new2 "auth get (wrong passwd: access denied)"
|
||||
expecteq "$(curl -u andy:foo -sS -X GET http://localhost/restconf/data)" '{"ietf-restconf:errors" : {"error": {"error-tag": "access-denied","error-type": "protocol","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)"
|
||||
expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/x)" '{"x": 0}
|
||||
|
|
@ -188,16 +188,16 @@ expecteq "$(curl -u wilma:bar -sS -X GET http://localhost/restconf/data/x)" '{"x
|
|||
'
|
||||
|
||||
new2 "guest get nacm"
|
||||
expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/x)" '{"ietf-restconf:errors" : {"error": {"error-tag": "access-denied","error-type": "protocol","error-severity": "error","error-message": "access denied"}}}
'
|
||||
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"}}}
'
|
||||
|
||||
new "admin edit nacm"
|
||||
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"x": 1}' http://localhost/restconf/data/x)" ""
|
||||
|
||||
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-tag": "access-denied","error-type": "protocol","error-severity": "error","error-message": "default deny"}}}
'
|
||||
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"}}}
'
|
||||
|
||||
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-tag": "access-denied","error-type": "protocol","error-severity": "error","error-message": "access denied"}}}
'
|
||||
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"}}}
'
|
||||
|
||||
new "cli show conf as admin"
|
||||
expectfn "$clixon_cli -1 -U andy -l o -f $cfg -y $fyang show conf" 0 "^x 1;$"
|
||||
|
|
@ -220,7 +220,7 @@ expectfn "$clixon_cli -1 -U guest -l o -f $cfg -y $fyang rpc ipv4" 255 "protocol
|
|||
new "Kill restconf daemon"
|
||||
sudo pkill -u www-data -f "/www-data/clixon_restconf"
|
||||
|
||||
if [ $BE -ne 0 ]; then
|
||||
if [ $BE -eq 0 ]; then
|
||||
exit # BE
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ sudo pkill -u www-data -f "/www-data/clixon_restconf"
|
|||
|
||||
sleep 1
|
||||
new "start restconf daemon (-a is enable basic authentication)"
|
||||
sudo su -c "$clixon_restconf -f $cfg -y $fyang -D 1 -- -a" -s /bin/sh www-data &
|
||||
sudo su -c "$clixon_restconf -f $cfg -y $fyang -- -a" -s /bin/sh www-data &
|
||||
|
||||
sleep $RCWAIT
|
||||
|
||||
|
|
@ -166,20 +166,20 @@ expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/x)" '{"x"
|
|||
|
||||
# Rule 1: deny-kill-session
|
||||
new "deny-kill-session: limited fail (netconf)"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang -U wilma" 0 "<rpc><kill-session><session-id>44</session-id></kill-session></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-tag>access-denied</error-tag><error-type>protocol</error-type><error-severity>error</error-severity><error-message>access denied</error-message></rpc-error></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang -U wilma" 0 "<rpc><kill-session><session-id>44</session-id></kill-session></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-type>protocol</error-type><error-tag>access-denied</error-tag><error-severity>error</error-severity><error-message>access denied</error-message></rpc-error></rpc-reply>]]>]]>$"
|
||||
|
||||
new "deny-kill-session: guest fail (netconf)"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang -U guest" 0 "<rpc><kill-session><session-id>44</session-id></kill-session></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-tag>access-denied</error-tag><error-type>protocol</error-type><error-severity>error</error-severity><error-message>access denied</error-message></rpc-error></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang -U guest" 0 "<rpc><kill-session><session-id>44</session-id></kill-session></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-type>protocol</error-type><error-tag>access-denied</error-tag><error-severity>error</error-severity><error-message>access denied</error-message></rpc-error></rpc-reply>]]>]]>$"
|
||||
|
||||
new "deny-kill-session: admin ok (netconf)"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang -U andy" 0 "<rpc><kill-session><session-id>44</session-id></kill-session></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
# Rule 2: deny-delete-config
|
||||
new "deny-delete-config: limited fail (netconf)"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang -U wilma" 0 "<rpc><delete-config><target><startup/></target></delete-config></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-tag>access-denied</error-tag><error-type>protocol</error-type><error-severity>error</error-severity><error-message>access denied</error-message></rpc-error></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang -U wilma" 0 "<rpc><delete-config><target><startup/></target></delete-config></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-type>protocol</error-type><error-tag>access-denied</error-tag><error-severity>error</error-severity><error-message>access denied</error-message></rpc-error></rpc-reply>]]>]]>$"
|
||||
|
||||
new2 "deny-delete-config: guest fail (restconf)"
|
||||
expecteq "$(curl -u guest:bar -sS -X DELETE http://localhost/restconf/data)" '{"ietf-restconf:errors" : {"error": {"error-tag": "access-denied","error-type": "protocol","error-severity": "error","error-message": "default deny"}}}
'
|
||||
expecteq "$(curl -u guest:bar -sS -X DELETE http://localhost/restconf/data)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
||||
|
||||
# In restconf delete-config is translated to edit-config which is permitted
|
||||
new "deny-delete-config: limited fail (restconf) ok"
|
||||
|
|
@ -207,12 +207,12 @@ new "permit-edit-config: limited ok restconf"
|
|||
expecteq "$(curl -u wilma:bar -sS -X PUT -d '{"x": 2}' http://localhost/restconf/data/x)" ''
|
||||
|
||||
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-tag": "access-denied","error-type": "protocol","error-severity": "error","error-message": "default deny"}}}
'
|
||||
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"}}}
'
|
||||
|
||||
new "Kill restconf daemon"
|
||||
sudo pkill -u www-data -f "/www-data/clixon_restconf"
|
||||
|
||||
if [ $BE -ne 0 ]; then
|
||||
if [ $BE -eq 0 ]; then
|
||||
exit # BE
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ new "netconf discard-changes"
|
|||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
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-tag>invalid-value</error-tag>"
|
||||
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>"
|
||||
|
||||
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>]]>]]>$"
|
||||
|
|
@ -254,7 +254,7 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><ex:empty/></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>]]>]]>$"
|
||||
|
||||
if [ $BE -ne 0 ]; then
|
||||
if [ $BE -eq 0 ]; then
|
||||
exit # BE
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ 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>]]>]]>$"
|
||||
|
||||
new "delete candidate"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><delete-config><target><candidate/></target></delete-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>]]>]]>$"
|
||||
|
||||
# LEAF_LISTS
|
||||
|
||||
|
|
@ -172,7 +172,7 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><can
|
|||
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>]]>]]>$"
|
||||
|
||||
if [ $BE -ne 0 ]; then
|
||||
if [ $BE -eq 0 ]; then
|
||||
exit # BE
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ expecteof "time -f %e $clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><
|
|||
new "Kill restconf daemon"
|
||||
sudo pkill -u www-data -f "/www-data/clixon_restconf"
|
||||
|
||||
if [ $BE -ne 0 ]; then
|
||||
if [ $BE -eq 0 ]; then
|
||||
exit # BE
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -52,14 +52,6 @@ module example{
|
|||
}
|
||||
rpc empty {
|
||||
}
|
||||
rpc input {
|
||||
input {
|
||||
}
|
||||
}
|
||||
rpc output {
|
||||
output {
|
||||
}
|
||||
}
|
||||
rpc client-rpc {
|
||||
description "Example local client-side rpc";
|
||||
input {
|
||||
|
|
@ -104,12 +96,15 @@ new "kill old restconf daemon"
|
|||
sudo pkill -u www-data clixon_restconf
|
||||
|
||||
new "start restconf daemon"
|
||||
sudo su -c "$clixon_restconf -f $cfg -y $fyang -D 1" -s /bin/sh www-data &
|
||||
sudo su -c "$clixon_restconf -f $cfg -y $fyang -D $DBG" -s /bin/sh www-data &
|
||||
|
||||
sleep $RCWAIT
|
||||
|
||||
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)"
|
||||
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'/>
|
||||
|
|
@ -125,12 +120,12 @@ expecteq "$(curl -s -H 'Accept: application/yang-data+xml' -G http://localhost/r
|
|||
'
|
||||
|
||||
new2 "restconf get restconf/operations. RFC8040 3.3.2 (json)"
|
||||
expecteq "$(curl -sG http://localhost/restconf/operations)" '{"operations": {"example:empty": null,"example:input": null,"example:output": null,"example:client-rpc": null,"ietf-routing:fib-route": null,"ietf-routing:route-count": null}}
|
||||
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}}
|
||||
'
|
||||
|
||||
new "restconf get restconf/operations. RFC8040 3.3.2 (xml)"
|
||||
ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/operations)
|
||||
expect='<operations><empty xmlns="urn:example:clixon"/><input xmlns="urn:example:clixon"/><output 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>'
|
||||
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>'
|
||||
match=`echo $ret | grep -EZo "$expect"`
|
||||
if [ -z "$match" ]; then
|
||||
err "$expect" "$ret"
|
||||
|
|
@ -161,6 +156,9 @@ expectfn "curl -s -I http://localhost/restconf/data" 0 "HTTP/1.1 200 OK"
|
|||
new "restconf empty rpc"
|
||||
expecteq "$(curl -s -X POST -d {\"input\":null} http://localhost/restconf/operations/example:empty)" ""
|
||||
|
||||
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"}}}
'
|
||||
|
||||
new2 "restconf get empty config + state json"
|
||||
expecteq "$(curl -sSG http://localhost/restconf/data/state)" '{"state": {"op": "42"}}
|
||||
'
|
||||
|
|
@ -170,7 +168,7 @@ expecteq "$(curl -sSG http://localhost/restconf/data/example:state)" '{"state":
|
|||
'
|
||||
|
||||
new2 "restconf get empty config + state json with wrong module name"
|
||||
expecteq "$(curl -sSG http://localhost/restconf/data/badmodule:state)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","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 yang node found: badmodule:state"}}}
'
|
||||
|
||||
new "restconf get empty config + state xml"
|
||||
ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/data/state)
|
||||
|
|
@ -215,10 +213,10 @@ 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'
|
||||
|
||||
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-tag": "data-exists","error-type": "application","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}}'
|
||||
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"}}}'
|
||||
|
||||
# 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-tag": "data-exists","error-type": "application","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"
|
||||
expectfn "curl -s -G http://localhost/restconf/data" 0 '{"interfaces": {"interface": \[{"name": "eth/0/0","type": "ex:eth","enabled": true}\]},"state": {"op": "42"}}
|
||||
|
|
@ -244,13 +242,13 @@ expecteq "$(curl -s -G http://localhost/restconf/data/state)" '{"state": {"op":
|
|||
'
|
||||
|
||||
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-tag": "data-exists","error-type": "application","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}}
'
|
||||
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"}}}
'
|
||||
|
||||
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)" ""
|
||||
|
||||
new "Add nothing using POST"
|
||||
expectfn 'curl -s -X POST http://localhost/restconf/data/interfaces/interface=eth%2f0%2f0' 0 '"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "malformed-message","error-type": "rpc","error-severity": "error","error-message": " on line 1: syntax error at or before:'
|
||||
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:'
|
||||
|
||||
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}]}}
|
||||
|
|
@ -263,7 +261,7 @@ new "Check deleted eth/0/0"
|
|||
expectfn 'curl -s -G http://localhost/restconf/data' 0 $state
|
||||
|
||||
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-tag": "data-missing","error-type": "application","error-severity": "error","error-message": "Data does not exist; cannot delete resource"}}}
'
|
||||
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"}}}
'
|
||||
|
||||
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)" ""
|
||||
|
|
@ -273,37 +271,38 @@ expecteq "$(curl -s -G http://localhost/restconf/data/interfaces)" '{"interfaces
|
|||
'
|
||||
|
||||
new2 "restconf rpc using POST json"
|
||||
expecteq "$(curl -s -X POST -d '{"input":{"routing-instance-name":"ipv4"}}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"output": {"route": {"address-family": "ipv4","next-hop": {"next-hop-list": "2.3.4.5"}}}}
|
||||
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"}}}
|
||||
'
|
||||
|
||||
# Cant get this to work due to quoting
|
||||
#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": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": " on line 1: syntax error at or before: i"}}}}
'
|
||||
#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"}}}
'
|
||||
|
||||
new2 "restconf rpc using POST json w/o mandatory element"
|
||||
expecteq "$(curl -s -X POST -d '{"input":{"wrongelement":"ipv4"}}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "Missing mandatory variable: routing-instance-name"}}}}
'
|
||||
new2 "restconf rpc non-existing rpc w/o namespace"
|
||||
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/kalle)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "yang node not found"}}}}
'
|
||||
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 rpc non-existing rpc without namespace"
|
||||
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/kalle)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "yang node not found"}}}
'
|
||||
|
||||
new2 "restconf rpc non-existing rpc"
|
||||
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/example:kalle)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "yang node not found"}}}}
'
|
||||
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/example:kalle)" '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "yang node not found"}}}
'
|
||||
|
||||
new2 "restconf rpc missing name"
|
||||
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","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"
|
||||
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "Missing mandatory variable: routing-instance-name"}}}}
'
|
||||
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"}}}
'
|
||||
|
||||
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)
|
||||
expect="<output><route><address-family>ipv4</address-family><next-hop><next-hop-list>2.3.4.5</next-hop-list></next-hop></route></output>"
|
||||
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>"
|
||||
match=`echo $ret | grep -EZo "$expect"`
|
||||
if [ -z "$match" ]; then
|
||||
err "$expect" "$ret"
|
||||
fi
|
||||
|
||||
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": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "yang module not found"}}}}
'
|
||||
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"}}}
'
|
||||
|
||||
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)
|
||||
|
|
@ -321,7 +320,7 @@ fi
|
|||
new "Kill restconf daemon"
|
||||
sudo pkill -u www-data -f "/www-data/clixon_restconf"
|
||||
|
||||
if [ $BE -ne 0 ]; then
|
||||
if [ $BE -eq 0 ]; then
|
||||
exit # BE
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -84,16 +84,16 @@ new "restconf GET if-type"
|
|||
expectfn "curl -s -X GET http://localhost/restconf/data/cont1/interface=local0/type" 0 '{"type": "regular"}'
|
||||
|
||||
new "restconf POST interface without mandatory type"
|
||||
expectfn 'curl -s -X POST -d {"interface":{"name":"TEST"}} http://localhost/restconf/data/cont1' 0 '"error-message": "Missing mandatory variable: 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"}}}
'
|
||||
|
||||
new "restconf POST interface"
|
||||
expectfn 'curl -s -X POST -d {"interface":{"name":"TEST","type":"eth0"}} http://localhost/restconf/data/cont1' 0 ""
|
||||
|
||||
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-tag": "data-exists","error-type": "application","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/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"
|
||||
expecteq "$(curl -s -X POST -d '{"cont1":{"interface":{"name":"TEST","type":"eth0"}}}' http://localhost/restconf/data)" '{"ietf-restconf:errors" : {"error": {"error-tag": "data-exists","error-type": "application","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}}
'
|
||||
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"}}}
'
|
||||
|
||||
new "restconf DELETE"
|
||||
expectfn 'curl -s -X DELETE http://localhost/restconf/data/cont1' 0 ""
|
||||
|
|
@ -138,12 +138,12 @@ new "restconf PUT add interface"
|
|||
expectfn 'curl -s -X PUT -d {"interface":{"name":"TEST","type":"eth0"}} http://localhost/restconf/data/cont1/interface=TEST' 0 ""
|
||||
|
||||
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": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","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/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"
|
||||
sudo pkill -u www-data -f "/www-data/clixon_restconf"
|
||||
|
||||
if [ $BE -ne 0 ]; then
|
||||
if [ $BE -eq 0 ]; then
|
||||
exit # BE
|
||||
fi
|
||||
|
||||
|
|
|
|||
125
test/test_rpc.sh
Executable file
125
test/test_rpc.sh
Executable file
|
|
@ -0,0 +1,125 @@
|
|||
#!/bin/bash
|
||||
# RPC tests
|
||||
# Validate parameters in restconf and netconf, check namespaces, etc
|
||||
# See rfc8040 3.6
|
||||
APPNAME=example
|
||||
|
||||
# include err() and new() functions and creates $dir
|
||||
. ./lib.sh
|
||||
cfg=$dir/conf.xml
|
||||
|
||||
# Use yang in example
|
||||
cat <<EOF > $cfg
|
||||
<config xmlns="urn:example:clixon">
|
||||
<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>$APPNAME</CLICON_YANG_MODULE_MAIN>
|
||||
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_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_MODE>$APPNAME</CLICON_CLI_MODE>
|
||||
<CLICON_RESTCONF_PRETTY>false</CLICON_RESTCONF_PRETTY>
|
||||
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
|
||||
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
|
||||
<CLICON_CLI_GENMODEL_COMPLETION>1</CLICON_CLI_GENMODEL_COMPLETION>
|
||||
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
|
||||
<CLICON_XMLDB_PLUGIN>/usr/local/lib/xmldb/text.so</CLICON_XMLDB_PLUGIN>
|
||||
</config>
|
||||
EOF
|
||||
|
||||
new "test params: -f $cfg"
|
||||
if [ $BE -ne 0 ]; then
|
||||
new "kill old backend"
|
||||
sudo clixon_backend -zf $cfg
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
new "start backend -s init -f $cfg"
|
||||
sudo $clixon_backend -s init -f $cfg -D $DBG
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
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" -s /bin/sh www-data &
|
||||
|
||||
sleep $RCWAIT
|
||||
|
||||
new "rpc tests"
|
||||
|
||||
# 1.First some positive tests vary media types
|
||||
#
|
||||
new2 "restconf example rpc json/json default - no headers"
|
||||
expecteq "$(curl -s -X POST -d '{"input":{"x":"0"}}' http://localhost/restconf/operations/example:example)" '{"output": {"x": "0","y": "42"}}
|
||||
'
|
||||
|
||||
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"}}
|
||||
'
|
||||
|
||||
new2 "restconf example rpc json/json"
|
||||
# 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"}}
|
||||
'
|
||||
|
||||
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"}}
|
||||
'
|
||||
|
||||
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 '{"input":{"x":"0"}}' http://localhost/restconf/operations/example:example)" '<output><x>0</x><y>42</y></output>
|
||||
'
|
||||
|
||||
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><x>0</x><y>42</y></output>
|
||||
'
|
||||
|
||||
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>]]>]]>$'
|
||||
|
||||
# 2. Then error cases
|
||||
#
|
||||
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"}}}
'
|
||||
|
||||
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"}}}
'
|
||||
|
||||
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": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "yang node not found"}}}
'
|
||||
|
||||
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"}}}
'
|
||||
|
||||
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>$'
|
||||
|
||||
# edit-config?
|
||||
|
||||
new "Kill restconf daemon"
|
||||
sudo pkill -u www-data -f "/www-data/clixon_restconf"
|
||||
|
||||
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
|
||||
|
||||
rm -rf $dir
|
||||
|
|
@ -150,10 +150,10 @@ 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
|
||||
|
||||
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-tag>invalid-value</error-tag><error-type>application</error-type><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><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"
|
||||
expectwait "$clixon_netconf -qf $cfg -y $fyang" '<rpc><create-subscription><stream>EXAMPLE</stream><startTime>kallekaka</startTime></create-subscription></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-tag>bad-element</error-tag><error-type>application</error-type><error-info><bad-element>startTime</bad-element></error-info><error-severity>error</error-severity><error-message>Expected timestamp</error-message></rpc-error></rpc-reply>]]>]]>$' 0
|
||||
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>Expected timestamp</error-message></rpc-error></rpc-reply>]]>]]>$' 0
|
||||
|
||||
#new "netconf EXAMPLE subscription with replay"
|
||||
#NOW=$(date +"%Y-%m-%dT%H:%M:%S")
|
||||
|
|
@ -176,7 +176,7 @@ sleep 2
|
|||
# Restconf stream subscription RFC8040 Sec 6.3
|
||||
# Start Subscription w error
|
||||
new "restconf monitor event nonexist stream"
|
||||
expectwait 'curl -s -X GET -H "Accept: text/event-stream" -H "Cache-Control: no-cache" -H "Connection: keep-alive" http://localhost/streams/NOTEXIST' 0 '<errors xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf"><error><error-tag>invalid-value</error-tag><error-type>application</error-type><error-severity>error</error-severity><error-message>No such stream</error-message></error></errors>' 2
|
||||
expectwait 'curl -s -X GET -H "Accept: text/event-stream" -H "Cache-Control: no-cache" -H "Connection: keep-alive" http://localhost/streams/NOTEXIST' 0 '<errors xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf"><error><error-type>application</error-type><error-tag>invalid-value</error-tag><error-severity>error</error-severity><error-message>No such stream</error-message></error></errors>' 2
|
||||
|
||||
# 2a) start subscription 8s - expect 1-2 notifications
|
||||
new "2a) start subscriptions 8s - expect 1-2 notifications"
|
||||
|
|
@ -278,7 +278,7 @@ sleep 5
|
|||
new "Kill restconf daemon"
|
||||
sudo pkill -u www-data -f "/www-data/clixon_restconf"
|
||||
|
||||
if [ $BE -ne 0 ]; then
|
||||
if [ $BE -eq 0 ]; then
|
||||
exit # BE
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ 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>]]>]]>"
|
||||
|
||||
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-tag>operation-failed</error-tag><error-type>application</error-type><error-severity>error</error-severity><error-message>validation of talle failed regexp match 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>]]>]]>$'
|
||||
|
||||
new "netconf discard-changes"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
|
@ -244,7 +244,7 @@ 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>]]>]]>"
|
||||
|
||||
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-tag>operation-failed</error-tag><error-type>application</error-type><error-severity>error</error-severity><error-message>validation of ulle failed"
|
||||
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>]]>]]>$"
|
||||
|
||||
new "netconf discard-changes"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
|
@ -303,7 +303,7 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><can
|
|||
new "cli bits validate"
|
||||
expectfn "$clixon_cli -1f $cfg -l o -y $fyang validate" 0 "^$"
|
||||
|
||||
if [ $BE -ne 0 ]; then
|
||||
if [ $BE -eq 0 ]; then
|
||||
exit # BE
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ expectfn "$clixon_cli -1f $cfg -l o -y $fyang set c ulle 33" 0 "^$"
|
|||
new "cli set transitive union error"
|
||||
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set c ulle kalle" 255 ""
|
||||
|
||||
if [ $BE -ne 0 ]; then
|
||||
if [ $BE -eq 0 ]; then
|
||||
exit # BE
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ new "when get config"
|
|||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><whenex><type>direct</type><name>r2</name><static-routes/></whenex><whenex><type>static</type><name>r1</name><static-routes/></whenex></data></rpc-reply>]]>]]>$"
|
||||
|
||||
new "when: validate fail"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-tag>operation-failed</error-tag><error-type>application</error-type><error-severity>error</error-severity><error-message>xpath static-routes validation failed</error-message></rpc-error></rpc-reply>]]>]]>$"
|
||||
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>]]>]]>$"
|
||||
|
||||
new "when: discard-changes"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
|
@ -133,15 +133,15 @@ new "must: add atm interface"
|
|||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><interface><ifType>atm</ifType><ifMTU>32</ifMTU></interface></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "must: atm validate fail"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-tag>operation-failed</error-tag><error-type>application</error-type><error-severity>error</error-severity><error-message>An ATM MTU must be 64 .. 17966</error-message></rpc-error></rpc-reply>]]>]]>$"
|
||||
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"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><interface><ifType>ethernet</ifType><ifMTU>989</ifMTU></interface></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "must: eth validate fail"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-tag>operation-failed</error-tag><error-type>application</error-type><error-severity>error</error-severity><error-message>An Ethernet MTU must be 1500</error-message></rpc-error></rpc-reply>]]>]]>"
|
||||
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>]]>]]>"
|
||||
|
||||
if [ $BE -ne 0 ]; then
|
||||
if [ $BE -eq 0 ]; then
|
||||
exit # BE
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ expectfn "$clixon_cli -1f $cfg -y $fyang set x f e foo" 0 ""
|
|||
new "cli show leaf-list"
|
||||
expectfn "$clixon_cli -1f $cfg -y $fyang show xpath /x/f/e" 0 "<e>foo</e>"
|
||||
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-tag>invalid-value"
|
||||
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"
|
||||
|
||||
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>]]>]]>$"
|
||||
|
|
@ -233,7 +233,7 @@ new "netconf validate anyxml"
|
|||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf delete candidate"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><delete-config><target><candidate/></target></delete-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><default-operation>none</default-operation><config operation="delete"/></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
# Check 3-keys
|
||||
new "netconf add one 3-key entry"
|
||||
|
|
@ -262,7 +262,7 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><cand
|
|||
|
||||
# clear db for next test
|
||||
new "netconf delete candidate"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><delete-config><target><candidate/></target></delete-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><default-operation>none</default-operation><config operation="delete"/></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf commit empty candidate"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
|
@ -279,7 +279,7 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candid
|
|||
new "netconf submodule discard-changes"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
if [ $BE -ne 0 ]; then
|
||||
if [ $BE -eq 0 ]; then
|
||||
exit # BE
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -88,12 +88,12 @@ 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>]]>]]>$'
|
||||
|
||||
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-tag>operation-failed</error-tag><error-type>application</error-type><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>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>]]>]]>$'
|
||||
|
||||
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-tag>operation-failed</error-tag><error-type>application</error-type><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>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>]]>]]>$'
|
||||
|
||||
if [ $BE -ne 0 ]; then
|
||||
if [ $BE -eq 0 ]; then
|
||||
exit # BE
|
||||
fi
|
||||
|
||||
|
|
@ -140,10 +140,10 @@ 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>]]>]]>$'
|
||||
|
||||
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-tag>operation-failed</error-tag><error-type>protocol</error-type><error-severity>error</error-severity><error-message>XML'
|
||||
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>]]>]]>$'
|
||||
|
||||
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-tag>operation-failed</error-tag><error-type>protocol</error-type><error-severity>error</error-severity><error-message>XML'
|
||||
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>]]>]]>$'
|
||||
|
||||
new "Kill backend"
|
||||
# Check if premature kill
|
||||
|
|
@ -184,10 +184,10 @@ 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>]]>]]>$'
|
||||
|
||||
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-tag>operation-failed</error-tag><error-type>protocol</error-type><error-severity>error</error-severity><error-message>XML'
|
||||
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>'
|
||||
|
||||
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-tag>operation-failed</error-tag><error-type>protocol</error-type><error-severity>error</error-severity><error-message>XML'
|
||||
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>'
|
||||
|
||||
new "Kill backend"
|
||||
# Check if premature kill
|
||||
|
|
@ -229,10 +229,10 @@ 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>]]>]]>$'
|
||||
|
||||
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-tag>operation-failed</error-tag><error-type>protocol</error-type><error-severity>error</error-severity><error-message>XML'
|
||||
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>'
|
||||
|
||||
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-tag>operation-failed</error-tag><error-type>protocol</error-type><error-severity>error</error-severity><error-message>XML'
|
||||
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>'
|
||||
|
||||
new "Kill backend"
|
||||
# Check if premature kill
|
||||
|
|
@ -273,7 +273,7 @@ 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>]]>]]>$'
|
||||
|
||||
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-tag>operation-failed</error-tag><error-type>protocol</error-type><error-severity>error</error-severity><error-message>XML'
|
||||
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>'
|
||||
|
||||
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>]]>]]>$'
|
||||
|
|
@ -318,7 +318,7 @@ 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>]]>]]>$'
|
||||
|
||||
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-tag>operation-failed</error-tag><error-type>protocol</error-type><error-severity>error</error-severity><error-message>XML'
|
||||
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>'
|
||||
|
||||
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>]]>]]>$'
|
||||
|
|
@ -365,7 +365,7 @@ 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>]]>]]>$'
|
||||
|
||||
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-tag>operation-failed</error-tag><error-type>protocol</error-type><error-severity>error</error-severity><error-message>XML'
|
||||
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>'
|
||||
|
||||
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>]]>]]>$'
|
||||
|
|
@ -411,10 +411,10 @@ 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>]]>]]>$'
|
||||
|
||||
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-tag>operation-failed</error-tag><error-type>protocol</error-type><error-severity>error</error-severity><error-message>XML'
|
||||
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>'
|
||||
|
||||
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-tag>operation-failed</error-tag><error-type>protocol</error-type><error-severity>error</error-severity><error-message>XML'
|
||||
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>'
|
||||
|
||||
new "Kill backend"
|
||||
# Check if premature kill
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><cand
|
|||
|
||||
# rpc
|
||||
|
||||
if [ $BE -ne 0 ]; then
|
||||
if [ $BE -eq 0 ]; then
|
||||
exit # BE
|
||||
fi
|
||||
new "Kill backend"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue