General-purpose upgrade
This commit is contained in:
parent
3748eefb8e
commit
b6812793f9
18 changed files with 286 additions and 165 deletions
|
|
@ -197,9 +197,11 @@ startup_common(clicon_handle h,
|
||||||
xt = NULL;
|
xt = NULL;
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
if (clixon_plugin_xmldb_repair(h, db, xt) < 0)
|
|
||||||
goto done;
|
|
||||||
/* Here xt is old syntax */
|
/* Here xt is old syntax */
|
||||||
|
/* General purpose datastore upgrade */
|
||||||
|
if (clixon_plugin_datastore_upgrade(h, db, xt, msd) < 0)
|
||||||
|
goto done;
|
||||||
|
/* Module-specific upgrade callbacks */
|
||||||
if ((ret = clixon_module_upgrade(h, xt, msd, cbret)) < 0)
|
if ((ret = clixon_module_upgrade(h, xt, msd, cbret)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
|
|
|
||||||
|
|
@ -173,98 +173,6 @@ main_abort(clicon_handle h,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct map_str2str{
|
|
||||||
char *ms_path;
|
|
||||||
char *ms_ns;
|
|
||||||
};
|
|
||||||
static const struct map_str2str path_namespace_map[] = {
|
|
||||||
{"/a:x/a:y/a:z/a:w", "urn:example:b"},
|
|
||||||
{"/a:x/a:y/a:z", "urn:example:b"},
|
|
||||||
{NULL, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
static int
|
|
||||||
main_repair_one(cxobj *xt,
|
|
||||||
char *mypath,
|
|
||||||
char *mynamespace,
|
|
||||||
cvec *nsc)
|
|
||||||
{
|
|
||||||
int retval = -1;
|
|
||||||
cxobj **xvec = NULL;
|
|
||||||
size_t xlen;
|
|
||||||
char *myprefix = NULL;
|
|
||||||
int i;
|
|
||||||
cxobj *x;
|
|
||||||
char *namespace;
|
|
||||||
char *pexist = NULL; /* Existing prefix */
|
|
||||||
|
|
||||||
if (xpath_vec(xt, nsc, "%s", &xvec, &xlen, mypath) < 0)
|
|
||||||
goto done;
|
|
||||||
if (xml_nsctx_get_prefix(nsc, mynamespace, &myprefix) == 0){
|
|
||||||
clicon_err(OE_XML, ENOENT, "Namespace %s not found in canonical namespace map",
|
|
||||||
mynamespace);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
for (i=0; i<xlen; i++){
|
|
||||||
x = xvec[i];
|
|
||||||
namespace = NULL;
|
|
||||||
if (xml2ns(x, xml_prefix(x), &namespace) < 0)
|
|
||||||
goto done;
|
|
||||||
if (strcmp(namespace, mynamespace) == 0)
|
|
||||||
continue; /* After this point namespace is not correct */
|
|
||||||
/* Is namespace already declared? */
|
|
||||||
if (xml2prefix(x, mynamespace, &pexist) == 1){
|
|
||||||
/* Yes it is declared and the prefix is pexists */
|
|
||||||
if (xml_prefix_set(x, pexist) < 0)
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
else{ /* Namespace does not exist, add it */
|
|
||||||
if (add_namespace(x, xml_parent(x), myprefix, mynamespace) < 0)
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
if (xvec)
|
|
||||||
free(xvec);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Datastore repair callback
|
|
||||||
* Gets called on startup after initial XML parsing, but before upgrading and before validation
|
|
||||||
* @param[in] h Clicon handle
|
|
||||||
* @param[in] db Name of datastore, eg "running"
|
|
||||||
* @param[in] xt XML tree (to repair)
|
|
||||||
* @retval -1 Error
|
|
||||||
* @retval 0 OK
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
main_repair(clicon_handle h,
|
|
||||||
char *db,
|
|
||||||
cxobj *xt)
|
|
||||||
{
|
|
||||||
int retval = -1;
|
|
||||||
cvec *nsc = NULL; /* Canonical namespace */
|
|
||||||
yang_stmt *yspec;
|
|
||||||
const struct map_str2str *ms;
|
|
||||||
|
|
||||||
if (strcmp(db, "startup") != 0) /* skip other than startup */
|
|
||||||
goto ok;
|
|
||||||
yspec = clicon_dbspec_yang(h); /* Get all yangs */
|
|
||||||
/* Get canonical namespace */
|
|
||||||
if (xml_nsctx_yangspec(yspec, &nsc) < 0)
|
|
||||||
goto done;
|
|
||||||
for (ms = &path_namespace_map[0]; ms->ms_path; ms++)
|
|
||||||
if (main_repair_one(xt, ms->ms_path, ms->ms_ns, nsc) < 0)
|
|
||||||
goto done;
|
|
||||||
ok:
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
if (nsc)
|
|
||||||
cvec_free(nsc);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Routing example notification timer handler. Here is where the periodic action is
|
/*! Routing example notification timer handler. Here is where the periodic action is
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
|
|
@ -502,6 +410,112 @@ example_extension(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Here follows code for general-purpose datastore upgrade
|
||||||
|
* Nodes affected are identified by paths.
|
||||||
|
* In this example nodes' namespaces are changed, or they are removed altogether
|
||||||
|
*/
|
||||||
|
/* Rename the namespaces of these paths.
|
||||||
|
* That is, paths (on the left) should get namespaces (to the right)
|
||||||
|
*/
|
||||||
|
static const map_str2str namespace_map[] = {
|
||||||
|
{"/a:x/a:y/a:z/descendant-or-self::node()", "urn:example:b"},
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Remove these paths */
|
||||||
|
static const char *remove_map[] = {
|
||||||
|
"/a:remove_me",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
/*! General-purpose datastore upgrade callback called once on startup
|
||||||
|
*
|
||||||
|
* Gets called on startup after initial XML parsing, but before module-specific upgrades
|
||||||
|
* and before validation.
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] db Name of datastore, eg "running", "startup" or "tmp"
|
||||||
|
* @param[in] xt XML tree. Upgrade this "in place"
|
||||||
|
* @param[in] msd Info on datastore module-state, if any
|
||||||
|
* @retval -1 Error
|
||||||
|
* @retval 0 OK
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
example_upgrade(clicon_handle h,
|
||||||
|
char *db,
|
||||||
|
cxobj *xt,
|
||||||
|
modstate_diff_t *msd)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cvec *nsc = NULL; /* Canonical namespace */
|
||||||
|
yang_stmt *yspec; yang_stmt *yspec;
|
||||||
|
const struct map_str2str *ms; /* map iterator */
|
||||||
|
cxobj **xvec = NULL; /* vector of result nodes */
|
||||||
|
size_t xlen;
|
||||||
|
int i;
|
||||||
|
const char **pp;
|
||||||
|
|
||||||
|
if (strcmp(db, "startup") != 0) /* skip other than startup datastore */
|
||||||
|
goto ok;
|
||||||
|
if (msd->md_status) /* skip if there is proper module-state in datastore */
|
||||||
|
goto ok;
|
||||||
|
yspec = clicon_dbspec_yang(h); /* Get all yangs */
|
||||||
|
/* Get canonical namespaces for using "normalized" prefixes */
|
||||||
|
if (xml_nsctx_yangspec(yspec, &nsc) < 0)
|
||||||
|
goto done;
|
||||||
|
/* 1. Remove paths */
|
||||||
|
for (pp = remove_map; *pp; ++pp){
|
||||||
|
/* Find all nodes matching n */
|
||||||
|
if (xpath_vec(xt, nsc, "%s", &xvec, &xlen, *pp) < 0)
|
||||||
|
goto done;
|
||||||
|
/* Remove them */
|
||||||
|
/* Loop through all nodes matching mypath and change theoir namespace */
|
||||||
|
for (i=0; i<xlen; i++){
|
||||||
|
if (xml_purge(xvec[i]) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (xvec){
|
||||||
|
free(xvec);
|
||||||
|
xvec = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 2. Rename namespaces of the paths declared in the namespace map
|
||||||
|
*/
|
||||||
|
for (ms = &namespace_map[0]; ms->ms_s0; ms++){
|
||||||
|
char *mypath;
|
||||||
|
char *mynamespace;
|
||||||
|
char *myprefix = NULL;
|
||||||
|
|
||||||
|
mypath = ms->ms_s0;
|
||||||
|
mynamespace = ms->ms_s1;
|
||||||
|
if (xml_nsctx_get_prefix(nsc, mynamespace, &myprefix) == 0){
|
||||||
|
clicon_err(OE_XML, ENOENT, "Namespace %s not found in canonical namespace map",
|
||||||
|
mynamespace);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
/* Find all nodes matching mypath */
|
||||||
|
if (xpath_vec(xt, nsc, "%s", &xvec, &xlen, mypath) < 0)
|
||||||
|
goto done;
|
||||||
|
/* Loop through all nodes matching mypath and change theoir namespace */
|
||||||
|
for (i=0; i<xlen; i++){
|
||||||
|
/* Change namespace of this node (using myprefix) */
|
||||||
|
if (xml_namespace_change(xvec[i], mynamespace, myprefix) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (xvec){
|
||||||
|
free(xvec);
|
||||||
|
xvec = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ok:
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (xvec)
|
||||||
|
free(xvec);
|
||||||
|
if (nsc)
|
||||||
|
cvec_free(nsc);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Testcase upgrade function moving interfaces-state to interfaces
|
/*! Testcase upgrade function moving interfaces-state to interfaces
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] xn XML tree to be updated
|
* @param[in] xn XML tree to be updated
|
||||||
|
|
@ -777,7 +791,7 @@ static clixon_plugin_api api = {
|
||||||
.ca_trans_revert=main_revert, /* trans revert */
|
.ca_trans_revert=main_revert, /* trans revert */
|
||||||
.ca_trans_end=main_end, /* trans end */
|
.ca_trans_end=main_end, /* trans end */
|
||||||
.ca_trans_abort=main_abort, /* trans abort */
|
.ca_trans_abort=main_abort, /* trans abort */
|
||||||
.ca_xmldb_repair=main_repair /* xmldb repair. */
|
.ca_datastore_upgrade=example_upgrade /* gneral-purpose upgrade. */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*! Backend plugin initialization
|
/*! Backend plugin initialization
|
||||||
|
|
|
||||||
|
|
@ -159,15 +159,18 @@ typedef int (trans_cb_t)(clicon_handle h, transaction_data td);
|
||||||
*/
|
*/
|
||||||
typedef char *(cli_prompthook_t)(clicon_handle, char *mode);
|
typedef char *(cli_prompthook_t)(clicon_handle, char *mode);
|
||||||
|
|
||||||
/*! Datastore repair callback
|
/*! General-purpose datastore upgrade callback called once on startup
|
||||||
* Gets called on startup after initial XML parsing, but before upgrading and before validation
|
*
|
||||||
|
* Gets called on startup after initial XML parsing, but before module-specific upgrades
|
||||||
|
* and before validation.
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] db Name of datastore, eg "running"
|
* @param[in] db Name of datastore, eg "running", "startup" or "tmp"
|
||||||
* @param[in] xt XML tree. Repair this "in place"
|
* @param[in] xt XML tree. Upgrade this "in place"
|
||||||
|
* @param[in] msd Info on datastore module-state, if any
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
*/
|
*/
|
||||||
typedef int (xmldb_repair_t)(clicon_handle h, char *db, cxobj *xt);
|
typedef int (datastore_upgrade_t)(clicon_handle h, char *db, cxobj *xt, modstate_diff_t *msd);
|
||||||
|
|
||||||
/*! Startup status for use in startup-callback
|
/*! Startup status for use in startup-callback
|
||||||
* Note that for STARTUP_ERR and _INVALID, running runs in failsafe mode
|
* Note that for STARTUP_ERR and _INVALID, running runs in failsafe mode
|
||||||
|
|
@ -216,8 +219,7 @@ struct clixon_plugin_api{
|
||||||
trans_cb_t *cb_trans_revert; /* Transaction revert */
|
trans_cb_t *cb_trans_revert; /* Transaction revert */
|
||||||
trans_cb_t *cb_trans_end; /* Transaction completed */
|
trans_cb_t *cb_trans_end; /* Transaction completed */
|
||||||
trans_cb_t *cb_trans_abort; /* Transaction aborted */
|
trans_cb_t *cb_trans_abort; /* Transaction aborted */
|
||||||
xmldb_repair_t *cb_xmldb_repair; /* Repair datastore on load */
|
datastore_upgrade_t *cb_datastore_upgrade; /* General-purpose datastore upgrade */
|
||||||
|
|
||||||
} cau_backend;
|
} cau_backend;
|
||||||
} u;
|
} u;
|
||||||
};
|
};
|
||||||
|
|
@ -235,7 +237,7 @@ struct clixon_plugin_api{
|
||||||
#define ca_trans_revert u.cau_backend.cb_trans_revert
|
#define ca_trans_revert u.cau_backend.cb_trans_revert
|
||||||
#define ca_trans_end u.cau_backend.cb_trans_end
|
#define ca_trans_end u.cau_backend.cb_trans_end
|
||||||
#define ca_trans_abort u.cau_backend.cb_trans_abort
|
#define ca_trans_abort u.cau_backend.cb_trans_abort
|
||||||
#define ca_xmldb_repair u.cau_backend.cb_xmldb_repair
|
#define ca_datastore_upgrade u.cau_backend.cb_datastore_upgrade
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -284,7 +286,7 @@ int clixon_plugin_auth(clicon_handle h, void *arg);
|
||||||
|
|
||||||
int clixon_plugin_extension(clicon_handle h, yang_stmt *yext, yang_stmt *ys);
|
int clixon_plugin_extension(clicon_handle h, yang_stmt *yext, yang_stmt *ys);
|
||||||
|
|
||||||
int clixon_plugin_xmldb_repair(clicon_handle h, char *db, cxobj *xt);
|
int clixon_plugin_datastore_upgrade(clicon_handle h, char *db, cxobj *xt, modstate_diff_t *msd);
|
||||||
|
|
||||||
/* rpc callback API */
|
/* rpc callback API */
|
||||||
int rpc_callback_register(clicon_handle h, clicon_rpc_cb cb, void *arg, char *namespace, char *name);
|
int rpc_callback_register(clicon_handle h, clicon_rpc_cb cb, void *arg, char *namespace, char *name);
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@
|
||||||
#ifndef _CLIXON_STRING_H_
|
#ifndef _CLIXON_STRING_H_
|
||||||
#define _CLIXON_STRING_H_
|
#define _CLIXON_STRING_H_
|
||||||
|
|
||||||
/* Struct used to map between int and strings. Typically used to map between
|
/*! Struct used to map between int and strings. Typically used to map between
|
||||||
* values and their names. Note NULL terminated
|
* values and their names. Note NULL terminated
|
||||||
* Example:
|
* Example:
|
||||||
* @code
|
* @code
|
||||||
|
|
@ -55,6 +55,14 @@ struct map_str2int{
|
||||||
};
|
};
|
||||||
typedef struct map_str2int map_str2int;
|
typedef struct map_str2int map_str2int;
|
||||||
|
|
||||||
|
/*! Struct used to map between two strings.
|
||||||
|
*/
|
||||||
|
struct map_str2str{
|
||||||
|
char *ms_s0;
|
||||||
|
char *ms_s1;
|
||||||
|
};
|
||||||
|
typedef struct map_str2str map_str2str;
|
||||||
|
|
||||||
/*! A malloc version that aligns on 4 bytes. To avoid warning from valgrind */
|
/*! A malloc version that aligns on 4 bytes. To avoid warning from valgrind */
|
||||||
#define align4(s) (((s)/4)*4 + 4)
|
#define align4(s) (((s)/4)*4 + 4)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ int xml_diff(yang_stmt *yspec, cxobj *x0, cxobj *x1,
|
||||||
cxobj ***changed_x0, cxobj ***changed_x1, size_t *changedlen);
|
cxobj ***changed_x0, cxobj ***changed_x1, size_t *changedlen);
|
||||||
int xml_tree_prune_flagged_sub(cxobj *xt, int flag, int test, int *upmark);
|
int xml_tree_prune_flagged_sub(cxobj *xt, int flag, int test, int *upmark);
|
||||||
int xml_tree_prune_flagged(cxobj *xt, int flag, int test);
|
int xml_tree_prune_flagged(cxobj *xt, int flag, int test);
|
||||||
int add_namespace(cxobj *x1, cxobj *x1p, char *prefix1, char *namespace);
|
int xml_namespace_change(cxobj *x, char *namespace, char *prefix);
|
||||||
int xml_default(cxobj *x, void *arg);
|
int xml_default(cxobj *x, void *arg);
|
||||||
int xml_sanity(cxobj *x, void *arg);
|
int xml_sanity(cxobj *x, void *arg);
|
||||||
int xml_non_config_data(cxobj *xt, void *arg);
|
int xml_non_config_data(cxobj *xt, void *arg);
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,8 @@
|
||||||
* This is in state of flux so it needs to be contained and easily changed.
|
* This is in state of flux so it needs to be contained and easily changed.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
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_del; /* yang module state deletes */
|
||||||
cxobj *md_mod; /* yang module state modifications */
|
cxobj *md_mod; /* yang module state modifications */
|
||||||
} modstate_diff_t;
|
} modstate_diff_t;
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,7 @@
|
||||||
#include "clixon_yang.h"
|
#include "clixon_yang.h"
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
#include "clixon_xml_sort.h"
|
#include "clixon_xml_sort.h"
|
||||||
|
#include "clixon_yang_module.h"
|
||||||
#include "clixon_options.h"
|
#include "clixon_options.h"
|
||||||
#include "clixon_plugin.h"
|
#include "clixon_plugin.h"
|
||||||
#include "clixon_xpath_ctx.h"
|
#include "clixon_xpath_ctx.h"
|
||||||
|
|
|
||||||
|
|
@ -69,12 +69,11 @@
|
||||||
#include "clixon_file.h"
|
#include "clixon_file.h"
|
||||||
#include "clixon_yang.h"
|
#include "clixon_yang.h"
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
|
#include "clixon_yang_module.h"
|
||||||
#include "clixon_plugin.h"
|
#include "clixon_plugin.h"
|
||||||
#include "clixon_options.h"
|
#include "clixon_options.h"
|
||||||
#include "clixon_data.h"
|
#include "clixon_data.h"
|
||||||
#include "clixon_yang_module.h"
|
|
||||||
#include "clixon_datastore.h"
|
#include "clixon_datastore.h"
|
||||||
|
|
||||||
#include "clixon_datastore_write.h"
|
#include "clixon_datastore_write.h"
|
||||||
#include "clixon_datastore_read.h"
|
#include "clixon_datastore_read.h"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -245,7 +245,8 @@ text_read_modstate(clicon_handle h,
|
||||||
if ((xmodst = xml_find_type(xt, NULL, "modules-state", CX_ELMNT)) == NULL){
|
if ((xmodst = xml_find_type(xt, NULL, "modules-state", CX_ELMNT)) == NULL){
|
||||||
/* 1) There is no modules-state info in the file */
|
/* 1) There is no modules-state info in the file */
|
||||||
}
|
}
|
||||||
else if (xmcache && msd){
|
else if (xmcache && msd){ /* There is module state. */
|
||||||
|
msd->md_status = 1;
|
||||||
/* Create diff trees */
|
/* Create diff trees */
|
||||||
if (xml_parse_string("<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\"/>", yspec, &msd->md_del) < 0)
|
if (xml_parse_string("<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\"/>", yspec, &msd->md_del) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -258,6 +259,13 @@ text_read_modstate(clicon_handle h,
|
||||||
|
|
||||||
/* 3) For each module state m in the file */
|
/* 3) For each module state m in the file */
|
||||||
while ((xm = xml_child_each(xmodst, xm, CX_ELMNT)) != NULL) {
|
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){
|
||||||
|
clicon_err(OE_UNIX, errno, "strdup");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue; /* ignore other tags, such as module-set-id */
|
||||||
if (strcmp(xml_name(xm), "module"))
|
if (strcmp(xml_name(xm), "module"))
|
||||||
continue; /* ignore other tags, such as module-set-id */
|
continue; /* ignore other tags, such as module-set-id */
|
||||||
if ((name = xml_find_body(xm, "name")) == NULL)
|
if ((name = xml_find_body(xm, "name")) == NULL)
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@
|
||||||
#include "clixon_handle.h"
|
#include "clixon_handle.h"
|
||||||
#include "clixon_yang.h"
|
#include "clixon_yang.h"
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
|
#include "clixon_yang_module.h"
|
||||||
#include "clixon_plugin.h"
|
#include "clixon_plugin.h"
|
||||||
|
|
||||||
/* List of plugins XXX
|
/* List of plugins XXX
|
||||||
|
|
@ -467,27 +468,34 @@ clixon_plugin_extension(clicon_handle h,
|
||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
/*! Call plugin module repair in all plugins
|
/*! Call plugingeneral-purpose datastore upgrade in all plugins
|
||||||
*
|
*
|
||||||
* Repair datastore on load before or as an alternative to the upgrading mechanism
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] db Name of datastore, eg "running", "startup" or "tmp"
|
||||||
|
* @param[in] xt XML tree. Upgrade this "in place"
|
||||||
|
* @param[in] msd Module-state diff, info on datastore module-state
|
||||||
|
* @retval -1 Error
|
||||||
|
* @retval 0 OK
|
||||||
|
* Upgrade datastore on load before or as an alternative to module-specific upgrading mechanism
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* Call plugin start functions (if defined)
|
* Call plugin start functions (if defined)
|
||||||
* @note Start functions used to have argc/argv. Use clicon_argv_get() instead
|
* @note Start functions used to have argc/argv. Use clicon_argv_get() instead
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clixon_plugin_xmldb_repair(clicon_handle h,
|
clixon_plugin_datastore_upgrade(clicon_handle h,
|
||||||
char *db,
|
char *db,
|
||||||
cxobj *xt)
|
cxobj *xt,
|
||||||
|
modstate_diff_t *msd)
|
||||||
{
|
{
|
||||||
clixon_plugin *cp;
|
clixon_plugin *cp;
|
||||||
int i;
|
int i;
|
||||||
xmldb_repair_t *repairfn;
|
datastore_upgrade_t *repairfn;
|
||||||
|
|
||||||
for (i = 0; i < _clixon_nplugins; i++) {
|
for (i = 0; i < _clixon_nplugins; i++) {
|
||||||
cp = &_clixon_plugins[i];
|
cp = &_clixon_plugins[i];
|
||||||
if ((repairfn = cp->cp_api.ca_xmldb_repair) == NULL)
|
if ((repairfn = cp->cp_api.ca_datastore_upgrade) == NULL)
|
||||||
continue;
|
continue;
|
||||||
if (repairfn(h, db, xt) < 0) {
|
if (repairfn(h, db, xt, msd) < 0) {
|
||||||
clicon_debug(1, "%s() failed", __FUNCTION__);
|
clicon_debug(1, "%s() failed", __FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
#include "clixon_options.h"
|
#include "clixon_options.h"
|
||||||
#include "clixon_data.h"
|
#include "clixon_data.h"
|
||||||
|
#include "clixon_yang_module.h"
|
||||||
#include "clixon_plugin.h"
|
#include "clixon_plugin.h"
|
||||||
#include "clixon_string.h"
|
#include "clixon_string.h"
|
||||||
#include "clixon_xpath_ctx.h"
|
#include "clixon_xpath_ctx.h"
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@
|
||||||
#include "clixon_yang.h"
|
#include "clixon_yang.h"
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
#include "clixon_options.h"
|
#include "clixon_options.h"
|
||||||
|
#include "clixon_yang_module.h"
|
||||||
#include "clixon_plugin.h"
|
#include "clixon_plugin.h"
|
||||||
#include "clixon_xml_nsctx.h"
|
#include "clixon_xml_nsctx.h"
|
||||||
#include "clixon_xpath_ctx.h"
|
#include "clixon_xpath_ctx.h"
|
||||||
|
|
@ -708,7 +709,7 @@ xml_tree_prune_flagged(cxobj *xt,
|
||||||
|
|
||||||
/*! Add prefix:namespace pair to xml node, set cache, prefix, etc
|
/*! Add prefix:namespace pair to xml node, set cache, prefix, etc
|
||||||
*/
|
*/
|
||||||
int
|
static int
|
||||||
add_namespace(cxobj *x1, /* target */
|
add_namespace(cxobj *x1, /* target */
|
||||||
cxobj *x1p,
|
cxobj *x1p,
|
||||||
char *prefix1,
|
char *prefix1,
|
||||||
|
|
@ -746,6 +747,49 @@ add_namespace(cxobj *x1, /* target */
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Change namespace of XML node
|
||||||
|
*
|
||||||
|
* @param[in] x XML node
|
||||||
|
* @param[in] namespace Change to this namespace (if it does not already belong to it)
|
||||||
|
* @param[in] prefix If change, use this namespace
|
||||||
|
* @param 0 OK
|
||||||
|
* @param -1 Error
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml_namespace_change(cxobj *x,
|
||||||
|
char *namespace,
|
||||||
|
char *prefix)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cxobj *xp;
|
||||||
|
char *ns0 = NULL; /* existing namespace */
|
||||||
|
char *prefix0 = NULL; /* existing prefix */
|
||||||
|
|
||||||
|
ns0 = NULL;
|
||||||
|
if (xml2ns(x, xml_prefix(x), &ns0) < 0)
|
||||||
|
goto done;
|
||||||
|
if (strcmp(ns0, namespace) == 0)
|
||||||
|
goto ok; /* Already has right namespace */
|
||||||
|
/* Is namespace already declared? */
|
||||||
|
if (xml2prefix(x, namespace, &prefix0) == 1){
|
||||||
|
/* Yes it is declared and the prefix is pexists */
|
||||||
|
if (xml_prefix_set(x, prefix0) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
else{ /* Namespace does not exist, add it */
|
||||||
|
if ((xp = xml_parent(x)) == NULL){
|
||||||
|
clicon_err(OE_XML, ENOENT, "XML node must have parent");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (add_namespace(x, xp, prefix0, namespace) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
ok:
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Add default values (if not set)
|
/*! Add default values (if not set)
|
||||||
* @param[in] xt XML tree with some node marked
|
* @param[in] xt XML tree with some node marked
|
||||||
* @param[in] arg Ignored
|
* @param[in] arg Ignored
|
||||||
|
|
|
||||||
|
|
@ -122,11 +122,11 @@ static const map_str2int xpath_tree_map[] = {
|
||||||
static const map_str2int axis_type_map[] = {
|
static const map_str2int axis_type_map[] = {
|
||||||
{"NaN", A_NAN},
|
{"NaN", A_NAN},
|
||||||
{"ancestor", A_ANCESTOR},
|
{"ancestor", A_ANCESTOR},
|
||||||
{"ancestor-or-selgf", A_ANCESTOR_OR_SELF},
|
{"ancestor-or-self", A_ANCESTOR_OR_SELF},
|
||||||
{"attribute", A_ATTRIBUTE},
|
{"attribute", A_ATTRIBUTE},
|
||||||
{"child", A_CHILD},
|
{"child", A_CHILD},
|
||||||
{"descendant", A_DESCENDANT},
|
{"descendant", A_DESCENDANT},
|
||||||
{"descendeant-or-self", A_DESCENDANT_OR_SELF},
|
{"descendant-or-self", A_DESCENDANT_OR_SELF},
|
||||||
{"following", A_FOLLOWING},
|
{"following", A_FOLLOWING},
|
||||||
{"following-sibling", A_FOLLOWING_SIBLING},
|
{"following-sibling", A_FOLLOWING_SIBLING},
|
||||||
{"namespace", A_NAMESPACE},
|
{"namespace", A_NAMESPACE},
|
||||||
|
|
|
||||||
|
|
@ -362,8 +362,19 @@ xp_eval_step(xp_ctx *xc0,
|
||||||
}
|
}
|
||||||
ctx_nodeset_replace(xc, vec, veclen);
|
ctx_nodeset_replace(xc, vec, veclen);
|
||||||
break;
|
break;
|
||||||
case A_DESCENDANT:
|
|
||||||
case A_DESCENDANT_OR_SELF:
|
case A_DESCENDANT_OR_SELF:
|
||||||
|
for (i=0; i<xc->xc_size; i++){
|
||||||
|
xv = xc->xc_nodeset[i];
|
||||||
|
if (nodetest_recursive(xv, xs->xs_c0, CX_ELMNT, 0x0, nsc, localonly, &vec, &veclen) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
for (i=0; i<veclen; i++){
|
||||||
|
x = vec[i];
|
||||||
|
if (cxvec_append(x, &xc->xc_nodeset, &xc->xc_size) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case A_DESCENDANT:
|
||||||
for (i=0; i<xc->xc_size; i++){
|
for (i=0; i<xc->xc_size; i++){
|
||||||
xv = xc->xc_nodeset[i];
|
xv = xc->xc_nodeset[i];
|
||||||
if (nodetest_recursive(xv, xs->xs_c0, CX_ELMNT, 0x0, nsc, localonly, &vec, &veclen) < 0)
|
if (nodetest_recursive(xv, xs->xs_c0, CX_ELMNT, 0x0, nsc, localonly, &vec, &veclen) < 0)
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,7 @@
|
||||||
#include "clixon_yang.h"
|
#include "clixon_yang.h"
|
||||||
#include "clixon_hash.h"
|
#include "clixon_hash.h"
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
|
#include "clixon_yang_module.h"
|
||||||
#include "clixon_plugin.h"
|
#include "clixon_plugin.h"
|
||||||
#include "clixon_data.h"
|
#include "clixon_data.h"
|
||||||
#include "clixon_options.h"
|
#include "clixon_options.h"
|
||||||
|
|
|
||||||
|
|
@ -74,10 +74,10 @@
|
||||||
#include "clixon_xpath.h"
|
#include "clixon_xpath.h"
|
||||||
#include "clixon_options.h"
|
#include "clixon_options.h"
|
||||||
#include "clixon_data.h"
|
#include "clixon_data.h"
|
||||||
|
#include "clixon_yang_module.h"
|
||||||
#include "clixon_plugin.h"
|
#include "clixon_plugin.h"
|
||||||
#include "clixon_netconf_lib.h"
|
#include "clixon_netconf_lib.h"
|
||||||
#include "clixon_xml_map.h"
|
#include "clixon_xml_map.h"
|
||||||
#include "clixon_yang_module.h"
|
|
||||||
#include "clixon_yang_internal.h" /* internal */
|
#include "clixon_yang_internal.h" /* internal */
|
||||||
|
|
||||||
modstate_diff_t *
|
modstate_diff_t *
|
||||||
|
|
@ -97,6 +97,8 @@ modstate_diff_free(modstate_diff_t *md)
|
||||||
{
|
{
|
||||||
if (md == NULL)
|
if (md == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
if (md->md_set_id)
|
||||||
|
free(md->md_set_id);
|
||||||
if (md->md_del)
|
if (md->md_del)
|
||||||
xml_free(md->md_del);
|
xml_free(md->md_del);
|
||||||
if (md->md_mod)
|
if (md->md_mod)
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,7 @@
|
||||||
#include "clixon_yang.h"
|
#include "clixon_yang.h"
|
||||||
#include "clixon_hash.h"
|
#include "clixon_hash.h"
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
|
#include "clixon_yang_module.h"
|
||||||
#include "clixon_plugin.h"
|
#include "clixon_plugin.h"
|
||||||
#include "clixon_options.h"
|
#include "clixon_options.h"
|
||||||
#include "clixon_yang.h"
|
#include "clixon_yang.h"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Keep a vector of {xpath, namespace} pairs, match xpath in parsed XML and check if symbols belong to namespace
|
# Test of the general-purpose (raw) upgrade mechanism.
|
||||||
# If not, set that namespace.
|
# Input is a startup db without mod-state info.
|
||||||
# This is a primitive upgrade mechanism if th emore general upgrade mechanism can not be used
|
# It has wrong namespace bindings and needs to remove some nodes
|
||||||
|
# Output is a valid config woith correct namespaces and removed nods
|
||||||
|
# The code for this is in the main example backend plugin.
|
||||||
|
|
||||||
# Magic line must be first in script (see README.md)
|
# Magic line must be first in script (see README.md)
|
||||||
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||||
|
|
@ -40,6 +42,12 @@ module A{
|
||||||
container y {
|
container y {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
list remove_me {
|
||||||
|
key k;
|
||||||
|
leaf k {
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
|
@ -65,18 +73,6 @@ EOF
|
||||||
# permission kludges
|
# permission kludges
|
||||||
sudo touch $dir/startup_db
|
sudo touch $dir/startup_db
|
||||||
sudo chmod 666 $dir/startup_db
|
sudo chmod 666 $dir/startup_db
|
||||||
# Create startup db of "old" db with incorrect augment namespace tagging
|
|
||||||
cat <<EOF > $dir/startup_db
|
|
||||||
<config>
|
|
||||||
<x xmlns="urn:example:a">
|
|
||||||
<y>
|
|
||||||
<z>
|
|
||||||
<w>foo</w>
|
|
||||||
</z>
|
|
||||||
</y>
|
|
||||||
</x>
|
|
||||||
</config>
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# This is how it should look after repair, using prefixes
|
# This is how it should look after repair, using prefixes
|
||||||
AFTER=$(cat <<EOF
|
AFTER=$(cat <<EOF
|
||||||
|
|
@ -84,9 +80,7 @@ AFTER=$(cat <<EOF
|
||||||
EOF
|
EOF
|
||||||
)
|
)
|
||||||
|
|
||||||
# Or using default:
|
testrun(){
|
||||||
# <config><x xmlns="urn:example:a"><y><z xmlns="urn:example:b"><w>foo</w></z></y></x></config>
|
|
||||||
|
|
||||||
new "test params: -f $cfg"
|
new "test params: -f $cfg"
|
||||||
# Bring your own backend
|
# Bring your own backend
|
||||||
if [ $BE -ne 0 ]; then
|
if [ $BE -ne 0 ]; then
|
||||||
|
|
@ -106,6 +100,7 @@ fi
|
||||||
new "netconf get config"
|
new "netconf get config"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data>$AFTER</data></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data>$AFTER</data></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
if [ $BE -ne 0 ]; then
|
||||||
new "Kill backend"
|
new "Kill backend"
|
||||||
# Check if premature kill
|
# Check if premature kill
|
||||||
pid=$(pgrep -u root -f clixon_backend)
|
pid=$(pgrep -u root -f clixon_backend)
|
||||||
|
|
@ -114,5 +109,27 @@ if [ -z "$pid" ]; then
|
||||||
fi
|
fi
|
||||||
# kill backend
|
# kill backend
|
||||||
stop_backend -f $cfg
|
stop_backend -f $cfg
|
||||||
|
fi
|
||||||
|
|
||||||
#rm -rf $dir
|
} # end testrun
|
||||||
|
|
||||||
|
# Create startup db of "old" db with incorrect augment namespace tagging
|
||||||
|
# without modstate
|
||||||
|
cat <<EOF > $dir/startup_db
|
||||||
|
<config>
|
||||||
|
<x xmlns="urn:example:a">
|
||||||
|
<y>
|
||||||
|
<z>
|
||||||
|
<w>foo</w>
|
||||||
|
</z>
|
||||||
|
</y>
|
||||||
|
</x>
|
||||||
|
<remove_me xmlns="urn:example:a"><k>This node is obsolete</k></remove_me>
|
||||||
|
<remove_me xmlns="urn:example:a"><k>this too</k></remove_me>
|
||||||
|
</config>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
new "general-purpose upgrade without modstate"
|
||||||
|
testrun
|
||||||
|
|
||||||
|
rm -rf $dir
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue