Many validation functions have changed error parameter from cbuf to xml tree.

This commit is contained in:
Olof hagsand 2019-06-10 12:49:40 +02:00
parent dfa3970ab2
commit fc78824110
22 changed files with 527 additions and 384 deletions

View file

@ -69,6 +69,9 @@
### API changes on existing features (you may need to change your code) ### API changes on existing features (you may need to change your code)
* Many validation functions have changed error parameter from cbuf to xml tree.
* XML trees are more flexible for utility tools
* If you use these(mostly internal), you need to change the error function: `generic_validate, from_validate_common, xml_yang_validate_all_top, xml_yang_validate_all, xml_yang_validate_add, xml_yang_validate_rpc, xml_yang_validate_list_key_only`
* Replaced `CLIXON_DATADIR` with two configurable options defining where Clixon installs Yang files. * Replaced `CLIXON_DATADIR` with two configurable options defining where Clixon installs Yang files.
* use `--with-yang-installdir=DIR` to install Clixon yang files in DIR * use `--with-yang-installdir=DIR` to install Clixon yang files in DIR
* use `--with-std-yang-installdir=DIR` to install standard yang files that Clixon may use in DIR * use `--with-std-yang-installdir=DIR` to install standard yang files that Clixon may use in DIR

View file

@ -411,6 +411,7 @@ from_client_edit_config(clicon_handle h,
cbuf *cbx = NULL; /* Assist cbuf */ cbuf *cbx = NULL; /* Assist cbuf */
int ret; int ret;
char *username; char *username;
cxobj *xret = NULL;
username = clicon_username_get(h); username = clicon_username_get(h);
if ((yspec = clicon_dbspec_yang(h)) == NULL){ if ((yspec = clicon_dbspec_yang(h)) == NULL){
@ -470,10 +471,13 @@ from_client_edit_config(clicon_handle h,
goto ok; goto ok;
} }
/* xmldb_put (difflist handling) requires list keys */ /* xmldb_put (difflist handling) requires list keys */
if ((ret = xml_yang_validate_list_key_only(h, xc, cbret)) < 0) if ((ret = xml_yang_validate_list_key_only(h, xc, &xret)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0){
if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
goto done;
goto ok; goto ok;
}
/* Cant do this earlier since we dont have a yang spec to /* Cant do this earlier since we dont have a yang spec to
* the upper part of the tree, until we get the "config" tree. * the upper part of the tree, until we get the "config" tree.
*/ */
@ -493,6 +497,8 @@ from_client_edit_config(clicon_handle h,
ok: ok:
retval = 0; retval = 0;
done: done:
if (xret)
xml_free(xret);
if (cbx) if (cbx)
cbuf_free(cbx); cbuf_free(cbx);
clicon_debug(1, "%s done cbret:%s", __FUNCTION__, cbuf_get(cbret)); clicon_debug(1, "%s done cbret:%s", __FUNCTION__, cbuf_get(cbret));
@ -1121,6 +1127,7 @@ from_client_msg(clicon_handle h,
yang_stmt *ye; yang_stmt *ye;
yang_stmt *ymod; yang_stmt *ymod;
cxobj *xnacm = NULL; cxobj *xnacm = NULL;
cxobj *xret = NULL;
clicon_debug(1, "%s", __FUNCTION__); clicon_debug(1, "%s", __FUNCTION__);
yspec = clicon_dbspec_yang(h); yspec = clicon_dbspec_yang(h);
@ -1147,10 +1154,13 @@ from_client_msg(clicon_handle h,
* maybe not necessary since it should be */ * maybe not necessary since it should be */
if (xml_spec_populate_rpc(h, x, yspec) < 0) if (xml_spec_populate_rpc(h, x, yspec) < 0)
goto done; goto done;
if ((ret = xml_yang_validate_rpc(h, x, cbret)) < 0) if ((ret = xml_yang_validate_rpc(h, x, &xret)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0){
if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
goto done;
goto reply; goto reply;
}
xe = NULL; xe = NULL;
username = xml_find_value(x, "username"); username = xml_find_value(x, "username");
/* May be used by callbacks, etc */ /* May be used by callbacks, etc */
@ -1222,6 +1232,8 @@ from_client_msg(clicon_handle h,
retval = 0; retval = 0;
done: done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval); clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
if (xret)
xml_free(xret);
if (xt) if (xt)
xml_free(xt); xml_free(xt);
if (cbret) if (cbret)

View file

@ -81,7 +81,7 @@
* are if code comes via XML/NETCONF. * are if code comes via XML/NETCONF.
* @param[in] yspec Yang spec * @param[in] yspec Yang spec
* @param[in] td Transaction data * @param[in] td Transaction data
* @param[out] cbret Cligen buffer containing netconf error (if retval == 0) * @param[out] xret Error XML tree. Free with xml_free after use
* @retval -1 Error * @retval -1 Error
* @retval 0 Validation failed (with cbret set) * @retval 0 Validation failed (with cbret set)
* @retval 1 Validation OK * @retval 1 Validation OK
@ -90,7 +90,7 @@ static int
generic_validate(clicon_handle h, generic_validate(clicon_handle h,
yang_stmt *yspec, yang_stmt *yspec,
transaction_data_t *td, transaction_data_t *td,
cbuf *cbret) cxobj **xret)
{ {
int retval = -1; int retval = -1;
cxobj *x1; cxobj *x1;
@ -100,7 +100,7 @@ generic_validate(clicon_handle h,
int ret; int ret;
/* All entries */ /* All entries */
if ((ret = xml_yang_validate_all_top(h, td->td_target, cbret)) < 0) if ((ret = xml_yang_validate_all_top(h, td->td_target, xret)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0)
goto fail; goto fail;
@ -109,7 +109,7 @@ generic_validate(clicon_handle h,
x1 = td->td_scvec[i]; /* source changed */ x1 = td->td_scvec[i]; /* source changed */
x2 = td->td_tcvec[i]; /* target changed */ x2 = td->td_tcvec[i]; /* target changed */
/* Should this be recursive? */ /* Should this be recursive? */
if ((ret = xml_yang_validate_add(h, x2, cbret)) < 0) if ((ret = xml_yang_validate_add(h, x2, xret)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0)
goto fail; goto fail;
@ -119,7 +119,7 @@ generic_validate(clicon_handle h,
x1 = td->td_dvec[i]; x1 = td->td_dvec[i];
ys = xml_spec(x1); ys = xml_spec(x1);
if (ys && yang_mandatory(ys) && yang_config(ys)==0){ if (ys && yang_mandatory(ys) && yang_config(ys)==0){
if (netconf_missing_element(cbret, "protocol", xml_name(x1), "Missing mandatory variable") < 0) if (netconf_missing_element_xml(xret, "protocol", xml_name(x1), "Missing mandatory variable") < 0)
goto done; goto done;
goto fail; goto fail;
} }
@ -127,7 +127,7 @@ generic_validate(clicon_handle h,
/* added entries */ /* added entries */
for (i=0; i<td->td_alen; i++){ for (i=0; i<td->td_alen; i++){
x2 = td->td_avec[i]; x2 = td->td_avec[i];
if ((ret = xml_yang_validate_add(h, x2, cbret)) < 0) if ((ret = xml_yang_validate_add(h, x2, xret)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0)
goto fail; goto fail;
@ -175,6 +175,7 @@ startup_common(clicon_handle h,
modstate_diff_t *msd = NULL; modstate_diff_t *msd = NULL;
cxobj *xt = NULL; cxobj *xt = NULL;
cxobj *x; cxobj *x;
cxobj *xret = NULL;
/* If CLICON_XMLDB_MODSTATE is enabled, then get the db XML with /* If CLICON_XMLDB_MODSTATE is enabled, then get the db XML with
* potentially non-matching module-state in msd * potentially non-matching module-state in msd
@ -225,11 +226,13 @@ startup_common(clicon_handle h,
/* 5. Make generic validation on all new or changed data. /* 5. Make generic validation on all new or changed data.
Note this is only call that uses 3-values */ Note this is only call that uses 3-values */
clicon_debug(1, "Validating startup %s", db); clicon_debug(1, "Validating startup %s", db);
if ((ret = generic_validate(h, yspec, td, cbret)) < 0) if ((ret = generic_validate(h, yspec, td, &xret)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0){
if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
goto done;
goto fail; /* STARTUP_INVALID */ goto fail; /* STARTUP_INVALID */
}
/* 6. Call plugin transaction validate callbacks */ /* 6. Call plugin transaction validate callbacks */
if (plugin_transaction_validate(h, td) < 0) if (plugin_transaction_validate(h, td) < 0)
goto done; goto done;
@ -240,6 +243,8 @@ startup_common(clicon_handle h,
ok: ok:
retval = 1; retval = 1;
done: done:
if (xret)
xml_free(xret);
if (xt) if (xt)
xml_free(xt); xml_free(xt);
if (msd) if (msd)
@ -374,6 +379,7 @@ startup_commit(clicon_handle h,
* and call application callback validations. * and call application callback validations.
* @param[in] h Clicon handle * @param[in] h Clicon handle
* @param[in] candidate The candidate database. The wanted backend state * @param[in] candidate The candidate database. The wanted backend state
* @param[out] xret Error XML tree. Free with xml_free after use
* @retval -1 Error - or validation failed (but cbret not set) * @retval -1 Error - or validation failed (but cbret not set)
* @retval 0 Validation failed (with cbret set) * @retval 0 Validation failed (with cbret set)
* @retval 1 Validation OK * @retval 1 Validation OK
@ -385,7 +391,7 @@ static int
from_validate_common(clicon_handle h, from_validate_common(clicon_handle h,
char *candidate, char *candidate,
transaction_data_t *td, transaction_data_t *td,
cbuf *cbret) cxobj **xret)
{ {
int retval = -1; int retval = -1;
yang_stmt *yspec; yang_stmt *yspec;
@ -409,7 +415,7 @@ from_validate_common(clicon_handle h,
* But xml_diff requires some basic validation, at least check that yang-specs * But xml_diff requires some basic validation, at least check that yang-specs
* have been assigned * have been assigned
*/ */
if ((ret = xml_yang_validate_all_top(h, td->td_target, cbret)) < 0) if ((ret = xml_yang_validate_all_top(h, td->td_target, xret)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0)
goto fail; goto fail;
@ -462,7 +468,7 @@ from_validate_common(clicon_handle h,
/* 5. Make generic validation on all new or changed data. /* 5. Make generic validation on all new or changed data.
Note this is only call that uses 3-values */ Note this is only call that uses 3-values */
if ((ret = generic_validate(h, yspec, td, cbret)) < 0) if ((ret = generic_validate(h, yspec, td, xret)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0)
goto fail; goto fail;
@ -503,6 +509,7 @@ candidate_commit(clicon_handle h,
int retval = -1; int retval = -1;
transaction_data_t *td = NULL; transaction_data_t *td = NULL;
int ret; int ret;
cxobj *xret = NULL;
/* 1. Start transaction */ /* 1. Start transaction */
if ((td = transaction_new()) == NULL) if ((td = transaction_new()) == NULL)
@ -511,10 +518,13 @@ candidate_commit(clicon_handle h,
/* Common steps (with validate). Load candidate and running and compute diffs /* Common steps (with validate). Load candidate and running and compute diffs
* Note this is only call that uses 3-values * Note this is only call that uses 3-values
*/ */
if ((ret = from_validate_common(h, candidate, td, cbret)) < 0) if ((ret = from_validate_common(h, candidate, td, &xret)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0){
if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
goto done;
goto fail; goto fail;
}
/* 7. Call plugin transaction commit callbacks */ /* 7. Call plugin transaction commit callbacks */
if (plugin_transaction_commit(h, td) < 0) if (plugin_transaction_commit(h, td) < 0)
@ -563,7 +573,9 @@ candidate_commit(clicon_handle h,
xmldb_get0_free(h, &td->td_src); xmldb_get0_free(h, &td->td_src);
transaction_free(td); transaction_free(td);
} }
return retval; if (xret)
xml_free(xret);
return retval;
fail: fail:
retval = 0; retval = 0;
goto done; goto done;
@ -725,6 +737,7 @@ from_client_validate(clicon_handle h,
transaction_data_t *td = NULL; transaction_data_t *td = NULL;
int ret; int ret;
char *db; char *db;
cxobj *xret = NULL;
if ((db = netconf_db_find(xe, "source")) == NULL){ if ((db = netconf_db_find(xe, "source")) == NULL){
if (netconf_missing_element(cbret, "protocol", "source", NULL) < 0) if (netconf_missing_element(cbret, "protocol", "source", NULL) < 0)
@ -737,9 +750,15 @@ from_client_validate(clicon_handle h,
if ((td = transaction_new()) == NULL) if ((td = transaction_new()) == NULL)
goto done; goto done;
/* Common steps (with commit) */ /* Common steps (with commit) */
if ((ret = from_validate_common(h, db, td, cbret)) < 1){ if ((ret = from_validate_common(h, db, td, &xret)) < 1){
/* A little complex due to several sources of validation fails or errors.
* (1) xerr is set -> translate to cbret; (2) cbret set use that; otherwise
* use clicon_err. */
if (xret && clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
goto done;
plugin_transaction_abort(h, td); plugin_transaction_abort(h, td);
if (netconf_operation_failed(cbret, "application", clicon_err_reason)< 0) if (!cbuf_len(cbret) &&
netconf_operation_failed(cbret, "application", clicon_err_reason)< 0)
goto done; goto done;
goto ok; goto ok;
} }
@ -773,6 +792,8 @@ from_client_validate(clicon_handle h,
xmldb_get0_free(h, &td->td_src); xmldb_get0_free(h, &td->td_src);
transaction_free(td); transaction_free(td);
} }
if (xret)
xml_free(xret);
return retval; return retval;
} /* from_client_validate */ } /* from_client_validate */

View file

@ -84,7 +84,7 @@ static int ignore_packet_errors = 1;
*/ */
static int static int
netconf_input_packet(clicon_handle h, netconf_input_packet(clicon_handle h,
cbuf *cb) cbuf *cb)
{ {
int retval = -1; int retval = -1;
char *str; char *str;
@ -125,9 +125,10 @@ netconf_input_packet(clicon_handle h,
isrpc++; isrpc++;
if (xml_spec_populate_rpc(h, xrpc, yspec) < 0) if (xml_spec_populate_rpc(h, xrpc, yspec) < 0)
goto done; goto done;
if ((ret = xml_yang_validate_rpc(h, xrpc, cbret)) < 0) if ((ret = xml_yang_validate_rpc(h, xrpc, &xret)) < 0)
goto done; goto done;
if (ret == 0){ if (ret == 0){
clicon_xml2cbuf(cbret, xret, 0, 0);
netconf_output_encap(1, cbret, "rpc-error"); netconf_output_encap(1, cbret, "rpc-error");
goto ok; goto ok;
} }
@ -155,7 +156,7 @@ netconf_input_packet(clicon_handle h,
netconf_output_encap(1, cbret, "rpc-error"); netconf_output_encap(1, cbret, "rpc-error");
goto done; goto done;
} }
if ((xc = xml_child_i(xret,0))!=NULL){ if ((xc = xml_child_i(xret, 0))!=NULL){
xa=NULL; xa=NULL;
/* Copy message-id attribute from incoming to reply. /* Copy message-id attribute from incoming to reply.
* RFC 6241: * RFC 6241:

View file

@ -547,6 +547,7 @@ netconf_application_rpc(clicon_handle h,
yang_stmt *yinput; yang_stmt *yinput;
yang_stmt *youtput; yang_stmt *youtput;
cxobj *xoutput; cxobj *xoutput;
cxobj *xerr = NULL;
cbuf *cb = NULL; cbuf *cb = NULL;
cbuf *cbret = NULL; cbuf *cbret = NULL;
int ret; int ret;
@ -587,15 +588,13 @@ netconf_application_rpc(clicon_handle h,
xml_spec_set(xn, yinput); /* needed for xml_spec_populate */ xml_spec_set(xn, yinput); /* needed for xml_spec_populate */
if (xml_apply(xn, CX_ELMNT, xml_spec_populate, yspec) < 0) if (xml_apply(xn, CX_ELMNT, xml_spec_populate, yspec) < 0)
goto done; goto done;
if ((ret = xml_yang_validate_all_top(h, xn, cbret)) < 0) if ((ret = xml_yang_validate_all_top(h, xn, &xerr)) < 0)
goto done; goto done;
if (ret == 0){ if (ret > 0 && (ret = xml_yang_validate_add(h, xn, &xerr)) < 0)
netconf_output_encap(1, cbret, "rpc-error");
goto ok;
}
if ((ret = xml_yang_validate_add(h, xn, cbret)) < 0)
goto done; goto done;
if (ret == 0){ if (ret == 0){
if (clicon_xml2cbuf(cbret, xerr, 0, 0) < 0)
goto done;
netconf_output_encap(1, cbret, "rpc-error"); netconf_output_encap(1, cbret, "rpc-error");
goto ok; goto ok;
} }
@ -622,15 +621,13 @@ netconf_application_rpc(clicon_handle h,
if (xml_apply(xoutput, CX_ELMNT, xml_spec_populate, yspec) < 0) if (xml_apply(xoutput, CX_ELMNT, xml_spec_populate, yspec) < 0)
goto done; goto done;
if ((ret = xml_yang_validate_all_top(h, xoutput, cbret)) < 0) if ((ret = xml_yang_validate_all_top(h, xoutput, &xerr)) < 0)
goto done; goto done;
if (ret == 0){ if (ret > 0 && (ret = xml_yang_validate_add(h, xoutput, &xerr)) < 0)
clicon_log(LOG_WARNING, "Errors in output netconf %s", cbuf_get(cbret));
goto ok;
}
if ((ret = xml_yang_validate_add(h, xoutput, cbret)) < 0)
goto done; goto done;
if (ret == 0){ if (ret == 0){
if (clicon_xml2cbuf(cbret, xerr, 0, 0) < 0)
goto done;
clicon_log(LOG_WARNING, "Errors in output netconf %s", cbuf_get(cbret)); clicon_log(LOG_WARNING, "Errors in output netconf %s", cbuf_get(cbret));
goto ok; goto ok;
} }
@ -641,6 +638,8 @@ netconf_application_rpc(clicon_handle h,
ok: ok:
retval = 0; retval = 0;
done: done:
if (xerr)
xml_free(xerr);
if (cb) if (cb)
cbuf_free(cb); cbuf_free(cb);
if (cbret) if (cbret)

View file

@ -1476,14 +1476,9 @@ api_operations_post_output(clicon_handle h,
cxobj *xa; /* xml attribute (xmlns) */ cxobj *xa; /* xml attribute (xmlns) */
cxobj *x; cxobj *x;
cxobj *xok; cxobj *xok;
cbuf *cbret = NULL;
int isempty; int isempty;
// clicon_debug(1, "%s", __FUNCTION__); // clicon_debug(1, "%s", __FUNCTION__);
if ((cbret = cbuf_new()) == NULL){
clicon_err(OE_UNIX, 0, "cbuf_new");
goto done;
}
/* Validate that exactly only <rpc-reply> tag */ /* Validate that exactly only <rpc-reply> tag */
if ((xoutput = xml_child_i_type(xret, 0, CX_ELMNT)) == NULL || if ((xoutput = xml_child_i_type(xret, 0, CX_ELMNT)) == NULL ||
strcmp(xml_name(xoutput),"rpc-reply") != 0 || strcmp(xml_name(xoutput),"rpc-reply") != 0 ||
@ -1521,14 +1516,12 @@ api_operations_post_output(clicon_handle h,
#if 0 #if 0
if (xml_apply(xoutput, CX_ELMNT, xml_spec_populate, yspec) < 0) if (xml_apply(xoutput, CX_ELMNT, xml_spec_populate, yspec) < 0)
goto done; goto done;
if ((ret = xml_yang_validate_all(xoutput, cbret)) < 0) if ((ret = xml_yang_validate_all(xoutput, &xerr)) < 0)
goto done; goto done;
if (ret == 1 && if (ret == 1 &&
(ret = xml_yang_validate_add(h, xoutput, cbret)) < 0) (ret = xml_yang_validate_add(h, xoutput, &xerr)) < 0)
goto done; goto done;
if (ret == 0){ /* validation failed */ 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 ((xe = xpath_first(xerr, "rpc-reply/rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto done;
@ -1573,8 +1566,6 @@ api_operations_post_output(clicon_handle h,
retval = 1; retval = 1;
done: done:
clicon_debug(1, "%s retval: %d", __FUNCTION__, retval); clicon_debug(1, "%s retval: %d", __FUNCTION__, retval);
if (cbret)
cbuf_free(cbret);
if (xerr) if (xerr)
xml_free(xerr); xml_free(xerr);
return retval; return retval;
@ -1760,14 +1751,12 @@ api_operations_post(clicon_handle h,
/* 6. Validate incoming RPC and fill in defaults */ /* 6. Validate incoming RPC and fill in defaults */
if (xml_spec_populate_rpc(h, xtop, yspec) < 0) /* */ if (xml_spec_populate_rpc(h, xtop, yspec) < 0) /* */
goto done; goto done;
if ((ret = xml_yang_validate_rpc(h, xtop, cbret)) < 0) if ((ret = xml_yang_validate_rpc(h, xtop, &xret)) < 0)
goto done; goto done;
if (ret == 0){ if (ret == 0){
if (xml_parse_string(cbuf_get(cbret), NULL, &xret) < 0) if ((xe = xpath_first(xret, "rpc-error")) == NULL){
goto done;
if ((xe = xpath_first(xret, "rpc-reply/rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto ok;
} }
if (api_return_err(h, r, xe, pretty, use_xml) < 0) if (api_return_err(h, r, xe, pretty, use_xml) < 0)
goto done; goto done;

View file

@ -32,7 +32,8 @@
***** END LICENSE BLOCK ***** ***** END LICENSE BLOCK *****
* Netconf library functions. See RFC6241 * Netconf library functions. See RFC6241
* * Functions to generate a netconf error message come in two forms: xml-tree and
* cbuf. XML tree is preferred.
*/ */
#ifndef _CLIXON_NETCONF_LIB_H #ifndef _CLIXON_NETCONF_LIB_H
#define _CLIXON_NETCONF_LIB_H #define _CLIXON_NETCONF_LIB_H
@ -60,16 +61,18 @@ int netconf_lock_denied(cbuf *cb, char *info, char *message);
int netconf_resource_denied(cbuf *cb, char *type, char *message); int netconf_resource_denied(cbuf *cb, char *type, char *message);
int netconf_rollback_failed(cbuf *cb, char *type, char *message); int netconf_rollback_failed(cbuf *cb, char *type, char *message);
int netconf_data_exists(cbuf *cb, char *message); int netconf_data_exists(cbuf *cb, char *message);
int netconf_data_missing(cbuf *cb, char *message); int netconf_data_missing(cbuf *cb, char *missing_choice, char *message);
int netconf_data_missing_xml(cxobj **xret, char *missing_choice, char *message);
int netconf_operation_not_supported(cbuf *cb, char *type, char *message); int netconf_operation_not_supported(cbuf *cb, char *type, char *message);
int netconf_operation_failed(cbuf *cb, char *type, char *message); int netconf_operation_failed(cbuf *cb, char *type, char *message);
int netconf_operation_failed_xml(cxobj **xret, char *type, char *message); int netconf_operation_failed_xml(cxobj **xret, char *type, char *message);
int netconf_malformed_message(cbuf *cb, char *message); int netconf_malformed_message(cbuf *cb, char *message);
int netconf_malformed_message_xml(cxobj **xret, char *message); int netconf_malformed_message_xml(cxobj **xret, char *message);
int netconf_data_not_unique(cbuf *cb, cxobj *x, cvec *cvk); int netconf_data_not_unique_xml(cxobj **xret, cxobj *x, cvec *cvk);
int netconf_minmax_elements(cbuf *cb, cxobj *x, int max); int netconf_minmax_elements_xml(cxobj **xret, cxobj *x, int max);
int netconf_trymerge(cxobj *x, yang_stmt *yspec, cxobj **xret); int netconf_trymerge(cxobj *x, yang_stmt *yspec, cxobj **xret);
int netconf_module_load(clicon_handle h); int netconf_module_load(clicon_handle h);
char *netconf_db_find(cxobj *xn, char *name); char *netconf_db_find(cxobj *xn, char *name);
int netconf_err2cb(cxobj *xerr, cbuf **cberr);
#endif /* _CLIXON_NETCONF_LIB_H */ #endif /* _CLIXON_NETCONF_LIB_H */

View file

@ -48,11 +48,11 @@ int xml2txt(FILE *f, cxobj *x, int level);
int xml2cli(FILE *f, cxobj *x, char *prepend, enum genmodel_type gt); int xml2cli(FILE *f, cxobj *x, char *prepend, enum genmodel_type gt);
int xml_yang_root(cxobj *x, cxobj **xr); int xml_yang_root(cxobj *x, cxobj **xr);
int xmlns_assign(cxobj *x); int xmlns_assign(cxobj *x);
int xml_yang_validate_rpc(clicon_handle h, cxobj *xrpc, cbuf *cbret); int xml_yang_validate_rpc(clicon_handle h, cxobj *xrpc, cxobj **xret);
int xml_yang_validate_list_key_only(clicon_handle h, cxobj *xt, cbuf *cbret); int xml_yang_validate_list_key_only(clicon_handle h, cxobj *xt, cxobj **xret);
int xml_yang_validate_add(clicon_handle h, cxobj *xt, cbuf *cbret); int xml_yang_validate_add(clicon_handle h, cxobj *xt, cxobj **xret);
int xml_yang_validate_all(clicon_handle h, cxobj *xt, cbuf *cbret); int xml_yang_validate_all(clicon_handle h, cxobj *xt, cxobj **xret);
int xml_yang_validate_all_top(clicon_handle h, cxobj *xt, cbuf *cbret); int xml_yang_validate_all_top(clicon_handle h, cxobj *xt, cxobj **xret);
int xml2cvec(cxobj *xt, yang_stmt *ys, cvec **cvv0); int xml2cvec(cxobj *xt, yang_stmt *ys, cvec **cvv0);
int cvec2xml_1(cvec *cvv, char *toptag, cxobj *xp, cxobj **xt0); int cvec2xml_1(cvec *cvv, char *toptag, cxobj *xp, cxobj **xt0);

View file

@ -219,7 +219,7 @@ text_modify(clicon_handle h,
break; break;
case OP_DELETE: case OP_DELETE:
if (x0==NULL){ if (x0==NULL){
if (netconf_data_missing(cbret, "Data does not exist; cannot delete resource") < 0) if (netconf_data_missing(cbret, NULL, "Data does not exist; cannot delete resource") < 0)
goto done; goto done;
goto fail; goto fail;
} }
@ -376,7 +376,7 @@ text_modify(clicon_handle h,
break; break;
case OP_DELETE: case OP_DELETE:
if (x0==NULL){ if (x0==NULL){
if (netconf_data_missing(cbret, "Data does not exist; cannot delete resource") < 0) if (netconf_data_missing(cbret, NULL, "Data does not exist; cannot delete resource") < 0)
goto done; goto done;
goto fail; goto fail;
} }
@ -488,7 +488,7 @@ text_modify_top(clicon_handle h,
I.e., curl -u andy:bar -sS -X DELETE http://localhost/restconf/data I.e., curl -u andy:bar -sS -X DELETE http://localhost/restconf/data
*/ */
case OP_DELETE: case OP_DELETE:
if (netconf_data_missing(cbret, "Data does not exist; cannot delete resource") < 0) if (netconf_data_missing(cbret, NULL, "Data does not exist; cannot delete resource") < 0)
goto done; goto done;
goto fail; goto fail;
break; break;

View file

@ -32,6 +32,8 @@
***** END LICENSE BLOCK ***** ***** END LICENSE BLOCK *****
* Netconf library functions. See RFC6241 * Netconf library functions. See RFC6241
* Functions to generate a netconf error message come in two forms: xml-tree and
* cbuf. XML tree is preferred.
*/ */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
@ -63,6 +65,8 @@
#include "clixon_options.h" #include "clixon_options.h"
#include "clixon_data.h" #include "clixon_data.h"
#include "clixon_xml_map.h" #include "clixon_xml_map.h"
#include "clixon_xpath_ctx.h"
#include "clixon_xpath.h"
#include "clixon_netconf_lib.h" #include "clixon_netconf_lib.h"
/*! Create Netconf in-use error XML tree according to RFC 6241 Appendix A /*! Create Netconf in-use error XML tree according to RFC 6241 Appendix A
@ -752,38 +756,81 @@ netconf_data_exists(cbuf *cb,
* does not exist. For example, a "delete" operation was attempted on * does not exist. For example, a "delete" operation was attempted on
* data that does not exist. * data that does not exist.
* @param[out] cb CLIgen buf. Error XML is written in this buffer * @param[out] cb CLIgen buf. Error XML is written in this buffer
* @param[in] missing_choice If set, see RFC7950: 15.6 violates mandatiry choice
* @param[in] message Error message * @param[in] message Error message
*/ */
int int
netconf_data_missing(cbuf *cb, netconf_data_missing(cbuf *cb,
char *missing_choice,
char *message) char *message)
{ {
int retval = -1; int retval = -1;
char *encstr = NULL; cxobj *xret = NULL;
if (cprintf(cb, "<rpc-reply><rpc-error>" if (netconf_data_missing_xml(&xret, missing_choice, message) < 0)
"<error-type>application</error-type>" goto done;
"<error-tag>data-missing</error-tag>" if (clicon_xml2cbuf(cb, xret, 0, 0) < 0)
"<error-severity>error</error-severity>") <0) goto done;
goto err; retval = 0;
done:
if (xret)
xml_free(xret);
return retval;
}
/*! Create Netconf data-missing error XML tree according to RFC 6241 App A
*
* Request could not be completed because the relevant data model content
* does not exist. For example, a "delete" operation was attempted on
* data that does not exist.
* @param[out] xret Error XML tree. Free with xml_free after use
* @param[in] missing_choice If set, see RFC7950: 15.6 violates mandatiry choice
* @param[in] message Error message
*/
int
netconf_data_missing_xml(cxobj **xret,
char *missing_choice,
char *message)
{
int retval = -1;
char *encstr = NULL;
cxobj *xerr;
if (*xret == NULL){
if ((*xret = xml_new("rpc-reply", NULL, NULL)) == NULL)
goto done;
}
else if (xml_name_set(*xret, "rpc-reply") < 0)
goto done;
if ((xerr = xml_new("rpc-error", *xret, NULL)) == NULL)
goto done;
if (xml_parse_va(&xerr, NULL,
"<error-type>application</error-type>"
"<error-tag>data-missing</error-tag>") < 0)
goto done;
if (missing_choice) /* NYI: RFC7950: 15.6 <error-path> */
if (xml_parse_va(&xerr, NULL,
"<error-app-tag>missing-choice</error-app-tag>"
"<error-info><missing-choice>%s</missing-choice></error-info>",
missing_choice) < 0)
goto done;
if (xml_parse_va(&xerr, NULL,
"<error-severity>error</error-severity>") < 0)
goto done;
if (message){ if (message){
if (xml_chardata_encode(&encstr, "%s", message) < 0) if (xml_chardata_encode(&encstr, "%s", message) < 0)
goto done; goto done;
if (cprintf(cb, "<error-message>%s</error-message>", encstr) < 0) if (xml_parse_va(&xerr, NULL,
goto err; "<error-message>%s</error-message>", encstr) < 0)
goto done;
} }
if (cprintf(cb, "</rpc-error></rpc-reply>") <0)
goto err;
retval = 0; retval = 0;
done: done:
if (encstr) if (encstr)
free(encstr); free(encstr);
return retval; return retval;
err:
clicon_err(OE_XML, errno, "cprintf");
goto done;
} }
/*! Create Netconf operation-not-supported error XML according to RFC 6241 App A /*! Create Netconf operation-not-supported error XML according to RFC 6241 App A
* *
* Request could not be completed because the requested operation is not * Request could not be completed because the requested operation is not
@ -970,79 +1017,97 @@ netconf_malformed_message_xml(cxobj **xret,
* *
* A NETCONF operation would result in configuration data where a * A NETCONF operation would result in configuration data where a
* "unique" constraint is invalidated. * "unique" constraint is invalidated.
* @param[out] cb CLIgen buf. Error XML is written in this buffer * @param[out] xret Error XML tree. Free with xml_free after use
* @param[in] x List element containing duplicate * @param[in] x List element containing duplicate
* @param[in] cvk List of comonents in x that are non-unique * @param[in] cvk List of comonents in x that are non-unique
* @see RFC7950 Sec 15.1 * @see RFC7950 Sec 15.1
*/ */
int int
netconf_data_not_unique(cbuf *cb, netconf_data_not_unique_xml(cxobj **xret,
cxobj *x, cxobj *x,
cvec *cvk) cvec *cvk)
{ {
int retval = -1; int retval = -1;
cg_var *cvi = NULL; cg_var *cvi = NULL;
cxobj *xi; cxobj *xi;
cxobj *xerr;
cxobj *xinfo;
cbuf *cb = NULL;
if (cprintf(cb, "<rpc-reply><rpc-error>" if (*xret == NULL){
"<error-type>protocol</error-type>" if ((*xret = xml_new("rpc-reply", NULL, NULL)) == NULL)
"<error-tag>operation-failed</error-tag>" goto done;
"<error-app-tag>data-not-unique</error-app-tag>" }
"<error-severity>error</error-severity>" else if (xml_name_set(*xret, "rpc-reply") < 0)
"<error-info>") < 0) goto done;
goto err; if ((xerr = xml_new("rpc-error", *xret, NULL)) == NULL)
while ((cvi = cvec_each(cvk, cvi)) != NULL){ goto done;
if ((xi = xml_find(x, cv_string_get(cvi))) == NULL) if (xml_parse_va(&xerr, NULL, "<error-type>protocol</error-type>"
continue; /* ignore, shouldnt happen */ "<error-tag>operation-failed</error-tag>"
cprintf(cb, "<non-unique>"); "<error-app-tag>data-not-unique</error-app-tag>"
clicon_xml2cbuf(cb, xi, 0, 0); "<error-severity>error</error-severity>") < 0)
cprintf(cb, "</non-unique>"); goto done;
if (cvec_len(cvk)){
if ((xinfo = xml_new("error-info", xerr, NULL)) == NULL)
goto done;
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
while ((cvi = cvec_each(cvk, cvi)) != NULL){
if ((xi = xml_find(x, cv_string_get(cvi))) == NULL)
continue; /* ignore, shouldnt happen */
clicon_xml2cbuf(cb, xi, 0, 0);
if (xml_parse_va(&xinfo, NULL, "<non-unique>%s</non-unique>", cbuf_get(cb)) < 0)
goto done;
cbuf_reset(cb);
}
} }
if (cprintf(cb, "</error-info></rpc-error></rpc-reply>") <0)
goto err;
retval = 0; retval = 0;
done: done:
if (cb)
cbuf_free(cb);
return retval; return retval;
err:
clicon_err(OE_XML, errno, "cprintf");
goto done;
} }
/*! Create Netconf too-many/few-elements err msg according to RFC 7950 15.2/15.3 /*! Create Netconf too-many/few-elements err msg according to RFC 7950 15.2/15.3
* *
* A NETCONF operation would result in configuration data where a * A NETCONF operation would result in configuration data where a
list or a leaf-list would have too many entries, the following error list or a leaf-list would have too many entries, the following error
* @param[out] cb CLIgen buf. Error XML is written in this buffer * @param[out] xret Error XML tree. Free with xml_free after use
* @param[in] x List element containing duplicate * @param[in] x List element containing duplicate
* @param[in] max If set, return too-many, otherwise too-few * @param[in] max If set, return too-many, otherwise too-few
* @see RFC7950 Sec 15.1 * @see RFC7950 Sec 15.1
*/ */
int int
netconf_minmax_elements(cbuf *cb, netconf_minmax_elements_xml(cxobj **xret,
cxobj *x, cxobj *x,
int max) int max)
{ {
int retval = -1; int retval = -1;
cxobj *xerr;
if (cprintf(cb, "<rpc-reply><rpc-error>" if (*xret == NULL){
"<error-type>protocol</error-type>" if ((*xret = xml_new("rpc-reply", NULL, NULL)) == NULL)
"<error-tag>operation-failed</error-tag>" goto done;
"<error-app-tag>too-%s-elements</error-app-tag>" }
"<error-severity>error</error-severity>" else if (xml_name_set(*xret, "rpc-reply") < 0)
"<error-path>%s</error-path>" goto done;
"</rpc-error></rpc-reply>", if ((xerr = xml_new("rpc-error", *xret, NULL)) == NULL)
max?"many":"few", goto done;
xml_name(x)) < 0) /* XXX should be xml2xpath */ if (xml_parse_va(&xerr, NULL, "<error-type>protocol</error-type>"
goto err; "<error-tag>operation-failed</error-tag>"
"<error-app-tag>too-%s-elements</error-app-tag>"
"<error-severity>error</error-severity>"
"<error-path>%s</error-path>",
max?"many":"few",
xml_name(x)) < 0) /* XXX should be xml2xpath */
goto done;
retval = 0; retval = 0;
done: done:
return retval; return retval;
err:
clicon_err(OE_XML, errno, "cprintf");
goto done;
} }
/*! Help function: merge - check yang - if error make netconf errmsg /*! Help function: merge - check yang - if error make netconf errmsg
* @param[in] x XML tree * @param[in] x XML tree
* @param[in] yspec Yang spec * @param[in] yspec Yang spec
@ -1156,3 +1221,41 @@ netconf_db_find(cxobj *xn,
return db; return db;
} }
/*! Generate netconf error msg to cbuf to use in string printout or logs
* @param[in] xerr Netconf error message on the level: <rpc-reply><rpc-error>
* @param[out] cberr Translation from netconf err to cbuf. Free with cbuf_free.
* @retval 0 OK, with cberr set
* @retval -1 Error
* @code
* cbuf *cb = NULL;
* if (netconf_err2cb(xerr, &cb) < 0)
* err;
* printf("%s", cbuf_get(cb));
* @endcode
* @see clicon_rpc_generate_error
*/
int
netconf_err2cb(cxobj *xerr,
cbuf **cberr)
{
int retval = -1;
cbuf *cb = NULL;
cxobj *x;
if ((cb = cbuf_new()) ==NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
if ((x=xpath_first(xerr, "error-type"))!=NULL)
cprintf(cb, "%s ", xml_body(x));
if ((x=xpath_first(xerr, "error-tag"))!=NULL)
cprintf(cb, "%s ", xml_body(x));
if ((x=xpath_first(xerr, "error-message"))!=NULL)
cprintf(cb, "%s ", xml_body(x));
if ((x=xpath_first(xerr, "error-info"))!=NULL)
clicon_xml2cbuf(cb, xml_child_i(x,0), 0, 0);
*cberr = cb;
retval = 0;
done:
return retval;
}

View file

@ -72,6 +72,7 @@
#include "clixon_data.h" #include "clixon_data.h"
#include "clixon_xpath_ctx.h" #include "clixon_xpath_ctx.h"
#include "clixon_xpath.h" #include "clixon_xpath.h"
#include "clixon_netconf_lib.h"
#include "clixon_xml_map.h" #include "clixon_xml_map.h"
/* Mapping between Clicon startup modes string <--> constants, /* Mapping between Clicon startup modes string <--> constants,
@ -145,6 +146,7 @@ parse_configfile(clicon_handle h,
char *body; char *body;
clicon_hash_t *copt = clicon_options(h); clicon_hash_t *copt = clicon_options(h);
cbuf *cbret = NULL; cbuf *cbret = NULL;
cxobj *xret = NULL;
int ret; int ret;
if (filename == NULL || !strlen(filename)){ if (filename == NULL || !strlen(filename)){
@ -194,13 +196,11 @@ parse_configfile(clicon_handle h,
} }
if (xml_apply0(xc, CX_ELMNT, xml_default, h) < 0) if (xml_apply0(xc, CX_ELMNT, xml_default, h) < 0)
goto done; goto done;
if ((cbret = cbuf_new()) == NULL){ if ((ret = xml_yang_validate_add(h, xc, &xret)) < 0)
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
if ((ret = xml_yang_validate_add(h, xc, cbret)) < 0)
goto done; goto done;
if (ret == 0){ if (ret == 0){
if (netconf_err2cb(xret, &cbret) < 0)
goto done;
clicon_err(OE_CFG, 0, "Config file validation: %s", cbuf_get(cbret)); clicon_err(OE_CFG, 0, "Config file validation: %s", cbuf_get(cbret));
goto done; goto done;
} }
@ -234,6 +234,8 @@ parse_configfile(clicon_handle h,
done: done:
if (cbret) if (cbret)
cbuf_free(cbret); cbuf_free(cbret);
if (xret)
xml_free(xret);
if (xt) if (xt)
xml_free(xt); xml_free(xt);
if (f) if (f)

View file

@ -71,6 +71,7 @@
#include "clixon_proto.h" #include "clixon_proto.h"
#include "clixon_err.h" #include "clixon_err.h"
#include "clixon_err_string.h" #include "clixon_err_string.h"
#include "clixon_netconf_lib.h"
#include "clixon_proto_client.h" #include "clixon_proto_client.h"
/*! Send internal netconf rpc from client to backend /*! Send internal netconf rpc from client to backend
@ -224,29 +225,22 @@ clicon_rpc_netconf_xml(clicon_handle h,
} }
/*! Generate and log clicon error function call from Netconf error message /*! Generate and log clicon error function call from Netconf error message
* @param[in] prefix Print this string (if given) before: "<prefix>: <error>"
* @param[in] xerr Netconf error message on the level: <rpc-reply><rpc-error> * @param[in] xerr Netconf error message on the level: <rpc-reply><rpc-error>
*/ */
int int
clicon_rpc_generate_error(char *format, clicon_rpc_generate_error(char *prefix,
cxobj *xerr) cxobj *xerr)
{ {
int retval = -1; int retval = -1;
cbuf *cb = NULL; cbuf *cb = NULL;
cxobj *x;
if ((cb = cbuf_new()) ==NULL){ if (netconf_err2cb(xerr, &cb) < 0)
clicon_err(OE_XML, errno, "cbuf_new");
goto done; goto done;
} if (prefix)
if ((x=xpath_first(xerr, "error-type"))!=NULL) clicon_log(LOG_ERR, "%s: %s", prefix, cbuf_get(cb));
cprintf(cb, "%s ", xml_body(x)); else
if ((x=xpath_first(xerr, "error-tag"))!=NULL) clicon_log(LOG_ERR, "%s", cbuf_get(cb));
cprintf(cb, "%s ", xml_body(x));
if ((x=xpath_first(xerr, "error-message"))!=NULL)
cprintf(cb, "%s ", xml_body(x));
if ((x=xpath_first(xerr, "error-info"))!=NULL)
clicon_xml2cbuf(cb, xml_child_i(x,0), 0, 0);
clicon_log(LOG_ERR, "%s: %s", format, cbuf_get(cb));
retval = 0; retval = 0;
done: done:
if (cb) if (cb)

View file

@ -67,6 +67,7 @@
#include "clixon_options.h" #include "clixon_options.h"
#include "clixon_data.h" #include "clixon_data.h"
#include "clixon_yang_module.h" #include "clixon_yang_module.h"
#include "clixon_netconf_lib.h"
#include "clixon_xml_map.h" #include "clixon_xml_map.h"
#include "clixon_xml_changelog.h" #include "clixon_xml_changelog.h"
#include "clixon_xpath_ctx.h" #include "clixon_xpath_ctx.h"
@ -424,8 +425,9 @@ clixon_xml_changelog_init(clicon_handle h)
int fd = -1; int fd = -1;
cxobj *xt = NULL; cxobj *xt = NULL;
yang_stmt *yspec; yang_stmt *yspec;
cbuf *cbret = NULL;
int ret; int ret;
cxobj *xret = NULL;
cbuf *cbret = NULL;
yspec = clicon_dbspec_yang(h); yspec = clicon_dbspec_yang(h);
if ((filename = clicon_option_str(h, "CLICON_XML_CHANGELOG_FILE")) != NULL){ if ((filename = clicon_option_str(h, "CLICON_XML_CHANGELOG_FILE")) != NULL){
@ -437,15 +439,13 @@ clixon_xml_changelog_init(clicon_handle h)
goto done; goto done;
if (xml_rootchild(xt, 0, &xt) < 0) if (xml_rootchild(xt, 0, &xt) < 0)
goto done; goto done;
if ((cbret = cbuf_new()) == NULL){ if ((ret = xml_yang_validate_all(h, xt, &xret)) < 0)
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done; goto done;
} if (ret==1 && (ret = xml_yang_validate_add(h, xt, &xret)) < 0)
if ((ret = xml_yang_validate_all(h, xt, cbret)) < 0)
goto done;
if (ret==1 && (ret = xml_yang_validate_add(h, xt, cbret)) < 0)
goto done; goto done;
if (ret == 0){ /* validation failed */ if (ret == 0){ /* validation failed */
if (netconf_err2cb(xret, &cbret) < 0)
goto done;
clicon_err(OE_YANG, 0, "validation failed: %s", cbuf_get(cbret)); clicon_err(OE_YANG, 0, "validation failed: %s", cbuf_get(cbret));
goto done; goto done;
} }
@ -455,12 +455,14 @@ clixon_xml_changelog_init(clicon_handle h)
} }
retval = 0; retval = 0;
done: done:
if (cbret)
cbuf_free(cbret);
if (xret)
xml_free(xret);
if (fd != -1) if (fd != -1)
close(fd); close(fd);
if (xt) if (xt)
xml_free(xt); xml_free(xt);
if (cbret)
cbuf_free(cbret);
return retval; return retval;
} }

View file

@ -248,7 +248,7 @@ xml2cli(FILE *f,
/*! Validate xml node of type leafref, ensure the value is one of that path's reference /*! 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] xt XML leaf node of type leafref
* @param[in] ytype Yang type statement belonging to the XML node * @param[in] ytype Yang type statement belonging to the XML node
* @param[out] cbret Error buffer * @param[out] xret Error XML tree. Free with xml_free after use
* @retval 1 Validation OK * @retval 1 Validation OK
* @retval 0 Validation failed * @retval 0 Validation failed
* @retval -1 Error * @retval -1 Error
@ -256,7 +256,7 @@ xml2cli(FILE *f,
static int static int
validate_leafref(cxobj *xt, validate_leafref(cxobj *xt,
yang_stmt *ytype, yang_stmt *ytype,
cbuf *cbret) cxobj **xret)
{ {
int retval = -1; int retval = -1;
yang_stmt *ypath; yang_stmt *ypath;
@ -270,7 +270,7 @@ validate_leafref(cxobj *xt,
if ((leafrefbody = xml_body(xt)) == NULL) if ((leafrefbody = xml_body(xt)) == NULL)
goto ok; goto ok;
if ((ypath = yang_find(ytype, Y_PATH, NULL)) == NULL){ if ((ypath = yang_find(ytype, Y_PATH, NULL)) == NULL){
if (netconf_missing_element(cbret, "application", yang_argument_get(ytype), "Leafref requires path statement") < 0) if (netconf_missing_element_xml(xret, "application", yang_argument_get(ytype), "Leafref requires path statement") < 0)
goto done; goto done;
goto fail; goto fail;
} }
@ -284,12 +284,12 @@ validate_leafref(cxobj *xt,
break; break;
} }
if (i==xlen){ if (i==xlen){
if (netconf_bad_element(cbret, "application", leafrefbody, "Leafref validation failed: No such leaf") < 0) if (netconf_bad_element_xml(xret, "application", leafrefbody, "Leafref validation failed: No such leaf") < 0)
goto done; goto done;
goto fail; goto fail;
} }
ok: ok:
retval = 0; retval = 1;
done: done:
if (xvec) if (xvec)
free(xvec); free(xvec);
@ -312,7 +312,7 @@ validate_leafref(cxobj *xt,
* @param[in] xt XML leaf node of type identityref * @param[in] xt XML leaf node of type identityref
* @param[in] ys Yang spec of leaf * @param[in] ys Yang spec of leaf
* @param[in] ytype Yang type field of type identityref * @param[in] ytype Yang type field of type identityref
* @param[out] cbret Error buffer * @param[out] xret Error XML tree. Free with xml_free after use
* @retval 1 Validation OK * @retval 1 Validation OK
* @retval 0 Validation failed * @retval 0 Validation failed
* @retval -1 Error * @retval -1 Error
@ -324,7 +324,8 @@ static int
validate_identityref(cxobj *xt, validate_identityref(cxobj *xt,
yang_stmt *ys, yang_stmt *ys,
yang_stmt *ytype, yang_stmt *ytype,
cbuf *cbret) cxobj **xret)
{ {
int retval = -1; int retval = -1;
char *node; char *node;
@ -350,13 +351,13 @@ validate_identityref(cxobj *xt,
} }
/* This is the type's base reference */ /* This is the type's base reference */
if ((ybaseref = yang_find(ytype, Y_BASE, NULL)) == NULL){ if ((ybaseref = yang_find(ytype, Y_BASE, NULL)) == NULL){
if (netconf_missing_element(cbret, "application", yang_argument_get(ytype), "Identityref validation failed, no base") < 0) if (netconf_missing_element_xml(xret, "application", yang_argument_get(ytype), "Identityref validation failed, no base") < 0)
goto done; goto done;
goto fail; goto fail;
} }
/* This is the actual base identity */ /* This is the actual base identity */
if ((ybaseid = yang_find_identity(ybaseref, yang_argument_get(ybaseref))) == NULL){ if ((ybaseid = yang_find_identity(ybaseref, yang_argument_get(ybaseref))) == NULL){
if (netconf_missing_element(cbret, "application", yang_argument_get(ybaseref), "Identityref validation failed, no base identity") < 0) if (netconf_missing_element_xml(xret, "application", yang_argument_get(ybaseref), "Identityref validation failed, no base identity") < 0)
goto done; goto done;
goto fail; goto fail;
} }
@ -367,7 +368,7 @@ validate_identityref(cxobj *xt,
cbuf_reset(cb); cbuf_reset(cb);
cprintf(cb, "Identityref validation failed, %s not derived from %s", cprintf(cb, "Identityref validation failed, %s not derived from %s",
node, yang_argument_get(ybaseid)); node, yang_argument_get(ybaseid));
if (netconf_operation_failed(cbret, "application", cbuf_get(cb)) < 0) if (netconf_operation_failed_xml(xret, "application", cbuf_get(cb)) < 0)
goto done; goto done;
goto fail; goto fail;
} }
@ -413,10 +414,12 @@ xml_yang_root(cxobj *x,
} }
/*! Validate an RPC node /*! Validate an RPC node
* @param[in] xt XML node to be validated * @param[in] h Clicon handle
* @retval 1 Validation OK * @param[in] xrpc XML node to be validated
* @retval 0 Validation failed * @param[out] xret Error XML tree. Free with xml_free after use
* @retval -1 Error * @retval 1 Validation OK
* @retval 0 Validation failed
* @retval -1 Error
* rfc7950 * rfc7950
* 7.14.2 * 7.14.2
* If a leaf in the input tree has a "mandatory" statement with the * If a leaf in the input tree has a "mandatory" statement with the
@ -454,8 +457,8 @@ xml_yang_root(cxobj *x,
*/ */
int int
xml_yang_validate_rpc(clicon_handle h, xml_yang_validate_rpc(clicon_handle h,
cxobj *xrpc, cxobj *xrpc,
cbuf *cbret) cxobj **xret)
{ {
int retval = -1; int retval = -1;
yang_stmt *yn=NULL; /* rpc name */ yang_stmt *yn=NULL; /* rpc name */
@ -469,15 +472,15 @@ xml_yang_validate_rpc(clicon_handle h,
/* xn is name of rpc, ie <rcp><xn/></rpc> */ /* xn is name of rpc, ie <rcp><xn/></rpc> */
while ((xn = xml_child_each(xrpc, xn, CX_ELMNT)) != NULL) { while ((xn = xml_child_each(xrpc, xn, CX_ELMNT)) != NULL) {
if ((yn = xml_spec(xn)) == NULL){ if ((yn = xml_spec(xn)) == NULL){
if (netconf_unknown_element(cbret, "application", xml_name(xn), NULL) < 0) if (netconf_unknown_element_xml(xret, "application", xml_name(xn), NULL) < 0)
goto done; goto done;
goto fail; goto fail;
} }
if ((retval = xml_yang_validate_all(h, xn, cbret)) < 1) if ((retval = xml_yang_validate_all(h, xn, xret)) < 1)
goto done; /* error or validation fail */ goto done; /* error or validation fail */
if ((retval = xml_yang_validate_add(h, xn, cbret)) < 1) if ((retval = xml_yang_validate_add(h, xn, xret)) < 1)
goto done; /* error or validation fail */ goto done; /* error or validation fail */
if (xml_apply0(xn, CX_ELMNT, xml_default, NULL) < 0) if (xml_apply0(xn, CX_ELMNT, xml_default, h) < 0)
goto done; goto done;
} }
// ok: /* pass validation */ // ok: /* pass validation */
@ -492,7 +495,7 @@ xml_yang_validate_rpc(clicon_handle h,
/*! Check if an xml node is a part of a choice and have >1 siblings /*! Check if an xml node is a part of a choice and have >1 siblings
* @param[in] xt XML node to be validated * @param[in] xt XML node to be validated
* @param[in] yt xt:s yang statement * @param[in] yt xt:s yang statement
* @param[out] cbret Error buffer (set w netconf error if retval == 0) * @param[out] xret Error XML tree. Free with xml_free after use
* @retval 1 Validation OK * @retval 1 Validation OK
* @retval 0 Validation failed (cbret set) * @retval 0 Validation failed (cbret set)
* @retval -1 Error * @retval -1 Error
@ -501,7 +504,7 @@ xml_yang_validate_rpc(clicon_handle h,
static int static int
check_choice(cxobj *xt, check_choice(cxobj *xt,
yang_stmt *yt, yang_stmt *yt,
cbuf *cbret) cxobj **xret)
{ {
int retval = -1; int retval = -1;
yang_stmt *y; yang_stmt *y;
@ -552,7 +555,7 @@ check_choice(cxobj *xt,
continue; /* not choice */ continue; /* not choice */
break; break;
} }
if (netconf_bad_element(cbret, "application", xml_name(x), "Element in choice statement already exists") < 0) if (netconf_bad_element_xml(xret, "application", xml_name(x), "Element in choice statement already exists") < 0)
goto done; goto done;
goto fail; goto fail;
} /* while */ } /* while */
@ -569,7 +572,7 @@ check_choice(cxobj *xt,
/*! Check if an xml node lacks mandatory children /*! Check if an xml node lacks mandatory children
* @param[in] xt XML node to be validated * @param[in] xt XML node to be validated
* @param[in] yt xt:s yang statement * @param[in] yt xt:s yang statement
* @param[out] cbret Error buffer (set w netconf error if retval == 0) * @param[out] xret Error XML tree. Free with xml_free after use
* @retval 1 Validation OK * @retval 1 Validation OK
* @retval 0 Validation failed (cbret set) * @retval 0 Validation failed (cbret set)
* @retval -1 Error * @retval -1 Error
@ -577,7 +580,8 @@ check_choice(cxobj *xt,
static int static int
check_mandatory(cxobj *xt, check_mandatory(cxobj *xt,
yang_stmt *yt, yang_stmt *yt,
cbuf *cbret) cxobj **xret)
{ {
int retval = -1; int retval = -1;
int i; int i;
@ -600,7 +604,7 @@ check_mandatory(cxobj *xt,
while ((cvi = cvec_each(cvk, cvi)) != NULL) { while ((cvi = cvec_each(cvk, cvi)) != NULL) {
keyname = cv_string_get(cvi); keyname = cv_string_get(cvi);
if (xml_find_type(xt, NULL, keyname, CX_ELMNT) == NULL){ if (xml_find_type(xt, NULL, keyname, CX_ELMNT) == NULL){
if (netconf_missing_element(cbret, "application", keyname, "Mandatory key") < 0) if (netconf_missing_element_xml(xret, "application", keyname, "Mandatory key") < 0)
goto done; goto done;
goto fail; goto fail;
} }
@ -623,7 +627,7 @@ check_mandatory(cxobj *xt,
break; /* got it */ break; /* got it */
} }
if (x == NULL){ if (x == NULL){
if (netconf_missing_element(cbret, "application", yc->ys_argument, "Mandatory variable") < 0) if (netconf_missing_element_xml(xret, "application", yc->ys_argument, "Mandatory variable") < 0)
goto done; goto done;
goto fail; goto fail;
} }
@ -640,17 +644,7 @@ check_mandatory(cxobj *xt,
if (x == NULL){ if (x == NULL){
/* @see RFC7950: 15.6 Error Message for Data That Violates /* @see RFC7950: 15.6 Error Message for Data That Violates
* a Mandatory "choice" Statement */ * a Mandatory "choice" Statement */
if (cprintf(cbret, "<rpc-reply><rpc-error>" if (netconf_data_missing_xml(xret, yc->ys_argument, NULL) < 0)
"<error-type>application</error-type>"
"<error-tag>data-missing</error-tag>"
"<error-app-tag>missing-choice</error-app-tag>"
#ifdef NYI
// "<error-path></error-path>"
#endif
"<error-info><missing-choice>%s</missing-choice></error-info>"
"<error-severity>error</error-severity>"
"</rpc-error></rpc-reply>",
yc->ys_argument) <0)
goto done; goto done;
goto fail; goto fail;
} }
@ -667,10 +661,14 @@ check_mandatory(cxobj *xt,
goto done; goto done;
} }
/*!
* @param[out] xret Error XML tree. Free with xml_free after use
*/
static int static int
check_list_key(cxobj *xt, check_list_key(cxobj *xt,
yang_stmt *yt, yang_stmt *yt,
cbuf *cbret) cxobj **xret)
{ {
int retval = -1; int retval = -1;
int i; int i;
@ -690,7 +688,7 @@ check_list_key(cxobj *xt,
while ((cvi = cvec_each(cvk, cvi)) != NULL) { while ((cvi = cvec_each(cvk, cvi)) != NULL) {
keyname = cv_string_get(cvi); keyname = cv_string_get(cvi);
if (xml_find_type(xt, NULL, keyname, CX_ELMNT) == NULL){ if (xml_find_type(xt, NULL, keyname, CX_ELMNT) == NULL){
if (netconf_missing_element(cbret, "application", keyname, "Mandatory key") < 0) if (netconf_missing_element_xml(xret, "application", keyname, "Mandatory key") < 0)
goto done; goto done;
goto fail; goto fail;
} }
@ -739,7 +737,7 @@ check_insert_duplicate(char **vec,
* @param[in] xt The parent of x * @param[in] xt The parent of x
* @param[in] y Its yang spec (Y_LIST) * @param[in] y Its yang spec (Y_LIST)
* @param[in] yu A yang unique spec (Y_UNIQUE) * @param[in] yu A yang unique spec (Y_UNIQUE)
* @param[out] cbret Error buffer (set w netconf error if retval == 0) * @param[out] xret Error XML tree. Free with xml_free after use
* @retval 1 Validation OK * @retval 1 Validation OK
* @retval 0 Validation failed (cbret set) * @retval 0 Validation failed (cbret set)
* @retval -1 Error * @retval -1 Error
@ -750,7 +748,8 @@ check_unique_list(cxobj *x,
cxobj *xt, cxobj *xt,
yang_stmt *y, yang_stmt *y,
yang_stmt *yu, yang_stmt *yu,
cbuf *cbret) cxobj **xret)
{ {
int retval = -1; int retval = -1;
cvec *cvk; /* unique vector */ cvec *cvk; /* unique vector */
@ -784,7 +783,7 @@ check_unique_list(cxobj *x,
if (cvi==NULL){ if (cvi==NULL){
/* Last element (i) is newly inserted, see if it is already there */ /* Last element (i) is newly inserted, see if it is already there */
if (check_insert_duplicate(vec, i, vlen) < 0){ if (check_insert_duplicate(vec, i, vlen) < 0){
if (netconf_data_not_unique(cbret, x, cvk) < 0) if (netconf_data_not_unique_xml(xret, x, cvk) < 0)
goto done; goto done;
goto fail; goto fail;
} }
@ -807,7 +806,7 @@ check_unique_list(cxobj *x,
* @param[in] x One x (the last) of a specific lis * @param[in] x One x (the last) of a specific lis
* @param[in] y Yang spec of x * @param[in] y Yang spec of x
* @param[in] nr Number of elements (like x) in thlist * @param[in] nr Number of elements (like x) in thlist
* @param[out] cbret Error buffer (set w netconf error if retval == 0) * @param[out] xret Error XML tree. Free with xml_free after use
* @retval 1 Validation OK * @retval 1 Validation OK
* @retval 0 Validation failed (cbret set) * @retval 0 Validation failed (cbret set)
* @retval -1 Error * @retval -1 Error
@ -817,7 +816,7 @@ static int
check_min_max(cxobj *x, check_min_max(cxobj *x,
yang_stmt *y, yang_stmt *y,
int nr, int nr,
cbuf *cbret) cxobj **xret)
{ {
int retval = -1; int retval = -1;
yang_stmt *ymin; /* yang min */ yang_stmt *ymin; /* yang min */
@ -827,7 +826,7 @@ check_min_max(cxobj *x,
if ((ymin = yang_find(y, Y_MIN_ELEMENTS, NULL)) != NULL){ if ((ymin = yang_find(y, Y_MIN_ELEMENTS, NULL)) != NULL){
cv = yang_cv_get(ymin); cv = yang_cv_get(ymin);
if (nr < cv_uint32_get(cv)){ if (nr < cv_uint32_get(cv)){
if (netconf_minmax_elements(cbret, x, 0) < 0) if (netconf_minmax_elements_xml(xret, x, 0) < 0)
goto done; goto done;
goto fail; goto fail;
} }
@ -836,7 +835,7 @@ check_min_max(cxobj *x,
cv = yang_cv_get(ymax); cv = yang_cv_get(ymax);
if (cv_uint32_get(cv) > 0 && /* 0 means unbounded */ if (cv_uint32_get(cv) > 0 && /* 0 means unbounded */
nr > cv_uint32_get(cv)){ nr > cv_uint32_get(cv)){
if (netconf_minmax_elements(cbret, x, 1) < 0) if (netconf_minmax_elements_xml(xret, x, 1) < 0)
goto done; goto done;
goto fail; goto fail;
} }
@ -851,9 +850,9 @@ check_min_max(cxobj *x,
/*! Detect unique constraint for duplicates from parent node and minmax /*! Detect unique constraint for duplicates from parent node and minmax
* @param[in] xt XML parent (may have lists w unique constraints as child) * @param[in] xt XML parent (may have lists w unique constraints as child)
* @param[out] cbret Error buffer (set w netconf error if retval == 0) * @param[out] xret Error XML tree. Free with xml_free after use
* @retval 1 Validation OK * @retval 1 Validation OK
* @retval 0 Validation failed (cbret set) * @retval 0 Validation failed (xret set)
* @retval -1 Error * @retval -1 Error
* Assume xt:s children are sorted and yang populated. * Assume xt:s children are sorted and yang populated.
* The function does two different things of the children of an XML node: * The function does two different things of the children of an XML node:
@ -889,8 +888,8 @@ check_min_max(cxobj *x,
* are not allowed. * are not allowed.
*/ */
static int static int
check_list_unique_minmax(cxobj *xt, check_list_unique_minmax(cxobj *xt,
cbuf *cbret) cxobj **xret)
{ {
int retval = -1; int retval = -1;
cxobj *x = NULL; cxobj *x = NULL;
@ -932,7 +931,7 @@ check_list_unique_minmax(cxobj *xt,
} }
else { else {
/* Check if the list length violates min/max */ /* Check if the list length violates min/max */
if ((ret = check_min_max(xp, yp, nr, cbret)) < 0) if ((ret = check_min_max(xp, yp, nr, xret)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0)
goto fail; goto fail;
@ -953,7 +952,7 @@ check_list_unique_minmax(cxobj *xt,
do { do {
if (yang_keyword_get(ye) == Y_LIST || yang_keyword_get(ye) == Y_LEAF_LIST){ if (yang_keyword_get(ye) == Y_LIST || yang_keyword_get(ye) == Y_LEAF_LIST){
/* Check if the list length violates min/max */ /* Check if the list length violates min/max */
if ((ret = check_min_max(xt, ye, 0, cbret)) < 0) if ((ret = check_min_max(xt, ye, 0, xret)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0)
goto fail; goto fail;
@ -973,7 +972,7 @@ check_list_unique_minmax(cxobj *xt,
* its first element x, its yang spec y, its parent xt, and * its first element x, its yang spec y, its parent xt, and
* a unique yang spec yu, * a unique yang spec yu,
*/ */
if ((ret = check_unique_list(x, xt, y, yu, cbret)) < 0) if ((ret = check_unique_list(x, xt, y, yu, xret)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0)
goto fail; goto fail;
@ -984,7 +983,7 @@ check_list_unique_minmax(cxobj *xt,
*/ */
if (yp){ if (yp){
/* Check if the list length violates min/max */ /* Check if the list length violates min/max */
if ((ret = check_min_max(xp, yp, nr, cbret)) < 0) if ((ret = check_min_max(xp, yp, nr, xret)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0)
goto fail; goto fail;
@ -996,7 +995,7 @@ check_list_unique_minmax(cxobj *xt,
do { do {
if (yang_keyword_get(ye) == Y_LIST || yang_keyword_get(ye) == Y_LEAF_LIST){ if (yang_keyword_get(ye) == Y_LIST || yang_keyword_get(ye) == Y_LEAF_LIST){
/* Check if the list length violates min/max */ /* Check if the list length violates min/max */
if ((ret = check_min_max(xt, ye, 0, cbret)) < 0) if ((ret = check_min_max(xt, ye, 0, xret)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0)
goto fail; goto fail;
@ -1014,14 +1013,14 @@ check_list_unique_minmax(cxobj *xt,
* 1. Check if mandatory leafs present as subs. * 1. Check if mandatory leafs present as subs.
* 2. Check leaf values, eg int ranges and string regexps. * 2. Check leaf values, eg int ranges and string regexps.
* @param[in] xt XML node to be validated * @param[in] xt XML node to be validated
* @param[out] cbret Error buffer (set w netconf error if retval == 0) * @param[out] xret Error XML tree. Free with xml_free after use
* @retval 1 Validation OK * @retval 1 Validation OK
* @retval 0 Validation failed (cbret set) * @retval 0 Validation failed (cbret set)
* @retval -1 Error * @retval -1 Error
* @code * @code
* cxobj *x; * cxobj *x;
* cbuf *cbret = cbuf_new(); * cbuf *xret = NULL;
* if ((ret = xml_yang_validate_add(h, x, cbret)) < 0) * if ((ret = xml_yang_validate_add(h, x, &xret)) < 0)
* err; * err;
* if (ret == 0) * if (ret == 0)
* fail; * fail;
@ -1032,8 +1031,8 @@ check_list_unique_minmax(cxobj *xt,
*/ */
int int
xml_yang_validate_add(clicon_handle h, xml_yang_validate_add(clicon_handle h,
cxobj *xt, cxobj *xt,
cbuf *cbret) cxobj **xret)
{ {
int retval = -1; int retval = -1;
cg_var *cv = NULL; cg_var *cv = NULL;
@ -1047,11 +1046,11 @@ xml_yang_validate_add(clicon_handle h,
/* if not given by argument (overide) use default link /* if not given by argument (overide) use default link
and !Node has a config sub-statement and it is false */ and !Node has a config sub-statement and it is false */
if ((yt = xml_spec(xt)) != NULL && yang_config(yt) != 0){ if ((yt = xml_spec(xt)) != NULL && yang_config(yt) != 0){
if ((ret = check_choice(xt, yt, cbret)) < 0) if ((ret = check_choice(xt, yt, xret)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0)
goto fail; goto fail;
if ((ret = check_mandatory(xt, yt, cbret)) < 0) if ((ret = check_mandatory(xt, yt, xret)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0)
goto fail; goto fail;
@ -1073,21 +1072,21 @@ xml_yang_validate_add(clicon_handle h,
* are considered as "" */ * are considered as "" */
cvtype = cv_type_get(cv); cvtype = cv_type_get(cv);
if (cv_isint(cvtype) || cvtype == CGV_BOOL || cvtype == CGV_DEC64){ if (cv_isint(cvtype) || cvtype == CGV_BOOL || cvtype == CGV_DEC64){
if (netconf_bad_element(cbret, "application", yt->ys_argument, "Invalid NULL value") < 0) if (netconf_bad_element_xml(xret, "application", yt->ys_argument, "Invalid NULL value") < 0)
goto done; goto done;
goto fail; goto fail;
} }
} }
else{ else{
if (cv_parse1(body, cv, &reason) != 1){ if (cv_parse1(body, cv, &reason) != 1){
if (netconf_bad_element(cbret, "application", yt->ys_argument, reason) < 0) if (netconf_bad_element_xml(xret, "application", yt->ys_argument, reason) < 0)
goto done; goto done;
goto fail; goto fail;
} }
} }
if ((ys_cv_validate(h, cv, yt, &reason)) != 1){ if ((ys_cv_validate(h, cv, yt, &reason)) != 1){
if (netconf_bad_element(cbret, "application", yt->ys_argument, reason) < 0) if (netconf_bad_element_xml(xret, "application", yt->ys_argument, reason) < 0)
goto done; goto done;
goto fail; goto fail;
} }
@ -1098,7 +1097,7 @@ xml_yang_validate_add(clicon_handle h,
} }
x = NULL; x = NULL;
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) { while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
if ((ret = xml_yang_validate_add(h, x, cbret)) < 0) if ((ret = xml_yang_validate_add(h, x, xret)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0)
goto fail; goto fail;
@ -1116,11 +1115,12 @@ xml_yang_validate_add(clicon_handle h,
} }
/*! Some checks done only at edit_config, eg keys in lists /*! Some checks done only at edit_config, eg keys in lists
* @param[out] xret Error XML tree. Free with xml_free after use
*/ */
int int
xml_yang_validate_list_key_only(clicon_handle h, xml_yang_validate_list_key_only(clicon_handle h,
cxobj *xt, cxobj *xt,
cbuf *cbret) cxobj **xret)
{ {
int retval = -1; int retval = -1;
yang_stmt *yt; /* yang spec of xt going in */ yang_stmt *yt; /* yang spec of xt going in */
@ -1130,14 +1130,14 @@ xml_yang_validate_list_key_only(clicon_handle h,
/* if not given by argument (overide) use default link /* if not given by argument (overide) use default link
and !Node has a config sub-statement and it is false */ and !Node has a config sub-statement and it is false */
if ((yt = xml_spec(xt)) != NULL && yang_config(yt) != 0){ if ((yt = xml_spec(xt)) != NULL && yang_config(yt) != 0){
if ((ret = check_list_key(xt, yt, cbret)) < 0) if ((ret = check_list_key(xt, yt, xret)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0)
goto fail; goto fail;
} }
x = NULL; x = NULL;
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) { while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
if ((ret = xml_yang_validate_list_key_only(h, x, cbret)) < 0) if ((ret = xml_yang_validate_list_key_only(h, x, xret)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0)
goto fail; goto fail;
@ -1154,17 +1154,18 @@ xml_yang_validate_list_key_only(clicon_handle h,
/*! Validate a single XML node with yang specification for all (not only added) entries /*! 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. * 1. Check leafrefs. Eg you delete a leaf and a leafref references it.
* @param[in] xt XML node to be validated * @param[in] xt XML node to be validated
* @param[out] cbret Error buffer (set w netconf error if retval == 0) * @param[out] xret Error XML tree (if retval=0). Free with xml_free after use
* @retval 1 Validation OK * @retval 1 Validation OK
* @retval 0 Validation failed (cbret set) * @retval 0 Validation failed (cbret set)
* @retval -1 Error * @retval -1 Error
* @code * @code
* cxobj *x; * cxobj *x;
* cbuf *cbret = cbuf_new(); * cbuf *xret = NULL;
* if ((ret = xml_yang_validate_all(x, cbret)) < 0) * if ((ret = xml_yang_validate_all(h, x, &xret)) < 0)
* err; * err;
* if (ret == 0) * if (ret == 0)
* fail; * fail;
* xml_free(xret);
* @endcode * @endcode
* @see xml_yang_validate_add * @see xml_yang_validate_add
* @see xml_yang_validate_rpc * @see xml_yang_validate_rpc
@ -1172,8 +1173,8 @@ xml_yang_validate_list_key_only(clicon_handle h,
*/ */
int int
xml_yang_validate_all(clicon_handle h, xml_yang_validate_all(clicon_handle h,
cxobj *xt, cxobj *xt,
cbuf *cbret) cxobj **xret)
{ {
int retval = -1; int retval = -1;
yang_stmt *ys; /* yang node */ yang_stmt *ys; /* yang node */
@ -1188,7 +1189,7 @@ xml_yang_validate_all(clicon_handle h,
and !Node has a config sub-statement and it is false */ and !Node has a config sub-statement and it is false */
ys=xml_spec(xt); ys=xml_spec(xt);
if (ys==NULL){ if (ys==NULL){
if (netconf_unknown_element(cbret, "application", xml_name(xt), NULL) < 0) if (netconf_unknown_element_xml(xret, "application", xml_name(xt), NULL) < 0)
goto done; goto done;
goto fail; goto fail;
} }
@ -1207,12 +1208,16 @@ xml_yang_validate_all(clicon_handle h,
*/ */
if ((yc = yang_find(ys, Y_TYPE, NULL)) != NULL){ if ((yc = yang_find(ys, Y_TYPE, NULL)) != NULL){
if (strcmp(yc->ys_argument, "leafref") == 0){ if (strcmp(yc->ys_argument, "leafref") == 0){
if (validate_leafref(xt, yc, cbret) < 0) if ((ret = validate_leafref(xt, yc, xret)) < 0)
goto done; goto done;
if (ret == 0)
goto fail;
} }
else if (strcmp(yc->ys_argument, "identityref") == 0){ else if (strcmp(yc->ys_argument, "identityref") == 0){
if (validate_identityref(xt, ys, yc, cbret) < 0) if ((ret = validate_identityref(xt, ys, yc, xret)) < 0)
goto done; goto done;
if (ret == 0)
goto fail;
} }
} }
break; break;
@ -1230,7 +1235,7 @@ xml_yang_validate_all(clicon_handle h,
goto done; goto done;
if (!nr){ if (!nr){
ye = yang_find(yc, Y_ERROR_MESSAGE, NULL); ye = yang_find(yc, Y_ERROR_MESSAGE, NULL);
if (netconf_operation_failed(cbret, "application", if (netconf_operation_failed_xml(xret, "application",
ye?ye->ys_argument:"must xpath validation failed") < 0) ye?ye->ys_argument:"must xpath validation failed") < 0)
goto done; goto done;
goto fail; goto fail;
@ -1242,7 +1247,7 @@ xml_yang_validate_all(clicon_handle h,
if ((nr = xpath_vec_bool(xt, "%s", xpath)) < 0) if ((nr = xpath_vec_bool(xt, "%s", xpath)) < 0)
goto done; goto done;
if (!nr){ if (!nr){
if (netconf_operation_failed(cbret, "application", if (netconf_operation_failed_xml(xret, "application",
"when xpath validation failed") < 0) "when xpath validation failed") < 0)
goto done; goto done;
goto fail; goto fail;
@ -1251,7 +1256,7 @@ xml_yang_validate_all(clicon_handle h,
} }
x = NULL; x = NULL;
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) { while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
if ((ret = xml_yang_validate_all(h, x, cbret)) < 0) if ((ret = xml_yang_validate_all(h, x, xret)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0)
goto fail; goto fail;
@ -1259,7 +1264,7 @@ xml_yang_validate_all(clicon_handle h,
/* Check unique and min-max after choice test for example*/ /* Check unique and min-max after choice test for example*/
if (yang_config(ys) != 0){ if (yang_config(ys) != 0){
/* Checks if next level contains any unique list constraints */ /* Checks if next level contains any unique list constraints */
if ((ret = check_list_unique_minmax(xt, cbret)) < 0) if ((ret = check_list_unique_minmax(xt, xret)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0)
goto fail; goto fail;
@ -1274,24 +1279,25 @@ xml_yang_validate_all(clicon_handle h,
} }
/*! Translate a single xml node to a cligen variable vector. Note not recursive /*! Translate a single xml node to a cligen variable vector. Note not recursive
* @param[out] xret Error XML tree (if ret == 0). Free with xml_free after use
* @retval 1 Validation OK * @retval 1 Validation OK
* @retval 0 Validation failed (cbret set) * @retval 0 Validation failed (xret set)
* @retval -1 Error * @retval -1 Error
*/ */
int int
xml_yang_validate_all_top(clicon_handle h, xml_yang_validate_all_top(clicon_handle h,
cxobj *xt, cxobj *xt,
cbuf *cbret) cxobj **xret)
{ {
int ret; int ret;
cxobj *x; cxobj *x;
x = NULL; x = NULL;
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) { while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
if ((ret = xml_yang_validate_all(h, x, cbret)) < 1) if ((ret = xml_yang_validate_all(h, x, xret)) < 1)
return ret; return ret;
} }
if ((ret = check_list_unique_minmax(xt, cbret)) < 1) if ((ret = check_list_unique_minmax(xt, xret)) < 1)
return ret; return ret;
return 1; return 1;
} }

View file

@ -15,7 +15,7 @@ testnr=0
for test in $pattern; do for test in $pattern; do
if [ $testnr != 0 ]; then echo; fi if [ $testnr != 0 ]; then echo; fi
testfile=$test testfile=$test
ret=$(./$test) # . ./$test . ./$test
errcode=$? errcode=$?
if [ $errcode -ne 0 ]; then if [ $errcode -ne 0 ]; then
err=1 err=1

View file

@ -15,6 +15,7 @@ cat <<EOF > $cfg
<CLICON_YANG_DIR>$dir</CLICON_YANG_DIR> <CLICON_YANG_DIR>$dir</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR> <CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR> <CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR> <CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
<CLICON_BACKEND_REGEXP>example_backend.so$</CLICON_BACKEND_REGEXP> <CLICON_BACKEND_REGEXP>example_backend.so$</CLICON_BACKEND_REGEXP>
@ -108,80 +109,82 @@ cat <<EOF > $fyang
} }
EOF EOF
new "test params: -f $cfg -y $fyang" new "test params: -f $cfg"
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "kill old backend" new "kill old backend"
sudo clixon_backend -zf $cfg sudo clixon_backend -zf $cfg
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
err err
fi fi
new "start backend -s init -f $cfg -y $fyang" new "start backend -s init -f $cfg"
start_backend -s init -f $cfg -y $fyang start_backend -s init -f $cfg
new "waiting" new "waiting"
sleep $RCWAIT sleep $RCWAIT
fi fi
new "Set crypto to aes" new "Set crypto to aes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><edit-config><target><candidate/></target><config><crypto xmlns="urn:example:my-crypto">aes</crypto></config></edit-config></rpc>]]>]]>' '^<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><ok/></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><edit-config><target><candidate/></target><config><crypto xmlns="urn:example:my-crypto">aes</crypto></config></edit-config></rpc>]]>]]>' '^<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><ok/></rpc-reply>]]>]]>$'
new "netconf validate " new "netconf validate "
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "Set crypto to mc:aes" new "Set crypto to mc:aes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><crypto xmlns="urn:example:my-crypto">mc:aes</crypto></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><crypto xmlns="urn:example:my-crypto">mc:aes</crypto></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf validate" new "netconf validate"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "Set crypto to des:des3" new "Set crypto to des:des3"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><crypto xmlns="urn:example:my-crypto">des:des3</crypto></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><crypto xmlns="urn:example:my-crypto">des:des3</crypto></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf validate" new "netconf validate"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "Set crypto to mc:foo" new "Set crypto to mc:foo"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><crypto xmlns="urn:example:my-crypto">mc:foo</crypto></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><crypto xmlns="urn:example:my-crypto">mc:foo</crypto></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf validate" new "netconf validate"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "Set crypto to des:des3 using xmlns" new "Set crypto to des:des3 using xmlns"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><crypto xmlns="urn:example:my-crypto" xmlns:des="urn:example:des">des:des3</crypto></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><crypto xmlns="urn:example:my-crypto" xmlns:des="urn:example:des">des:des3</crypto></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf validate" new "netconf validate"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
if false; then
# XXX this is not supported # XXX this is not supported
#new "Set crypto to x:des3 using xmlns" new "Set crypto to x:des3 using xmlns"
#expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><crypto xmlns="urn:example:my-crypto" xmlns:x="urn:example:des">x:des3</crypto></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><crypto xmlns="urn:example:my-crypto" xmlns:x="urn:example:des">x:des3</crypto></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf validate" new "netconf validate"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
fi # not supported
new "Set crypto to foo:bar" new "Set crypto to foo:bar"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><crypto xmlns="urn:example:my-crypto">foo:bar</crypto></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><crypto xmlns="urn:example:my-crypto">foo:bar</crypto></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf validate" new "netconf validate (expect fail)"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>Identityref validation failed, foo:bar not derived from crypto-alg</error-message></rpc-error></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 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" new "cli set crypto to mc:aes"
expectfn "$clixon_cli -1 -f $cfg -y $fyang -l o set crypto mc:aes" 0 "^$" expectfn "$clixon_cli -1 -f $cfg -l o set crypto mc:aes" 0 "^$"
new "cli validate" new "cli validate"
expectfn "$clixon_cli -1 -f $cfg -y $fyang -l o validate" 0 "^$" expectfn "$clixon_cli -1 -f $cfg -l o validate" 0 "^$"
new "cli set crypto to aes" new "cli set crypto to aes"
expectfn "$clixon_cli -1 -f $cfg -y $fyang -l o set crypto aes" 0 "^$" expectfn "$clixon_cli -1 -f $cfg -l o set crypto aes" 0 "^$"
new "cli validate" new "cli validate"
expectfn "$clixon_cli -1 -f $cfg -y $fyang -l o validate" 0 "^$" expectfn "$clixon_cli -1 -f $cfg -l o validate" 0 "^$"
new "cli set crypto to des:des3" new "cli set crypto to des:des3"
expectfn "$clixon_cli -1 -f $cfg -y $fyang -l o set crypto des:des3" 0 "^$" expectfn "$clixon_cli -1 -f $cfg -l o set crypto des:des3" 0 "^$"
new "cli validate" new "cli validate"
expectfn "$clixon_cli -1 -f $cfg -y $fyang -l o validate" 0 "^$" expectfn "$clixon_cli -1 -f $cfg -l o validate" 0 "^$"
if [ $BE -eq 0 ]; then if [ $BE -eq 0 ]; then
exit # BE exit # BE

View file

@ -33,6 +33,7 @@ cat <<EOF > $cfg
<CLICON_CONFIGFILE>/tmp/conf_yang.xml</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>/tmp/conf_yang.xml</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR> <CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR> <CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR> <CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE> <CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
@ -149,16 +150,16 @@ cat <<EOF > $dbdir/running_db
</config> </config>
EOF EOF
new "test params: -s running -f $cfg -y $fyang -- -s" new "test params: -s running -f $cfg -- -s"
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "kill old backend" new "kill old backend"
sudo clixon_backend -zf $cfg -y $fyang sudo clixon_backend -zf $cfg
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
err err
fi fi
new "start backend" new "start backend"
start_backend -s running -f $cfg -y $fyang -- -s start_backend -s running -f $cfg -- -s
new "waiting" new "waiting"
sleep $RCWAIT sleep $RCWAIT
@ -169,75 +170,75 @@ new "state data (should be unordered: 42,41,43)"
cat <<EOF > $tmp cat <<EOF > $tmp
<rpc><get><filter type="xpath" select="state"/></get></rpc>]]>]]> <rpc><get><filter type="xpath" select="state"/></get></rpc>]]>]]>
EOF EOF
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "$(cat $tmp)" '<rpc-reply><data><state xmlns="urn:example:clixon"><op>42</op><op>41</op><op>43</op></state></data></rpc-reply>]]>]]>' expecteof "$clixon_netconf -qf $cfg" 0 "$(cat $tmp)" '<rpc-reply><data><state xmlns="urn:example:clixon"><op>42</op><op>41</op><op>43</op></state></data></rpc-reply>]]>]]>'
# Check as file # Check as file
new "verify running from start, should be: c,l,y0,y1,y2,y3; y1 and y3 sorted." new "verify running from start, should be: c,l,y0,y1,y2,y3; y1 and y3 sorted."
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><running/></source></get-config></rpc>]]>]]>' '^<rpc-reply><data><c xmlns="urn:example:order"><d>hej</d></c><l xmlns="urn:example:order">hopp</l><y0 xmlns="urn:example:order">d</y0><y0 xmlns="urn:example:order">b</y0><y0 xmlns="urn:example:order">c</y0><y0 xmlns="urn:example:order">a</y0><y1 xmlns="urn:example:order">a</y1><y1 xmlns="urn:example:order">b</y1><y1 xmlns="urn:example:order">c</y1><y1 xmlns="urn:example:order">d</y1><y2 xmlns="urn:example:order"><k>d</k><a>bar</a></y2><y2 xmlns="urn:example:order"><k>a</k><a>bar</a></y2><y2 xmlns="urn:example:order"><k>c</k><a>bar</a></y2><y2 xmlns="urn:example:order"><k>b</k><a>bar</a></y2><y3 xmlns="urn:example:order"><k>a</k><a>bar</a></y3><y3 xmlns="urn:example:order"><k>b</k><a>bar</a></y3><y3 xmlns="urn:example:order"><k>c</k><a>bar</a></y3><y3 xmlns="urn:example:order"><k>d</k><a>bar</a></y3></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><running/></source></get-config></rpc>]]>]]>' '^<rpc-reply><data><c xmlns="urn:example:order"><d>hej</d></c><l xmlns="urn:example:order">hopp</l><y0 xmlns="urn:example:order">d</y0><y0 xmlns="urn:example:order">b</y0><y0 xmlns="urn:example:order">c</y0><y0 xmlns="urn:example:order">a</y0><y1 xmlns="urn:example:order">a</y1><y1 xmlns="urn:example:order">b</y1><y1 xmlns="urn:example:order">c</y1><y1 xmlns="urn:example:order">d</y1><y2 xmlns="urn:example:order"><k>d</k><a>bar</a></y2><y2 xmlns="urn:example:order"><k>a</k><a>bar</a></y2><y2 xmlns="urn:example:order"><k>c</k><a>bar</a></y2><y2 xmlns="urn:example:order"><k>b</k><a>bar</a></y2><y3 xmlns="urn:example:order"><k>a</k><a>bar</a></y3><y3 xmlns="urn:example:order"><k>b</k><a>bar</a></y3><y3 xmlns="urn:example:order"><k>c</k><a>bar</a></y3><y3 xmlns="urn:example:order"><k>d</k><a>bar</a></y3></data></rpc-reply>]]>]]>$'
new "get each ordered-by user leaf-list" new "get each ordered-by user leaf-list"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y2[k='a']\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><y2 xmlns="urn:example:order"><k>a</k><a>bar</a></y2></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y2[k='a']\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><y2 xmlns="urn:example:order"><k>a</k><a>bar</a></y2></data></rpc-reply>]]>]]>$'
new "get each ordered-by user leaf-list" new "get each ordered-by user leaf-list"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y3[k='a']\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><y3 xmlns="urn:example:order"><k>a</k><a>bar</a></y3></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y3[k='a']\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><y3 xmlns="urn:example:order"><k>a</k><a>bar</a></y3></data></rpc-reply>]]>]]>$'
new "get each ordered-by user leaf-list" new "get each ordered-by user leaf-list"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y2[k='b']\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><y2 xmlns="urn:example:order"><k>b</k><a>bar</a></y2></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y2[k='b']\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><y2 xmlns="urn:example:order"><k>b</k><a>bar</a></y2></data></rpc-reply>]]>]]>$'
new "get each ordered-by user leaf-list" new "get each ordered-by user leaf-list"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y3[k='b']\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><y3 xmlns="urn:example:order"><k>b</k><a>bar</a></y3></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y3[k='b']\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><y3 xmlns="urn:example:order"><k>b</k><a>bar</a></y3></data></rpc-reply>]]>]]>$'
new "delete candidate" new "delete candidate"
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>]]>]]>$" 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 # LEAF_LISTS
new "add two entries (c,b) to leaf-list user order" new "add two entries (c,b) to leaf-list user order"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><y0 xmlns="urn:example:order">c</y0><y0 xmlns="urn:example:order">b</y0></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><y0 xmlns="urn:example:order">c</y0><y0 xmlns="urn:example:order">b</y0></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "add one entry (a) to leaf-list user order" new "add one entry (a) to leaf-list user order"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><y0 xmlns="urn:example:order">a</y0></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><y0 xmlns="urn:example:order">a</y0></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf commit" new "netconf commit"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "add one entry (0) to leaf-list user order after commit" new "add one entry (0) to leaf-list user order after commit"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><y0 xmlns="urn:example:order">0</y0></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><y0 xmlns="urn:example:order">0</y0></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf commit" new "netconf commit"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "verify leaf-list user order in running (as entered: c,b,a,0)" new "verify leaf-list user order in running (as entered: c,b,a,0)"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><running/></source><filter type="xpath" select="/y0"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><y0 xmlns="urn:example:order">c</y0><y0 xmlns="urn:example:order">b</y0><y0 xmlns="urn:example:order">a</y0><y0 xmlns="urn:example:order">0</y0></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><running/></source><filter type="xpath" select="/y0"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><y0 xmlns="urn:example:order">c</y0><y0 xmlns="urn:example:order">b</y0><y0 xmlns="urn:example:order">a</y0><y0 xmlns="urn:example:order">0</y0></data></rpc-reply>]]>]]>$'
# LISTS # LISTS
new "add two entries to list user order" new "add two entries to list user order"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><y2 xmlns="urn:example:order"><k>c</k><a>bar</a></y2><y2 xmlns="urn:example:order"><k>b</k><a>foo</a></y2></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><y2 xmlns="urn:example:order"><k>c</k><a>bar</a></y2><y2 xmlns="urn:example:order"><k>b</k><a>foo</a></y2></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "add one entry to list user order" new "add one entry to list user order"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><y2 xmlns="urn:example:order"><k>a</k><a>fie</a></y2></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><y2 xmlns="urn:example:order"><k>a</k><a>fie</a></y2></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "verify list user order (as entered)" new "verify list user order (as entered)"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/y2"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><y2 xmlns="urn:example:order"><k>c</k><a>bar</a></y2><y2 xmlns="urn:example:order"><k>b</k><a>foo</a></y2><y2 xmlns="urn:example:order"><k>a</k><a>fie</a></y2></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/y2"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><y2 xmlns="urn:example:order"><k>c</k><a>bar</a></y2><y2 xmlns="urn:example:order"><k>b</k><a>foo</a></y2><y2 xmlns="urn:example:order"><k>a</k><a>fie</a></y2></data></rpc-reply>]]>]]>$'
new "Overwrite existing ordered-by user y2->c" new "Overwrite existing ordered-by user y2->c"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><y2 xmlns="urn:example:order"> expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><y2 xmlns="urn:example:order">
<k>c</k><a>newc</a> <k>c</k><a>newc</a>
</y2></config></edit-config></rpc>]]>]]>' </y2></config></edit-config></rpc>]]>]]>'
new "Overwrite existing ordered-by user y2->b" new "Overwrite existing ordered-by user y2->b"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><y2 xmlns="urn:example:order"> expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><y2 xmlns="urn:example:order">
<k>b</k><a>newb</a> <k>b</k><a>newb</a>
</y2></config></edit-config></rpc>]]>]]>' </y2></config></edit-config></rpc>]]>]]>'
new "Overwrite existing ordered-by user y2->a" new "Overwrite existing ordered-by user y2->a"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><y2 xmlns="urn:example:order"> expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><y2 xmlns="urn:example:order">
<k>a</k><a>newa</a> <k>a</k><a>newa</a>
</y2></config></edit-config></rpc>]]>]]>' </y2></config></edit-config></rpc>]]>]]>'
new "Tests for no duplicates." new "Tests for no duplicates."
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/y2"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><y2 xmlns="urn:example:order"><k>c</k><a>newc</a></y2><y2 xmlns="urn:example:order"><k>b</k><a>newb</a></y2><y2 xmlns="urn:example:order"><k>a</k><a>newa</a></y2></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/y2"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><y2 xmlns="urn:example:order"><k>c</k><a>newc</a></y2><y2 xmlns="urn:example:order"><k>b</k><a>newb</a></y2><y2 xmlns="urn:example:order"><k>a</k><a>newa</a></y2></data></rpc-reply>]]>]]>$'
#-- order by type rather than strings. #-- order by type rather than strings.
# there are three leaf-lists:strings, ints, and decimal64, and two lists: # there are three leaf-lists:strings, ints, and decimal64, and two lists:
@ -246,44 +247,44 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><cand
# The check is to write the entries as: 10,2,1, and then expect them to # The check is to write the entries as: 10,2,1, and then expect them to
# get back as 1,2,10 (if typed). # get back as 1,2,10 (if typed).
new "put strings (10,2,1)" new "put strings (10,2,1)"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><types xmlns="urn:example:order"> expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><types xmlns="urn:example:order">
<strings>10</strings><strings>2</strings><strings>1</strings> <strings>10</strings><strings>2</strings><strings>1</strings>
</types></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" </types></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "check string order (1,10,2)" new "check string order (1,10,2)"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/types/strings"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><types xmlns="urn:example:order"><strings>1</strings><strings>10</strings><strings>2</strings></types></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/types/strings"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><types xmlns="urn:example:order"><strings>1</strings><strings>10</strings><strings>2</strings></types></data></rpc-reply>]]>]]>$'
new "put leaf-list int (10,2,1)" new "put leaf-list int (10,2,1)"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><types xmlns="urn:example:order"> expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><types xmlns="urn:example:order">
<ints>10</ints><ints>2</ints><ints>1</ints> <ints>10</ints><ints>2</ints><ints>1</ints>
</types></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" </types></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "check leaf-list int order (1,2,10)" new "check leaf-list int order (1,2,10)"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/types/ints"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><types xmlns="urn:example:order"><ints>1</ints><ints>2</ints><ints>10</ints></types></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/types/ints"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><types xmlns="urn:example:order"><ints>1</ints><ints>2</ints><ints>10</ints></types></data></rpc-reply>]]>]]>$'
new "put list int (10,2,1)" new "put list int (10,2,1)"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><types xmlns="urn:example:order"> expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><types xmlns="urn:example:order">
<listints><a>10</a></listints><listints><a>2</a></listints><listints><a>1</a></listints> <listints><a>10</a></listints><listints><a>2</a></listints><listints><a>1</a></listints>
</types></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" </types></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "check list int order (1,2,10)" new "check list int order (1,2,10)"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/types/listints"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><types xmlns="urn:example:order"><listints><a>1</a></listints><listints><a>2</a></listints><listints><a>10</a></listints></types></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/types/listints"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><types xmlns="urn:example:order"><listints><a>1</a></listints><listints><a>2</a></listints><listints><a>10</a></listints></types></data></rpc-reply>]]>]]>$'
new "put leaf-list decimal64 (10,2,1)" new "put leaf-list decimal64 (10,2,1)"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><types xmlns="urn:example:order"> expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><types xmlns="urn:example:order">
<decs>10.0</decs><decs>2.0</decs><decs>1.0</decs> <decs>10.0</decs><decs>2.0</decs><decs>1.0</decs>
</types></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" </types></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "check leaf-list decimal64 order (1,2,10)" new "check leaf-list decimal64 order (1,2,10)"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/types/decs"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><types xmlns="urn:example:order"><decs>1.0</decs><decs>2.0</decs><decs>10.0</decs></types></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/types/decs"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><types xmlns="urn:example:order"><decs>1.0</decs><decs>2.0</decs><decs>10.0</decs></types></data></rpc-reply>]]>]]>$'
new "put list decimal64 (10,2,1)" new "put list decimal64 (10,2,1)"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><types xmlns="urn:example:order"> expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><types xmlns="urn:example:order">
<listdecs><a>10.0</a></listdecs><listdecs><a>2.0</a></listdecs><listdecs><a>1.0</a></listdecs> <listdecs><a>10.0</a></listdecs><listdecs><a>2.0</a></listdecs><listdecs><a>1.0</a></listdecs>
</types></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" </types></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "check list decimal64 order (1,2,10)" new "check list decimal64 order (1,2,10)"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/types/listdecs"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><types xmlns="urn:example:order"><listdecs><a>1.0</a></listdecs><listdecs><a>2.0</a></listdecs><listdecs><a>10.0</a></listdecs></types></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/types/listdecs"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><types xmlns="urn:example:order"><listdecs><a>1.0</a></listdecs><listdecs><a>2.0</a></listdecs><listdecs><a>10.0</a></listdecs></types></data></rpc-reply>]]>]]>$'
if [ $BE -eq 0 ]; then if [ $BE -eq 0 ]; then
exit # BE exit # BE

View file

@ -39,6 +39,7 @@ cat <<EOF > $cfg
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR> <CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
<CLICON_RESTCONF_PRETTY>false</CLICON_RESTCONF_PRETTY> <CLICON_RESTCONF_PRETTY>false</CLICON_RESTCONF_PRETTY>
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK> <CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR> <CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
@ -101,7 +102,7 @@ cat <<EOF > $fyang
} }
EOF EOF
new "test params: -f $cfg -y $fyang" new "test params: -f $cfg"
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "kill old backend" new "kill old backend"
@ -109,15 +110,15 @@ if [ $BE -ne 0 ]; then
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
err err
fi fi
new "start backend -s init -f $cfg -y $fyang" new "start backend -s init -f $cfg"
start_backend -s init -f $cfg -y $fyang start_backend -s init -f $cfg
fi fi
new "kill old restconf daemon" new "kill old restconf daemon"
sudo pkill -u www-data -f "/www-data/clixon_restconf" sudo pkill -u www-data -f "/www-data/clixon_restconf"
new "start restconf daemon" new "start restconf daemon"
start_restconf -f $cfg -y $fyang start_restconf -f $cfg
new "waiting" new "waiting"
wait_backend wait_backend
@ -128,35 +129,35 @@ wait_restconf
new "1. Netconf RFC5277 stream testing" new "1. Netconf RFC5277 stream testing"
# 1.1 Stream discovery # 1.1 Stream discovery
new "netconf event stream discovery RFC5277 Sec 3.2.5" new "netconf event stream discovery RFC5277 Sec 3.2.5"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get><filter type="xpath" select="netconf/streams" xmlns="urn:ietf:params:xml:ns:netmod:notification"/></get></rpc>]]>]]>' '<rpc-reply><data><netconf xmlns="urn:ietf:params:xml:ns:netmod:notification"><streams><stream><name>EXAMPLE</name><description>Example event stream</description><replay-support>true</replay-support></stream></streams></netconf></data></rpc-reply>]]>]]>' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get><filter type="xpath" select="netconf/streams" xmlns="urn:ietf:params:xml:ns:netmod:notification"/></get></rpc>]]>]]>' '<rpc-reply><data><netconf xmlns="urn:ietf:params:xml:ns:netmod:notification"><streams><stream><name>EXAMPLE</name><description>Example event stream</description><replay-support>true</replay-support></stream></streams></netconf></data></rpc-reply>]]>]]>'
new "netconf event stream discovery RFC8040 Sec 6.2" new "netconf event stream discovery RFC8040 Sec 6.2"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get><filter type="xpath" select="restconf-state/streams"/></get></rpc>]]>]]>' '<rpc-reply><data><restconf-state xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf-monitoring"><streams><stream><name>EXAMPLE</name><description>Example event stream</description><replay-support>true</replay-support><access><encoding>xml</encoding><location>https://localhost/streams/EXAMPLE</location></access></stream></streams></restconf-state></data></rpc-reply>]]>]]>' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get><filter type="xpath" select="restconf-state/streams"/></get></rpc>]]>]]>' '<rpc-reply><data><restconf-state xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf-monitoring"><streams><stream><name>EXAMPLE</name><description>Example event stream</description><replay-support>true</replay-support><access><encoding>xml</encoding><location>https://localhost/streams/EXAMPLE</location></access></stream></streams></restconf-state></data></rpc-reply>]]>]]>'
# #
# 1.2 Netconf stream subscription # 1.2 Netconf stream subscription
new "netconf EXAMPLE subscription" new "netconf EXAMPLE subscription"
expectwait "$clixon_netconf -qf $cfg -y $fyang" '<rpc><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"><stream>EXAMPLE</stream></create-subscription></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]><notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>20' $NCWAIT expectwait "$clixon_netconf -qf $cfg" '<rpc><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"><stream>EXAMPLE</stream></create-subscription></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]><notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>20' $NCWAIT
new "netconf subscription with empty startTime" new "netconf subscription with empty startTime"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"><stream>EXAMPLE</stream><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>regexp match fail:' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"><stream>EXAMPLE</stream><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>regexp match fail:'
new "netconf EXAMPLE subscription with simple filter" new "netconf EXAMPLE subscription with simple filter"
expectwait "$clixon_netconf -qf $cfg -y $fyang" '<rpc><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"><stream>EXAMPLE</stream><filter type="xpath" select="event"/></create-subscription></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]><notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>20' $NCWAIT expectwait "$clixon_netconf -qf $cfg" '<rpc><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"><stream>EXAMPLE</stream><filter type="xpath" select="event"/></create-subscription></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]><notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>20' $NCWAIT
new "netconf EXAMPLE subscription with filter classifier" new "netconf EXAMPLE subscription with filter classifier"
expectwait "$clixon_netconf -qf $cfg -y $fyang" "<rpc><create-subscription xmlns=\"urn:ietf:params:xml:ns:netmod:notification\"><stream>EXAMPLE</stream><filter type=\"xpath\" select=\"event[event-class='fault']\"/></create-subscription></rpc>]]>]]>" '^<rpc-reply><ok/></rpc-reply>]]>]]><notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>20' $NCWAIT expectwait "$clixon_netconf -qf $cfg" "<rpc><create-subscription xmlns=\"urn:ietf:params:xml:ns:netmod:notification\"><stream>EXAMPLE</stream><filter type=\"xpath\" select=\"event[event-class='fault']\"/></create-subscription></rpc>]]>]]>" '^<rpc-reply><ok/></rpc-reply>]]>]]><notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>20' $NCWAIT
new "netconf NONEXIST subscription" new "netconf NONEXIST subscription"
expectwait "$clixon_netconf -qf $cfg -y $fyang" '<rpc><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"><stream>NONEXIST</stream></create-subscription></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>invalid-value</error-tag><error-severity>error</error-severity><error-message>No such stream</error-message></rpc-error></rpc-reply>]]>]]>$' $NCWAIT expectwait "$clixon_netconf -qf $cfg" '<rpc><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"><stream>NONEXIST</stream></create-subscription></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>invalid-value</error-tag><error-severity>error</error-severity><error-message>No such stream</error-message></rpc-error></rpc-reply>]]>]]>$' $NCWAIT
new "netconf EXAMPLE subscription with wrong date" new "netconf EXAMPLE subscription with wrong date"
expectwait "$clixon_netconf -qf $cfg -y $fyang" '<rpc><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"><stream>EXAMPLE</stream><startTime>kallekaka</startTime></create-subscription></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>startTime</bad-element></error-info><error-severity>error</error-severity><error-message>regexp match fail:' 0 expectwait "$clixon_netconf -qf $cfg" '<rpc><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"><stream>EXAMPLE</stream><startTime>kallekaka</startTime></create-subscription></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>startTime</bad-element></error-info><error-severity>error</error-severity><error-message>regexp match fail:' 0
#new "netconf EXAMPLE subscription with replay" #new "netconf EXAMPLE subscription with replay"
#NOW=$(date +"%Y-%m-%dT%H:%M:%S") #NOW=$(date +"%Y-%m-%dT%H:%M:%S")
#sleep 10 #sleep 10
#expectwait "$clixon_netconf -qf $cfg -y $fyang" "<rpc><create-subscription xmlns=\"urn:ietf:params:xml:ns:netmod:notification\"><stream>EXAMPLE</stream><startTime>$NOW</startTime></create-subscription></rpc>]]>]]>" '^<rpc-reply><ok/></rpc-reply>]]>]]><notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>20' 10 #expectwait "$clixon_netconf -qf $cfg" "<rpc><create-subscription xmlns=\"urn:ietf:params:xml:ns:netmod:notification\"><stream>EXAMPLE</stream><startTime>$NOW</startTime></create-subscription></rpc>]]>]]>" '^<rpc-reply><ok/></rpc-reply>]]>]]><notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>20' 10
sleep 2 sleep 2
# #

View file

@ -18,6 +18,7 @@ cat <<EOF > $cfg
<CLICON_YANG_DIR>$dir</CLICON_YANG_DIR> <CLICON_YANG_DIR>$dir</CLICON_YANG_DIR>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR> <CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR> <CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR> <CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE> <CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
@ -76,7 +77,7 @@ module example{
} }
EOF EOF
new "test params: -f $cfg -y $fyang" new "test params: -f $cfg"
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "kill old backend" new "kill old backend"
@ -84,21 +85,21 @@ if [ $BE -ne 0 ]; then
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
err err
fi fi
new "start backend -s init -f $cfg -y $fyang" new "start backend -s init -f $cfg"
start_backend -s init -f $cfg -y $fyang start_backend -s init -f $cfg
new "waiting" new "waiting"
sleep $RCWAIT sleep $RCWAIT
fi fi
new "cli set transitive string" new "cli set transitive string"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set c talle x" 0 "^$" expectfn "$clixon_cli -1f $cfg -l o set c talle x" 0 "^$"
new "cli set transitive union" new "cli set transitive union"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set c ulle 33" 0 "^$" expectfn "$clixon_cli -1f $cfg -l o set c ulle 33" 0 "^$"
new "cli set transitive union error" new "cli set transitive union error"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set c ulle kalle" 255 '^CLI syntax error: "set c ulle kalle": Unknown command$' expectfn "$clixon_cli -1f $cfg -l o set c ulle kalle" 255 '^CLI syntax error: "set c ulle kalle": Unknown command$'
if [ $BE -eq 0 ]; then if [ $BE -eq 0 ]; then
exit # BE exit # BE

View file

@ -15,6 +15,7 @@ cat <<EOF > $cfg
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR> <CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR> <CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR> <CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE> <CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
@ -89,56 +90,56 @@ module $APPNAME{
} }
EOF EOF
new "test params: -f $cfg -y $fyang" new "test params: -f $cfg"
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "kill old backend" new "kill old backend"
sudo clixon_backend -zf $cfg -y $fyang sudo clixon_backend -zf $cfg
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
err err
fi fi
new "start backend -s init -f $cfg -y $fyang" new "start backend -s init -f $cfg"
start_backend -s init -f $cfg -y $fyang start_backend -s init -f $cfg
new "waiting" new "waiting"
sleep $RCWAIT sleep $RCWAIT
fi fi
new "when: add static route" new "when: add static route"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><whenex xmlns="urn:example:clixon"><type>static</type><name>r1</name><static-routes/></whenex></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><whenex xmlns="urn:example:clixon"><type>static</type><name>r1</name><static-routes/></whenex></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "when: validate ok" new "when: validate ok"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "when: add direct route" new "when: add direct route"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><whenex xmlns="urn:example:clixon"><type>direct</type><name>r2</name><static-routes/></whenex></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><whenex xmlns="urn:example:clixon"><type>direct</type><name>r2</name><static-routes/></whenex></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "when get config" new "when get config"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" '^<rpc-reply><data><whenex xmlns="urn:example:clixon"><type>direct</type><name>r2</name><static-routes/></whenex><whenex xmlns="urn:example:clixon"><type>static</type><name>r1</name><static-routes/></whenex></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" '^<rpc-reply><data><whenex xmlns="urn:example:clixon"><type>direct</type><name>r2</name><static-routes/></whenex><whenex xmlns="urn:example:clixon"><type>static</type><name>r1</name><static-routes/></whenex></data></rpc-reply>]]>]]>$'
new "when: validate fail" new "when: validate fail"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>when xpath validation failed</error-message></rpc-error></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 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" new "when: discard-changes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "must: add interface" new "must: add interface"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><interface xmlns="urn:example:clixon"><ifType>ethernet</ifType><ifMTU>1500</ifMTU></interface></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><interface xmlns="urn:example:clixon"><ifType>ethernet</ifType><ifMTU>1500</ifMTU></interface></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "must: validate ok" new "must: validate ok"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "must: add atm interface" new "must: add atm interface"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><interface xmlns="urn:example:clixon"><ifType>atm</ifType><ifMTU>32</ifMTU></interface></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><interface xmlns="urn:example:clixon"><ifType>atm</ifType><ifMTU>32</ifMTU></interface></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "must: atm validate fail" new "must: atm validate fail"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>An ATM MTU must be 64 .. 17966</error-message></rpc-error></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>An ATM MTU must be 64 .. 17966</error-message></rpc-error></rpc-reply>]]>]]>$"
new "must: add eth interface" new "must: add eth interface"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><interface xmlns="urn:example:clixon"><ifType>ethernet</ifType><ifMTU>989</ifMTU></interface></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><interface xmlns="urn:example:clixon"><ifType>ethernet</ifType><ifMTU>989</ifMTU></interface></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "must: eth validate fail" new "must: eth validate fail"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>An Ethernet MTU must be 1500</error-message></rpc-error></rpc-reply>]]>]]>" expecteof "$clixon_netconf -qf $cfg" 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 -eq 0 ]; then if [ $BE -eq 0 ]; then
exit # BE exit # BE

View file

@ -17,6 +17,7 @@ cat <<EOF > $cfg
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$dir</CLICON_YANG_DIR> <CLICON_YANG_DIR>$dir</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR> <CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR> <CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR> <CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE> <CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
@ -141,35 +142,35 @@ module $APPNAME{
} }
EOF EOF
new "test params: -f $cfg -y $fyang" new "test params: -f $cfg"
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "kill old backend" new "kill old backend"
sudo clixon_backend -zf $cfg -y $fyang sudo clixon_backend -zf $cfg
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
err err
fi fi
new "start backend -s init -f $cfg -y $fyang" new "start backend -s init -f $cfg"
start_backend -s init -f $cfg -y $fyang start_backend -s init -f $cfg
new "waiting" new "waiting"
wait_backend wait_backend
fi fi
new "cli defined extension" new "cli defined extension"
expectfn "$clixon_cli -1f $cfg -y $fyang show version" 0 "3." expectfn "$clixon_cli -1f $cfg show version" 0 "3."
new "empty values in leaf-list" new "empty values in leaf-list"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><f><e>a</e></f></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><f><e>a</e></f></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "empty values in leaf-list2" new "empty values in leaf-list2"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><f><e/></f></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><f><e/></f></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf get config" new "netconf get config"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" '^<rpc-reply><data><x xmlns="urn:example:clixon"><f><e/><e>a</e></f></x></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" '^<rpc-reply><data><x xmlns="urn:example:clixon"><f><e/><e>a</e></f></x></data></rpc-reply>]]>]]>$'
new "netconf discard-changes" new "netconf discard-changes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
#new "cli not defined extension" #new "cli not defined extension"
@ -179,106 +180,106 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]
#expectfn "$clixon_cli -1f $cfg -y $fyangerr show version" 0 "Yang error: Extension ex:not-defined not found" #expectfn "$clixon_cli -1f $cfg -y $fyangerr show version" 0 "Yang error: Extension ex:not-defined not found"
new "netconf schema resource, RFC 7895" new "netconf schema resource, RFC 7895"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get><filter type="xpath" select="modules-state/module" xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library"/></get></rpc>]]>]]>' '<module><name>ietf-yang-types</name><revision>2013-07-15</revision><namespace>urn:ietf:params:xml:ns:yang:ietf-yang-types</namespace><conformance-type>implement</conformance-type></module>' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get><filter type="xpath" select="modules-state/module" xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library"/></get></rpc>]]>]]>' '<module><name>ietf-yang-types</name><revision>2013-07-15</revision><namespace>urn:ietf:params:xml:ns:yang:ietf-yang-types</namespace><conformance-type>implement</conformance-type></module>'
new "netconf edit config" new "netconf edit config"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><y><a>1</a><b>2</b><c>5</c><val>one</val></y><d/></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><y><a>1</a><b>2</b><c>5</c><val>one</val></y><d/></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf commit" new "netconf commit"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
# text empty type in running # text empty type in running
new "netconf commit 2nd" new "netconf commit 2nd"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf get config xpath" new "netconf get config xpath"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/x/y[a=1][b=2][c=5]\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><x xmlns="urn:example:clixon"><y><a>1</a><b>2</b><c>5</c><val>one</val></y></x></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/x/y[a=1][b=2][c=5]\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><x xmlns="urn:example:clixon"><y><a>1</a><b>2</b><c>5</c><val>one</val></y></x></data></rpc-reply>]]>]]>$'
new "netconf edit leaf-list" new "netconf edit leaf-list"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><f><e>hej</e><e>hopp</e></f></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><f><e>hej</e><e>hopp</e></f></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf get leaf-list" new "netconf get leaf-list"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/x/f/e"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><x xmlns="urn:example:clixon"><f><e>hej</e><e>hopp</e></f></x></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/x/f/e"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><x xmlns="urn:example:clixon"><f><e>hej</e><e>hopp</e></f></x></data></rpc-reply>]]>]]>$'
new "netconf get leaf-list path" new "netconf get leaf-list path"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/x/f[e='hej']\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><x xmlns=\"urn:example:clixon\"><f><e>hej</e><e>hopp</e></f></x></data></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/x/f[e='hej']\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><x xmlns=\"urn:example:clixon\"><f><e>hej</e><e>hopp</e></f></x></data></rpc-reply>]]>]]>$"
new "netconf get (should be some)" new "netconf get (should be some)"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get><filter type=\"xpath\" select=\"/\"/></get></rpc>]]>]]>" '^<rpc-reply><data><x xmlns="urn:example:clixon"><y><a>1</a><b>2</b><c>5</c><val>one</val></y><d/></x>' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get><filter type=\"xpath\" select=\"/\"/></get></rpc>]]>]]>" '^<rpc-reply><data><x xmlns="urn:example:clixon"><y><a>1</a><b>2</b><c>5</c><val>one</val></y><d/></x>'
new "cli set leaf-list" new "cli set leaf-list"
expectfn "$clixon_cli -1f $cfg -y $fyang set x f e foo" 0 "" expectfn "$clixon_cli -1f $cfg set x f e foo" 0 ""
new "cli show leaf-list" new "cli show leaf-list"
expectfn "$clixon_cli -1f $cfg -y $fyang show xpath /x/f/e" 0 "<e>foo</e>" expectfn "$clixon_cli -1f $cfg show xpath /x/f/e" 0 "<e>foo</e>"
new "netconf set state data (not allowed)" new "netconf set state data (not allowed)"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><state xmlns="urn:example:clixon"><op>42</op></state></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>protocol</error-type><error-tag>invalid-value</error-tag><error-severity>error</error-severity><error-message>State data not allowed</error-message></rpc-error></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><state xmlns="urn:example:clixon"><op>42</op></state></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>protocol</error-type><error-tag>invalid-value</error-tag><error-severity>error</error-severity><error-message>State data not allowed</error-message></rpc-error></rpc-reply>]]>]]>$'
new "netconf set presence and not present" new "netconf set presence and not present"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><nopresence/><presence/></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><nopresence/><presence/></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf get presence only" new "netconf get presence only"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/x/presence"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><x xmlns="urn:example:clixon"><presence/></x></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/x/presence"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><x xmlns="urn:example:clixon"><presence/></x></data></rpc-reply>]]>]]>$'
new "netconf get presence only" new "netconf get presence only"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/x/nopresence"/></get-config></rpc>]]>]]>' "^<rpc-reply><data/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/x/nopresence"/></get-config></rpc>]]>]]>' "^<rpc-reply><data/></rpc-reply>]]>]]>$"
new "netconf discard-changes" new "netconf discard-changes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf anyxml" new "netconf anyxml"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><any><foo><bar a="nisse"/></foo></any></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><any><foo><bar a="nisse"/></foo></any></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf validate anyxml" new "netconf validate anyxml"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf delete candidate" new "netconf delete candidate"
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>]]>]]>$" 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>]]>]]>$"
# Check 3-keys # Check 3-keys
new "netconf add one 3-key entry" new "netconf add one 3-key entry"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><y><a>1</a><b>1</b><c>1</c><val>one</val></y></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><y><a>1</a><b>1</b><c>1</c><val>one</val></y></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf check add one 3-key" new "netconf check add one 3-key"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '<rpc-reply><data><x xmlns="urn:example:clixon"><y><a>1</a><b>1</b><c>1</c><val>one</val></y></x></data></rpc-reply>]]>]]>' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '<rpc-reply><data><x xmlns="urn:example:clixon"><y><a>1</a><b>1</b><c>1</c><val>one</val></y></x></data></rpc-reply>]]>]]>'
new "netconf add another (with same 1st key)" new "netconf add another (with same 1st key)"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><y><a>1</a><b>2</b><c>1</c><val>two</val></y></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><y><a>1</a><b>2</b><c>1</c><val>two</val></y></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf check add another" new "netconf check add another"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '<rpc-reply><data><x xmlns="urn:example:clixon"><y><a>1</a><b>1</b><c>1</c><val>one</val></y><y><a>1</a><b>2</b><c>1</c><val>two</val></y></x></data></rpc-reply>]]>]]>' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '<rpc-reply><data><x xmlns="urn:example:clixon"><y><a>1</a><b>1</b><c>1</c><val>one</val></y><y><a>1</a><b>2</b><c>1</c><val>two</val></y></x></data></rpc-reply>]]>]]>'
new "netconf replace first" new "netconf replace first"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><y><a>1</a><b>1</b><c>1</c><val>replace</val></y></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><y><a>1</a><b>1</b><c>1</c><val>replace</val></y></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf check replace" new "netconf check replace"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '<rpc-reply><data><x xmlns="urn:example:clixon"><y><a>1</a><b>1</b><c>1</c><val>replace</val></y><y><a>1</a><b>2</b><c>1</c><val>two</val></y></x></data></rpc-reply>]]>]]>' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '<rpc-reply><data><x xmlns="urn:example:clixon"><y><a>1</a><b>1</b><c>1</c><val>replace</val></y><y><a>1</a><b>2</b><c>1</c><val>two</val></y></x></data></rpc-reply>]]>]]>'
new "netconf delete first" new "netconf delete first"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><y operation="remove"><a>1</a><b>1</b><c>1</c></y></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><y operation="remove"><a>1</a><b>1</b><c>1</c></y></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf check delete" new "netconf check delete"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '<rpc-reply><data><x xmlns="urn:example:clixon"><y><a>1</a><b>2</b><c>1</c><val>two</val></y></x></data></rpc-reply>]]>]]>' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '<rpc-reply><data><x xmlns="urn:example:clixon"><y><a>1</a><b>2</b><c>1</c><val>two</val></y></x></data></rpc-reply>]]>]]>'
# clear db for next test # clear db for next test
new "netconf delete candidate" new "netconf delete candidate"
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>]]>]]>$" 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>]]>]]>$"
new "netconf commit empty candidate" new "netconf commit empty candidate"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconfig config submodule" new "netconfig config submodule"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><mylist xmlns="urn:example:clixon"><x>a</x><subm-container><subm-leaf>foo</subm-leaf></subm-container></mylist></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><mylist xmlns="urn:example:clixon"><x>a</x><subm-container><subm-leaf>foo</subm-leaf></subm-container></mylist></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf submodule get config" new "netconf submodule get config"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply><data><mylist xmlns="urn:example:clixon"><x>a</x><subm-container><subm-leaf>foo</subm-leaf></subm-container></mylist></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply><data><mylist xmlns="urn:example:clixon"><x>a</x><subm-container><subm-leaf>foo</subm-leaf></subm-container></mylist></data></rpc-reply>]]>]]>$'
new "netconf submodule validate" new "netconf submodule validate"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf submodule discard-changes" new "netconf submodule discard-changes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
if [ $BE -eq 0 ]; then if [ $BE -eq 0 ]; then
exit # BE exit # BE

View file

@ -118,7 +118,7 @@ main(int argc,
struct stat st; struct stat st;
int fd = 0; /* stdin */ int fd = 0; /* stdin */
cxobj *xcfg = NULL; cxobj *xcfg = NULL;
cbuf *cberr; cbuf *cbret = NULL;
/* In the startup, logs to stderr & debug flag set later */ /* In the startup, logs to stderr & debug flag set later */
clicon_log_init(__FILE__, LOG_INFO, CLICON_LOG_STDERR); clicon_log_init(__FILE__, LOG_INFO, CLICON_LOG_STDERR);
@ -205,13 +205,13 @@ main(int argc,
if ((ret = json_parse_file(fd, yspec, &xt, &xerr)) < 0) if ((ret = json_parse_file(fd, yspec, &xt, &xerr)) < 0)
goto done; goto done;
if (ret == 0){ if (ret == 0){
xml_print(stderr, xerr); clicon_rpc_generate_error("util_xml", xerr);
goto done; goto done;
} }
} }
else{ else{
if (xml_parse_file(fd, "</config>", NULL, &xt) < 0){ if (xml_parse_file(fd, "</config>", NULL, &xt) < 0){
fprintf(stderr, "xml parse error %s\n", clicon_err_reason); fprintf(stderr, "xml parse error: %s\n", clicon_err_reason);
goto done; goto done;
} }
} }
@ -227,10 +227,6 @@ main(int argc,
/* 3. Validate data (if yspec) */ /* 3. Validate data (if yspec) */
if (validate){ if (validate){
xc = xml_child_i(xt, 0); xc = xml_child_i(xt, 0);
if ((cberr = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
/* Populate */ /* Populate */
if (xml_apply0(xc, CX_ELMNT, xml_spec_populate, yspec) < 0) if (xml_apply0(xc, CX_ELMNT, xml_spec_populate, yspec) < 0)
goto done; goto done;
@ -242,12 +238,14 @@ main(int argc,
goto done; goto done;
if (xml_apply0(xc, -1, xml_sort_verify, h) < 0) if (xml_apply0(xc, -1, xml_sort_verify, h) < 0)
clicon_log(LOG_NOTICE, "%s: sort verify failed", __FUNCTION__); clicon_log(LOG_NOTICE, "%s: sort verify failed", __FUNCTION__);
if ((ret = xml_yang_validate_all_top(h, xc, cberr)) < 0) if ((ret = xml_yang_validate_all_top(h, xc, &xerr)) < 0)
goto done; goto done;
if (ret > 0 && (ret = xml_yang_validate_add(h, xc, cberr)) < 0) if (ret > 0 && (ret = xml_yang_validate_add(h, xc, &xerr)) < 0)
goto done; goto done;
if (ret == 0){ if (ret == 0){
fprintf(stderr, "%s", cbuf_get(cberr)); if (netconf_err2cb(xerr, &cbret) < 0)
goto done;
fprintf(stderr, "xml validation error: %s\n", cbuf_get(cbret));
goto done; goto done;
} }
} }
@ -264,6 +262,8 @@ main(int argc,
} }
retval = 0; retval = 0;
done: done:
if (cbret)
cbuf_free(cbret);
if (xt) if (xt)
xml_free(xt); xml_free(xt);
if (cb) if (cb)