* Add multiple yang support also for obsolete versions

* This means that files and datastores supporting modstate also looks for deleted or updated yang modules.
  * A stricter binding which gives error if loading outdated YANG file does not exist.
* Stricter yang checks: you cannot do get-config on datastores that have obsolete YANG
* Added xerr output parameter to `xmldb_get0()`
This commit is contained in:
Olof hagsand 2021-03-16 15:25:34 +01:00
parent d542cd5530
commit 8469a0962e
20 changed files with 328 additions and 118 deletions

View file

@ -33,14 +33,17 @@ Expected: April
### New features ### New features
* Add multiple yang support also for obsolete versions
* This means that files and datastores supporting modstate also looks for deleted or updated yang modules.
* A stricter binding which gives error if loading outdated YANG file does not exist.
### API changes on existing protocol/config features ### API changes on existing protocol/config features
* Native RESTCONF mode * Native RESTCONF mode
* Renamed restconf "evhtp" mode to "native" mode * Renamed restconf "evhtp" mode to "native" mode
* To configure native mode use: `configure --with-restconf=native`, changed from: `configure --with-restconf=evhtp` * To configure native mode use: `configure --with-restconf=native`, changed from: `configure --with-restconf=evhtp`
* Native mode MUST use libevhtp from https://github.com/clixon/clixon-libevhtp.git instead from criticalstack * Native mode MUST use libevhtp from https://github.com/clixon/clixon-libevhtp.git instead from criticalstack
* Stricter yang checks: you cannot do get-config on datastores that have obsolete YANG.
* NETCONF Hello message semantics has been made stricter according to RFC 6241 Sec 8.1, for example: * NETCONF Hello message semantics has been made stricter according to RFC 6241 Sec 8.1, for example:
* A client MUST send a <hello> element. * A client MUST send a <hello> element.
* Each peer MUST send at least the base NETCONF capability, "urn:ietf:params:netconf:base:1.1" (or 1.0 for RFC 4741) * Each peer MUST send at least the base NETCONF capability, "urn:ietf:params:netconf:base:1.1" (or 1.0 for RFC 4741)
@ -59,6 +62,7 @@ Developers may need to change their code
* Removed `cli_debug()`. Use `cli_debug_backend()` or `cli_debug_restconf()` instead. * Removed `cli_debug()`. Use `cli_debug_backend()` or `cli_debug_restconf()` instead.
* Removed `yspec_free()` - replace with `ys_free()` * Removed `yspec_free()` - replace with `ys_free()`
* Added xerr output parameter to `xmldb_get0()`
* Removed `endtag` parameter of `clixon_xml_parse_file()` * Removed `endtag` parameter of `clixon_xml_parse_file()`
* Restconf authentication callback (ca_auth) signature changed (again) * Restconf authentication callback (ca_auth) signature changed (again)
* Minor modification to 5.0 change: userp removed. * Minor modification to 5.0 change: userp removed.

View file

@ -419,17 +419,24 @@ client_get_config_only(clicon_handle h,
cxobj *xret = NULL; cxobj *xret = NULL;
cxobj *xnacm = NULL; cxobj *xnacm = NULL;
cxobj **xvec = NULL; cxobj **xvec = NULL;
cxobj *xerr = NULL;
size_t xlen; size_t xlen;
int ret;
/* Note xret can be pruned by nacm below (and change name), /* Note xret can be pruned by nacm below (and change name),
* so zero-copy cant be used * so zero-copy cant be used
* Also, must use external namespace context here due to <filter stmt * Also, must use external namespace context here due to <filter stmt
*/ */
if (xmldb_get0(h, db, YB_MODULE, nsc, xpath, 1, &xret, NULL) < 0) { if ((ret = xmldb_get0(h, db, YB_MODULE, nsc, xpath, 1, &xret, NULL, &xerr)) < 0) {
if (netconf_operation_failed(cbret, "application", "read registry")< 0) if (netconf_operation_failed(cbret, "application", "read registry")< 0)
goto done; goto done;
goto ok; goto ok;
} }
if (ret == 0){
if (clicon_xml2cbuf(cbret, xerr, 0, 0, -1) < 0)
goto done;
goto ok;
}
/* Pre-NACM access step */ /* Pre-NACM access step */
xnacm = clicon_nacm_cache(h); xnacm = clicon_nacm_cache(h);
if (xnacm != NULL){ /* Do NACM validation */ if (xnacm != NULL){ /* Do NACM validation */
@ -452,6 +459,8 @@ client_get_config_only(clicon_handle h,
ok: ok:
retval = 0; retval = 0;
done: done:
if (xerr)
xml_free(xerr);
if (xvec) if (xvec)
free(xvec); free(xvec);
if (xret) if (xret)
@ -1120,14 +1129,14 @@ from_client_get(clicon_handle h,
* Also, must use external namespace context here due to <filter> stmt * Also, must use external namespace context here due to <filter> stmt
*/ */
if (clicon_option_bool(h, "CLICON_VALIDATE_STATE_XML")){ if (clicon_option_bool(h, "CLICON_VALIDATE_STATE_XML")){
if (xmldb_get0(h, "running", YB_MODULE, nsc, NULL, 1, &xret, NULL) < 0) { if (xmldb_get0(h, "running", YB_MODULE, nsc, NULL, 1, &xret, NULL, NULL) < 0) {
if (netconf_operation_failed(cbret, "application", "read registry")< 0) if (netconf_operation_failed(cbret, "application", "read registry")< 0)
goto done; goto done;
goto ok; goto ok;
} }
} }
else{ else{
if (xmldb_get0(h, "running", YB_MODULE, nsc, xpath, 1, &xret, NULL) < 0) { if (xmldb_get0(h, "running", YB_MODULE, nsc, xpath, 1, &xret, NULL, NULL) < 0) {
if (netconf_operation_failed(cbret, "application", "read registry")< 0) if (netconf_operation_failed(cbret, "application", "read registry")< 0)
goto done; goto done;
goto ok; goto ok;

View file

@ -203,8 +203,9 @@ startup_common(clicon_handle h,
/* Get the startup datastore WITHOUT binding to YANG, sorting and default setting. /* Get the startup datastore WITHOUT binding to YANG, sorting and default setting.
* It is done below, later in this function * It is done below, later in this function
*/ */
if (xmldb_get0(h, db, YB_NONE, NULL, "/", 0, &xt, msdiff) < 0) if ((ret = xmldb_get0(h, db, YB_NONE, NULL, "/", 0, &xt, msdiff, NULL)) < 0)
goto done; goto done;
/* ret should not be 0 */
if ((yspec = clicon_dbspec_yang(h)) == NULL){ if ((yspec = clicon_dbspec_yang(h)) == NULL){
clicon_err(OE_YANG, 0, "Yang spec not set"); clicon_err(OE_YANG, 0, "Yang spec not set");
goto done; goto done;
@ -484,7 +485,7 @@ from_validate_common(clicon_handle h,
goto done; goto done;
} }
/* This is the state we are going to */ /* This is the state we are going to */
if (xmldb_get0(h, candidate, YB_MODULE, NULL, "/", 0, &td->td_target, NULL) < 0) if (xmldb_get0(h, candidate, YB_MODULE, NULL, "/", 0, &td->td_target, NULL, NULL) < 0)
goto done; goto done;
/* Clear flags xpath for get */ /* Clear flags xpath for get */
@ -492,7 +493,7 @@ from_validate_common(clicon_handle h,
(void*)(XML_FLAG_MARK|XML_FLAG_CHANGE)); (void*)(XML_FLAG_MARK|XML_FLAG_CHANGE));
/* 2. Parse xml trees /* 2. Parse xml trees
* This is the state we are going from */ * This is the state we are going from */
if (xmldb_get0(h, "running", YB_MODULE, NULL, "/", 0, &td->td_src, NULL) < 0) if (xmldb_get0(h, "running", YB_MODULE, NULL, "/", 0, &td->td_src, NULL, NULL) < 0)
goto done; goto done;
/* Clear flags xpath for get */ /* Clear flags xpath for get */
xml_apply0(td->td_src, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, xml_apply0(td->td_src, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset,
@ -884,7 +885,7 @@ from_client_restart_one(clicon_handle h,
if ((td = transaction_new()) == NULL) if ((td = transaction_new()) == NULL)
goto done; goto done;
/* This is the state we are going to */ /* This is the state we are going to */
if (xmldb_get0(h, "running", YB_MODULE, NULL, "/", 0, &td->td_target, NULL) < 0) if (xmldb_get0(h, "running", YB_MODULE, NULL, "/", 0, &td->td_target, NULL, NULL) < 0)
goto done; goto done;
if ((ret = xml_yang_validate_all_top(h, td->td_target, &xerr)) < 0) if ((ret = xml_yang_validate_all_top(h, td->td_target, &xerr)) < 0)
goto done; goto done;
@ -894,7 +895,7 @@ from_client_restart_one(clicon_handle h,
goto fail; goto fail;
} }
/* This is the state we are going from */ /* This is the state we are going from */
if (xmldb_get0(h, db, YB_MODULE, NULL, "/", 0, &td->td_src, NULL) < 0) if (xmldb_get0(h, db, YB_MODULE, NULL, "/", 0, &td->td_src, NULL, NULL) < 0)
goto done; goto done;
/* 3. Compute differences */ /* 3. Compute differences */

View file

@ -946,6 +946,8 @@ main(int argc,
if (startup_failsafe(h) < 0){ if (startup_failsafe(h) < 0){
goto done; goto done;
} }
status = STARTUP_OK;
cbuf_reset(cbret); /* cbret contains error info */
} }
/* Initiate the shared candidate. */ /* Initiate the shared candidate. */

View file

@ -86,7 +86,7 @@ db_merge(clicon_handle h,
cxobj *xt = NULL; cxobj *xt = NULL;
/* Get data as xml from db1 */ /* Get data as xml from db1 */
if (xmldb_get0(h, (char*)db1, YB_MODULE, NULL, NULL, 0, &xt, NULL) < 0) if (xmldb_get0(h, (char*)db1, YB_MODULE, NULL, NULL, 0, &xt, NULL, NULL) < 0)
goto done; goto done;
xml_name_set(xt, NETCONF_INPUT_CONFIG); xml_name_set(xt, NETCONF_INPUT_CONFIG);
/* Merge xml into db2. Without commit */ /* Merge xml into db2. Without commit */

View file

@ -439,7 +439,7 @@ example_statedata(clicon_handle h,
* Get config according to xpath */ * Get config according to xpath */
if ((nsc1 = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:yang:ietf-interfaces")) == NULL) if ((nsc1 = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:yang:ietf-interfaces")) == NULL)
goto done; goto done;
if (xmldb_get0(h, "running", YB_MODULE, nsc1, "/interfaces/interface/name", 1, &xt, NULL) < 0) if (xmldb_get0(h, "running", YB_MODULE, nsc1, "/interfaces/interface/name", 1, &xt, NULL, NULL) < 0)
goto done; goto done;
if (xpath_vec(xt, nsc1, "/interfaces/interface/name", &xvec, &xlen) < 0) if (xpath_vec(xt, nsc1, "/interfaces/interface/name", &xvec, &xlen) < 0)
goto done; goto done;

View file

@ -53,7 +53,7 @@ int xmldb_disconnect(clicon_handle h);
int xmldb_get(clicon_handle h, const char *db, cvec *nsc, char *xpath, cxobj **xtop); int xmldb_get(clicon_handle h, const char *db, cvec *nsc, char *xpath, cxobj **xtop);
int xmldb_get0(clicon_handle h, const char *db, yang_bind yb, int xmldb_get0(clicon_handle h, const char *db, yang_bind yb,
cvec *nsc, const char *xpath, cvec *nsc, const char *xpath,
int copy, cxobj **xtop, modstate_diff_t *msd); int copy, cxobj **xtop, modstate_diff_t *msd, cxobj **xerr);
int xmldb_get0_clear(clicon_handle h, cxobj *x); int xmldb_get0_clear(clicon_handle h, cxobj *x);
int xmldb_get0_free(clicon_handle h, cxobj **xp); int xmldb_get0_free(clicon_handle h, cxobj **xp);
int xmldb_put(clicon_handle h, const char *db, enum operation_type op, cxobj *xt, char *username, cbuf *cbret); /* in clixon_datastore_write.[ch] */ int xmldb_put(clicon_handle h, const char *db, enum operation_type op, cxobj *xt, char *username, cbuf *cbret); /* in clixon_datastore_write.[ch] */

View file

@ -211,10 +211,12 @@ yang_stmt *yspec_new(void);
yang_stmt *ys_new(enum rfc_6020 keyw); yang_stmt *ys_new(enum rfc_6020 keyw);
yang_stmt *ys_prune(yang_stmt *yp, int i); yang_stmt *ys_prune(yang_stmt *yp, int i);
int ys_free1(yang_stmt *ys, int self);
int ys_free(yang_stmt *ys); int ys_free(yang_stmt *ys);
int ys_cp(yang_stmt *nw, yang_stmt *old); int ys_cp(yang_stmt *nw, yang_stmt *old);
yang_stmt *ys_dup(yang_stmt *old); yang_stmt *ys_dup(yang_stmt *old);
int yn_insert(yang_stmt *ys_parent, yang_stmt *ys_child); int yn_insert(yang_stmt *ys_parent, yang_stmt *ys_child);
int yn_insert1(yang_stmt *ys_parent, yang_stmt *ys_child);
yang_stmt *yn_each(yang_stmt *yn, yang_stmt *ys); yang_stmt *yn_each(yang_stmt *yn, yang_stmt *ys);
char *yang_key2str(int keyword); char *yang_key2str(int keyword);
int ys_module_by_xml(yang_stmt *ysp, struct xml *xt, yang_stmt **ymodp); int ys_module_by_xml(yang_stmt *ysp, struct xml *xt, yang_stmt **ymodp);

View file

@ -73,6 +73,8 @@ int clixon_module_upgrade(clicon_handle h, cxobj *xt, modstate_diff_t *msd, cbuf
yang_stmt *yang_find_module_by_prefix(yang_stmt *ys, char *prefix); yang_stmt *yang_find_module_by_prefix(yang_stmt *ys, char *prefix);
yang_stmt *yang_find_module_by_prefix_yspec(yang_stmt *yspec, char *prefix); yang_stmt *yang_find_module_by_prefix_yspec(yang_stmt *yspec, char *prefix);
yang_stmt *yang_find_module_by_namespace(yang_stmt *yspec, char *ns); yang_stmt *yang_find_module_by_namespace(yang_stmt *yspec, char *ns);
yang_stmt *yang_find_module_by_namespace_revision(yang_stmt *yspec, const char *ns, const char *revision);
yang_stmt *yang_find_module_by_name_revision(yang_stmt *yspec, const char *name, const char *revision);
yang_stmt *yang_find_module_by_name(yang_stmt *yspec, char *name); yang_stmt *yang_find_module_by_name(yang_stmt *yspec, char *name);
#endif /* _CLIXON_YANG_MODULE_H_ */ #endif /* _CLIXON_YANG_MODULE_H_ */

View file

@ -76,10 +76,10 @@
#include "clixon_path.h" #include "clixon_path.h"
#include "clixon_netconf_lib.h" #include "clixon_netconf_lib.h"
#include "clixon_yang_module.h" #include "clixon_yang_module.h"
#include "clixon_yang_parse_lib.h"
#include "clixon_xml_map.h" #include "clixon_xml_map.h"
#include "clixon_xml_io.h" #include "clixon_xml_io.h"
#include "clixon_xml_nsctx.h" #include "clixon_xml_nsctx.h"
#include "clixon_datastore.h" #include "clixon_datastore.h"
#include "clixon_datastore_read.h" #include "clixon_datastore_read.h"
@ -307,6 +307,7 @@ text_read_modstate(clicon_handle h,
clicon_err(OE_UNIX, errno, "strdup"); clicon_err(OE_UNIX, errno, "strdup");
goto done; goto done;
} }
continue;
} }
if (strcmp(xml_name(xf), "module")) if (strcmp(xml_name(xf), "module"))
continue; /* ignore other tags, such as module-set-id */ continue; /* ignore other tags, such as module-set-id */
@ -420,13 +421,14 @@ disable_nacm_on_empty(cxobj *xt,
* @param[out] xp XML tree read from file * @param[out] xp XML tree read from file
* @param[out] de If set, return db-element status (eg empty flag) * @param[out] de If set, return db-element status (eg empty flag)
* @param[out] msdiff If set, return modules-state differences * @param[out] msdiff If set, return modules-state differences
* @param[out] xerr XML error if retval is 0
* @retval -1 General error, check specific clicon_errno, clicon_suberrno * @retval -1 General error, check specific clicon_errno, clicon_suberrno
* @retval 0 Parse OK but yang assigment not made (or only partial) and xerr set * @retval 0 Parse OK but yang assigment not made (or only partial) and xerr set
* @retval 1 OK * @retval 1 OK
* @note Use of 1 for OK * @note Use of 1 for OK
* @note retval 0 is NYI because calling functions cannot handle it yet * @note retval 0 is NYI because calling functions cannot handle it yet
* XXX if this code pass tests this code can be rewritten, esp the modstate stuff
*/ */
#undef XMLDB_READFILE_FAIL /* See comment on retval = 0 above */
int int
xmldb_readfile(clicon_handle h, xmldb_readfile(clicon_handle h,
const char *db, const char *db,
@ -434,15 +436,30 @@ xmldb_readfile(clicon_handle h,
yang_stmt *yspec, yang_stmt *yspec,
cxobj **xp, cxobj **xp,
db_elmnt *de, db_elmnt *de,
modstate_diff_t *msdiff) modstate_diff_t *msdiff0,
cxobj **xerr)
{ {
int retval = -1; int retval = -1;
cxobj *x0 = NULL; cxobj *x0 = NULL;
char *dbfile = NULL; char *dbfile = NULL;
FILE *fp = NULL; FILE *fp = NULL;
char *format; char *format;
int ret; int ret;
modstate_diff_t *msdiff = NULL;
cxobj *xmsd; /* XML module state diff */
yang_stmt *ymod;
char *name;
char *ns; /* namespace */
char *rev; /* revision */
int needclone;
cxobj *xmodfile = NULL;
cxobj *x;
yang_stmt *yspec1 = NULL;
if (yb != YB_MODULE && yb != YB_NONE){
clicon_err(OE_XML, EINVAL, "yb is %d but should be module or none", yb);
goto done;
}
if (xmldb_db2file(h, db, &dbfile) < 0) if (xmldb_db2file(h, db, &dbfile) < 0)
goto done; goto done;
if (dbfile==NULL){ if (dbfile==NULL){
@ -458,19 +475,16 @@ xmldb_readfile(clicon_handle h,
clicon_err(OE_UNIX, errno, "open(%s)", dbfile); clicon_err(OE_UNIX, errno, "open(%s)", dbfile);
goto done; goto done;
} }
/* ret == 0 should not happen with YB_NONE. Binding is done later */
if (strcmp(format, "json")==0){ if (strcmp(format, "json")==0){
if ((ret = clixon_json_parse_file(fp, yb, yspec, &x0, NULL)) < 0) /* XXX: ret == 0*/ if (clixon_json_parse_file(fp, YB_NONE, yspec, &x0, xerr) < 0)
goto done; goto done;
} }
else { else {
if ((ret = clixon_xml_parse_file(fp, yb, yspec, &x0, NULL)) < 0){ if (clixon_xml_parse_file(fp, YB_NONE, yspec, &x0, xerr) < 0){
goto done; goto done;
} }
} }
#ifdef XMLDB_READFILE_FAIL /* The functions calling this function cannot handle a failed parse yet */
if (ret == 0)
goto fail;
#endif
/* Always assert a top-level called "config". /* Always assert a top-level called "config".
* To ensure that, deal with two cases: * To ensure that, deal with two cases:
* 1. File is empty <top/> -> rename top-level to "config" * 1. File is empty <top/> -> rename top-level to "config"
@ -491,15 +505,102 @@ xmldb_readfile(clicon_handle h,
/* Datastore files may contain module-state defining /* Datastore files may contain module-state defining
* which modules are used in the file. * which modules are used in the file.
* Strip module-state and return msdiff
*/ */
if (clicon_option_bool(h, "CLICON_XMLDB_MODSTATE"))
if ((msdiff = modstate_diff_new()) == NULL)
goto done;
if ((x = xml_find_type(x0, NULL, "modules-state", CX_ELMNT)) != NULL)
if ((xmodfile = xml_dup(x)) == NULL)
goto done;
if (text_read_modstate(h, yspec, x0, msdiff) < 0) if (text_read_modstate(h, yspec, x0, msdiff) < 0)
goto done; goto done;
if (yb == YB_MODULE){
if (msdiff){
/* Check if old/deleted yangs not present in the loaded/running yangspec.
* If so, append them to the global yspec
*/
needclone = 0;
xmsd = NULL;
while ((xmsd = xml_child_each(msdiff->md_diff, xmsd, CX_ELMNT)) != NULL) {
if (xml_flag(xmsd, XML_FLAG_CHANGE|XML_FLAG_DEL) == 0)
continue;
needclone++;
/* Extract name, namespace, and revision */
if ((name = xml_find_body(xmsd, "name")) == NULL)
continue;
if ((ns = xml_find_body(xmsd, "namespace")) == NULL)
continue;
/* Extract revision */
if ((rev = xml_find_body(xmsd, "revision")) == NULL)
continue;
if ((ymod = yang_find_module_by_namespace_revision(yspec, ns, rev)) == NULL){
/* Append it */
if (yang_spec_parse_module(h, name, rev, yspec) < 0){
/* Special case: file-not-found errors */
if (clicon_suberrno == ENOENT){
cbuf *cberr = NULL;
if ((cberr = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
cprintf(cberr, "Internal error: %s", clicon_err_reason);
clicon_err_reset();
if (netconf_operation_failed_xml(xerr, "application", cbuf_get(cberr))< 0)
goto done;
cbuf_free(cberr);
goto fail;
}
goto done;
}
}
}
/* If we found an obsolete yang module, we need to make a clone yspec with the
* exactly the yang modules found
*/
if (needclone && xmodfile){
if ((yspec1 = yspec_new()) == NULL)
goto done;
xmsd = NULL;
while ((xmsd = xml_child_each(xmodfile, xmsd, CX_ELMNT)) != NULL) {
if (strcmp(xml_name(xmsd), "module"))
continue;
if ((ns = xml_find_body(xmsd, "namespace")) == NULL)
continue;
if ((rev = xml_find_body(xmsd, "revision")) == NULL)
continue;
if ((ymod = yang_find_module_by_namespace_revision(yspec, ns, rev)) == NULL)
continue; // XXX error?
if (yn_insert1(yspec1, ymod) < 0)
goto done;
}
}
}
/* xml looks like: <top><config><x>... actually YB_MODULE_NEXT
*/
if ((ret = xml_bind_yang(x0, YB_MODULE, yspec1?yspec1:yspec, xerr)) < 0)
goto done;
if (ret == 0)
goto fail;
}
if (xp){ if (xp){
*xp = x0; *xp = x0;
x0 = NULL; x0 = NULL;
} }
if (msdiff0){
*msdiff0 = *msdiff;
free(msdiff); /* Just body */
msdiff = NULL;
}
retval = 1; retval = 1;
done: done:
if (yspec1){
ys_free1(yspec1, 1); // XXX free childvec
}
if (xmodfile)
xml_free(xmodfile);
if (msdiff)
modstate_diff_free(msdiff);
if (fp) if (fp)
fclose(fp); fclose(fp);
if (dbfile) if (dbfile)
@ -507,11 +608,9 @@ xmldb_readfile(clicon_handle h,
if (x0) if (x0)
xml_free(x0); xml_free(x0);
return retval; return retval;
#ifdef XMLDB_READFILE_FAIL /* The functions calling this function cannot handle a failed parse yet */
fail: fail:
retval = 0; retval = 0;
goto done; goto done;
#endif
} }
/*! Get content of database using xpath. return a set of matching sub-trees /*! Get content of database using xpath. return a set of matching sub-trees
@ -524,7 +623,8 @@ xmldb_readfile(clicon_handle h,
* @param[in] nsc External XML namespace context, or NULL * @param[in] nsc External XML namespace context, or NULL
* @param[in] xpath String with XPATH syntax. or NULL for all * @param[in] xpath String with XPATH syntax. or NULL for all
* @param[out] xret Single return XML tree. Free with xml_free() * @param[out] xret Single return XML tree. Free with xml_free()
* @param[out] msdiff If set, return modules-state differences * @param[out] msdiff If set, return modules-state differences
* @param[out] xerr XML error if retval is 0
* @retval -1 General error, check specific clicon_errno, clicon_suberrno * @retval -1 General error, check specific clicon_errno, clicon_suberrno
* @retval 0 Parse OK but yang assigment not made (or only partial) and xerr set * @retval 0 Parse OK but yang assigment not made (or only partial) and xerr set
* @retval 1 OK * @retval 1 OK
@ -538,7 +638,8 @@ xmldb_get_nocache(clicon_handle h,
cvec *nsc, cvec *nsc,
const char *xpath, const char *xpath,
cxobj **xtop, cxobj **xtop,
modstate_diff_t *msdiff) modstate_diff_t *msdiff,
cxobj **xerr)
{ {
int retval = -1; int retval = -1;
char *dbfile = NULL; char *dbfile = NULL;
@ -557,9 +658,7 @@ xmldb_get_nocache(clicon_handle h,
goto done; goto done;
} }
/* xml looks like: <top><config><x>... where "x" is a top-level symbol in a module */ /* xml looks like: <top><config><x>... where "x" is a top-level symbol in a module */
if ((ret = xmldb_readfile(h, db, if ((ret = xmldb_readfile(h, db, yb, yspec, &xt, &de0, msdiff, xerr)) < 0)
yb==YB_MODULE?YB_MODULE_NEXT:yb,
yspec, &xt, &de0, msdiff)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0)
goto fail; goto fail;
@ -635,7 +734,8 @@ xmldb_get_nocache(clicon_handle h,
* @param[in] nsc External XML namespace context, or NULL * @param[in] nsc External XML namespace context, or NULL
* @param[in] xpath String with XPATH syntax. or NULL for all * @param[in] xpath String with XPATH syntax. or NULL for all
* @param[out] xret Single return XML tree. Free with xml_free() * @param[out] xret Single return XML tree. Free with xml_free()
* @param[out] msdiff If set, return modules-state differences * @param[out] msdiff If set, return modules-state differences
* @param[out] xerr XML error if retval is 0
* @retval -1 General error, check specific clicon_errno, clicon_suberrno * @retval -1 General error, check specific clicon_errno, clicon_suberrno
* @retval 0 Parse OK but yang assigment not made (or only partial) and xerr set * @retval 0 Parse OK but yang assigment not made (or only partial) and xerr set
* @retval 1 OK * @retval 1 OK
@ -649,19 +749,21 @@ xmldb_get_cache(clicon_handle h,
cvec *nsc, cvec *nsc,
const char *xpath, const char *xpath,
cxobj **xtop, cxobj **xtop,
modstate_diff_t *msdiff) modstate_diff_t *msdiff,
cxobj **xerr)
{ {
int retval = -1; int retval = -1;
yang_stmt *yspec; yang_stmt *yspec;
cxobj *x0t = NULL; /* (cached) top of tree */ cxobj *x0t = NULL; /* (cached) top of tree */
cxobj *x0; cxobj *x0;
cxobj **xvec = NULL; cxobj **xvec = NULL;
size_t xlen; size_t xlen;
int i; int i;
db_elmnt *de = NULL; db_elmnt *de = NULL;
cxobj *x1t = NULL; cxobj *x1t = NULL;
db_elmnt de0 = {0,}; db_elmnt de0 = {0,};
int ret; int ret;
if ((yspec = clicon_dbspec_yang(h)) == NULL){ if ((yspec = clicon_dbspec_yang(h)) == NULL){
clicon_err(OE_YANG, ENOENT, "No yang spec"); clicon_err(OE_YANG, ENOENT, "No yang spec");
@ -671,9 +773,7 @@ xmldb_get_cache(clicon_handle h,
if (de == NULL || de->de_xml == NULL){ /* Cache miss, read XML from file */ if (de == NULL || de->de_xml == NULL){ /* Cache miss, read XML from file */
/* If there is no xml x0 tree (in cache), then read it from file */ /* If there is no xml x0 tree (in cache), then read it from file */
/* xml looks like: <top><config><x>... where "x" is a top-level symbol in a module */ /* xml looks like: <top><config><x>... where "x" is a top-level symbol in a module */
if ((ret = xmldb_readfile(h, db, if ((ret = xmldb_readfile(h, db, yb, yspec, &x0t, &de0, msdiff, xerr)) < 0)
yb==YB_MODULE?YB_MODULE_NEXT:yb,
yspec, &x0t, &de0, msdiff)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0)
goto fail; goto fail;
@ -686,9 +786,12 @@ xmldb_get_cache(clicon_handle h,
else else
x0t = de->de_xml; x0t = de->de_xml;
if (yb == YB_MODULE && !xml_spec(x0t)) if (yb == YB_MODULE && !xml_spec(x0t)){
if (xml_bind_yang(x0t, YB_MODULE, yspec, NULL) < 0) if ((ret = xml_bind_yang(x0t, YB_MODULE, yspec, xerr)) < 0)
goto done; goto done;
if (ret == 0)
; /* XXX */
}
/* Here x0t looks like: <config>...</config> */ /* Here x0t looks like: <config>...</config> */
/* Given the xpath, return a vector of matches in xvec /* Given the xpath, return a vector of matches in xvec
@ -784,7 +887,8 @@ xmldb_get_cache(clicon_handle h,
* @param[in] xpath String with XPATH syntax. or NULL for all * @param[in] xpath String with XPATH syntax. or NULL for all
* @param[in] config If set only configuration data, else also state * @param[in] config If set only configuration data, else also state
* @param[out] xret Single return XML tree. Free with xml_free() * @param[out] xret Single return XML tree. Free with xml_free()
* @param[out] msdiff If set, return modules-state differences * @param[out] msdiff If set, return modules-state differences
* @param[out] xerr XML error if retval is 0
* @retval -1 General error, check specific clicon_errno, clicon_suberrno * @retval -1 General error, check specific clicon_errno, clicon_suberrno
* @retval 0 Parse OK but yang assigment not made (or only partial) and xerr set * @retval 0 Parse OK but yang assigment not made (or only partial) and xerr set
* @retval 1 OK * @retval 1 OK
@ -797,7 +901,9 @@ xmldb_get_zerocopy(clicon_handle h,
cvec *nsc, cvec *nsc,
const char *xpath, const char *xpath,
cxobj **xtop, cxobj **xtop,
modstate_diff_t *msdiff) modstate_diff_t *msdiff,
cxobj **xerr)
{ {
int retval = -1; int retval = -1;
yang_stmt *yspec; yang_stmt *yspec;
@ -818,9 +924,7 @@ xmldb_get_zerocopy(clicon_handle h,
if (de == NULL || de->de_xml == NULL){ /* Cache miss, read XML from file */ if (de == NULL || de->de_xml == NULL){ /* Cache miss, read XML from file */
/* If there is no xml x0 tree (in cache), then read it from file */ /* If there is no xml x0 tree (in cache), then read it from file */
/* xml looks like: <top><config><x>... where "x" is a top-level symbol in a module */ /* xml looks like: <top><config><x>... where "x" is a top-level symbol in a module */
if ((ret = xmldb_readfile(h, db, if ((ret = xmldb_readfile(h, db, yb, yspec, &x0t, &de0, msdiff, xerr)) < 0)
yb==YB_MODULE?YB_MODULE_NEXT:yb,
yspec, &x0t, &de0, msdiff)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0)
goto fail; goto fail;
@ -896,7 +1000,7 @@ xmldb_get(clicon_handle h,
char *xpath, char *xpath,
cxobj **xret) cxobj **xret)
{ {
return xmldb_get0(h, db, YB_MODULE, nsc, xpath, 1, xret, NULL); return xmldb_get0(h, db, YB_MODULE, nsc, xpath, 1, xret, NULL, NULL);
} }
/*! Zero-copy variant of get content of database /*! Zero-copy variant of get content of database
@ -915,13 +1019,14 @@ xmldb_get(clicon_handle h,
* @param[in] copy Force copy. Overrides cache_zerocopy -> cache * @param[in] copy Force copy. Overrides cache_zerocopy -> cache
* @param[out] xret Single return XML tree. Free with xml_free() * @param[out] xret Single return XML tree. Free with xml_free()
* @param[out] msdiff If set, return modules-state differences (upgrade code) * @param[out] msdiff If set, return modules-state differences (upgrade code)
* @param[out] xerr XML error if retval is 0
* @retval -1 General error, check specific clicon_errno, clicon_suberrno * @retval -1 General error, check specific clicon_errno, clicon_suberrno
* @retval 0 Parse OK but yang assigment not made (or only partial) and xerr set * @retval 0 Parse OK but yang assigment not made (or only partial) and xerr set
* @retval 1 OK * @retval 1 OK
* @note Use of 1 for OK * @note Use of 1 for OK
* @code * @code
* cxobj *xt; * cxobj *xt;
* if (xmldb_get0(h, "running", YB_MODULE, nsc, "/interface[name="eth"]", 0, &xt, NULL) < 0) * if (xmldb_get0(h, "running", YB_MODULE, nsc, "/interface[name="eth"]", 0, &xt, NULL, NULL) < 0)
* err; * err;
* ... * ...
* xmldb_get0_clear(h, xt); # Clear tree from default values and flags * xmldb_get0_clear(h, xt); # Clear tree from default values and flags
@ -938,7 +1043,7 @@ xmldb_get(clicon_handle h,
* And a db content: * And a db content:
* <c><x>1</x></c> * <c><x>1</x></c>
* With the following call: * With the following call:
* xmldb_get0(h, "running", NULL, NULL, "/c[x=0]", 1, &xt, NULL) * xmldb_get0(h, "running", NULL, NULL, "/c[x=0]", 1, &xt, NULL, NULL)
* which result in a miss (there is no c with x=0), but when the returned xt is printed * which result in a miss (there is no c with x=0), but when the returned xt is printed
* (the existing tree is discarded), the default (empty) xml tree is: * (the existing tree is discarded), the default (empty) xml tree is:
* <c><x>0</x></c> * <c><x>0</x></c>
@ -951,7 +1056,8 @@ xmldb_get0(clicon_handle h,
const char *xpath, const char *xpath,
int copy, int copy,
cxobj **xret, cxobj **xret,
modstate_diff_t *msdiff) modstate_diff_t *msdiff,
cxobj **xerr)
{ {
int retval = -1; int retval = -1;
@ -961,7 +1067,7 @@ xmldb_get0(clicon_handle h,
* Add default values in copy * Add default values in copy
* Copy deleted by xmldb_free * Copy deleted by xmldb_free
*/ */
retval = xmldb_get_nocache(h, db, yb, nsc, xpath, xret, msdiff); retval = xmldb_get_nocache(h, db, yb, nsc, xpath, xret, msdiff, xerr);
break; break;
case DATASTORE_CACHE_ZEROCOPY: case DATASTORE_CACHE_ZEROCOPY:
/* Get cache (file if empty) mark xpath match in original tree /* Get cache (file if empty) mark xpath match in original tree
@ -969,7 +1075,7 @@ xmldb_get0(clicon_handle h,
* Default values and markings removed in xmldb_clear * Default values and markings removed in xmldb_clear
*/ */
if (!copy){ if (!copy){
retval = xmldb_get_zerocopy(h, db, yb, nsc, xpath, xret, msdiff); retval = xmldb_get_zerocopy(h, db, yb, nsc, xpath, xret, msdiff, xerr);
break; break;
} }
/* fall through */ /* fall through */
@ -978,7 +1084,7 @@ xmldb_get0(clicon_handle h,
* Add default values in copy, return copy * Add default values in copy, return copy
* Copy deleted by xmldb_free * Copy deleted by xmldb_free
*/ */
retval = xmldb_get_cache(h, db, yb, nsc, xpath, xret, msdiff); retval = xmldb_get_cache(h, db, yb, nsc, xpath, xret, msdiff, xerr);
break; break;
} }
return retval; return retval;

View file

@ -42,6 +42,6 @@
* Prototypes * Prototypes
*/ */
int xmldb_readfile(clicon_handle h, const char *db, yang_bind yb, yang_stmt *yspec, int xmldb_readfile(clicon_handle h, const char *db, yang_bind yb, yang_stmt *yspec,
cxobj **xp, db_elmnt *de, modstate_diff_t *msd); cxobj **xp, db_elmnt *de, modstate_diff_t *msd, cxobj **xerr);
#endif /* _CLIXON_DATASTORE_READ_H */ #endif /* _CLIXON_DATASTORE_READ_H */

View file

@ -910,22 +910,23 @@ xmldb_put(clicon_handle h,
char *username, char *username,
cbuf *cbret) cbuf *cbret)
{ {
int retval = -1; int retval = -1;
char *dbfile = NULL; char *dbfile = NULL;
FILE *f = NULL; FILE *f = NULL;
cbuf *cb = NULL; cbuf *cb = NULL;
yang_stmt *yspec; yang_stmt *yspec;
cxobj *x0 = NULL; cxobj *x0 = NULL;
db_elmnt *de = NULL; db_elmnt *de = NULL;
int ret; int ret;
cxobj *xnacm = NULL; cxobj *xnacm = NULL;
cxobj *xmodst = NULL; cxobj *xmodst = NULL;
cxobj *x; cxobj *x;
int permit = 0; /* nacm permit all */ int permit = 0; /* nacm permit all */
char *format; char *format;
cvec *nsc = NULL; /* nacm namespace context */ cvec *nsc = NULL; /* nacm namespace context */
int firsttime = 0; int firsttime = 0;
int pretty; int pretty;
cxobj *xerr = NULL;
if (cbret == NULL){ if (cbret == NULL){
clicon_err(OE_XML, EINVAL, "cbret is NULL"); clicon_err(OE_XML, EINVAL, "cbret is NULL");
@ -948,7 +949,7 @@ xmldb_put(clicon_handle h,
if (x0 == NULL){ if (x0 == NULL){
firsttime++; /* to avoid leakage on error, see fail from text_modify */ firsttime++; /* to avoid leakage on error, see fail from text_modify */
/* xml looks like: <top><config><x>... where "x" is a top-level symbol in a module */ /* xml looks like: <top><config><x>... where "x" is a top-level symbol in a module */
if ((ret = xmldb_readfile(h, db, YB_MODULE_NEXT, yspec, &x0, de, NULL)) < 0) if ((ret = xmldb_readfile(h, db, YB_MODULE, yspec, &x0, de, NULL, &xerr)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0)
goto fail; goto fail;
@ -1052,6 +1053,8 @@ xmldb_put(clicon_handle h,
done: done:
if (f != NULL) if (f != NULL)
fclose(f); fclose(f);
if (xerr)
xml_free(xerr);
if (nsc) if (nsc)
xml_nsctx_free(nsc); xml_nsctx_free(nsc);
if (dbfile) if (dbfile)

View file

@ -1212,7 +1212,7 @@ nacm_access_pre(clicon_handle h,
goto done; goto done;
} }
else if (strcmp(mode, "internal")==0){ else if (strcmp(mode, "internal")==0){
if (xmldb_get0(h, "running", YB_MODULE, nsc, "nacm", 1, &xnacm0, NULL) < 0) if (xmldb_get0(h, "running", YB_MODULE, nsc, "nacm", 1, &xnacm0, NULL, NULL) < 0)
goto done; goto done;
} }
else{ else{

View file

@ -355,7 +355,6 @@ xml_bind_yang(cxobj *xt,
int retval = -1; int retval = -1;
cxobj *xc; /* xml child */ cxobj *xc; /* xml child */
int ret; int ret;
int failed = 0; /* we continue loop after failure, should we stop at fail?`*/
strip_whitespace(xt); strip_whitespace(xt);
xc = NULL; /* Apply on children */ xc = NULL; /* Apply on children */
@ -363,10 +362,8 @@ xml_bind_yang(cxobj *xt,
if ((ret = xml_bind_yang0(xc, yb, yspec, xerr)) < 0) if ((ret = xml_bind_yang0(xc, yb, yspec, xerr)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0)
failed++; goto fail;
} }
if (failed)
goto fail;
retval = 1; retval = 1;
done: done:
return retval; return retval;
@ -384,7 +381,6 @@ xml_bind_yang0_opt(cxobj *xt,
int retval = -1; int retval = -1;
cxobj *xc; /* xml child */ cxobj *xc; /* xml child */
int ret; int ret;
int failed = 0; /* we continue loop after failure, should we stop at fail?`*/
yang_stmt *yc0 = NULL; yang_stmt *yc0 = NULL;
cxobj *xc0 = NULL; cxobj *xc0 = NULL;
cxobj *xs; cxobj *xs;
@ -428,14 +424,12 @@ xml_bind_yang0_opt(cxobj *xt,
else if ((ret = xml_bind_yang0_opt(xc, YB_PARENT, NULL, xerr)) < 0) else if ((ret = xml_bind_yang0_opt(xc, YB_PARENT, NULL, xerr)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0)
failed++; goto fail;
xc0 = xc; xc0 = xc;
yc0 = xml_spec(xc); /* cache */ yc0 = xml_spec(xc); /* cache */
name0 = xml_name(xc); name0 = xml_name(xc);
prefix0 = xml_prefix(xc); prefix0 = xml_prefix(xc);
} }
if (failed)
goto fail;
ok: ok:
retval = 1; retval = 1;
done: done:
@ -466,7 +460,6 @@ xml_bind_yang0(cxobj *xt,
int retval = -1; int retval = -1;
cxobj *xc; /* xml child */ cxobj *xc; /* xml child */
int ret; int ret;
int failed = 0; /* we continue loop after failure, should we stop at fail?`*/
switch (yb){ switch (yb){
case YB_MODULE: case YB_MODULE:
@ -495,10 +488,8 @@ xml_bind_yang0(cxobj *xt,
if ((ret = xml_bind_yang0_opt(xc, YB_PARENT, NULL, xerr)) < 0) if ((ret = xml_bind_yang0_opt(xc, YB_PARENT, NULL, xerr)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0)
failed++; goto fail;
} }
if (failed)
goto fail;
ok: ok:
retval = 1; retval = 1;
done: done:

View file

@ -452,7 +452,7 @@ ys_new(enum rfc_6020 keyw)
* @retval -1 Error * @retval -1 Error
* @see ys_free * @see ys_free
*/ */
static int int
ys_free1(yang_stmt *ys, ys_free1(yang_stmt *ys,
int self) int self)
{ {
@ -708,6 +708,20 @@ yn_insert(yang_stmt *ys_parent,
return 0; return 0;
} }
/*! Variant of yn_insert where parent is not set
*/
int
yn_insert1(yang_stmt *ys_parent,
yang_stmt *ys_child)
{
int pos = ys_parent->ys_len;
if (yn_realloc(ys_parent) < 0)
return -1;
ys_parent->ys_stmt[pos] = ys_child;
return 0;
}
/*! Iterate through all yang statements from a yang node /*! Iterate through all yang statements from a yang node
* *
* @param[in] yparent yang statement whose children should be iterated * @param[in] yparent yang statement whose children should be iterated

View file

@ -86,6 +86,7 @@ modstate_diff_t *
modstate_diff_new(void) modstate_diff_new(void)
{ {
modstate_diff_t *md; modstate_diff_t *md;
if ((md = malloc(sizeof(modstate_diff_t))) == NULL){ if ((md = malloc(sizeof(modstate_diff_t))) == NULL){
clicon_err(OE_UNIX, errno, "malloc"); clicon_err(OE_UNIX, errno, "malloc");
return NULL; return NULL;
@ -582,6 +583,83 @@ yang_find_module_by_namespace(yang_stmt *yspec,
return ymod; return ymod;
} }
/*! Given a yang spec, a namespace and revision, return yang module
*
* @param[in] yspec A yang specification
* @param[in] ns Namespace
* @param[in] rev Revision
* @retval ymod Yang module statement if found
* @retval NULL not found
* @see yang_find_module_by_namespace
* @note a module may have many revisions, but only the first is significant
*/
yang_stmt *
yang_find_module_by_namespace_revision(yang_stmt *yspec,
const char *ns,
const char *rev)
{
yang_stmt *ymod = NULL;
yang_stmt *yrev;
char *rev1;
if (ns == NULL || rev == NULL){
clicon_err(OE_CFG, EINVAL, "No ns or rev");
goto done;
}
while ((ymod = yn_each(yspec, ymod)) != NULL) {
if (yang_find(ymod, Y_NAMESPACE, ns) != NULL)
/* Get FIRST revision */
if ((yrev = yang_find(ymod, Y_REVISION, NULL)) != NULL){
rev1 = yang_argument_get(yrev);
if (strcmp(rev, rev1) == 0)
break; /* return this ymod */
}
}
done:
return ymod;
}
/*! Given a yang spec, name and revision, return yang module
*
* @param[in] yspec A yang specification
* @param[in] name Name
* @param[in] rev Revision
* @retval ymod Yang module statement if found
* @retval NULL not found
* @see yang_find_module_by_namespace
* @note a module may have many revisions, but only the first is significant
*/
yang_stmt *
yang_find_module_by_name_revision(yang_stmt *yspec,
const char *name,
const char *rev)
{
yang_stmt *ymod = NULL;
yang_stmt *yrev;
char *rev1;
if (name == NULL){
clicon_err(OE_CFG, EINVAL, "No ns or rev");
goto done;
}
while ((ymod = yn_each(yspec, ymod)) != NULL) {
if (yang_keyword_get(ymod) != Y_MODULE)
continue;
if (strcmp(yang_argument_get(ymod), name) != 0)
continue;
if (rev == NULL)
break; /* Matching revision is NULL, match that */
/* Get FIRST revision */
if ((yrev = yang_find(ymod, Y_REVISION, NULL)) != NULL){
rev1 = yang_argument_get(yrev);
if (strcmp(rev, rev1) == 0)
break; /* return this ymod */
}
}
done:
return ymod;
}
/*! Given a yang spec and a module name, return yang module or submodule /*! Given a yang spec and a module name, return yang module or submodule
* *
* @param[in] yspec A yang specification * @param[in] yspec A yang specification

View file

@ -1404,7 +1404,7 @@ yang_parse_post(clicon_handle h,
*/ */
int int
yang_spec_parse_module(clicon_handle h, yang_spec_parse_module(clicon_handle h,
const char *module, const char *name,
const char *revision, const char *revision,
yang_stmt *yspec) yang_stmt *yspec)
{ {
@ -1416,16 +1416,16 @@ yang_spec_parse_module(clicon_handle h,
clicon_err(OE_YANG, EINVAL, "yang spec is NULL"); clicon_err(OE_YANG, EINVAL, "yang spec is NULL");
goto done; goto done;
} }
if (module == NULL){ if (name == NULL){
clicon_err(OE_YANG, EINVAL, "yang module not set"); clicon_err(OE_YANG, EINVAL, "yang module not set");
goto done; goto done;
} }
/* Apply steps 2.. on new modules, ie ones after modmin. */ /* Apply steps 2.. on new modules, ie ones after modmin. */
modmin = yang_len_get(yspec); modmin = yang_len_get(yspec);
/* Do not load module if it already exists */ /* Do not load module if it already exists */
if (yang_find(yspec, Y_MODULE, module) != NULL) if (yang_find_module_by_name_revision(yspec, name, revision) != NULL)
goto ok; goto ok;
if (yang_parse_module(h, module, revision, yspec) == NULL) if (yang_parse_module(h, name, revision, yspec) == NULL)
goto done; goto done;
if (yang_parse_post(h, yspec, modmin) < 0) if (yang_parse_post(h, yspec, modmin) < 0)
goto done; goto done;

View file

@ -98,6 +98,7 @@ cat <<EOF > $cfg
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_FEATURE>ietf-netconf:startup</CLICON_FEATURE> <CLICON_FEATURE>ietf-netconf:startup</CLICON_FEATURE>
<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_MAIN_DIR>$dir</CLICON_YANG_MAIN_DIR> <CLICON_YANG_MAIN_DIR>$dir</CLICON_YANG_MAIN_DIR>
<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/example/backend</CLICON_BACKEND_DIR> <CLICON_BACKEND_DIR>/usr/local/lib/example/backend</CLICON_BACKEND_DIR>
@ -266,13 +267,12 @@ runtest(){
new "start backend -s $mode -f $cfg -o \"CLICON_XMLDB_MODSTATE=$modstate\"" new "start backend -s $mode -f $cfg -o \"CLICON_XMLDB_MODSTATE=$modstate\""
start_backend -s $mode -f $cfg -o "CLICON_XMLDB_MODSTATE=$modstate" start_backend -s $mode -f $cfg -o "CLICON_XMLDB_MODSTATE=$modstate"
new "waiting" # new "Restart backend as eg follows: -Ff $cfg -s $mode -o \"CLICON_XMLDB_MODSTATE=$modstate\" ($BETIMEOUT s)"
wait_backend
else
new "Restart backend as eg follows: -Ff $cfg -s $mode -o \"CLICON_XMLDB_MODSTATE=$modstate\" ($BETIMEOUT s)"
# sleep $BETIMEOUT
fi fi
new "wait backend"
wait_backend
new "Check running db content" new "Check running db content"
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><get-config><source><running/></source></get-config></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS>$exprun</rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><get-config><source><running/></source></get-config></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS>$exprun</rpc-reply>]]>]]>$"
@ -333,14 +333,13 @@ new "4. Load non-compat valid startup"
# Just test that a valid db survives start from running # Just test that a valid db survives start from running
(cd $dir; rm -f tmp_db candidate_db running_db startup_db) # remove databases (cd $dir; rm -f tmp_db candidate_db running_db startup_db) # remove databases
(cd $dir; cp non-compat-valid.xml startup_db) (cd $dir; cp non-compat-valid.xml startup_db)
runtest true startup '<data><a1 xmlns="urn:example:a">always work</a1><b xmlns="urn:example:b">other text</b></data>' '<data><a1 xmlns="urn:example:a">always work</a1><b xmlns="urn:example:b">other text</b></data>' runtest true startup '<data><a1 xmlns="urn:example:a">always work</a1><b xmlns="urn:example:b">other text</b></data>' #'<data><a1 xmlns="urn:example:a">always work</a1><b xmlns="urn:example:b">other text</b></data>'
new "5. Load non-compat invalid startup. Enter failsafe, startup invalid." new "5. Load non-compat invalid startup. Enter failsafe, startup invalid."
# A test that if a non-valid startup is encountered, validation fails and failsafe is entered # A test that if a non-valid startup is encountered, validation fails and failsafe is entered
(cd $dir; rm -f tmp_db candidate_db running_db startup_db) # remove databases (cd $dir; rm -f tmp_db candidate_db running_db startup_db) # remove databases
(cd $dir; cp non-compat-invalid.xml startup_db) (cd $dir; cp non-compat-invalid.xml startup_db)
runtest true startup '<data><a1 xmlns="urn:example:a">always work</a1></data>' '<data><a0 xmlns="urn:example:a">old version</a0><a1 xmlns="urn:example:a">always work</a1><b xmlns="urn:example:b">other text</b><c xmlns="urn:example:c">bla bla</c></data>' # sorted runtest true startup '<data><a1 xmlns="urn:example:a">always work</a1></data>' # '<data><a0 xmlns="urn:example:a">old version</a0><a1 xmlns="urn:example:a">always work</a1><b xmlns="urn:example:b">other text</b><c xmlns="urn:example:c">bla bla</c></data>' # sorted
#runtest true startup '<data><a1 xmlns="urn:example:a">always work</a1></data>' '<data><a0 xmlns="urn:example:a">old version</a0><c xmlns="urn:example:c">bla bla</c><a1 xmlns="urn:example:a">always work</a1><b xmlns="urn:example:b">other text</b></data>' # unsorted
new "6. Load non-compat invalid running. Enter failsafe, startup invalid." new "6. Load non-compat invalid running. Enter failsafe, startup invalid."
(cd $dir; rm -f tmp_db candidate_db running_db startup_db) # remove databases (cd $dir; rm -f tmp_db candidate_db running_db startup_db) # remove databases
@ -353,8 +352,7 @@ runtest true running '<data><a1 xmlns="urn:example:a">always work</a1></data>' '
new "7. Load compatible invalid startup." new "7. Load compatible invalid startup."
(cd $dir; rm -f tmp_db candidate_db running_db startup_db) # remove databases (cd $dir; rm -f tmp_db candidate_db running_db startup_db) # remove databases
(cd $dir; cp compat-invalid.xml startup_db) (cd $dir; cp compat-invalid.xml startup_db)
runtest true startup '<data><a1 xmlns="urn:example:a">always work</a1></data>' '<data><a0 xmlns="urn:example:a">old version</a0><a1 xmlns="urn:example:a">always work</a1><b xmlns="urn:example:b">other text</b><c xmlns="urn:example:c">bla bla</c></data>' # sorted runtest true startup '<data><a1 xmlns="urn:example:a">always work</a1></data>' # '<data><a0 xmlns="urn:example:a">old version</a0><a1 xmlns="urn:example:a">always work</a1><b xmlns="urn:example:b">other text</b><c xmlns="urn:example:c">bla bla</c></data>' # sorted
#runtest true startup '<data><a1 xmlns="urn:example:a">always work</a1></data>' '<data><a0 xmlns="urn:example:a">old version</a0><c xmlns="urn:example:c">bla bla</c><a1 xmlns="urn:example:a">always work</a1><b xmlns="urn:example:b">other text</b></data>' # unsorted
# This testcase contains an error/exception of the clixon xml parser, and # This testcase contains an error/exception of the clixon xml parser, and
# I cant track down the memory leakage. # I cant track down the memory leakage.

View file

@ -59,6 +59,7 @@ cat <<EOF > $cfg
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_FEATURE>ietf-netconf:startup</CLICON_FEATURE> <CLICON_FEATURE>ietf-netconf:startup</CLICON_FEATURE>
<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_MAIN_DIR>$dir</CLICON_YANG_MAIN_DIR> <CLICON_YANG_MAIN_DIR>$dir</CLICON_YANG_MAIN_DIR>
<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/example/backend</CLICON_BACKEND_DIR> <CLICON_BACKEND_DIR>/usr/local/lib/example/backend</CLICON_BACKEND_DIR>

View file

@ -116,12 +116,11 @@ function testrun()
XML="$XMLA$XMLU" XML="$XMLA$XMLU"
else else
XML="$XMLA" XML="$XMLA"
unknownreply="<rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>u1</bad-element></error-info><error-severity>error</error-severity><error-message>Failed to find YANG spec of XML node: u1 with parent: config in namespace: urn:example:unknown</error-message></rpc-error>" unknownreply="<rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>u3</bad-element></error-info><error-severity>error</error-severity><error-message>Failed to find YANG spec of XML node: u3 with parent: b in namespace: urn:example:unknown</error-message></rpc-error>"
fi fi
else else
XML="$XMLA" XML="$XMLA"
unknownreply="<rpc-error><error-type>application</error-type><error-tag>unknown unknownreply="<rpc-error><error-type>application</error-type><error-tag>unknown-element</error-tag><error-info><bad-element>u3</bad-element></error-info><error-severity>error</error-severity><error-message>Failed to find YANG spec of XML node: u3 with parent: b in namespace: urn:example:unknown</error-message></rpc-error>"
-element</error-tag><error-info><bad-element>u1</bad-element></error-info><error-severity>error</error-severity><error-message>Failed to find YANG spec of XML node: u1 with parent: config in namespace: urn:example:unknown</error-message></rpc-error>"
fi fi
if $startup; then # get config from startup if $startup; then # get config from startup
@ -268,16 +267,16 @@ EOF
new "test params: -f $cfg" new "test params: -f $cfg"
new "no startup, dont treat unknown as anydata----" new "1. no startup, dont treat unknown as anydata----"
testrun false false testrun false false
new "startup, dont treat unknown as anydata----" new "2. startup, dont treat unknown as anydata----"
testrun true false testrun true false
new "no startup, treat unknown as anydata----" new "3. no startup, treat unknown as anydata----"
testrun false true testrun false true
new "startup, treat unknown as anydata----" new "4. startup, treat unknown as anydata----"
testrun true true testrun true true
# Set by restconf_config # Set by restconf_config