* Added: stats RPC for clixon XML and memory statistics.
  * Added: restart-plugin RPC for restarting individual plugins without restarting backend.
* xml-stats moved from clixon-config.yang as state data to an rpc `datastats` in clixon-lib.yang
* Experimental: restart_plugin
* Two new plugin callbacks added
  * ca_daemon: Called just after a server has "daemonized", ie put in background.
  * ca_trans_commit_done: Called when all plugin commits have been done.
    * Note: If you have used "end" callback and usign transaction data, you should probably use this instead.
This commit is contained in:
Olof hagsand 2020-04-28 22:10:06 +02:00
parent 1c99bd6a9b
commit 9a8c6cf3e6
25 changed files with 926 additions and 308 deletions

View file

@ -67,62 +67,150 @@
/*! Request plugins to reset system state
* The system 'state' should be the same as the contents of running_db
* @param[in] cp Plugin handle
* @param[in] h Clicon handle
* @param[in] db Name of database
* @param[in] db Name of datastore
* @retval 0 OK
* @retval -1 Error
*/
int
clixon_plugin_reset(clicon_handle h,
char *db)
clixon_plugin_reset_one(clixon_plugin *cp,
clicon_handle h,
char *db)
{
clixon_plugin *cp = NULL;
plgreset_t *resetfn; /* Plugin auth */
int retval = 1;
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
if ((resetfn = cp->cp_api.ca_reset) == NULL)
continue;
if ((retval = resetfn(h, db)) < 0) {
clicon_debug(1, "plugin_start() failed");
return -1;
int retval = -1;
plgreset_t *fn; /* callback */
if ((fn = cp->cp_api.ca_reset) != NULL){
if (fn(h, db) < 0) {
if (clicon_errno < 0)
clicon_log(LOG_WARNING, "%s: Internal error: Reset callback in plugin: %s returned -1 but did not make a clicon_err call",
__FUNCTION__, cp->cp_name);
goto done;
}
break;
}
retval = 0;
done:
return retval;
}
/*! Call all plugins reset callbacks
* The system 'state' should be the same as the contents of running_db
* @param[in] h Clixon handle
* @param[in] db Name of datastore
* @retval 0 OK
* @retval -1 Error
*/
int
clixon_plugin_reset_all(clicon_handle h,
char *db)
{
int retval = -1;
clixon_plugin *cp = NULL;
/* Loop through all plugins, call callbacks in each */
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
if (clixon_plugin_reset_one(cp, h, db) < 0)
goto done;
}
retval = 0;
done:
return retval;
}
/*! 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
/*! Call single plugin "post-" daemonize callback
* @param[in] cp Plugin handle
* @param[in] h Clixon handle
* @retval 0 OK
* @retval -1 Error
*/
int
clixon_plugin_daemon(clicon_handle h)
clixon_plugin_daemon_one(clixon_plugin *cp,
clicon_handle h)
{
clixon_plugin *cp = NULL;
plgdaemon_t *daemonfn; /* Plugin auth */
int retval = 1;
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
if ((daemonfn = cp->cp_api.ca_daemon) == NULL)
continue;
if ((retval = daemonfn(h)) < 0) {
clicon_debug(1, "plugin_daemon() failed");
return -1;
int retval = -1;
plgdaemon_t *fn; /* Daemonize plugin callback function */
if ((fn = cp->cp_api.ca_daemon) != NULL){
if (fn(h) < 0) {
if (clicon_errno < 0)
clicon_log(LOG_WARNING, "%s: Internal error: Daemon callback in plugin: %s returned -1 but did not make a clicon_err call",
__FUNCTION__, cp->cp_name);
goto done;
}
break;
}
retval = 0;
done:
return retval;
}
/*! Call all plugins "post-" daemonize callbacks
* @param[in] h Clicon handle
* @retval 0 OK
* @retval -1 Error
*/
int
clixon_plugin_daemon_all(clicon_handle h)
{
int retval = -1;
clixon_plugin *cp = NULL;
/* Loop through all plugins, call callbacks in each */
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
if (clixon_plugin_daemon_one(cp, h) < 0)
goto done;
}
retval = 0;
done:
return retval;
}
/*! Call single backend statedata callback
* @param[in] cp Plugin handle
* @param[in] h clicon handle
* @param[in] xpath String with XPATH syntax. or NULL for all
* @retval -1 Error
* @retval 0 Statedata callback failed
* @retval 1 OK if callback found (and called) xp is set, otherwise xp is not set
* @note xtop can be replaced
*/
static int
clixon_plugin_statedata_one(clixon_plugin *cp,
clicon_handle h,
cvec *nsc,
char *xpath,
cxobj **xp)
{
int retval = -1;
plgstatedata_t *fn; /* Plugin statedata fn */
cxobj *x = NULL;
if ((fn = cp->cp_api.ca_statedata) != NULL){
if ((x = xml_new("config", NULL, CX_ELMNT)) == NULL)
goto done;
if (fn(h, nsc, xpath, x) < 0){
if (clicon_errno < 0)
clicon_log(LOG_WARNING, "%s: Internal error: State callback in plugin: %s returned -1 but did not make a clicon_err call",
__FUNCTION__, cp->cp_name);
goto fail; /* Dont quit here on user callbacks */
}
}
if (xp && x)
*xp = x;
retval = 1;
done:
return retval;
fail:
retval = 0;
goto done;
}
/*! 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] yspec Yang spec
* @param[in] nsc Namespace context
* @param[in] xpath String with XPATH syntax. or NULL for all
* @param[in,out] xtop State XML tree is merged with existing tree.
* @retval -1 Error
@ -131,27 +219,31 @@ clixon_plugin_daemon(clicon_handle h)
* @note xtop can be replaced
*/
int
clixon_plugin_statedata(clicon_handle h,
yang_stmt *yspec,
cvec *nsc,
char *xpath,
cxobj **xret)
clixon_plugin_statedata_all(clicon_handle h,
yang_stmt *yspec,
cvec *nsc,
char *xpath,
cxobj **xret)
{
int retval = -1;
int ret;
cxobj *x = NULL;
clixon_plugin *cp = NULL;
plgstatedata_t *fn; /* Plugin statedata fn */
cbuf *cberr = NULL;
clicon_debug(1, "%s", __FUNCTION__);
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
if ((fn = cp->cp_api.ca_statedata) == NULL)
continue;
if ((x = xml_new("config", NULL, CX_ELMNT)) == NULL)
if ((ret = clixon_plugin_statedata_one(cp, h, nsc, xpath, &x)) < 0)
goto done;
if (fn(h, nsc, xpath, x) < 0)
goto fail; /* Dont quit here on user callbacks */
/* if x contains no data, then continue? */
if (ret == 0)
goto fail;
if (x == NULL)
continue;
if (xml_child_nr(x) == 0){
xml_free(x);
x = NULL;
continue;
}
#if 1
if (debug)
clicon_log_xml(LOG_DEBUG, x, "%s STATE:", __FUNCTION__);
@ -220,6 +312,27 @@ transaction_free(transaction_data_t *td)
return 0;
}
int
plugin_transaction_begin_one(clixon_plugin *cp,
clicon_handle h,
transaction_data_t *td)
{
int retval = -1;
trans_cb_t *fn;
if ((fn = cp->cp_api.ca_trans_begin) != NULL){
if (fn(h, (transaction_data)td) < 0){
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
__FUNCTION__, cp->cp_name);
goto done;
}
}
retval = 0;
done:
return retval;
}
/* The plugin_transaction routines need access to struct plugin which is local to this file */
/*! Call transaction_begin() in all plugins before a validate/commit.
@ -229,24 +342,39 @@ transaction_free(transaction_data_t *td)
* @retval -1 Error: one of the plugin callbacks returned error
*/
int
plugin_transaction_begin(clicon_handle h,
transaction_data_t *td)
plugin_transaction_begin_all(clicon_handle h,
transaction_data_t *td)
{
int retval = 0;
int retval = -1;
clixon_plugin *cp = NULL;
trans_cb_t *fn;
while ((cp = clixon_plugin_each(h, 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);
if (plugin_transaction_begin_one(cp, h, td) < 0)
goto done;
}
retval = 0;
done:
return retval;
}
break;
int
plugin_transaction_validate_one(clixon_plugin *cp,
clicon_handle h,
transaction_data_t *td)
{
int retval = -1;
trans_cb_t *fn;
if ((fn = cp->cp_api.ca_trans_validate) != NULL){
if (fn(h, (transaction_data)td) < 0){
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
__FUNCTION__, cp->cp_name);
goto done;
}
}
retval = 0;
done:
return retval;
}
@ -257,23 +385,39 @@ plugin_transaction_begin(clicon_handle h,
* @retval -1 Error: one of the plugin callbacks returned validation fail
*/
int
plugin_transaction_validate(clicon_handle h,
transaction_data_t *td)
plugin_transaction_validate_all(clicon_handle h,
transaction_data_t *td)
{
int retval = 0;
int retval = -1;
clixon_plugin *cp = NULL;
trans_cb_t *fn;
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
if ((fn = cp->cp_api.ca_trans_validate) == NULL)
continue;
if ((retval = fn(h, (transaction_data)td)) < 0){
if (plugin_transaction_validate_one(cp, h, td) < 0)
goto done;
}
retval = 0;
done:
return retval;
}
int
plugin_transaction_complete_one(clixon_plugin *cp,
clicon_handle h,
transaction_data_t *td)
{
int retval = -1;
trans_cb_t *fn;
if ((fn = cp->cp_api.ca_trans_complete) != NULL){
if (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;
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
__FUNCTION__, cp->cp_name);
goto done;
}
}
retval = 0;
done:
return retval;
}
@ -286,24 +430,18 @@ plugin_transaction_validate(clicon_handle h,
* @note Rename to transaction_complete?
*/
int
plugin_transaction_complete(clicon_handle h,
transaction_data_t *td)
plugin_transaction_complete_all(clicon_handle h,
transaction_data_t *td)
{
int retval = 0;
int retval = -1;
clixon_plugin *cp = NULL;
trans_cb_t *fn;
while ((cp = clixon_plugin_each(h, 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;
}
if (plugin_transaction_complete_one(cp, h, td) < 0)
goto done;
}
retval = 0;
done:
return retval;
}
@ -316,10 +454,10 @@ plugin_transaction_complete(clicon_handle h,
* The revert is made in plugin before this one. Eg if error occurred in
* plugin 2, then the revert will be made in plugins 1 and 0.
*/
int
plugin_transaction_revert(clicon_handle h,
transaction_data_t *td,
int nr)
static int
plugin_transaction_revert_all(clicon_handle h,
transaction_data_t *td,
int nr)
{
int retval = 0;
clixon_plugin *cp = NULL;
@ -337,6 +475,27 @@ plugin_transaction_revert(clicon_handle h,
return retval; /* ignore errors */
}
int
plugin_transaction_commit_one(clixon_plugin *cp,
clicon_handle h,
transaction_data_t *td)
{
int retval = -1;
trans_cb_t *fn;
if ((fn = cp->cp_api.ca_trans_commit) != NULL){
if (fn(h, (transaction_data)td) < 0){
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
__FUNCTION__, cp->cp_name);
goto done;
}
}
retval = 0;
done:
return retval;
}
/*! Call transaction_commit callbacks in all backend plugins
* @param[in] h Clicon handle
* @param[in] td Transaction data
@ -347,27 +506,44 @@ plugin_transaction_revert(clicon_handle h,
* and in reverse order.
*/
int
plugin_transaction_commit(clicon_handle h,
transaction_data_t *td)
plugin_transaction_commit_all(clicon_handle h,
transaction_data_t *td)
{
int retval = 0;
int retval = -1;
clixon_plugin *cp = NULL;
trans_cb_t *fn;
int i=0;
while ((cp = clixon_plugin_each(h, 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);
if (plugin_transaction_commit_one(cp, h, td) < 0){
/* Make an effort to revert transaction */
plugin_transaction_revert(h, td, i-1);
break;
plugin_transaction_revert_all(h, td, i-1);
goto done;
}
}
retval = 0;
done:
return retval;
}
int
plugin_transaction_commit_done_one(clixon_plugin *cp,
clicon_handle h,
transaction_data_t *td)
{
int retval = -1;
trans_cb_t *fn;
if ((fn = cp->cp_api.ca_trans_commit_done) != NULL){
if (fn(h, (transaction_data)td) < 0){
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
__FUNCTION__, cp->cp_name);
goto done;
}
}
retval = 0;
done:
return retval;
}
@ -379,25 +555,39 @@ plugin_transaction_commit(clicon_handle h,
* @note no revert is done
*/
int
plugin_transaction_commit_done(clicon_handle h,
transaction_data_t *td)
plugin_transaction_commit_done_all(clicon_handle h,
transaction_data_t *td)
{
int retval = 0;
int retval = -1;
clixon_plugin *cp = NULL;
trans_cb_t *fn;
int i=0;
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
i++;
if ((fn = cp->cp_api.ca_trans_commit_done) == NULL)
continue;
if ((retval = fn(h, (transaction_data)td)) < 0){
if (plugin_transaction_commit_done_one(cp, h, td) < 0)
goto done;
}
retval = 0;
done:
return retval;
}
int
plugin_transaction_end_one(clixon_plugin *cp,
clicon_handle h,
transaction_data_t *td)
{
int retval = -1;
trans_cb_t *fn;
if ((fn = cp->cp_api.ca_trans_end) != NULL){
if (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_done callback does not make clicon_err call on error",
__FUNCTION__, cp->cp_name);
break;
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
__FUNCTION__, cp->cp_name);
goto done;
}
}
retval = 0;
done:
return retval;
}
@ -408,23 +598,39 @@ plugin_transaction_commit_done(clicon_handle h,
* @retval -1 Error
*/
int
plugin_transaction_end(clicon_handle h,
transaction_data_t *td)
plugin_transaction_end_all(clicon_handle h,
transaction_data_t *td)
{
int retval = 0;
int retval = -1;
clixon_plugin *cp = NULL;
trans_cb_t *fn;
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
if ((fn = cp->cp_api.ca_trans_end) == NULL)
continue;
if ((retval = fn(h, (transaction_data)td)) < 0){
if (plugin_transaction_end_one(cp, h, td) < 0)
goto done;
}
retval = 0;
done:
return retval;
}
int
plugin_transaction_abort_one(clixon_plugin *cp,
clicon_handle h,
transaction_data_t *td)
{
int retval = -1;
trans_cb_t *fn;
if ((fn = cp->cp_api.ca_trans_abort) != NULL){
if (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;
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
__FUNCTION__, cp->cp_name);
goto done;
}
}
retval = 0;
done:
return retval;
}
@ -435,18 +641,17 @@ plugin_transaction_end(clicon_handle h,
* @retval -1 Error
*/
int
plugin_transaction_abort(clicon_handle h,
transaction_data_t *td)
plugin_transaction_abort_all(clicon_handle h,
transaction_data_t *td)
{
int retval = 0;
int retval = -1;
clixon_plugin *cp = NULL;
trans_cb_t *fn;
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
if ((fn = cp->cp_api.ca_trans_abort) == NULL)
continue;
fn(h, (transaction_data)td); /* dont abort on error */
if (plugin_transaction_abort_one(cp, h, td) < 0)
; /* dont abort on error */
}
retval = 0;
return retval;
}