Restructure and more generic plugin API for backend
This commit is contained in:
parent
7fbd95d491
commit
b9a54f07f3
19 changed files with 570 additions and 629 deletions
|
|
@ -55,8 +55,6 @@ CLIXON_MINOR = @CLIXON_VERSION_MINOR@
|
|||
|
||||
# Use this clixon lib for linking
|
||||
CLIXON_LIB = libclixon.so.$(CLIXON_MAJOR).$(CLIXON_MINOR)
|
||||
# Location of system plugins
|
||||
CLIXON_BACKEND_SYSDIR = $(libdir)/clixon/plugins/backend
|
||||
|
||||
# For dependency. A little strange that we rely on it being built in the src dir
|
||||
# even though it may exist in $(libdir). But the new version may not have been installed yet.
|
||||
|
|
@ -119,7 +117,7 @@ install-include: clixon_backend.h clixon_backend_handle.h clixon_backend_transac
|
|||
.SUFFIXES: .c .o
|
||||
|
||||
.c.o:
|
||||
$(CC) $(INCLUDES) -D__PROGRAM__=\"$(APPL)\" -DCLIXON_BACKEND_SYSDIR=\"$(CLIXON_BACKEND_SYSDIR)\" $(CPPFLAGS) $(CFLAGS) -c $<
|
||||
$(CC) $(INCLUDES) -D__PROGRAM__=\"$(APPL)\" $(CPPFLAGS) $(CFLAGS) -c $<
|
||||
|
||||
# Just link test programs
|
||||
test.c :
|
||||
|
|
|
|||
|
|
@ -289,7 +289,7 @@ from_client_get(clicon_handle h,
|
|||
/* Get state data from plugins as defined by plugin_statedata(), if any */
|
||||
assert(xret);
|
||||
clicon_err_reset();
|
||||
if ((ret = backend_statedata_call(h, selector, xret)) < 0)
|
||||
if ((ret = clixon_plugin_statedata(h, selector, xret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){ /* OK */
|
||||
cprintf(cbret, "<rpc-reply>");
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ backend_terminate(clicon_handle h)
|
|||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if ((yspec = clicon_dbspec_yang(h)) != NULL)
|
||||
yspec_free(yspec);
|
||||
plugin_finish(h);
|
||||
clixon_plugin_exit(h);
|
||||
/* Delete all backend plugin RPC callbacks */
|
||||
backend_rpc_cb_delete_all();
|
||||
if (pidfile)
|
||||
|
|
@ -254,7 +254,7 @@ plugin_start_useroptions(clicon_handle h,
|
|||
|
||||
tmp = *(argv-1);
|
||||
*(argv-1) = argv0;
|
||||
if (plugin_start_argv(h, argc+1, argv-1) < 0)
|
||||
if (clixon_plugin_start(h, argc+1, argv-1) < 0)
|
||||
return -1;
|
||||
*(argv-1) = tmp;
|
||||
return 0;
|
||||
|
|
@ -370,7 +370,7 @@ startup_mode_running(clicon_handle h,
|
|||
if (db_reset(h, "tmp") < 0)
|
||||
goto done;
|
||||
/* Application may define extra xml in its reset function*/
|
||||
if (plugin_reset_state(h, "tmp") < 0)
|
||||
if (clixon_plugin_reset(h, "tmp") < 0)
|
||||
goto done;
|
||||
/* Get application extra xml from file */
|
||||
if (load_extraxml(h, extraxml_file, "tmp") < 0)
|
||||
|
|
@ -443,7 +443,7 @@ startup_mode_startup(clicon_handle h,
|
|||
if (db_reset(h, "tmp") < 0)
|
||||
goto done;
|
||||
/* Application may define extra xml in its reset function*/
|
||||
if (plugin_reset_state(h, "tmp") < 0)
|
||||
if (clixon_plugin_reset(h, "tmp") < 0)
|
||||
goto done;
|
||||
/* Get application extra xml from file */
|
||||
if (load_extraxml(h, extraxml_file, "tmp") < 0)
|
||||
|
|
|
|||
|
|
@ -64,58 +64,6 @@
|
|||
#include "backend_plugin.h"
|
||||
#include "backend_commit.h"
|
||||
|
||||
/*
|
||||
* Types
|
||||
*/
|
||||
/* Following are specific to backend. For common see clicon_plugin.h
|
||||
* @note the following should match the prototypes in clixon_backend.h
|
||||
*/
|
||||
#define PLUGIN_RESET "plugin_reset"
|
||||
|
||||
|
||||
/*! Plugin callback, if defined called to get state data from plugin
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] xpath String with XPATH syntax. or NULL for all
|
||||
* @param[in] xtop XML tree, <config/> on entry.
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see xmldb_get
|
||||
*/
|
||||
#define PLUGIN_STATEDATA "plugin_statedata"
|
||||
|
||||
|
||||
#define PLUGIN_TRANS_BEGIN "transaction_begin"
|
||||
#define PLUGIN_TRANS_VALIDATE "transaction_validate"
|
||||
#define PLUGIN_TRANS_COMPLETE "transaction_complete"
|
||||
#define PLUGIN_TRANS_COMMIT "transaction_commit"
|
||||
#define PLUGIN_TRANS_END "transaction_end"
|
||||
#define PLUGIN_TRANS_ABORT "transaction_abort"
|
||||
|
||||
|
||||
/* Backend (config) plugins */
|
||||
struct plugin {
|
||||
char p_name[PATH_MAX]; /* Plugin name */
|
||||
void *p_handle; /* Dynamic object handle */
|
||||
plginit_t *p_init; /* Init */
|
||||
plgstart_t *p_start; /* Start */
|
||||
plgexit_t *p_exit; /* Exit */
|
||||
plgreset_t *p_reset; /* Reset state */
|
||||
plgstatedata_t *p_statedata; /* State-data callback */
|
||||
trans_cb_t *p_trans_begin; /* Transaction start */
|
||||
trans_cb_t *p_trans_validate; /* Transaction validation */
|
||||
trans_cb_t *p_trans_complete; /* Transaction validation complete */
|
||||
trans_cb_t *p_trans_commit; /* Transaction commit */
|
||||
trans_cb_t *p_trans_end; /* Transaction completed */
|
||||
trans_cb_t *p_trans_abort; /* Transaction aborted */
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* Local variables
|
||||
*/
|
||||
static int _nplugins = 0;
|
||||
static struct plugin *_plugins = NULL;
|
||||
|
||||
/*! Initialize plugin code (not the plugins themselves)
|
||||
* @param[in] h Clicon handle
|
||||
* @retval 0 OK
|
||||
|
|
@ -127,263 +75,6 @@ backend_plugin_init(clicon_handle h)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*! Unload a plugin
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] plg Plugin structure
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
backend_plugin_unload(clicon_handle h,
|
||||
struct plugin *plg)
|
||||
{
|
||||
int retval=-1;
|
||||
char *error;
|
||||
|
||||
/* Call exit function is it exists */
|
||||
if (plg->p_exit)
|
||||
plg->p_exit(h);
|
||||
|
||||
dlerror(); /* Clear any existing error */
|
||||
if (dlclose(plg->p_handle) != 0) {
|
||||
error = (char*)dlerror();
|
||||
clicon_err(OE_UNIX, 0, "dlclose: %s", error?error:"Unknown error");
|
||||
goto done;
|
||||
/* Just report */
|
||||
}
|
||||
else
|
||||
clicon_debug(1, "Plugin '%s' unloaded.", plg->p_name);
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*! Load a dynamic plugin and call its init-function
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] file The plugin (.so) to load
|
||||
* @param[in] dlflags Arguments to dlopen(3)
|
||||
* @retval plugin Plugin struct
|
||||
* @retval NULL Error
|
||||
*/
|
||||
static struct plugin *
|
||||
backend_plugin_load (clicon_handle h,
|
||||
char *file,
|
||||
int dlflags)
|
||||
{
|
||||
void *handle;
|
||||
char *name;
|
||||
struct plugin *new = NULL;
|
||||
|
||||
if ((handle = plugin_load(h, file, dlflags)) == NULL)
|
||||
goto done;
|
||||
if ((new = malloc(sizeof(*new))) == NULL) {
|
||||
clicon_err(OE_UNIX, errno, "dhunk: %s", strerror(errno));
|
||||
dlclose(handle);
|
||||
return NULL;
|
||||
}
|
||||
memset(new, 0, sizeof(*new));
|
||||
name = strrchr(file, '/') ? strrchr(file, '/')+1 : file;
|
||||
clicon_debug(2, "Loading plugin '%s'.", name);
|
||||
snprintf(new->p_name, sizeof(new->p_name), "%*s",
|
||||
(int)strlen(name)-2, name);
|
||||
new->p_handle = handle;
|
||||
if ((new->p_start = dlsym(handle, PLUGIN_START)) != NULL)
|
||||
clicon_debug(2, "%s callback registered.", PLUGIN_START);
|
||||
if ((new->p_exit = dlsym(handle, PLUGIN_EXIT)) != NULL)
|
||||
clicon_debug(2, "%s callback registered.", PLUGIN_EXIT);
|
||||
if ((new->p_reset = dlsym(handle, PLUGIN_RESET)) != NULL)
|
||||
clicon_debug(2, "%s callback registered.", PLUGIN_RESET);
|
||||
if ((new->p_statedata = dlsym(handle, PLUGIN_STATEDATA)) != NULL)
|
||||
clicon_debug(2, "%s callback registered.", PLUGIN_STATEDATA);
|
||||
if ((new->p_trans_begin = dlsym(handle, PLUGIN_TRANS_BEGIN)) != NULL)
|
||||
clicon_debug(2, "%s callback registered.", PLUGIN_TRANS_BEGIN);
|
||||
if ((new->p_trans_validate = dlsym(handle, PLUGIN_TRANS_VALIDATE)) != NULL)
|
||||
clicon_debug(2, "%s callback registered.", PLUGIN_TRANS_VALIDATE);
|
||||
if ((new->p_trans_complete = dlsym(handle, PLUGIN_TRANS_COMPLETE)) != NULL)
|
||||
clicon_debug(2, "%s callback registered.", PLUGIN_TRANS_COMPLETE);
|
||||
if ((new->p_trans_commit = dlsym(handle, PLUGIN_TRANS_COMMIT)) != NULL)
|
||||
clicon_debug(2, "%s callback registered.", PLUGIN_TRANS_COMMIT);
|
||||
if ((new->p_trans_end = dlsym(handle, PLUGIN_TRANS_END)) != NULL)
|
||||
clicon_debug(2, "%s callback registered.", PLUGIN_TRANS_END);
|
||||
if ((new->p_trans_abort = dlsym(handle, PLUGIN_TRANS_ABORT)) != NULL)
|
||||
clicon_debug(2, "%s callback registered.", PLUGIN_TRANS_ABORT);
|
||||
clicon_debug(2, "Plugin '%s' loaded.\n", name);
|
||||
done:
|
||||
return new;
|
||||
}
|
||||
|
||||
/*! Request plugins to reset system state
|
||||
* The system 'state' should be the same as the contents of running_db
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] dbname Name of database
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
plugin_reset_state(clicon_handle h,
|
||||
const char *db)
|
||||
{
|
||||
int i;
|
||||
struct plugin *p;
|
||||
|
||||
for (i = 0; i < _nplugins; i++) {
|
||||
p = &_plugins[i];
|
||||
if (p->p_reset) {
|
||||
clicon_debug(1, "Calling plugin_reset() for %s\n",
|
||||
p->p_name);
|
||||
if (((p->p_reset)(h, db)) < 0) {
|
||||
clicon_err(OE_FATAL, 0, "plugin_reset() failed for %s\n",
|
||||
p->p_name);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Call plugin_start in all plugins
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] argc Command-line arguments
|
||||
* @param[in] argv Command-line arguments
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
plugin_start_argv(clicon_handle h,
|
||||
int argc,
|
||||
char **argv)
|
||||
{
|
||||
int i;
|
||||
struct plugin *p;
|
||||
|
||||
for (i = 0; i < _nplugins; i++) {
|
||||
p = &_plugins[i];
|
||||
if (p->p_start) {
|
||||
optind = 0;
|
||||
if (((p->p_start)(h, argc, argv)) < 0) {
|
||||
clicon_err(OE_FATAL, 0, "plugin_start() failed for %s\n",
|
||||
p->p_name);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Append plugin to list
|
||||
* @param[in] p Plugin
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
plugin_append(struct plugin *p)
|
||||
{
|
||||
struct plugin *new;
|
||||
|
||||
if ((new = realloc(_plugins, (_nplugins+1) * sizeof (*p))) == NULL) {
|
||||
clicon_err(OE_UNIX, errno, "realloc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset (&new[_nplugins], 0, sizeof(new[_nplugins]));
|
||||
memcpy (&new[_nplugins], p, sizeof(new[_nplugins]));
|
||||
_plugins = new;
|
||||
_nplugins++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Load backend plugins found in a directory
|
||||
* The plugins must have the '.so' suffix
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] dir Backend plugin directory
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
backend_plugin_load_dir(clicon_handle h,
|
||||
const char *dir)
|
||||
{
|
||||
int retval = -1;
|
||||
int i;
|
||||
int np = 0;
|
||||
int ndp;
|
||||
struct stat st;
|
||||
char filename[MAXPATHLEN];
|
||||
struct dirent *dp = NULL;
|
||||
struct plugin *new;
|
||||
struct plugin *p = NULL;
|
||||
char master[MAXPATHLEN];
|
||||
char *master_plugin;
|
||||
|
||||
/* Format master plugin path */
|
||||
if ((master_plugin = clicon_master_plugin(h)) == NULL){
|
||||
clicon_err(OE_PLUGIN, 0, "clicon_master_plugin option not set");
|
||||
goto quit;
|
||||
}
|
||||
snprintf(master, MAXPATHLEN-1, "%s.so", master_plugin);
|
||||
|
||||
/* Allocate plugin group object */
|
||||
/* Get plugin objects names from plugin directory */
|
||||
if((ndp = clicon_file_dirent(dir, &dp, "(.so)$", S_IFREG))<0)
|
||||
goto quit;
|
||||
|
||||
/* reset num plugins */
|
||||
np = 0;
|
||||
|
||||
/* Master plugin must be loaded first if it exists. */
|
||||
snprintf(filename, MAXPATHLEN-1, "%s/%s", dir, master);
|
||||
if (stat(filename, &st) == 0) {
|
||||
clicon_debug(1, "Loading master plugin '%.*s' ...",
|
||||
(int)strlen(filename), filename);
|
||||
|
||||
new = backend_plugin_load(h, filename, RTLD_NOW|RTLD_GLOBAL);
|
||||
if (new == NULL)
|
||||
goto quit;
|
||||
if (plugin_append(new) < 0)
|
||||
goto quit;
|
||||
free(new);
|
||||
}
|
||||
|
||||
/* Now load the rest. Note plugins is the global variable */
|
||||
for (i = 0; i < ndp; i++) {
|
||||
if (strcmp(dp[i].d_name, master) == 0)
|
||||
continue; /* Skip master now */
|
||||
snprintf(filename, MAXPATHLEN-1, "%s/%s", dir, dp[i].d_name);
|
||||
clicon_debug(1, "Loading plugin '%.*s' ...", (int)strlen(filename), filename);
|
||||
new = backend_plugin_load(h, filename, RTLD_NOW);
|
||||
if (new == NULL)
|
||||
goto quit;
|
||||
/* Append to 'plugins' */
|
||||
if (plugin_append(new) < 0)
|
||||
goto quit;
|
||||
free(new);
|
||||
}
|
||||
|
||||
/* All good. */
|
||||
retval = 0;
|
||||
|
||||
quit:
|
||||
if (retval != 0) {
|
||||
/* XXX p is always NULL */
|
||||
if (_plugins) {
|
||||
while (--np >= 0){
|
||||
if ((p = &_plugins[np]) == NULL)
|
||||
continue;
|
||||
backend_plugin_unload(h, p);
|
||||
free(p);
|
||||
}
|
||||
free(_plugins);
|
||||
_plugins=0;
|
||||
}
|
||||
}
|
||||
if (dp)
|
||||
free(dp);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*! Load a plugin group.
|
||||
* @param[in] h Clicon handle
|
||||
* @retval 0 OK
|
||||
|
|
@ -394,42 +85,115 @@ plugin_initiate(clicon_handle h)
|
|||
{
|
||||
char *dir;
|
||||
|
||||
/* First load CLICON system plugins */
|
||||
if (backend_plugin_load_dir(h, CLIXON_BACKEND_SYSDIR) < 0)
|
||||
return -1;
|
||||
|
||||
/* Then load application plugins */
|
||||
dir = clicon_backend_dir(h);
|
||||
/* If backend directory, load the backend plugisn */
|
||||
if (dir && backend_plugin_load_dir(h, dir) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
/* Load application plugins */
|
||||
if ((dir = clicon_backend_dir(h)) == NULL)
|
||||
return 0;
|
||||
return clixon_plugins_load(h, CLIXON_PLUGIN_INIT, dir);
|
||||
}
|
||||
|
||||
/*! Unload and deallocate all backend plugins
|
||||
/*! Request plugins to reset system state
|
||||
* The system 'state' should be the same as the contents of running_db
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] db Name of database
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
plugin_finish(clicon_handle h)
|
||||
clixon_plugin_reset(clicon_handle h,
|
||||
char *db)
|
||||
{
|
||||
int i;
|
||||
struct plugin *p;
|
||||
|
||||
for (i = 0; i < _nplugins; i++) {
|
||||
p = &_plugins[i];
|
||||
backend_plugin_unload(h, p);
|
||||
clixon_plugin *cp = NULL;
|
||||
plgreset_t *resetfn; /* Plugin auth */
|
||||
int retval = 1;
|
||||
|
||||
while ((cp = plugin_each(cp)) != NULL) {
|
||||
if ((resetfn = cp->cp_api.ca_reset) == NULL)
|
||||
continue;
|
||||
if ((retval = resetfn(h, db)) < 0) {
|
||||
clicon_debug(1, "plugin_start() failed\n");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (_plugins){
|
||||
free(_plugins);
|
||||
_plugins = NULL;
|
||||
}
|
||||
_nplugins = 0;
|
||||
return 0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*! Go through all backend statedata callbacks and collect state data
|
||||
* This is internal system call, plugin is invoked (does not call) this function
|
||||
* Backend plugins can register
|
||||
* @param[in] h clicon handle
|
||||
* @param[in] xpath String with XPATH syntax. or NULL for all
|
||||
* @param[in,out] xml XML tree.
|
||||
* @retval -1 Error
|
||||
* @retval 0 OK
|
||||
* @retval 1 Statedata callback failed
|
||||
*/
|
||||
int
|
||||
clixon_plugin_statedata(clicon_handle h,
|
||||
char *xpath,
|
||||
cxobj *xtop)
|
||||
{
|
||||
int retval = -1;
|
||||
int i;
|
||||
cxobj *x = NULL;
|
||||
yang_spec *yspec;
|
||||
cxobj **xvec = NULL;
|
||||
size_t xlen;
|
||||
clixon_plugin *cp = NULL;
|
||||
plgstatedata_t *fn; /* Plugin statedata fn */
|
||||
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
clicon_err(OE_YANG, ENOENT, "No yang spec");
|
||||
goto done;
|
||||
}
|
||||
if (xtop==NULL){
|
||||
clicon_err(OE_CFG, ENOENT, "XML tree expected");
|
||||
goto done;
|
||||
}
|
||||
while ((cp = plugin_each(cp)) != NULL) {
|
||||
if ((fn = cp->cp_api.ca_statedata) == NULL)
|
||||
continue;
|
||||
if ((x = xml_new("config", NULL, NULL)) == NULL)
|
||||
goto done;
|
||||
if (fn(h, xpath, x) < 0){
|
||||
retval = 1;
|
||||
goto done; /* Dont quit here on user callbacks */
|
||||
}
|
||||
if (xml_merge(xtop, x, yspec) < 0)
|
||||
goto done;
|
||||
if (x){
|
||||
xml_free(x);
|
||||
x = NULL;
|
||||
}
|
||||
}
|
||||
/* Code complex to filter out anything that is outside of xpath */
|
||||
if (xpath_vec(xtop, xpath?xpath:"/", &xvec, &xlen) < 0)
|
||||
goto done;
|
||||
|
||||
/* If vectors are specified then mark the nodes found and
|
||||
* then filter out everything else,
|
||||
* otherwise return complete tree.
|
||||
*/
|
||||
if (xvec != NULL){
|
||||
for (i=0; i<xlen; i++)
|
||||
xml_flag_set(xvec[i], XML_FLAG_MARK);
|
||||
}
|
||||
/* Remove everything that is not marked */
|
||||
if (!xml_flag(xtop, XML_FLAG_MARK))
|
||||
if (xml_tree_prune_flagged_sub(xtop, XML_FLAG_MARK, 1, NULL) < 0)
|
||||
goto done;
|
||||
/* reset flag */
|
||||
if (xml_apply(xtop, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, (void*)XML_FLAG_MARK) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
if (x)
|
||||
xml_free(x);
|
||||
if (xvec)
|
||||
free(xvec);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Create and initialize transaction */
|
||||
transaction_data_t *
|
||||
transaction_new(void)
|
||||
|
|
@ -478,21 +242,20 @@ int
|
|||
plugin_transaction_begin(clicon_handle h,
|
||||
transaction_data_t *td)
|
||||
{
|
||||
int i;
|
||||
int retval = 0;
|
||||
struct plugin *p;
|
||||
clixon_plugin *cp = NULL;
|
||||
trans_cb_t *fn;
|
||||
|
||||
for (i = 0; i < _nplugins; i++) {
|
||||
p = &_plugins[i];
|
||||
if (p->p_trans_begin)
|
||||
if ((retval = (p->p_trans_begin)(h, (transaction_data)td)) < 0){
|
||||
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
|
||||
clicon_log(LOG_NOTICE, "%s: Plugin '%s' %s callback does not make clicon_err call on error",
|
||||
__FUNCTION__, p->p_name, PLUGIN_TRANS_BEGIN);
|
||||
while ((cp = plugin_each(cp)) != NULL) {
|
||||
if ((fn = cp->cp_api.ca_trans_begin) == NULL)
|
||||
continue;
|
||||
if ((retval = fn(h, (transaction_data)td)) < 0){
|
||||
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
|
||||
clicon_log(LOG_NOTICE, "%s: Plugin '%s' transaction_begin callback does not make clicon_err call on error",
|
||||
__FUNCTION__, cp->cp_name);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -508,20 +271,18 @@ plugin_transaction_validate(clicon_handle h,
|
|||
transaction_data_t *td)
|
||||
{
|
||||
int retval = 0;
|
||||
int i;
|
||||
clixon_plugin *cp = NULL;
|
||||
trans_cb_t *fn;
|
||||
|
||||
struct plugin *p;
|
||||
|
||||
for (i = 0; i < _nplugins; i++){
|
||||
p = &_plugins[i];
|
||||
if (p->p_trans_validate)
|
||||
if ((retval = (p->p_trans_validate)(h, (transaction_data)td)) < 0){
|
||||
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
|
||||
clicon_log(LOG_NOTICE, "%s: Plugin '%s' %s callback does not make clicon_err call on error",
|
||||
__FUNCTION__, p->p_name, PLUGIN_TRANS_VALIDATE);
|
||||
|
||||
break;
|
||||
}
|
||||
while ((cp = plugin_each(cp)) != NULL) {
|
||||
if ((fn = cp->cp_api.ca_trans_validate) == NULL)
|
||||
continue;
|
||||
if ((retval = fn(h, (transaction_data)td)) < 0){
|
||||
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
|
||||
clicon_log(LOG_NOTICE, "%s: Plugin '%s' transaction_validate callback does not make clicon_err call on error",
|
||||
__FUNCTION__, cp->cp_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -538,20 +299,20 @@ int
|
|||
plugin_transaction_complete(clicon_handle h,
|
||||
transaction_data_t *td)
|
||||
{
|
||||
int i;
|
||||
int retval = 0;
|
||||
struct plugin *p;
|
||||
clixon_plugin *cp = NULL;
|
||||
trans_cb_t *fn;
|
||||
|
||||
for (i = 0; i < _nplugins; i++){
|
||||
p = &_plugins[i];
|
||||
if (p->p_trans_complete)
|
||||
if ((retval = (p->p_trans_complete)(h, (transaction_data)td)) < 0){
|
||||
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
|
||||
clicon_log(LOG_NOTICE, "%s: Plugin '%s' %s callback does not make clicon_err call on error",
|
||||
__FUNCTION__, p->p_name, PLUGIN_TRANS_COMPLETE);
|
||||
|
||||
break;
|
||||
}
|
||||
while ((cp = plugin_each(cp)) != NULL) {
|
||||
if ((fn = cp->cp_api.ca_trans_complete) == NULL)
|
||||
continue;
|
||||
if ((retval = fn(h, (transaction_data)td)) < 0){
|
||||
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
|
||||
clicon_log(LOG_NOTICE, "%s: Plugin '%s' trans_complete callback does not make clicon_err call on error",
|
||||
__FUNCTION__, cp->cp_name);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -572,9 +333,9 @@ plugin_transaction_revert(clicon_handle h,
|
|||
{
|
||||
int retval = 0;
|
||||
transaction_data_t tr; /* revert transaction */
|
||||
int i;
|
||||
struct plugin *p;
|
||||
|
||||
clixon_plugin *cp = NULL;
|
||||
trans_cb_t *fn;
|
||||
|
||||
/* Create a new reversed transaction from the original where src and target
|
||||
are swapped */
|
||||
memcpy(&tr, td, sizeof(tr));
|
||||
|
|
@ -588,14 +349,14 @@ plugin_transaction_revert(clicon_handle h,
|
|||
tr.td_scvec = td->td_tcvec;
|
||||
tr.td_tcvec = td->td_scvec;
|
||||
|
||||
for (i = nr-1; i>=0; i--){
|
||||
p = &_plugins[i];
|
||||
if (p->p_trans_commit)
|
||||
if ((p->p_trans_commit)(h, (transaction_data)&tr) < 0){
|
||||
clicon_log(LOG_NOTICE, "Plugin '%s' %s revert callback failed",
|
||||
p->p_name, PLUGIN_TRANS_COMMIT);
|
||||
while ((cp = plugin_each_revert(cp, nr)) != NULL) {
|
||||
if ((fn = cp->cp_api.ca_trans_commit) == NULL)
|
||||
continue;
|
||||
if ((retval = fn(h, (transaction_data)td)) < 0){
|
||||
clicon_log(LOG_NOTICE, "%s: Plugin '%s' trans_commit revert callback failed",
|
||||
__FUNCTION__, cp->cp_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return retval; /* ignore errors */
|
||||
}
|
||||
|
|
@ -614,20 +375,22 @@ plugin_transaction_commit(clicon_handle h,
|
|||
transaction_data_t *td)
|
||||
{
|
||||
int retval = 0;
|
||||
int i;
|
||||
struct plugin *p;
|
||||
clixon_plugin *cp = NULL;
|
||||
trans_cb_t *fn;
|
||||
int i=0;
|
||||
|
||||
for (i = 0; i < _nplugins; i++){
|
||||
p = &_plugins[i];
|
||||
if (p->p_trans_commit)
|
||||
if ((retval = (p->p_trans_commit)(h, (transaction_data)td)) < 0){
|
||||
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
|
||||
clicon_log(LOG_NOTICE, "%s: Plugin '%s' %s callback does not make clicon_err call on error",
|
||||
__FUNCTION__, p->p_name, PLUGIN_TRANS_COMMIT);
|
||||
/* Make an effort to revert transaction */
|
||||
plugin_transaction_revert(h, td, i);
|
||||
break;
|
||||
}
|
||||
while ((cp = plugin_each(cp)) != NULL) {
|
||||
i++;
|
||||
if ((fn = cp->cp_api.ca_trans_commit) == NULL)
|
||||
continue;
|
||||
if ((retval = fn(h, (transaction_data)td)) < 0){
|
||||
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
|
||||
clicon_log(LOG_NOTICE, "%s: Plugin '%s' trans_commit callback does not make clicon_err call on error",
|
||||
__FUNCTION__, cp->cp_name);
|
||||
/* Make an effort to revert transaction */
|
||||
plugin_transaction_revert(h, td, i-1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -643,19 +406,18 @@ plugin_transaction_end(clicon_handle h,
|
|||
transaction_data_t *td)
|
||||
{
|
||||
int retval = 0;
|
||||
int i;
|
||||
struct plugin *p;
|
||||
clixon_plugin *cp = NULL;
|
||||
trans_cb_t *fn;
|
||||
|
||||
for (i = 0; i < _nplugins; i++) {
|
||||
p = &_plugins[i];
|
||||
if (p->p_trans_end)
|
||||
if ((retval = (p->p_trans_end)(h, (transaction_data)td)) < 0){
|
||||
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
|
||||
clicon_log(LOG_NOTICE, "%s: Plugin '%s' %s callback does not make clicon_err call on error",
|
||||
__FUNCTION__, p->p_name, PLUGIN_TRANS_END);
|
||||
|
||||
break;
|
||||
}
|
||||
while ((cp = plugin_each(cp)) != NULL) {
|
||||
if ((fn = cp->cp_api.ca_trans_end) == NULL)
|
||||
continue;
|
||||
if ((retval = fn(h, (transaction_data)td)) < 0){
|
||||
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
|
||||
clicon_log(LOG_NOTICE, "%s: Plugin '%s' trans_end callback does not make clicon_err call on error",
|
||||
__FUNCTION__, cp->cp_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -671,94 +433,14 @@ plugin_transaction_abort(clicon_handle h,
|
|||
transaction_data_t *td)
|
||||
{
|
||||
int retval = 0;
|
||||
int i;
|
||||
struct plugin *p;
|
||||
clixon_plugin *cp = NULL;
|
||||
trans_cb_t *fn;
|
||||
|
||||
for (i = 0; i < _nplugins; i++) {
|
||||
p = &_plugins[i];
|
||||
if (p->p_trans_abort)
|
||||
(p->p_trans_abort)(h, (transaction_data)td); /* dont abort on error */
|
||||
while ((cp = plugin_each(cp)) != NULL) {
|
||||
if ((fn = cp->cp_api.ca_trans_abort) == NULL)
|
||||
continue;
|
||||
fn(h, (transaction_data)td); /* dont abort on error */
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
* Backend state data callbacks
|
||||
*/
|
||||
|
||||
/*! Go through all backend statedata callbacks and collect state data
|
||||
* This is internal system call, plugin is invoked (does not call) this function
|
||||
* Backend plugins can register
|
||||
* @param[in] h clicon handle
|
||||
* @param[in] xpath String with XPATH syntax. or NULL for all
|
||||
* @param[in,out] xml XML tree.
|
||||
* @retval -1 Error
|
||||
* @retval 0 OK
|
||||
* @retval 1 Statedata callback failed
|
||||
*/
|
||||
int
|
||||
backend_statedata_call(clicon_handle h,
|
||||
char *xpath,
|
||||
cxobj *xtop)
|
||||
{
|
||||
int retval = -1;
|
||||
struct plugin *p;
|
||||
int i;
|
||||
cxobj *x = NULL;
|
||||
yang_spec *yspec;
|
||||
cxobj **xvec = NULL;
|
||||
size_t xlen;
|
||||
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
clicon_err(OE_YANG, ENOENT, "No yang spec");
|
||||
goto done;
|
||||
}
|
||||
if (xtop==NULL){
|
||||
clicon_err(OE_CFG, ENOENT, "XML tree expected");
|
||||
goto done;
|
||||
}
|
||||
for (i = 0; i < _nplugins; i++) {
|
||||
p = &_plugins[i];
|
||||
if (p->p_statedata) {
|
||||
if ((x = xml_new("config", NULL, NULL)) == NULL)
|
||||
goto done;
|
||||
if ((p->p_statedata)(h, xpath, x) < 0){
|
||||
retval = 1;
|
||||
goto done; /* Dont quit here on user callbacks */
|
||||
}
|
||||
if (xml_merge(xtop, x, yspec) < 0)
|
||||
goto done;
|
||||
if (x){
|
||||
xml_free(x);
|
||||
x = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Code complex to filter out anything that is outside of xpath */
|
||||
if (xpath_vec(xtop, xpath?xpath:"/", &xvec, &xlen) < 0)
|
||||
goto done;
|
||||
|
||||
/* If vectors are specified then mark the nodes found and
|
||||
* then filter out everything else,
|
||||
* otherwise return complete tree.
|
||||
*/
|
||||
if (xvec != NULL){
|
||||
for (i=0; i<xlen; i++)
|
||||
xml_flag_set(xvec[i], XML_FLAG_MARK);
|
||||
}
|
||||
/* Remove everything that is not marked */
|
||||
if (!xml_flag(xtop, XML_FLAG_MARK))
|
||||
if (xml_tree_prune_flagged_sub(xtop, XML_FLAG_MARK, 1, NULL) < 0)
|
||||
goto done;
|
||||
/* reset flag */
|
||||
if (xml_apply(xtop, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, (void*)XML_FLAG_MARK) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
if (x)
|
||||
xml_free(x);
|
||||
if (xvec)
|
||||
free(xvec);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,12 +69,10 @@ typedef struct {
|
|||
*/
|
||||
int backend_plugin_init(clicon_handle h);
|
||||
int plugin_initiate(clicon_handle h);
|
||||
int plugin_finish(clicon_handle h);
|
||||
|
||||
int plugin_reset_state(clicon_handle h, const char *db);
|
||||
int plugin_start_argv(clicon_handle h, int argc, char **argv);
|
||||
int clixon_plugin_reset(clicon_handle h, char *db);
|
||||
|
||||
int backend_statedata_call(clicon_handle h, char *xpath, cxobj *xml);
|
||||
int clixon_plugin_statedata(clicon_handle h, char *xpath, cxobj *xml);
|
||||
|
||||
transaction_data_t * transaction_new(void);
|
||||
int transaction_free(transaction_data_t *);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue