xml changelog next iteration

This commit is contained in:
Olof hagsand 2019-03-26 12:04:51 +01:00
parent 1991c3870c
commit 8624be0a67
9 changed files with 532 additions and 353 deletions

View file

@ -541,6 +541,7 @@ rpc_callback_call(clicon_handle h,
typedef struct {
qelem_t uc_qelem; /* List header */
clicon_upgrade_cb uc_callback; /* RPC Callback */
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 */
@ -555,6 +556,7 @@ static upgrade_callback_t *upgrade_cb_list = NULL;
*
* @param[in] h clicon handle
* @param[in] cb Callback called
* @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] rev To module revision (0 means module obsoleted)
@ -564,12 +566,13 @@ static upgrade_callback_t *upgrade_cb_list = NULL;
* @see upgrade_callback_call which makes the actual callback
*/
int
upgrade_callback_register(clicon_handle h,
clicon_upgrade_cb cb,
char *namespace,
uint32_t revision,
uint32_t from,
void *arg)
upgrade_callback_reg_fn(clicon_handle h,
clicon_upgrade_cb cb,
const char *fnstr,
char *namespace,
uint32_t revision,
uint32_t from,
void *arg)
{
upgrade_callback_t *uc;
@ -579,6 +582,7 @@ upgrade_callback_register(clicon_handle h,
}
memset(uc, 0, sizeof(*uc));
uc->uc_callback = cb;
uc->uc_fnstr = fnstr;
uc->uc_arg = arg;
if (namespace)
uc->uc_namespace = strdup(namespace);
@ -623,7 +627,7 @@ upgrade_callback_delete_all(void)
* @retval -1 Error
* @retval 0 Invalid - cbret contains reason as netconf
* @retval 1 OK
* @see upgrade_callback_register which registers the callbacks
* @see upgrade_callback_reg_fn which registers the callbacks
*/
int
upgrade_callback_call(clicon_handle h,
@ -657,8 +661,14 @@ upgrade_callback_call(clicon_handle h,
clicon_debug(1, "%s Error in: %s", __FUNCTION__, uc->uc_namespace);
goto done;
}
if (ret == 0)
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++;
}
uc = NEXTQ(upgrade_callback_t *, uc);

View file

@ -843,7 +843,7 @@ xml_addsub(cxobj *xp,
* @param[in] tag Name of new xml child
* @retval xc Return the new child (xc)
* @see xml_addsub
* The name of the function is somewhat misleading
* The name of the function is somewhat misleading, should be called "wrap"
*/
cxobj *
xml_insert(cxobj *xp,

View file

@ -71,10 +71,146 @@
#include "clixon_xpath_ctx.h"
#include "clixon_xpath.h"
static int
changelog_rename(clicon_handle h,
cxobj *xt,
cxobj *xw,
char *tag)
{
int retval = -1;
xp_ctx *xctx = NULL;
char *str = NULL;
if (tag == NULL){
clicon_err(OE_XML, 0, "tag required");
goto done;
}
if (xpath_vec_ctx(xw, tag, &xctx) < 0)
goto done;
if (ctx2string(xctx, &str) < 0)
goto done;
if (!strlen(str)){
clicon_err(OE_XML, 0, "invalid rename tag: \"%s\"", str);
goto done;
}
if (xml_name_set(xw, str) < 0)
goto done;
// ok:
retval = 1;
done:
if (xctx)
ctx_free(xctx);
if (str)
free(str);
return retval;
// fail:
retval = 0;
goto done;
}
/* replace target XML */
static int
changelog_replace(clicon_handle h,
cxobj *xt,
cxobj *xw,
cxobj *xnew)
{
int retval = -1;
cxobj *x;
/* create a new node by parsing fttransform string and insert it at
target */
if (xnew == NULL){
clicon_err(OE_XML, 0, "new required");
goto done;
}
/* replace: remove all children of target */
while ((x = xml_child_i(xw, 0)) != NULL)
if (xml_purge(x) < 0)
goto done;
/* replace: first single node under <new> */
if (xml_child_nr(xnew) != 1){
clicon_err(OE_XML, 0, "Single child to <new> required");
goto done;
}
x = xml_child_i(xnew, 0);
/* Copy from xnew to (now) empty target */
if (xml_copy(x, xw) < 0)
goto done;
retval = 1;
done:
return retval;
}
/* create a new node by parsing "new" and insert it at
target */
static int
changelog_insert(clicon_handle h,
cxobj *xt,
cxobj *xw,
cxobj *xnew)
{
int retval = -1;
cxobj *x;
if (xnew == NULL){
clicon_err(OE_XML, 0, "new required");
goto done;
}
/* replace: add all new children to target */
while ((x = xml_child_i(xnew, 0)) != NULL)
if (xml_addsub(xw, x) < 0)
goto done;
// ok:
retval = 1;
done:
return retval;
// fail:
retval = 0;
goto done;
}
/* delete target */
static int
changelog_delete(clicon_handle h,
cxobj *xt,
cxobj *xw)
{
int retval = -1;
if (xml_purge(xw) < 0)
goto done;
retval = 1;
done:
return retval;
}
/* Move target node to location */
static int
changelog_move(clicon_handle h,
cxobj *xt,
cxobj *xw,
char *dst)
{
int retval = -1;
cxobj *xp; /* destination parent node */
if ((xp = xpath_first(xt, "%s", dst)) == NULL){
clicon_err(OE_XML, 0, "path required");
goto done;
}
if (xml_addsub(xp, xw) < 0)
goto done;
retval = 1;
done:
return retval;
}
/*! Perform a changelog operation
* @param[in] h Clicon handle
* @param[in] xt XML to upgrade
* @param[in] xi Changelog item
* @param[in] xn XML to upgrade
* @note XXX error handling!
* @note XXX xn --> xt xpath may not match
*/
@ -84,72 +220,84 @@ changelog_op(clicon_handle h,
cxobj *xi)
{
int retval = -1;
char *op;
char *xptarget; /* xpath to target-node */
char *xplocation; /* xpath to location-node (move) */
char *ftransform; /* transform string format (modify, create) */
cxobj *xtrg; /* xml target node */
cxobj *xloc; /* xml location node */
cxobj *xnew = NULL;
cxobj *x;
int retval = -1;
char *op;
char *whenxpath; /* xpath to when */
char *tag; /* xpath to extra path (move) */
char *dst; /* xpath to extra path (move) */
cxobj *xnew; /* new xml (insert, replace) */
char *wxpath; /* xpath to where (target-node) */
cxobj **wvec = NULL; /* Vector of where(target) nodes */
size_t wlen;
cxobj *xw;
int ret;
xp_ctx *xctx = NULL;
int i;
if ((op = xml_find_body(xi, "change-operation")) == NULL)
if ((op = xml_find_body(xi, "op")) == NULL)
goto ok;
if ((xptarget = xml_find_body(xi, "target-node")) == NULL)
/* get common variables that may be used in the operations below */
tag = xml_find_body(xi, "tag");
dst = xml_find_body(xi, "dst");
xnew = xml_find(xi, "new");
whenxpath = xml_find_body(xi, "when");
if ((wxpath = xml_find_body(xi, "where")) == NULL)
goto ok;
/* target node (if any) */
if ((xtrg = xpath_first(xt, "%s", xptarget)) == NULL)
goto fail;
// fprintf(stderr, "%s %s %s\n", __FUNCTION__, op, xml_name(xt));
xplocation = xml_find_body(xi, "location-node");
ftransform = xml_find_body(xi, "transform");
if (strcmp(op, "insert") == 0){
/* create a new node by parsing fttransform string and insert it at
target */
if (ftransform == NULL)
goto fail;
if (xml_parse_va(&xtrg, NULL, "%s", ftransform) < 0)
goto done;
}
else if (strcmp(op, "delete") == 0){
/* delete target */
if (xml_purge(xtrg) < 0)
goto done;
}
else if (strcmp(op, "move") == 0){
/* Move target node to location */
if ((xloc = xpath_first(xt, "%s", xplocation)) == NULL)
goto fail;
if (xml_addsub(xloc, xtrg) < 0)
goto done;
}
else if (strcmp(op, "replace") == 0){
/* create a new node by parsing fttransform string and insert it at
target */
if (ftransform == NULL)
goto fail;
/* replace: remove all children of target */
while ((x = xml_child_i(xtrg, 0)) != NULL)
if (xml_purge(x) < 0)
goto done;
/* Parse the new node */
if (xml_parse_va(&xnew, NULL, "%s", ftransform) < 0)
goto done;
if (xml_rootchild(xnew, 0, &xnew) < 0)
goto done;
/* Copy old to new */
if (xml_copy(xnew, xtrg) < 0)
goto done;
if (xml_purge(xnew) < 0)
goto done;
}
/* Get vector of target nodes meeting the where requirement */
if (xpath_vec(xt, "%s", &wvec, &wlen, wxpath) < 0)
goto done;
for (i=0; i<wlen; i++){
xw = wvec[i];
/* If 'when' exists and is false, skip this target */
if (whenxpath){
if (xpath_vec_ctx(xw, whenxpath, &xctx) < 0)
goto done;
if ((ret = ctx2boolean(xctx)) < 0)
goto done;
if (xctx){
ctx_free(xctx);
xctx = NULL;
}
if (ret == 0)
continue;
}
/* Now switch on operation */
if (strcmp(op, "rename") == 0){
ret = changelog_rename(h, xt, xw, tag);
}
else if (strcmp(op, "replace") == 0){
ret = changelog_replace(h, xt, xw, xnew);
}
else if (strcmp(op, "insert") == 0){
ret = changelog_insert(h, xt, xw, xnew);
}
else if (strcmp(op, "delete") == 0){
ret = changelog_delete(h, xt, xw);
}
else if (strcmp(op, "move") == 0){
ret = changelog_move(h, xt, xw, dst);
}
else{
clicon_err(OE_XML, 0, "Unknown operation: %s", op);
goto done;
}
if (ret < 0)
goto done;
if (ret == 0)
goto fail;
}
ok:
retval = 1;
done:
if (wvec)
free(wvec);
if (xctx)
ctx_free(xctx);
return retval;
fail:
retval = 0;
clicon_debug(1, "%s fail op:%s ", __FUNCTION__, op);
goto done;
}
@ -170,7 +318,7 @@ changelog_iterate(clicon_handle h,
int ret;
int i;
if (xpath_vec(xch, "change-log", &vec, &veclen) < 0)
if (xpath_vec(xch, "step", &vec, &veclen) < 0)
goto done;
/* Iterate through changelog items */
for (i=0; i<veclen; i++){
@ -181,6 +329,7 @@ changelog_iterate(clicon_handle h,
}
retval = 1;
done:
clicon_debug(1, "%s retval: %d", __FUNCTION__, retval);
if (vec)
free(vec);
return retval;
@ -233,7 +382,7 @@ xml_changelog_upgrade(clicon_handle h,
* - find all changelogs in the interval: [from, to]
* - note it t=0 then no changelog is applied
*/
if (xpath_vec(xchlog, "module[namespace=\"%s\"]",
if (xpath_vec(xchlog, "changelog[namespace=\"%s\"]",
&vec, &veclen, namespace) < 0)
goto done;
/* Get all changelogs in the interval [from,to]*/

View file

@ -830,7 +830,6 @@ xp_union(xp_ctx *xc1,
return retval;
}
/*! Evaluate an XPATH on an XML tree
* The initial sequence of steps selects a set of nodes relative to a context node.
@ -1038,11 +1037,20 @@ xp_eval(xp_ctx *xc,
}
/*! Given XML tree and xpath, returns xpath context
* This is a raw form of xpath where you can do type conversion, etc,
* not just a nodeset.
* @param[in] xcur XML-tree where to search
* @param[in] xpath String with XPATH 1.0 syntax
* @param[out] xrp Return XPATH context
* @retval 0 OK
* @retval -1 Error
* @code
* xp_ctx *xc = NULL;
* if (xpath_vec_ctx(x, xpath, &xc) < 0)
* err;
* if (xc)
* ctx_free(xc);
* @endcode
*/
int
xpath_vec_ctx(cxobj *xcur,
@ -1295,6 +1303,7 @@ xpath_vec_flag(cxobj *xcur,
}
/*! Given XML tree and xpath, returns boolean
* Returns true if the nodeset is non-empty
* @param[in] xcur xml-tree where to search
* @param[in] xpath stdarg string with XPATH 1.0 syntax
* @retval 1 True