Changed module-specific upgrade API, not backward compatible. The API has been simplified which means more has to be done by the programmer.

* In summary, a user registers an upgrade callback per module. The callback is called at startup if the module is added, has been removed or if the revision on file is different from the one in the system.
  * The register function has removed `from` and `rev` parameters: `upgrade_callback_register(h, cb, namespace, arg)`
  * The callback function has a new `op` parameter with possible values: `XML_FLAG_ADD`, `XML_FLAG_CHANGE` or `XML_FLAG_CHANGE`: `clicon_upgrade_cb(h, xn, ns, op, from, to, arg, cbret)`
This commit is contained in:
Olof hagsand 2020-06-26 14:39:04 +02:00
parent e2b3cdb3f6
commit 8f1de15ad3
10 changed files with 257 additions and 185 deletions

View file

@ -51,6 +51,11 @@ Expected: July 2020
### C/CLI-API changes on existing features (For developers)
* Changed module-specific upgrade API, not backward compatible. The API has been simplified which means more has to be done by the programmer.
* In summary, a user registers an upgrade callback per module. The callback is called at startup if the module is added, has been removed or if the revision on file is different from the one in the system.
* The register function has removed `from` and `rev` parameters: `upgrade_callback_register(h, cb, namespace, arg)`
* The callback function has a new `op` parameter with possible values: `XML_FLAG_ADD`, `XML_FLAG_CHANGE` or `XML_FLAG_CHANGE`: `clicon_upgrade_cb(h, xn, ns, op, from, to, arg, cbret)`
* Added new cli show functions to work with cligen_output for cligen pageing to work. To achieve this, replace function calls as follows:
* xml2txt(...) --> xml2txt_cb(..., cligen_output)
* xml2cli(...) --> xml2cli_cb(..., cligen_output)

View file

@ -177,19 +177,19 @@ startup_common(clicon_handle h,
int retval = -1;
yang_stmt *yspec;
int ret;
modstate_diff_t *msd = NULL;
modstate_diff_t *msdiff = NULL;
cxobj *xt = NULL;
cxobj *x;
cxobj *xret = NULL;
/* 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 msdiff
*/
if (clicon_option_bool(h, "CLICON_XMLDB_MODSTATE"))
if ((msd = modstate_diff_new()) == NULL)
if ((msdiff = modstate_diff_new()) == NULL)
goto done;
clicon_debug(1, "Reading startup config from %s", db);
if (xmldb_get0(h, db, NULL, "/", 0, &xt, msd) < 0)
if (xmldb_get0(h, db, NULL, "/", 0, &xt, msdiff) < 0)
goto done;
clicon_debug(1, "Reading startup config done");
/* Clear flags xpath for get */
@ -202,13 +202,15 @@ startup_common(clicon_handle h,
}
/* Here xt is old syntax */
/* General purpose datastore upgrade */
if (clixon_plugin_datastore_upgrade_all(h, db, xt, msd) < 0)
if (clixon_plugin_datastore_upgrade_all(h, db, xt, msdiff) < 0)
goto done;
/* Module-specific upgrade callbacks */
if ((ret = clixon_module_upgrade(h, xt, msd, cbret)) < 0)
goto done;
if (ret == 0)
goto fail;
if (msdiff){
if ((ret = clixon_module_upgrade(h, xt, msdiff, cbret)) < 0)
goto done;
if (ret == 0)
goto fail;
}
if ((yspec = clicon_dbspec_yang(h)) == NULL){
clicon_err(OE_YANG, 0, "Yang spec not set");
goto done;
@ -257,8 +259,8 @@ startup_common(clicon_handle h,
xml_free(xret);
if (xt)
xml_free(xt);
if (msd)
modstate_diff_free(msd);
if (msdiff)
modstate_diff_free(msdiff);
return retval;
fail:
retval = 0;

View file

@ -535,9 +535,9 @@ static const map_str2str namespace_map[] = {
*/
int
example_upgrade(clicon_handle h,
char *db,
cxobj *xt,
modstate_diff_t *msd)
char *db,
cxobj *xt,
modstate_diff_t *msd)
{
int retval = -1;
cvec *nsc = NULL; /* Canonical namespace */
@ -616,16 +616,17 @@ example_upgrade(clicon_handle h,
* @param[in] h Clicon handle
* @param[in] xn XML tree to be updated
* @param[in] ns Namespace of module (for info)
* @param[in] op One of XML_FLAG_ADD, _DEL, _CHANGE
* @param[in] from From revision on the form YYYYMMDD
* @param[in] to To revision on the form YYYYMMDD (0 not in system)
* @param[in] arg User argument given at rpc_callback_register()
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error.. if retval = 0
* @retval 1 OK
* @retval 0 Invalid
* @retval -1 Error
* @see clicon_upgrade_cb
* @see test_upgrade_interfaces.sh
* @see upgrade_2016
* @see upgrade_2014_to_2016
* This example shows a two-step upgrade where the 2014 function does:
* - Move /if:interfaces-state/if:interface/if:admin-status to
* /if:interfaces/if:interface/
@ -634,13 +635,14 @@ example_upgrade(clicon_handle h,
* - Rename /interfaces/interface/description to descr
*/
static int
upgrade_2016(clicon_handle h,
cxobj *xt,
char *ns,
uint32_t from,
uint32_t to,
void *arg,
cbuf *cbret)
upgrade_2014_to_2016(clicon_handle h,
cxobj *xt,
char *ns,
uint16_t op,
uint32_t from,
uint32_t to,
void *arg,
cbuf *cbret)
{
int retval = -1;
yang_stmt *yspec;
@ -654,6 +656,7 @@ upgrade_2016(clicon_handle h,
int i;
char *name;
clicon_debug(1, "%s from:%d to:%d", __FUNCTION__, from, to);
/* Get Yang module for this namespace. Note it may not exist (if obsolete) */
yspec = clicon_dbspec_yang(h);
if ((ym = yang_find_module_by_namespace(yspec, ns)) == NULL)
@ -716,16 +719,17 @@ upgrade_2016(clicon_handle h,
* @param[in] h Clicon handle
* @param[in] xn XML tree to be updated
* @param[in] ns Namespace of module (for info)
* @param[in] op One of XML_FLAG_ADD, _DEL, _CHANGE
* @param[in] from From revision on the form YYYYMMDD
* @param[in] to To revision on the form YYYYMMDD (0 not in system)
* @param[in] arg User argument given at rpc_callback_register()
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error.. if retval = 0
* @retval 1 OK
* @retval 0 Invalid
* @retval -1 Error
* @see clicon_upgrade_cb
* @see test_upgrade_interfaces.sh
* @see upgrade_2016
* @see upgrade_2016_to_2018
* The 2016 function does:
* - Delete /if:interfaces-state
* - Wrap /interfaces/interface/descr to /interfaces/interface/docs/descr
@ -733,13 +737,14 @@ upgrade_2016(clicon_handle h,
* fraction-digits 3 and divide all values with 1000
*/
static int
upgrade_2018(clicon_handle h,
cxobj *xt,
char *ns,
uint32_t from,
uint32_t to,
void *arg,
cbuf *cbret)
upgrade_2016_to_2018(clicon_handle h,
cxobj *xt,
char *ns,
uint16_t op,
uint32_t from,
uint32_t to,
void *arg,
cbuf *cbret)
{
int retval = -1;
yang_stmt *yspec;
@ -752,6 +757,7 @@ upgrade_2018(clicon_handle h,
size_t vlen;
int i;
clicon_debug(1, "%s from:%d to:%d", __FUNCTION__, from, to);
/* Get Yang module for this namespace. Note it may not exist (if obsolete) */
yspec = clicon_dbspec_yang(h);
if ((ym = yang_find_module_by_namespace(yspec, ns)) == NULL)
@ -800,6 +806,58 @@ upgrade_2018(clicon_handle h,
return retval;
}
/*! Testcase module-specific upgrade function moving interfaces-state to interfaces
* @param[in] h Clicon handle
* @param[in] xn XML tree to be updated
* @param[in] ns Namespace of module (for info)
* @param[in] op One of XML_FLAG_ADD, _DEL, _CHANGE
* @param[in] from From revision on the form YYYYMMDD
* @param[in] to To revision on the form YYYYMMDD (0 not in system)
* @param[in] arg User argument given at rpc_callback_register()
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error.. if retval = 0
* @retval 1 OK
* @retval 0 Invalid
* @retval -1 Error
* @see clicon_upgrade_cb
* @see test_upgrade_interfaces.sh
* @see upgrade_2014_to_2016
* This example shows a two-step upgrade where the 2014 function does:
* - Move /if:interfaces-state/if:interface/if:admin-status to
* /if:interfaces/if:interface/
* - Move /if:interfaces-state/if:interface/if:statistics to
* /if:interfaces/if:interface/
* - Rename /interfaces/interface/description to descr
*/
static int
upgrade_interfaces(clicon_handle h,
cxobj *xt,
char *ns,
uint16_t op,
uint32_t from,
uint32_t to,
void *arg,
cbuf *cbret)
{
int retval = -1;
if (from <= 20140508){
if ((retval = upgrade_2014_to_2016(h, xt, ns, op, from, to, arg, cbret)) < 0)
goto done;
if (retval == 0)
goto done;
}
if (from <= 20160101){
if ((retval = upgrade_2016_to_2018(h, xt, ns, op, from, to, arg, cbret)) < 0)
goto done;
if (retval == 0)
goto done;
}
// ok:
retval = 1;
done:
return retval;
}
/*! Plugin state reset. Add xml or set state in backend machine.
* Called in each backend plugin. plugin_reset is called after all plugins
* have been initialized. This give the application a chance to reset
@ -1026,13 +1084,18 @@ clixon_plugin_init(clicon_handle h)
* test interface example. Otherwise the auto-upgrade feature is enabled.
*/
if (_module_upgrade){
if (upgrade_callback_register(h, upgrade_2016, "urn:example:interfaces", 20140508, 20160101, NULL) < 0)
#if 1
if (upgrade_callback_register(h, upgrade_interfaces, "urn:example:interfaces", NULL) < 0)
goto done;
if (upgrade_callback_register(h, upgrade_2018, "urn:example:interfaces", 20160101, 20180220, NULL) < 0)
#else
if (upgrade_callback_register(h, upgrade_2014_to_2016, "urn:example:interfaces", NULL) < 0)
goto done;
if (upgrade_callback_register(h, upgrade_2016_to_2018, "urn:example:interfaces", NULL) < 0)
goto done;
#endif
}
else
if (upgrade_callback_register(h, xml_changelog_upgrade, NULL, 0, 0, NULL) < 0)
if (upgrade_callback_register(h, xml_changelog_upgrade, NULL, NULL) < 0)
goto done;
/* Return plugin API */

View file

@ -45,7 +45,7 @@
/* Hardcoded plugin symbol. Must exist in all plugins to kickstart
* @see clixon_plugin_init
*/
#define CLIXON_PLUGIN_INIT "clixon_plugin_init"
#define CLIXON_PLUGIN_INIT "clixon_plugin_init"
/*
* Types
@ -72,10 +72,11 @@ typedef int (*clicon_rpc_cb)(
* @param[in] h Clicon handle
* @param[in] xn XML tree to be updated
* @param[in] namespace Namespace of module
* @param[in] from From revision on the form YYYYMMDD
* @param[in] to To revision on the form YYYYMMDD (0 not in system)
* @param[in] op One of XML_FLAG_ADD, _DEL, _CHANGE
* @param[in] from From revision on the form YYYYMMDD (if DEL or CHANGE)
* @param[in] to To revision on the form YYYYMMDD (if ADD or CHANGE)
* @param[in] arg User argument given at rpc_callback_register()
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error.. (if retval = 0)
* @retval 1 OK
* @retval 0 Invalid
* @retval -1 Error
@ -84,6 +85,7 @@ typedef int (*clicon_upgrade_cb)(
clicon_handle h,
cxobj *xn,
char *namespace,
uint16_t op,
uint32_t from,
uint32_t to,
void *arg,
@ -253,7 +255,7 @@ struct clixon_plugin_api{
/*
* Macros
*/
#define upgrade_callback_register(h, cb, namespace, from, rev, arg) upgrade_callback_reg_fn((h), (cb), #cb, (namespace), (from), (rev), (arg))
#define upgrade_callback_register(h, cb, namespace, arg) upgrade_callback_reg_fn((h), (cb), #cb, (namespace), (arg))
typedef struct clixon_plugin_api clixon_plugin_api;
@ -309,8 +311,8 @@ int rpc_callback_delete_all(clicon_handle h);
int rpc_callback_call(clicon_handle h, cxobj *xe, cbuf *cbret, void *arg);
/* upgrade callback API */
int upgrade_callback_reg_fn(clicon_handle h, clicon_upgrade_cb cb, const char *strfn, char *namespace, uint32_t from, uint32_t to, void *arg);
int upgrade_callback_reg_fn(clicon_handle h, clicon_upgrade_cb cb, const char *strfn, char *namespace, void *arg);
int upgrade_callback_delete_all(clicon_handle h);
int upgrade_callback_call(clicon_handle h, cxobj *xt, char *namespace, uint32_t from, uint32_t to, cbuf *cbret);
int upgrade_callback_call(clicon_handle h, cxobj *xt, char *namespace, uint16_t op, uint32_t from, uint32_t to, cbuf *cbret);
#endif /* _CLIXON_PLUGIN_H_ */

View file

@ -40,7 +40,7 @@
/*
* Prototypes
*/
int xml_changelog_upgrade(clicon_handle h, cxobj *xn, char *namespace, uint32_t from, uint32_t to, void *arg, cbuf *cbret);
int xml_changelog_upgrade(clicon_handle h, cxobj *xn, char *namespace, uint16_t op, uint32_t from, uint32_t to, void *arg, cbuf *cbret);
int clixon_xml_changelog_init(clicon_handle h);
int xml_namespace_vec(clicon_handle h, cxobj *xt, char *namespace, cxobj ***vec, size_t *veclen);

View file

@ -54,8 +54,7 @@
typedef struct {
int md_status; /* 0 if no module-state in a datastore, 1 if there is */
char *md_set_id; /* server-specific identifier */
cxobj *md_del; /* yang module state deletes */
cxobj *md_mod; /* yang module state modifications */
cxobj *md_diff; /* yang module state containing revisions and XML_FLAG_ADD|DEL|CHANGE */
} modstate_diff_t;
/*

View file

@ -212,92 +212,111 @@ xml_copy_marked(cxobj *x0,
/*! Read module-state in an XML tree
*
* @param[in] th Datastore text handle
* @param[in] yspec Top-level yang spec
* @param[in] xt XML tree
* @param[out] msd If set, return modules-state differences
* @param[in] th Datastore text handle
* @param[in] yspec Top-level yang spec
* @param[in] xt XML tree
* @param[out] msdiff Modules-state differences
*
* The modstate difference contains:
* - if there is a modstate
* - the modstate identifier
* - An entry for each modstate that differs marked with flag: ADD|DEL|CHANGE
*
* Algorithm:
* Read mst (module-state-tree) from xml tree (if any) and compare it with
* the system state mst.
* This can happen:
* 1) There is no modules-state info in the file
* 2) There is module state info in the file
* 3) For each module state m in the file:
* 3a) There is no such module in the system
* 3a) There is no such module in the system -> add to list mark as DEL
* 3b) File module-state matches system
* 3c) File module-state does not match system
* 3c) File module-state does not match system -> add to list mark as CHANGE
* 4) For each module state s in the system
* 4a) If there is no such module in the file -> add to list mark as ADD
*/
static int
text_read_modstate(clicon_handle h,
yang_stmt *yspec,
cxobj *xt,
modstate_diff_t *msd)
modstate_diff_t *msdiff)
{
int retval = -1;
cxobj *xmodst;
cxobj *xm = NULL;
cxobj *xm2;
cxobj *xs;
char *name; /* module name */
char *mrev; /* file revision */
char *srev; /* system revision */
cxobj *xmcache = NULL;
cxobj *xmodfile = NULL; /* modstate of system (loaded yang modules in runtime) */
cxobj *xmodsystem = NULL; /* modstate of file, eg startup */
cxobj *xf = NULL; /* xml modstate in file */
cxobj *xf2; /* copy */
cxobj *xs; /* xml modstate in system */
cxobj *xs2; /* copy */
char *name; /* module name */
char *frev; /* file revision */
char *srev; /* system revision */
xmcache = clicon_modst_cache_get(h, 1);
if ((xmodst = xml_find_type(xt, NULL, "modules-state", CX_ELMNT)) == NULL){
/* Read module-state as computed at startup, see startup_module_state() */
xmodsystem = clicon_modst_cache_get(h, 1);
if ((xmodfile = xml_find_type(xt, NULL, "modules-state", CX_ELMNT)) == NULL){
/* 1) There is no modules-state info in the file */
}
else if (xmcache && msd){
msd->md_status = 1; /* There is module state in the file */
/* Create diff trees */
else if (xmodsystem && msdiff){
msdiff->md_status = 1; /* There is module state in the file */
/* Create modstate tree for this file */
if (clixon_xml_parse_string("<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\"/>",
YB_MODULE, yspec, &msd->md_del, NULL) < 0)
YB_MODULE, yspec, &msdiff->md_diff, NULL) < 0)
goto done;
if (xml_rootchild(msd->md_del, 0, &msd->md_del) < 0)
goto done;
if (clixon_xml_parse_string("<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\"/>",
YB_MODULE, yspec, &msd->md_mod, NULL) < 0)
goto done;
if (xml_rootchild(msd->md_mod, 0, &msd->md_mod) < 0)
if (xml_rootchild(msdiff->md_diff, 0, &msdiff->md_diff) < 0)
goto done;
/* 3) For each module state m in the file */
while ((xm = xml_child_each(xmodst, xm, CX_ELMNT)) != NULL) {
if (strcmp(xml_name(xm), "module-set-id") == 0){
if (xml_body(xm) && (msd->md_set_id = strdup(xml_body(xm))) == NULL){
xf = NULL;
while ((xf = xml_child_each(xmodfile, xf, CX_ELMNT)) != NULL) {
if (strcmp(xml_name(xf), "module-set-id") == 0){
if (xml_body(xf) && (msdiff->md_set_id = strdup(xml_body(xf))) == NULL){
clicon_err(OE_UNIX, errno, "strdup");
goto done;
}
}
if (strcmp(xml_name(xm), "module"))
if (strcmp(xml_name(xf), "module"))
continue; /* ignore other tags, such as module-set-id */
if ((name = xml_find_body(xm, "name")) == NULL)
if ((name = xml_find_body(xf, "name")) == NULL)
continue;
/* 3a) There is no such module in the system */
if ((xs = xpath_first(xmcache, NULL, "module[name=\"%s\"]", name)) == NULL){
// fprintf(stderr, "%s: Module %s: not in system\n", __FUNCTION__, name);
if ((xm2 = xml_dup(xm)) == NULL)
if ((xs = xpath_first(xmodsystem, NULL, "module[name=\"%s\"]", name)) == NULL){
if ((xf2 = xml_dup(xf)) == NULL) /* Make a copy of this modstate */
goto done;
if (xml_addsub(msd->md_del, xm2) < 0)
if (xml_addsub(msdiff->md_diff, xf2) < 0) /* Add it to modstatediff */
goto done;
xml_flag_set(xf2, XML_FLAG_DEL);
continue;
}
/* These two shouldnt happen since revision is key, just ignore */
if ((mrev = xml_find_body(xm, "revision")) == NULL)
if ((frev = xml_find_body(xf, "revision")) == NULL)
continue;
if ((srev = xml_find_body(xs, "revision")) == NULL)
continue;
if (strcmp(mrev, srev)==0){
/* 3b) File module-state matches system */
// fprintf(stderr, "%s: Module %s: file \"%s\" and system revisions match\n", __FUNCTION__, name, mrev);
}
else{
if (strcmp(frev, srev)!=0){
/* 3c) File module-state does not match system */
// fprintf(stderr, "%s: Module %s: file \"%s\" and system \"%s\" revisions do not match\n", __FUNCTION__, name, mrev, srev);
if ((xm2 = xml_dup(xm)) == NULL)
if ((xf2 = xml_dup(xf)) == NULL)
goto done;
if (xml_addsub(msd->md_mod, xm2) < 0)
if (xml_addsub(msdiff->md_diff, xf2) < 0)
goto done;
xml_flag_set(xf2, XML_FLAG_CHANGE);
}
}
/* 4) For each module state s in the system (xmodsystem) */
xs = NULL;
while ((xs = xml_child_each(xmodsystem, xs, CX_ELMNT)) != NULL) {
if (strcmp(xml_name(xs), "module"))
continue; /* ignore other tags, such as module-set-id */
if ((name = xml_find_body(xs, "name")) == NULL)
continue;
/* 4a) If there is no such module in the file -> add to list mark as ADD */
if ((xf = xpath_first(xmodfile, NULL, "module[name=\"%s\"]", name)) == NULL){
if ((xs2 = xml_dup(xs)) == NULL) /* Make a copy of this modstate */
goto done;
if (xml_addsub(msdiff->md_diff, xs2) < 0) /* Add it to modstatediff */
goto done;
xml_flag_set(xs2, XML_FLAG_ADD);
continue;
}
}
}
@ -305,8 +324,8 @@ text_read_modstate(clicon_handle h,
* in all cases, whether CLICON_XMLDB_MODSTATE is on or not.
* Clixon systems with CLICON_XMLDB_MODSTATE disabled ignores it
*/
if (xmodst){
if (xml_purge(xmodst) < 0)
if (xmodfile){
if (xml_purge(xmodfile) < 0)
goto done;
}
retval = 0;
@ -319,14 +338,14 @@ text_read_modstate(clicon_handle h,
* @param[in] db Symbolic database name, eg "candidate", "running"
* @param[in] yspec Top-level yang spec
* @param[out] xp XML tree read from file
* @param[out] msd If set, return modules-state differences
* @param[out] msdiff If set, return modules-state differences
*/
int
xmldb_readfile(clicon_handle h,
const char *db,
yang_stmt *yspec,
cxobj **xp,
modstate_diff_t *msd)
modstate_diff_t *msdiff)
{
int retval = -1;
cxobj *x0 = NULL;
@ -373,7 +392,7 @@ xmldb_readfile(clicon_handle h,
/* From Clixon 3.10,datastore files may contain module-state defining
* which modules are used in the file.
*/
if (text_read_modstate(h, yspec, x0, msd) < 0)
if (text_read_modstate(h, yspec, x0, msdiff) < 0)
goto done;
if (xp){
*xp = x0;
@ -399,7 +418,7 @@ xmldb_readfile(clicon_handle h,
* @param[in] nsc External XML namespace context, or NULL
* @param[in] xpath String with XPATH syntax. or NULL for all
* @param[out] xret Single return XML tree. Free with xml_free()
* @param[out] msd If set, return modules-state differences
* @param[out] msdiff If set, return modules-state differences
* @retval 0 OK
* @retval -1 Error
* @see xmldb_get the generic API function
@ -410,7 +429,7 @@ xmldb_get_nocache(clicon_handle h,
cvec *nsc,
char *xpath,
cxobj **xtop,
modstate_diff_t *msd)
modstate_diff_t *msdiff)
{
int retval = -1;
char *dbfile = NULL;
@ -426,7 +445,7 @@ xmldb_get_nocache(clicon_handle h,
clicon_err(OE_YANG, ENOENT, "No yang spec");
goto done;
}
if (xmldb_readfile(h, db, yspec, &xt, msd) < 0)
if (xmldb_readfile(h, db, yspec, &xt, msdiff) < 0)
goto done;
/* Here xt looks like: <config>...</config> */
/* Given the xpath, return a vector of matches in xvec */
@ -483,7 +502,7 @@ xmldb_get_nocache(clicon_handle h,
* @param[in] nsc External XML namespace context, or NULL
* @param[in] xpath String with XPATH syntax. or NULL for all
* @param[out] xret Single return XML tree. Free with xml_free()
* @param[out] msd If set, return modules-state differences
* @param[out] msdiff If set, return modules-state differences
* @retval 0 OK
* @retval -1 Error
* @see xmldb_get the generic API function
@ -494,7 +513,7 @@ xmldb_get_cache(clicon_handle h,
cvec *nsc,
char *xpath,
cxobj **xtop,
modstate_diff_t *msd)
modstate_diff_t *msdiff)
{
int retval = -1;
yang_stmt *yspec;
@ -514,7 +533,7 @@ xmldb_get_cache(clicon_handle h,
de = clicon_db_elmnt_get(h, db);
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 (xmldb_readfile(h, db, yspec, &x0t, msd) < 0)
if (xmldb_readfile(h, db, yspec, &x0t, msdiff) < 0)
goto done;
/* XXX: should we validate file if read from disk?
* Argument against: we may want to have a semantically wrong file and wish
@ -585,7 +604,7 @@ xmldb_get_cache(clicon_handle h,
* @param[in] xpath String with XPATH syntax. or NULL for all
* @param[in] config If set only configuration data, else also state
* @param[out] xret Single return XML tree. Free with xml_free()
* @param[out] msd If set, return modules-state differences
* @param[out] msdiff If set, return modules-state differences
* @retval 0 OK
* @retval -1 Error
*/
@ -595,7 +614,7 @@ xmldb_get_zerocopy(clicon_handle h,
cvec *nsc,
char *xpath,
cxobj **xtop,
modstate_diff_t *msd)
modstate_diff_t *msdiff)
{
int retval = -1;
yang_stmt *yspec;
@ -614,7 +633,7 @@ xmldb_get_zerocopy(clicon_handle h,
de = clicon_db_elmnt_get(h, db);
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 (xmldb_readfile(h, db, yspec, &x0t, msd) < 0)
if (xmldb_readfile(h, db, yspec, &x0t, msdiff) < 0)
goto done;
/* XXX: should we validate file if read from disk?
* Argument against: we may want to have a semantically wrong file and wish
@ -689,7 +708,7 @@ xmldb_get(clicon_handle h,
* @param[in] xpath String with XPATH syntax. or NULL for all
* @param[in] copy Force copy. Overrides cache_zerocopy -> cache
* @param[out] xret Single return XML tree. Free with xml_free()
* @param[out] msd If set, return modules-state differences (upgrade code)
* @param[out] msdiff If set, return modules-state differences (upgrade code)
* @retval 0 OK
* @retval -1 Error
* @code
@ -710,7 +729,7 @@ xmldb_get0(clicon_handle h,
char *xpath,
int copy,
cxobj **xret,
modstate_diff_t *msd)
modstate_diff_t *msdiff)
{
int retval = -1;
@ -720,7 +739,7 @@ xmldb_get0(clicon_handle h,
* Add default values in copy
* Copy deleted by xmldb_free
*/
retval = xmldb_get_nocache(h, db, nsc, xpath, xret, msd);
retval = xmldb_get_nocache(h, db, nsc, xpath, xret, msdiff);
break;
case DATASTORE_CACHE_ZEROCOPY:
/* Get cache (file if empty) mark xpath match in original tree
@ -728,7 +747,7 @@ xmldb_get0(clicon_handle h,
* Default values and markings removed in xmldb_clear
*/
if (!copy){
retval = xmldb_get_zerocopy(h, db, nsc, xpath, xret, msd);
retval = xmldb_get_zerocopy(h, db, nsc, xpath, xret, msdiff);
break;
}
/* fall through */
@ -737,7 +756,7 @@ xmldb_get0(clicon_handle h,
* Add default values in copy, return copy
* Copy deleted by xmldb_free
*/
retval = xmldb_get_cache(h, db, nsc, xpath, xret, msd);
retval = xmldb_get_cache(h, db, nsc, xpath, xret, msdiff);
break;
}
return retval;

View file

@ -793,9 +793,6 @@ typedef struct {
const char *uc_fnstr; /* Stringified fn name for debug */
void *uc_arg; /* Application specific argument to cb */
char *uc_namespace; /* Module namespace */
uint32_t uc_rev; /* Module revision (to) in YYYYMMDD format or 0 */
uint32_t uc_from; /* Module revision (from) or 0 in YYYYMMDD format */
} upgrade_callback_t;
/* List of rpc callback entries XXX hang on handle */
@ -808,8 +805,6 @@ static upgrade_callback_t *upgrade_cb_list = NULL;
* @param[in] fnstr Stringified function for debug
* @param[in] arg Domain-specific argument to send to callback
* @param[in] namespace Module namespace (if NULL all modules)
* @param[in] from From module revision (0 from any revision)
* @param[in] revision To module revision (0 means module obsoleted)
* @retval 0 OK
* @retval -1 Error
* @see upgrade_callback_call which makes the actual callback
@ -819,8 +814,6 @@ upgrade_callback_reg_fn(clicon_handle h,
clicon_upgrade_cb cb,
const char *fnstr,
char *namespace,
uint32_t from,
uint32_t revision,
void *arg)
{
upgrade_callback_t *uc;
@ -835,8 +828,6 @@ upgrade_callback_reg_fn(clicon_handle h,
uc->uc_arg = arg;
if (namespace)
uc->uc_namespace = strdup(namespace);
uc->uc_rev = revision;
uc->uc_from = from;
ADDQ(uc, upgrade_cb_list);
return 0;
done:
@ -864,14 +855,14 @@ upgrade_callback_delete_all(clicon_handle h)
return 0;
}
/*! Search Upgrade callbacks and invoke if module match
/*! Upgrade specific module identified by namespace, search matching callbacks
*
* @param[in] h clicon handle
* @param[in] xt Top-level XML tree to be updated (includes other ns as well)
* @param[in] modname Name of module
* @param[in] modns Namespace of module (for info)
* @param[in] from From revision on the form YYYYMMDD
* @param[in] to To revision on the form YYYYMMDD (0 not in system)
* @param[in] ns Namespace of module
* @param[in] op One of XML_FLAG_ADD, _DEL or _CHANGE
* @param[in] from From revision on the form YYYYMMDD (if DEL or CHANGE)
* @param[in] to To revision on the form YYYYMMDD (if ADD or CHANGE)
* @param[out] cbret Return XML (as string in CLIgen buffer), on invalid
* @retval -1 Error
* @retval 0 Invalid - cbret contains reason as netconf
@ -881,7 +872,8 @@ upgrade_callback_delete_all(clicon_handle h)
int
upgrade_callback_call(clicon_handle h,
cxobj *xt,
char *namespace,
char *ns,
uint16_t op,
uint32_t from,
uint32_t to,
cbuf *cbret)
@ -903,23 +895,21 @@ upgrade_callback_call(clicon_handle h,
* - Registered from revision >= from AND
* - Registered to revision <= to (which includes case both 0)
*/
if (uc->uc_namespace == NULL || strcmp(uc->uc_namespace, namespace)==0)
if ((uc->uc_from == 0) ||
(uc->uc_from >= from && uc->uc_rev <= to)){
if ((ret = uc->uc_callback(h, xt, namespace, from, to, uc->uc_arg, cbret)) < 0){
clicon_debug(1, "%s Error in: %s", __FUNCTION__, uc->uc_namespace);
if (uc->uc_namespace == NULL || strcmp(uc->uc_namespace, ns)==0){
if ((ret = uc->uc_callback(h, xt, ns, op, from, to, uc->uc_arg, cbret)) < 0){
clicon_debug(1, "%s Error in: %s", __FUNCTION__, uc->uc_namespace);
goto done;
}
if (ret == 0){
if (cbuf_len(cbret)==0){
clicon_err(OE_CFG, 0, "Validation fail %s(%s): cbret not set",
uc->uc_fnstr, ns);
goto done;
}
if (ret == 0){
if (cbuf_len(cbret)==0){
clicon_err(OE_CFG, 0, "Validation fail %s(%s): cbret not set",
uc->uc_fnstr, namespace);
goto done;
}
goto fail;
}
nr++;
goto fail;
}
nr++;
}
uc = NEXTQ(upgrade_callback_t *, uc);
} while (uc != upgrade_cb_list);
retval = 1;

View file

@ -356,6 +356,7 @@ changelog_iterate(clicon_handle h,
* @param[in] h Clicon handle
* @param[in] xt Top-level XML tree to be updated (includes other ns as well)
* @param[in] namespace Namespace of module (for info)
* @param[in] op One of XML_FLAG_ADD, _DEL, _CHANGE
* @param[in] from From revision on the form YYYYMMDD
* @param[in] to To revision on the form YYYYMMDD (0 not in system)
* @param[in] arg User argument given at rpc_callback_register()
@ -367,12 +368,13 @@ changelog_iterate(clicon_handle h,
*/
int
xml_changelog_upgrade(clicon_handle h,
cxobj *xt,
char *namespace,
uint32_t from,
uint32_t to,
void *arg,
cbuf *cbret)
cxobj *xt,
char *namespace,
uint16_t op,
uint32_t from,
uint32_t to,
void *arg,
cbuf *cbret)
{
int retval = -1;
cxobj *xchlog; /* changelog */

View file

@ -101,10 +101,8 @@ modstate_diff_free(modstate_diff_t *md)
return 0;
if (md->md_set_id)
free(md->md_set_id);
if (md->md_del)
xml_free(md->md_del);
if (md->md_mod)
xml_free(md->md_mod);
if (md->md_diff)
xml_free(md->md_diff);
free(md);
return 0;
}
@ -375,13 +373,13 @@ yang_modules_state_get(clicon_handle h,
/*! For single module state with namespace, get revisions and send upgrade callbacks
* @param[in] h Clicon handle
* @param[in] xt Top-level XML tree to be updated (includes other ns as well)
* @param[in] xs XML module state (for one yang module)
* @param[in] xt Top-level XML tree to be updated (includes other ns as well)
* @param[in] xd XML module state diff (for one yang module)
* @param[in] xvec Help vector where to store XML child nodes (??)
* @param[in] xlen Length of xvec
* @param[in] ns0 Namespace of module state we are looking for
* @param[in] deleted If set, dont look for system yang module and "to" rev
* @param[out] cbret Netconf error message if invalid
* @param[in] op add,del, or mod
* @param[out] cbret Netconf error message if invalid
* @retval 1 OK
* @retval 0 Validation failed (cbret set)
* @retval -1 Error
@ -389,9 +387,8 @@ yang_modules_state_get(clicon_handle h,
static int
mod_ns_upgrade(clicon_handle h,
cxobj *xt,
cxobj *xs,
cxobj *xmod,
char *ns,
int deleted,
cbuf *cbret)
{
int retval = -1;
@ -403,15 +400,14 @@ mod_ns_upgrade(clicon_handle h,
int ret;
yang_stmt *yspec;
/* Make upgrade callback for this XML, specifying the module
* namespace, from and to revision.
*/
if ((b = xml_find_body(xs, "revision")) != NULL) /* Module revision */
if (ys_parse_date_arg(b, &from) < 0)
goto done;
if (deleted)
to = 0;
else { /* Look up system module (alt send it via argument) */
/* If modified or removed get from revision from file */
if (xml_flag(xmod, (XML_FLAG_CHANGE|XML_FLAG_DEL)) != 0x0){
if ((b = xml_find_body(xmod, "revision")) != NULL) /* Module revision */
if (ys_parse_date_arg(b, &from) < 0)
goto done;
}
/* If modified or added get to revision from system */
if (xml_flag(xmod, (XML_FLAG_CHANGE|XML_FLAG_ADD)) != 0x0){
yspec = clicon_dbspec_yang(h);
if ((ymod = yang_find_module_by_namespace(yspec, ns)) == NULL)
goto fail;
@ -420,7 +416,9 @@ mod_ns_upgrade(clicon_handle h,
if (ys_parse_date_arg(yang_argument_get(yrev), &to) < 0)
goto done;
}
if ((ret = upgrade_callback_call(h, xt, ns, from, to, cbret)) < 0)
if ((ret = upgrade_callback_call(h, xt, ns,
xml_flag(xmod, (XML_FLAG_CHANGE|XML_FLAG_ADD|XML_FLAG_CHANGE)),
from, to, cbret)) < 0)
goto done;
if (ret == 0) /* XXX ignore and continue? */
goto fail;
@ -447,33 +445,25 @@ clixon_module_upgrade(clicon_handle h,
modstate_diff_t *msd,
cbuf *cbret)
{
int retval = -1;
char *ns; /* Namespace */
cxobj *xs; /* XML module state */
int ret;
int retval = -1;
char *ns; /* Namespace */
cxobj *xmod; /* XML module state diff */
int ret;
if (msd == NULL)
if (msd == NULL){
clicon_err(OE_CFG, EINVAL, "No modstate");
goto done;
}
if (msd->md_status == 0) /* No modstate in startup */
goto ok;
/* Iterate through xml modified module state */
xs = NULL;
while ((xs = xml_child_each(msd->md_mod, xs, CX_ELMNT)) != NULL) {
xmod = NULL;
while ((xmod = xml_child_each(msd->md_diff, xmod, CX_ELMNT)) != NULL) {
/* Extract namespace */
if ((ns = xml_find_body(xs, "namespace")) == NULL)
if ((ns = xml_find_body(xmod, "namespace")) == NULL)
goto done;
/* Extract revisions and make callbacks */
if ((ret = mod_ns_upgrade(h, xt, xs, ns, 0, cbret)) < 0)
goto done;
if (ret == 0)
goto fail;
}
/* Iterate through xml deleted module state */
xs = NULL;
while ((xs = xml_child_each(msd->md_del, xs, CX_ELMNT)) != NULL) {
/* Extract namespace */
if ((ns = xml_find_body(xs, "namespace")) == NULL)
continue;
/* Extract revisions and make callbacks (now w deleted=1) */
if ((ret = mod_ns_upgrade(h, xt, xs, ns, 1, cbret)) < 0)
if ((ret = mod_ns_upgrade(h, xt, xmod, ns, cbret)) < 0)
goto done;
if (ret == 0)
goto fail;