* New clixon-lib@2020-04-23.yang revision
* 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:
parent
1c99bd6a9b
commit
9a8c6cf3e6
25 changed files with 926 additions and 308 deletions
13
CHANGELOG.md
13
CHANGELOG.md
|
|
@ -31,14 +31,14 @@ Expected: May 2020
|
||||||
|
|
||||||
### API changes on existing protocol/config features (You may have have to change how you use Clixon)
|
### API changes on existing protocol/config features (You may have have to change how you use Clixon)
|
||||||
|
|
||||||
* xml-stats moved from clixon-config.yang as state data to an rpc `datastats`in clixon-lib.yang
|
* New clixon-lib@2020-04-23.yang revision
|
||||||
|
* 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
|
||||||
* Stricter incoming RPC sanity checking, error messages may have changed.
|
* Stricter incoming RPC sanity checking, error messages may have changed.
|
||||||
|
|
||||||
### C-API changes on existing features (you may need to change your plugin C-code)
|
### C-API changes on existing features (you may need to change your plugin C-code)
|
||||||
|
|
||||||
* 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.
|
|
||||||
* Length of xml vector in many structs changed from `size_t` to `int`since it is a vector size, not byte size. This includes `transaction_data_t`
|
* Length of xml vector in many structs changed from `size_t` to `int`since it is a vector size, not byte size. This includes `transaction_data_t`
|
||||||
* `xml_merge()` changed to use 3-value return: 1:OK, 0:Yang failed, -1: Error
|
* `xml_merge()` changed to use 3-value return: 1:OK, 0:Yang failed, -1: Error
|
||||||
* `clixon_netconf_error(category, xerr, msg, arg)` removed first argument -> `clixon_netconf_error(xerr, msg, arg)`
|
* `clixon_netconf_error(category, xerr, msg, arg)` removed first argument -> `clixon_netconf_error(xerr, msg, arg)`
|
||||||
|
|
@ -48,6 +48,11 @@ Expected: May 2020
|
||||||
|
|
||||||
### Minor changes
|
### Minor changes
|
||||||
|
|
||||||
|
* 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.
|
||||||
* Adapted to CLIgen 4.5 API changes, eg: `cliread()` and `cliread_parse()`
|
* Adapted to CLIgen 4.5 API changes, eg: `cliread()` and `cliread_parse()`
|
||||||
* Renamed utility function `clixon_util_insert()` to `clixon_util_xml_mod()` and added merge functionality.
|
* Renamed utility function `clixon_util_insert()` to `clixon_util_xml_mod()` and added merge functionality.
|
||||||
* Sanity check of duplicates prefixes in Yang modules and submodules as defined in RFC 7950 Sec 7.1.4
|
* Sanity check of duplicates prefixes in Yang modules and submodules as defined in RFC 7950 Sec 7.1.4
|
||||||
|
|
|
||||||
|
|
@ -316,6 +316,7 @@ client_statedata(clicon_handle h,
|
||||||
char *namespace;
|
char *namespace;
|
||||||
cbuf *cb = NULL;
|
cbuf *cb = NULL;
|
||||||
|
|
||||||
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||||
clicon_err(OE_YANG, ENOENT, "No yang spec");
|
clicon_err(OE_YANG, ENOENT, "No yang spec");
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -367,7 +368,7 @@ client_statedata(clicon_handle h,
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if ((ret = clixon_plugin_statedata(h, yspec, nsc, xpath, xret)) < 0)
|
if ((ret = clixon_plugin_statedata_all(h, yspec, nsc, xpath, xret)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
@ -980,6 +981,7 @@ from_client_get(clicon_handle h,
|
||||||
cxobj *xb;
|
cxobj *xb;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
username = clicon_username_get(h);
|
username = clicon_username_get(h);
|
||||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||||
clicon_err(OE_YANG, ENOENT, "No yang spec9");
|
clicon_err(OE_YANG, ENOENT, "No yang spec9");
|
||||||
|
|
@ -1405,11 +1407,11 @@ from_client_ping(clicon_handle h,
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
from_client_datastats(clicon_handle h,
|
from_client_stats(clicon_handle h,
|
||||||
cxobj *xe,
|
cxobj *xe,
|
||||||
cbuf *cbret,
|
cbuf *cbret,
|
||||||
void *arg,
|
void *arg,
|
||||||
void *regarg)
|
void *regarg)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
uint64_t nr;
|
uint64_t nr;
|
||||||
|
|
@ -1430,6 +1432,55 @@ from_client_datastats(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef RESTART_PLUGIN_RPC
|
||||||
|
/*! Request restart of specific plugins
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] xe Request: <rpc><xn></rpc>
|
||||||
|
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
|
||||||
|
* @param[in] arg client-entry
|
||||||
|
* @param[in] regarg User argument given at rpc_callback_register()
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
from_client_restart_plugin(clicon_handle h,
|
||||||
|
cxobj *xe,
|
||||||
|
cbuf *cbret,
|
||||||
|
void *arg,
|
||||||
|
void *regarg)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
char *name;
|
||||||
|
cxobj **vec = NULL;
|
||||||
|
size_t veclen;
|
||||||
|
int i;
|
||||||
|
clixon_plugin *cp;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (xpath_vec(xe, NULL, "plugin", &vec, &veclen) < 0)
|
||||||
|
goto done;
|
||||||
|
for (i=0; i<veclen; i++){
|
||||||
|
name = xml_body(vec[i]);
|
||||||
|
if ((cp = clixon_plugin_find(h, name)) == NULL){
|
||||||
|
if (netconf_bad_element(cbret, "application", "plugin", "No such plugin") < 0)
|
||||||
|
goto done;
|
||||||
|
goto ok;
|
||||||
|
}
|
||||||
|
if ((ret = from_client_restart_one(h, cp, cbret)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (ret == 0)
|
||||||
|
goto ok; /* cbret set */
|
||||||
|
}
|
||||||
|
cprintf(cbret, "<rpc-reply><ok/></rpc-reply>");
|
||||||
|
ok:
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (vec)
|
||||||
|
free(vec);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
#endif /* RESTART_PLUGIN_RPC */
|
||||||
|
|
||||||
/*! Verify nacm user with peer uid credentials
|
/*! Verify nacm user with peer uid credentials
|
||||||
* @param[in] mode Peer credential mode: none, exact or except
|
* @param[in] mode Peer credential mode: none, exact or except
|
||||||
* @param[in] peername Peer username if any
|
* @param[in] peername Peer username if any
|
||||||
|
|
@ -1685,7 +1736,7 @@ from_client_msg(clicon_handle h,
|
||||||
cbuf_free(cbret);
|
cbuf_free(cbret);
|
||||||
/* Sanity: log if clicon_err() is not called ! */
|
/* Sanity: log if clicon_err() is not called ! */
|
||||||
if (retval < 0 && clicon_errno < 0)
|
if (retval < 0 && clicon_errno < 0)
|
||||||
clicon_log(LOG_NOTICE, "%s: Internal error: No clicon_err call on error (message: %s)",
|
clicon_log(LOG_NOTICE, "%s: Internal error: No clicon_err call on RPC error (message: %s)",
|
||||||
__FUNCTION__, rpc?rpc:"");
|
__FUNCTION__, rpc?rpc:"");
|
||||||
// clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
// clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||||
return retval;// -1 here terminates backend
|
return retval;// -1 here terminates backend
|
||||||
|
|
@ -1791,9 +1842,14 @@ backend_rpc_init(clicon_handle h)
|
||||||
if (rpc_callback_register(h, from_client_ping, NULL,
|
if (rpc_callback_register(h, from_client_ping, NULL,
|
||||||
CLIXON_LIB_NS, "ping") < 0)
|
CLIXON_LIB_NS, "ping") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (rpc_callback_register(h, from_client_datastats, NULL,
|
if (rpc_callback_register(h, from_client_stats, NULL,
|
||||||
CLIXON_LIB_NS, "datastats") < 0)
|
CLIXON_LIB_NS, "stats") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
#ifdef RESTART_PLUGIN_RPC
|
||||||
|
if (rpc_callback_register(h, from_client_restart_plugin, NULL,
|
||||||
|
CLIXON_LIB_NS, "restart-plugin") < 0)
|
||||||
|
goto done;
|
||||||
|
#endif
|
||||||
retval =0;
|
retval =0;
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
|
|
|
||||||
|
|
@ -202,7 +202,7 @@ startup_common(clicon_handle h,
|
||||||
}
|
}
|
||||||
/* Here xt is old syntax */
|
/* Here xt is old syntax */
|
||||||
/* General purpose datastore upgrade */
|
/* General purpose datastore upgrade */
|
||||||
if (clixon_plugin_datastore_upgrade(h, db, xt, msd) < 0)
|
if (clixon_plugin_datastore_upgrade_all(h, db, xt, msd) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Module-specific upgrade callbacks */
|
/* Module-specific upgrade callbacks */
|
||||||
if ((ret = clixon_module_upgrade(h, xt, msd, cbret)) < 0)
|
if ((ret = clixon_module_upgrade(h, xt, msd, cbret)) < 0)
|
||||||
|
|
@ -230,7 +230,7 @@ startup_common(clicon_handle h,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 4. Call plugin transaction start callbacks */
|
/* 4. Call plugin transaction start callbacks */
|
||||||
if (plugin_transaction_begin(h, td) < 0)
|
if (plugin_transaction_begin_all(h, td) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* 5. Make generic validation on all new or changed data.
|
/* 5. Make generic validation on all new or changed data.
|
||||||
|
|
@ -244,11 +244,11 @@ startup_common(clicon_handle h,
|
||||||
goto fail; /* STARTUP_INVALID */
|
goto fail; /* STARTUP_INVALID */
|
||||||
}
|
}
|
||||||
/* 6. Call plugin transaction validate callbacks */
|
/* 6. Call plugin transaction validate callbacks */
|
||||||
if (plugin_transaction_validate(h, td) < 0)
|
if (plugin_transaction_validate_all(h, td) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* 7. Call plugin transaction complete callbacks */
|
/* 7. Call plugin transaction complete callbacks */
|
||||||
if (plugin_transaction_complete(h, td) < 0)
|
if (plugin_transaction_complete_all(h, td) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
ok:
|
ok:
|
||||||
retval = 1;
|
retval = 1;
|
||||||
|
|
@ -289,14 +289,14 @@ startup_validate(clicon_handle h,
|
||||||
if ((td = transaction_new()) == NULL)
|
if ((td = transaction_new()) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if ((ret = startup_common(h, db, td, cbret)) < 0){
|
if ((ret = startup_common(h, db, td, cbret)) < 0){
|
||||||
plugin_transaction_abort(h, td);
|
plugin_transaction_abort_all(h, td);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (ret == 0){
|
if (ret == 0){
|
||||||
plugin_transaction_abort(h, td);
|
plugin_transaction_abort_all(h, td);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
plugin_transaction_end(h, td);
|
plugin_transaction_end_all(h, td);
|
||||||
/* Clear cached trees from default values and marking */
|
/* Clear cached trees from default values and marking */
|
||||||
if (xmldb_get0_clear(h, td->td_target) < 0)
|
if (xmldb_get0_clear(h, td->td_target) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -347,10 +347,10 @@ startup_commit(clicon_handle h,
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
/* 8. Call plugin transaction commit callbacks */
|
/* 8. Call plugin transaction commit callbacks */
|
||||||
if (plugin_transaction_commit(h, td) < 0)
|
if (plugin_transaction_commit_all(h, td) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* After commit, make a post-commit call (sure that all plugins have committed) */
|
/* After commit, make a post-commit call (sure that all plugins have committed) */
|
||||||
if (plugin_transaction_commit_done(h, td) < 0)
|
if (plugin_transaction_commit_done_all(h, td) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Clear cached trees from default values and marking */
|
/* Clear cached trees from default values and marking */
|
||||||
if (xmldb_get0_clear(h, td->td_target) < 0)
|
if (xmldb_get0_clear(h, td->td_target) < 0)
|
||||||
|
|
@ -373,12 +373,12 @@ startup_commit(clicon_handle h,
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
/* 10. Call plugin transaction end callbacks */
|
/* 10. Call plugin transaction end callbacks */
|
||||||
plugin_transaction_end(h, td);
|
plugin_transaction_end_all(h, td);
|
||||||
retval = 1;
|
retval = 1;
|
||||||
done:
|
done:
|
||||||
if (td){
|
if (td){
|
||||||
if (retval < 1)
|
if (retval < 1)
|
||||||
plugin_transaction_abort(h, td);
|
plugin_transaction_abort_all(h, td);
|
||||||
xmldb_get0_free(h, &td->td_target);
|
xmldb_get0_free(h, &td->td_target);
|
||||||
transaction_free(td);
|
transaction_free(td);
|
||||||
}
|
}
|
||||||
|
|
@ -477,7 +477,7 @@ from_validate_common(clicon_handle h,
|
||||||
xml_apply_ancestor(xn, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_CHANGE);
|
xml_apply_ancestor(xn, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_CHANGE);
|
||||||
}
|
}
|
||||||
/* 4. Call plugin transaction start callbacks */
|
/* 4. Call plugin transaction start callbacks */
|
||||||
if (plugin_transaction_begin(h, td) < 0)
|
if (plugin_transaction_begin_all(h, td) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* 5. Make generic validation on all new or changed data.
|
/* 5. Make generic validation on all new or changed data.
|
||||||
|
|
@ -488,11 +488,11 @@ from_validate_common(clicon_handle h,
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* 6. Call plugin transaction validate callbacks */
|
/* 6. Call plugin transaction validate callbacks */
|
||||||
if (plugin_transaction_validate(h, td) < 0)
|
if (plugin_transaction_validate_all(h, td) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* 7. Call plugin transaction complete callbacks */
|
/* 7. Call plugin transaction complete callbacks */
|
||||||
if (plugin_transaction_complete(h, td) < 0)
|
if (plugin_transaction_complete_all(h, td) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
retval = 1;
|
retval = 1;
|
||||||
done:
|
done:
|
||||||
|
|
@ -539,10 +539,10 @@ candidate_commit(clicon_handle h,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 7. Call plugin transaction commit callbacks */
|
/* 7. Call plugin transaction commit callbacks */
|
||||||
if (plugin_transaction_commit(h, td) < 0)
|
if (plugin_transaction_commit_all(h, td) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* After commit, make a post-commit call (sure that all plugins have committed) */
|
/* After commit, make a post-commit call (sure that all plugins have committed) */
|
||||||
if (plugin_transaction_commit_done(h, td) < 0)
|
if (plugin_transaction_commit_done_all(h, td) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* Clear cached trees from default values and marking */
|
/* Clear cached trees from default values and marking */
|
||||||
|
|
@ -576,14 +576,14 @@ candidate_commit(clicon_handle h,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 9. Call plugin transaction end callbacks */
|
/* 9. Call plugin transaction end callbacks */
|
||||||
plugin_transaction_end(h, td);
|
plugin_transaction_end_all(h, td);
|
||||||
|
|
||||||
retval = 1;
|
retval = 1;
|
||||||
done:
|
done:
|
||||||
/* In case of failure (or error), call plugin transaction termination callbacks */
|
/* In case of failure (or error), call plugin transaction termination callbacks */
|
||||||
if (td){
|
if (td){
|
||||||
if (retval < 1)
|
if (retval < 1)
|
||||||
plugin_transaction_abort(h, td);
|
plugin_transaction_abort_all(h, td);
|
||||||
xmldb_get0_free(h, &td->td_target);
|
xmldb_get0_free(h, &td->td_target);
|
||||||
xmldb_get0_free(h, &td->td_src);
|
xmldb_get0_free(h, &td->td_src);
|
||||||
transaction_free(td);
|
transaction_free(td);
|
||||||
|
|
@ -771,7 +771,7 @@ from_client_validate(clicon_handle h,
|
||||||
* use clicon_err. */
|
* use clicon_err. */
|
||||||
if (xret && clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0)
|
if (xret && clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
plugin_transaction_abort(h, td);
|
plugin_transaction_abort_all(h, td);
|
||||||
if (!cbuf_len(cbret) &&
|
if (!cbuf_len(cbret) &&
|
||||||
netconf_operation_failed(cbret, "application", clicon_err_reason)< 0)
|
netconf_operation_failed(cbret, "application", clicon_err_reason)< 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -780,13 +780,13 @@ from_client_validate(clicon_handle h,
|
||||||
|
|
||||||
if (xmldb_get0_clear(h, td->td_src) < 0 ||
|
if (xmldb_get0_clear(h, td->td_src) < 0 ||
|
||||||
xmldb_get0_clear(h, td->td_target) < 0){
|
xmldb_get0_clear(h, td->td_target) < 0){
|
||||||
plugin_transaction_abort(h, td);
|
plugin_transaction_abort_all(h, td);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Optionally write (potentially modified) tree back to candidate */
|
/* Optionally write (potentially modified) tree back to candidate */
|
||||||
if (clicon_option_bool(h, "CLICON_TRANSACTION_MOD")){
|
if (clicon_option_bool(h, "CLICON_TRANSACTION_MOD")){
|
||||||
plugin_transaction_abort(h, td);
|
plugin_transaction_abort_all(h, td);
|
||||||
if ((ret = xmldb_put(h, "candidate", OP_REPLACE, td->td_target,
|
if ((ret = xmldb_put(h, "candidate", OP_REPLACE, td->td_target,
|
||||||
clicon_username_get(h), cbret)) < 0)
|
clicon_username_get(h), cbret)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -794,13 +794,13 @@ from_client_validate(clicon_handle h,
|
||||||
}
|
}
|
||||||
cprintf(cbret, "<rpc-reply><ok/></rpc-reply>");
|
cprintf(cbret, "<rpc-reply><ok/></rpc-reply>");
|
||||||
/* Call plugin transaction end callbacks */
|
/* Call plugin transaction end callbacks */
|
||||||
plugin_transaction_end(h, td);
|
plugin_transaction_end_all(h, td);
|
||||||
ok:
|
ok:
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (td){
|
if (td){
|
||||||
if (retval < 0)
|
if (retval < 0)
|
||||||
plugin_transaction_abort(h, td);
|
plugin_transaction_abort_all(h, td);
|
||||||
xmldb_get0_free(h, &td->td_target);
|
xmldb_get0_free(h, &td->td_target);
|
||||||
xmldb_get0_free(h, &td->td_src);
|
xmldb_get0_free(h, &td->td_src);
|
||||||
transaction_free(td);
|
transaction_free(td);
|
||||||
|
|
@ -810,3 +810,143 @@ from_client_validate(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
} /* from_client_validate */
|
} /* from_client_validate */
|
||||||
|
|
||||||
|
#ifdef RESTART_PLUGIN_RPC
|
||||||
|
int
|
||||||
|
from_client_restart_one(clicon_handle h,
|
||||||
|
clixon_plugin *cp,
|
||||||
|
cbuf *cbret)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
char *db = "tmp";
|
||||||
|
transaction_data_t *td = NULL;
|
||||||
|
plgreset_t *resetfn; /* Plugin auth */
|
||||||
|
trans_cb_t *fn;
|
||||||
|
int ret;
|
||||||
|
cxobj *xerr = NULL;
|
||||||
|
yang_stmt *yspec;
|
||||||
|
int i;
|
||||||
|
cxobj *xn;
|
||||||
|
|
||||||
|
yspec = clicon_dbspec_yang(h);
|
||||||
|
if (xmldb_db_reset(h, db) < 0)
|
||||||
|
goto done;
|
||||||
|
/* Application may define extra xml in its reset function*/
|
||||||
|
if ((resetfn = cp->cp_api.ca_reset) != NULL){
|
||||||
|
if ((retval = resetfn(h, db)) < 0) {
|
||||||
|
clicon_debug(1, "plugin_start() failed");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 1. Start transaction */
|
||||||
|
if ((td = transaction_new()) == NULL)
|
||||||
|
goto done;
|
||||||
|
/* This is the state we are going to */
|
||||||
|
if (xmldb_get0(h, "running", NULL, "/", 0, &td->td_target, NULL) < 0)
|
||||||
|
goto done;
|
||||||
|
if ((ret = xml_yang_validate_all_top(h, td->td_target, &xerr)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (ret == 0){
|
||||||
|
if (clicon_xml2cbuf(cbret, xerr, 0, 0, -1) < 0)
|
||||||
|
goto done;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
/* This is the state we are going from */
|
||||||
|
if (xmldb_get0(h, db, NULL, "/", 0, &td->td_src, NULL) < 0)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
/* 3. Compute differences */
|
||||||
|
if (xml_diff(yspec,
|
||||||
|
td->td_src,
|
||||||
|
td->td_target,
|
||||||
|
&td->td_dvec, /* removed: only in running */
|
||||||
|
&td->td_dlen,
|
||||||
|
&td->td_avec, /* added: only in candidate */
|
||||||
|
&td->td_alen,
|
||||||
|
&td->td_scvec, /* changed: original values */
|
||||||
|
&td->td_tcvec, /* changed: wanted values */
|
||||||
|
&td->td_clen) < 0)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
/* Mark as changed in tree */
|
||||||
|
for (i=0; i<td->td_dlen; i++){ /* Also down */
|
||||||
|
xn = td->td_dvec[i];
|
||||||
|
xml_flag_set(xn, XML_FLAG_DEL);
|
||||||
|
xml_apply(xn, CX_ELMNT, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_DEL);
|
||||||
|
xml_apply_ancestor(xn, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_CHANGE);
|
||||||
|
}
|
||||||
|
for (i=0; i<td->td_alen; i++){ /* Also down */
|
||||||
|
xn = td->td_avec[i];
|
||||||
|
xml_flag_set(xn, XML_FLAG_ADD);
|
||||||
|
xml_apply(xn, CX_ELMNT, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_ADD);
|
||||||
|
xml_apply_ancestor(xn, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_CHANGE);
|
||||||
|
}
|
||||||
|
for (i=0; i<td->td_clen; i++){ /* Also up */
|
||||||
|
xn = td->td_scvec[i];
|
||||||
|
xml_flag_set(xn, XML_FLAG_CHANGE);
|
||||||
|
xml_apply_ancestor(xn, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_CHANGE);
|
||||||
|
xn = td->td_tcvec[i];
|
||||||
|
xml_flag_set(xn, XML_FLAG_CHANGE);
|
||||||
|
xml_apply_ancestor(xn, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_CHANGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 4. Call plugin transaction start callbacks */
|
||||||
|
if ((fn = cp->cp_api.ca_trans_begin) != NULL){
|
||||||
|
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);
|
||||||
|
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 5. Make generic validation on all new or changed data.
|
||||||
|
Note this is only call that uses 3-values */
|
||||||
|
if ((ret = generic_validate(h, yspec, td, &xerr)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (ret == 0){
|
||||||
|
if (clicon_xml2cbuf(cbret, xerr, 0, 0, -1) < 0)
|
||||||
|
goto done;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if ((fn = cp->cp_api.ca_trans_validate) != NULL){
|
||||||
|
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);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((fn = cp->cp_api.ca_trans_complete) != NULL){
|
||||||
|
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);
|
||||||
|
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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' trans_commit callback does not make clicon_err call on error",
|
||||||
|
__FUNCTION__, cp->cp_name);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((fn = cp->cp_api.ca_trans_end) != NULL){
|
||||||
|
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);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
retval = 1;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
fail:
|
||||||
|
retval = 0;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
#endif /* RESTART_PLUGIN_RPC */
|
||||||
|
|
|
||||||
|
|
@ -48,5 +48,8 @@ int from_client_commit(clicon_handle h, cxobj *xe, cbuf *cbret, void *arg, void
|
||||||
int from_client_discard_changes(clicon_handle h, cxobj *xe, cbuf *cbret, void *arg, void *regarg);
|
int from_client_discard_changes(clicon_handle h, cxobj *xe, cbuf *cbret, void *arg, void *regarg);
|
||||||
int from_client_cancel_commit(clicon_handle h, cxobj *xe, cbuf *cbret, void *arg, void *regarg);
|
int from_client_cancel_commit(clicon_handle h, cxobj *xe, cbuf *cbret, void *arg, void *regarg);
|
||||||
int from_client_validate(clicon_handle h, cxobj *xe, cbuf *cbret, void *arg, void *regarg);
|
int from_client_validate(clicon_handle h, cxobj *xe, cbuf *cbret, void *arg, void *regarg);
|
||||||
|
#ifdef RESTART_PLUGIN_RPC
|
||||||
|
int from_client_restart_one(clicon_handle h, clixon_plugin *cp, cbuf *cbret);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* _BACKEND_COMMIT_H_ */
|
#endif /* _BACKEND_COMMIT_H_ */
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@ backend_terminate(clicon_handle h)
|
||||||
if ((x = clicon_conf_xml(h)) != NULL)
|
if ((x = clicon_conf_xml(h)) != NULL)
|
||||||
xml_free(x);
|
xml_free(x);
|
||||||
stream_publish_exit();
|
stream_publish_exit();
|
||||||
clixon_plugin_exit(h);
|
clixon_plugin_exit_all(h);
|
||||||
/* Delete all backend plugin RPC callbacks */
|
/* Delete all backend plugin RPC callbacks */
|
||||||
rpc_callback_delete_all(h);
|
rpc_callback_delete_all(h);
|
||||||
/* Delete all backend plugin upgrade callbacks */
|
/* Delete all backend plugin upgrade callbacks */
|
||||||
|
|
@ -867,7 +867,7 @@ main(int argc,
|
||||||
clicon_log(LOG_NOTICE, "%s: %u %s", __PROGRAM__, getpid(), cbuf_get(cbret));
|
clicon_log(LOG_NOTICE, "%s: %u %s", __PROGRAM__, getpid(), cbuf_get(cbret));
|
||||||
|
|
||||||
/* Call backend plugin_start with user -- options */
|
/* Call backend plugin_start with user -- options */
|
||||||
if (clixon_plugin_start(h) < 0)
|
if (clixon_plugin_start_all(h) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* -1 option to run only once */
|
/* -1 option to run only once */
|
||||||
if (once)
|
if (once)
|
||||||
|
|
@ -886,7 +886,7 @@ main(int argc,
|
||||||
|
|
||||||
}
|
}
|
||||||
/* Call plugin callbacks when in background and before dropped privileges */
|
/* Call plugin callbacks when in background and before dropped privileges */
|
||||||
if (clixon_plugin_daemon(h) < 0)
|
if (clixon_plugin_daemon_all(h) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* Write pid-file */
|
/* Write pid-file */
|
||||||
|
|
|
||||||
|
|
@ -67,62 +67,150 @@
|
||||||
|
|
||||||
/*! Request plugins to reset system state
|
/*! Request plugins to reset system state
|
||||||
* The system 'state' should be the same as the contents of running_db
|
* 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] h Clicon handle
|
||||||
* @param[in] db Name of database
|
* @param[in] db Name of datastore
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clixon_plugin_reset(clicon_handle h,
|
clixon_plugin_reset_one(clixon_plugin *cp,
|
||||||
char *db)
|
clicon_handle h,
|
||||||
|
char *db)
|
||||||
{
|
{
|
||||||
clixon_plugin *cp = NULL;
|
int retval = -1;
|
||||||
plgreset_t *resetfn; /* Plugin auth */
|
plgreset_t *fn; /* callback */
|
||||||
int retval = 1;
|
|
||||||
|
|
||||||
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
|
if ((fn = cp->cp_api.ca_reset) != NULL){
|
||||||
if ((resetfn = cp->cp_api.ca_reset) == NULL)
|
if (fn(h, db) < 0) {
|
||||||
continue;
|
if (clicon_errno < 0)
|
||||||
if ((retval = resetfn(h, db)) < 0) {
|
clicon_log(LOG_WARNING, "%s: Internal error: Reset callback in plugin: %s returned -1 but did not make a clicon_err call",
|
||||||
clicon_debug(1, "plugin_start() failed");
|
__FUNCTION__, cp->cp_name);
|
||||||
return -1;
|
goto done;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Request plugins to reset system state
|
/*! Call all plugins reset callbacks
|
||||||
* The system 'state' should be the same as the contents of running_db
|
* The system 'state' should be the same as the contents of running_db
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clixon handle
|
||||||
* @param[in] db Name of database
|
* @param[in] db Name of datastore
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clixon_plugin_daemon(clicon_handle h)
|
clixon_plugin_reset_all(clicon_handle h,
|
||||||
|
char *db)
|
||||||
{
|
{
|
||||||
|
int retval = -1;
|
||||||
clixon_plugin *cp = NULL;
|
clixon_plugin *cp = NULL;
|
||||||
plgdaemon_t *daemonfn; /* Plugin auth */
|
|
||||||
int retval = 1;
|
|
||||||
|
|
||||||
|
/* Loop through all plugins, call callbacks in each */
|
||||||
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
|
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
|
||||||
if ((daemonfn = cp->cp_api.ca_daemon) == NULL)
|
if (clixon_plugin_reset_one(cp, h, db) < 0)
|
||||||
continue;
|
goto done;
|
||||||
if ((retval = daemonfn(h)) < 0) {
|
|
||||||
clicon_debug(1, "plugin_daemon() failed");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! 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_one(clixon_plugin *cp,
|
||||||
|
clicon_handle h)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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
|
/*! Go through all backend statedata callbacks and collect state data
|
||||||
* This is internal system call, plugin is invoked (does not call) this function
|
* This is internal system call, plugin is invoked (does not call) this function
|
||||||
* Backend plugins can register
|
* Backend plugins can register
|
||||||
* @param[in] h clicon handle
|
* @param[in] h clicon handle
|
||||||
* @param[in] yspec Yang spec
|
* @param[in] yspec Yang spec
|
||||||
|
* @param[in] nsc Namespace context
|
||||||
* @param[in] xpath String with XPATH syntax. or NULL for all
|
* @param[in] xpath String with XPATH syntax. or NULL for all
|
||||||
* @param[in,out] xtop State XML tree is merged with existing tree.
|
* @param[in,out] xtop State XML tree is merged with existing tree.
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
|
|
@ -131,27 +219,31 @@ clixon_plugin_daemon(clicon_handle h)
|
||||||
* @note xtop can be replaced
|
* @note xtop can be replaced
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clixon_plugin_statedata(clicon_handle h,
|
clixon_plugin_statedata_all(clicon_handle h,
|
||||||
yang_stmt *yspec,
|
yang_stmt *yspec,
|
||||||
cvec *nsc,
|
cvec *nsc,
|
||||||
char *xpath,
|
char *xpath,
|
||||||
cxobj **xret)
|
cxobj **xret)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
int ret;
|
int ret;
|
||||||
cxobj *x = NULL;
|
cxobj *x = NULL;
|
||||||
clixon_plugin *cp = NULL;
|
clixon_plugin *cp = NULL;
|
||||||
plgstatedata_t *fn; /* Plugin statedata fn */
|
|
||||||
cbuf *cberr = NULL;
|
cbuf *cberr = NULL;
|
||||||
|
|
||||||
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
|
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
|
||||||
if ((fn = cp->cp_api.ca_statedata) == NULL)
|
if ((ret = clixon_plugin_statedata_one(cp, h, nsc, xpath, &x)) < 0)
|
||||||
continue;
|
|
||||||
if ((x = xml_new("config", NULL, CX_ELMNT)) == NULL)
|
|
||||||
goto done;
|
goto done;
|
||||||
if (fn(h, nsc, xpath, x) < 0)
|
if (ret == 0)
|
||||||
goto fail; /* Dont quit here on user callbacks */
|
goto fail;
|
||||||
/* if x contains no data, then continue? */
|
if (x == NULL)
|
||||||
|
continue;
|
||||||
|
if (xml_child_nr(x) == 0){
|
||||||
|
xml_free(x);
|
||||||
|
x = NULL;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
#if 1
|
#if 1
|
||||||
if (debug)
|
if (debug)
|
||||||
clicon_log_xml(LOG_DEBUG, x, "%s STATE:", __FUNCTION__);
|
clicon_log_xml(LOG_DEBUG, x, "%s STATE:", __FUNCTION__);
|
||||||
|
|
@ -220,6 +312,27 @@ transaction_free(transaction_data_t *td)
|
||||||
return 0;
|
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 */
|
/* 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.
|
/*! 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
|
* @retval -1 Error: one of the plugin callbacks returned error
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
plugin_transaction_begin(clicon_handle h,
|
plugin_transaction_begin_all(clicon_handle h,
|
||||||
transaction_data_t *td)
|
transaction_data_t *td)
|
||||||
{
|
{
|
||||||
int retval = 0;
|
int retval = -1;
|
||||||
clixon_plugin *cp = NULL;
|
clixon_plugin *cp = NULL;
|
||||||
trans_cb_t *fn;
|
|
||||||
|
|
||||||
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
|
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
|
||||||
if ((fn = cp->cp_api.ca_trans_begin) == NULL)
|
if (plugin_transaction_begin_one(cp, h, td) < 0)
|
||||||
continue;
|
goto done;
|
||||||
if ((retval = fn(h, (transaction_data)td)) < 0){
|
}
|
||||||
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
|
retval = 0;
|
||||||
clicon_log(LOG_NOTICE, "%s: Plugin '%s' transaction_begin callback does not make clicon_err call on error",
|
done:
|
||||||
__FUNCTION__, cp->cp_name);
|
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;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -257,23 +385,39 @@ plugin_transaction_begin(clicon_handle h,
|
||||||
* @retval -1 Error: one of the plugin callbacks returned validation fail
|
* @retval -1 Error: one of the plugin callbacks returned validation fail
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
plugin_transaction_validate(clicon_handle h,
|
plugin_transaction_validate_all(clicon_handle h,
|
||||||
transaction_data_t *td)
|
transaction_data_t *td)
|
||||||
{
|
{
|
||||||
int retval = 0;
|
int retval = -1;
|
||||||
clixon_plugin *cp = NULL;
|
clixon_plugin *cp = NULL;
|
||||||
trans_cb_t *fn;
|
|
||||||
|
|
||||||
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
|
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
|
||||||
if ((fn = cp->cp_api.ca_trans_validate) == NULL)
|
if (plugin_transaction_validate_one(cp, h, td) < 0)
|
||||||
continue;
|
goto done;
|
||||||
if ((retval = fn(h, (transaction_data)td)) < 0){
|
}
|
||||||
|
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 ! */
|
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",
|
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
|
||||||
__FUNCTION__, cp->cp_name);
|
__FUNCTION__, cp->cp_name);
|
||||||
break;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -286,24 +430,18 @@ plugin_transaction_validate(clicon_handle h,
|
||||||
* @note Rename to transaction_complete?
|
* @note Rename to transaction_complete?
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
plugin_transaction_complete(clicon_handle h,
|
plugin_transaction_complete_all(clicon_handle h,
|
||||||
transaction_data_t *td)
|
transaction_data_t *td)
|
||||||
{
|
{
|
||||||
int retval = 0;
|
int retval = -1;
|
||||||
clixon_plugin *cp = NULL;
|
clixon_plugin *cp = NULL;
|
||||||
trans_cb_t *fn;
|
|
||||||
|
|
||||||
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
|
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
|
||||||
if ((fn = cp->cp_api.ca_trans_complete) == NULL)
|
if (plugin_transaction_complete_one(cp, h, td) < 0)
|
||||||
continue;
|
goto done;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
return retval;
|
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
|
* 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.
|
* plugin 2, then the revert will be made in plugins 1 and 0.
|
||||||
*/
|
*/
|
||||||
int
|
static int
|
||||||
plugin_transaction_revert(clicon_handle h,
|
plugin_transaction_revert_all(clicon_handle h,
|
||||||
transaction_data_t *td,
|
transaction_data_t *td,
|
||||||
int nr)
|
int nr)
|
||||||
{
|
{
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
clixon_plugin *cp = NULL;
|
clixon_plugin *cp = NULL;
|
||||||
|
|
@ -337,6 +475,27 @@ plugin_transaction_revert(clicon_handle h,
|
||||||
return retval; /* ignore errors */
|
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
|
/*! Call transaction_commit callbacks in all backend plugins
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] td Transaction data
|
* @param[in] td Transaction data
|
||||||
|
|
@ -347,27 +506,44 @@ plugin_transaction_revert(clicon_handle h,
|
||||||
* and in reverse order.
|
* and in reverse order.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
plugin_transaction_commit(clicon_handle h,
|
plugin_transaction_commit_all(clicon_handle h,
|
||||||
transaction_data_t *td)
|
transaction_data_t *td)
|
||||||
{
|
{
|
||||||
int retval = 0;
|
int retval = -1;
|
||||||
clixon_plugin *cp = NULL;
|
clixon_plugin *cp = NULL;
|
||||||
trans_cb_t *fn;
|
|
||||||
int i=0;
|
int i=0;
|
||||||
|
|
||||||
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
|
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
|
||||||
i++;
|
i++;
|
||||||
if ((fn = cp->cp_api.ca_trans_commit) == NULL)
|
if (plugin_transaction_commit_one(cp, h, td) < 0){
|
||||||
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 */
|
/* Make an effort to revert transaction */
|
||||||
plugin_transaction_revert(h, td, i-1);
|
plugin_transaction_revert_all(h, td, i-1);
|
||||||
break;
|
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;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -379,25 +555,39 @@ plugin_transaction_commit(clicon_handle h,
|
||||||
* @note no revert is done
|
* @note no revert is done
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
plugin_transaction_commit_done(clicon_handle h,
|
plugin_transaction_commit_done_all(clicon_handle h,
|
||||||
transaction_data_t *td)
|
transaction_data_t *td)
|
||||||
{
|
{
|
||||||
int retval = 0;
|
int retval = -1;
|
||||||
clixon_plugin *cp = NULL;
|
clixon_plugin *cp = NULL;
|
||||||
trans_cb_t *fn;
|
|
||||||
int i=0;
|
|
||||||
|
|
||||||
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
|
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
|
||||||
i++;
|
if (plugin_transaction_commit_done_one(cp, h, td) < 0)
|
||||||
if ((fn = cp->cp_api.ca_trans_commit_done) == NULL)
|
goto done;
|
||||||
continue;
|
}
|
||||||
if ((retval = fn(h, (transaction_data)td)) < 0){
|
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 ! */
|
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",
|
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
|
||||||
__FUNCTION__, cp->cp_name);
|
__FUNCTION__, cp->cp_name);
|
||||||
break;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -408,23 +598,39 @@ plugin_transaction_commit_done(clicon_handle h,
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
plugin_transaction_end(clicon_handle h,
|
plugin_transaction_end_all(clicon_handle h,
|
||||||
transaction_data_t *td)
|
transaction_data_t *td)
|
||||||
{
|
{
|
||||||
int retval = 0;
|
int retval = -1;
|
||||||
clixon_plugin *cp = NULL;
|
clixon_plugin *cp = NULL;
|
||||||
trans_cb_t *fn;
|
|
||||||
|
|
||||||
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
|
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
|
||||||
if ((fn = cp->cp_api.ca_trans_end) == NULL)
|
if (plugin_transaction_end_one(cp, h, td) < 0)
|
||||||
continue;
|
goto done;
|
||||||
if ((retval = fn(h, (transaction_data)td)) < 0){
|
}
|
||||||
|
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 ! */
|
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",
|
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
|
||||||
__FUNCTION__, cp->cp_name);
|
__FUNCTION__, cp->cp_name);
|
||||||
break;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -435,18 +641,17 @@ plugin_transaction_end(clicon_handle h,
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
plugin_transaction_abort(clicon_handle h,
|
plugin_transaction_abort_all(clicon_handle h,
|
||||||
transaction_data_t *td)
|
transaction_data_t *td)
|
||||||
{
|
{
|
||||||
int retval = 0;
|
int retval = -1;
|
||||||
clixon_plugin *cp = NULL;
|
clixon_plugin *cp = NULL;
|
||||||
trans_cb_t *fn;
|
|
||||||
|
|
||||||
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
|
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
|
||||||
if ((fn = cp->cp_api.ca_trans_abort) == NULL)
|
if (plugin_transaction_abort_one(cp, h, td) < 0)
|
||||||
continue;
|
; /* dont abort on error */
|
||||||
fn(h, (transaction_data)td); /* dont abort on error */
|
|
||||||
}
|
}
|
||||||
|
retval = 0;
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,21 +69,36 @@ typedef struct {
|
||||||
/*
|
/*
|
||||||
* Prototypes
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
int clixon_plugin_reset(clicon_handle h, char *db);
|
int clixon_plugin_reset_one(clixon_plugin *cp, clicon_handle h, char *db);
|
||||||
|
int clixon_plugin_reset_all(clicon_handle h, char *db);
|
||||||
|
|
||||||
int clixon_plugin_daemon(clicon_handle h);
|
int clixon_plugin_daemon_one(clixon_plugin *cp, clicon_handle h);
|
||||||
|
int clixon_plugin_daemon_all(clicon_handle h);
|
||||||
|
|
||||||
|
int clixon_plugin_statedata_all(clicon_handle h, yang_stmt *yspec, cvec *nsc, char *xpath, cxobj **xtop);
|
||||||
|
|
||||||
int clixon_plugin_statedata(clicon_handle h, yang_stmt *yspec, cvec *nsc,
|
|
||||||
char *xpath, cxobj **xtop);
|
|
||||||
transaction_data_t * transaction_new(void);
|
transaction_data_t * transaction_new(void);
|
||||||
int transaction_free(transaction_data_t *);
|
int transaction_free(transaction_data_t *);
|
||||||
|
|
||||||
int plugin_transaction_begin(clicon_handle h, transaction_data_t *td);
|
int plugin_transaction_begin_one(clixon_plugin *cp, clicon_handle h, transaction_data_t *td);
|
||||||
int plugin_transaction_validate(clicon_handle h, transaction_data_t *td);
|
int plugin_transaction_begin_all(clicon_handle h, transaction_data_t *td);
|
||||||
int plugin_transaction_complete(clicon_handle h, transaction_data_t *td);
|
|
||||||
int plugin_transaction_commit(clicon_handle h, transaction_data_t *td);
|
int plugin_transaction_validate_one(clixon_plugin *cp, clicon_handle h, transaction_data_t *td);
|
||||||
int plugin_transaction_commit_done(clicon_handle h, transaction_data_t *td);
|
int plugin_transaction_validate_all(clicon_handle h, transaction_data_t *td);
|
||||||
int plugin_transaction_end(clicon_handle h, transaction_data_t *td);
|
|
||||||
int plugin_transaction_abort(clicon_handle h, transaction_data_t *td);
|
int plugin_transaction_complete_one(clixon_plugin *cp, clicon_handle h, transaction_data_t *td);
|
||||||
|
int plugin_transaction_complete_all(clicon_handle h, transaction_data_t *td);
|
||||||
|
|
||||||
|
int plugin_transaction_commit_one(clixon_plugin *cp, clicon_handle h, transaction_data_t *td);
|
||||||
|
int plugin_transaction_commit_all(clicon_handle h, transaction_data_t *td);
|
||||||
|
|
||||||
|
int plugin_transaction_commit_done_one(clixon_plugin *cp, clicon_handle h, transaction_data_t *td);
|
||||||
|
int plugin_transaction_commit_done_all(clicon_handle h, transaction_data_t *td);
|
||||||
|
|
||||||
|
int plugin_transaction_end_one(clixon_plugin *cp, clicon_handle h, transaction_data_t *td);
|
||||||
|
int plugin_transaction_end_all(clicon_handle h, transaction_data_t *td);
|
||||||
|
|
||||||
|
int plugin_transaction_abort_one(clixon_plugin *cp, clicon_handle h, transaction_data_t *td);
|
||||||
|
int plugin_transaction_abort_all(clicon_handle h, transaction_data_t *td);
|
||||||
|
|
||||||
#endif /* _BACKEND_PLUGIN_H_ */
|
#endif /* _BACKEND_PLUGIN_H_ */
|
||||||
|
|
|
||||||
|
|
@ -227,7 +227,7 @@ startup_extraxml(clicon_handle h,
|
||||||
if (xmldb_db_reset(h, tmp_db) < 0)
|
if (xmldb_db_reset(h, tmp_db) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Application may define extra xml in its reset function*/
|
/* Application may define extra xml in its reset function*/
|
||||||
if (clixon_plugin_reset(h, tmp_db) < 0)
|
if (clixon_plugin_reset_all(h, tmp_db) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Extra XML can also be added via file */
|
/* Extra XML can also be added via file */
|
||||||
if (file){
|
if (file){
|
||||||
|
|
|
||||||
|
|
@ -596,7 +596,7 @@ main(int argc, char **argv)
|
||||||
|
|
||||||
/* Call start function in all plugins before we go interactive
|
/* Call start function in all plugins before we go interactive
|
||||||
*/
|
*/
|
||||||
if (clixon_plugin_start(h) < 0)
|
if (clixon_plugin_start_all(h) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
cligen_line_scrolling_set(cli_cligen(h), clicon_option_int(h,"CLICON_CLI_LINESCROLLING"));
|
cligen_line_scrolling_set(cli_cligen(h), clicon_option_int(h,"CLICON_CLI_LINESCROLLING"));
|
||||||
|
|
|
||||||
|
|
@ -423,7 +423,7 @@ cli_syntax_load(clicon_handle h)
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (retval != 0) {
|
if (retval != 0) {
|
||||||
clixon_plugin_exit(h);
|
clixon_plugin_exit_all(h);
|
||||||
cli_syntax_unload(h);
|
cli_syntax_unload(h);
|
||||||
cli_syntax_set(h, NULL);
|
cli_syntax_set(h, NULL);
|
||||||
}
|
}
|
||||||
|
|
@ -440,7 +440,7 @@ int
|
||||||
cli_plugin_finish(clicon_handle h)
|
cli_plugin_finish(clicon_handle h)
|
||||||
{
|
{
|
||||||
/* Remove all CLI plugins */
|
/* Remove all CLI plugins */
|
||||||
clixon_plugin_exit(h);
|
clixon_plugin_exit_all(h);
|
||||||
/* Remove all cligen syntax modes */
|
/* Remove all cligen syntax modes */
|
||||||
cli_syntax_unload(h);
|
cli_syntax_unload(h);
|
||||||
cli_syntax_set(h, NULL);
|
cli_syntax_set(h, NULL);
|
||||||
|
|
|
||||||
|
|
@ -326,7 +326,7 @@ netconf_terminate(clicon_handle h)
|
||||||
cvec *nsctx;
|
cvec *nsctx;
|
||||||
cxobj *x;
|
cxobj *x;
|
||||||
|
|
||||||
clixon_plugin_exit(h);
|
clixon_plugin_exit_all(h);
|
||||||
rpc_callback_delete_all(h);
|
rpc_callback_delete_all(h);
|
||||||
clicon_rpc_close_session(h);
|
clicon_rpc_close_session(h);
|
||||||
if ((yspec = clicon_dbspec_yang(h)) != NULL)
|
if ((yspec = clicon_dbspec_yang(h)) != NULL)
|
||||||
|
|
@ -571,7 +571,7 @@ main(int argc,
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* Call start function is all plugins before we go interactive */
|
/* Call start function is all plugins before we go interactive */
|
||||||
if (clixon_plugin_start(h) < 0)
|
if (clixon_plugin_start_all(h) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
#if 1
|
#if 1
|
||||||
/* XXX get session id from backend hello */
|
/* XXX get session id from backend hello */
|
||||||
|
|
|
||||||
|
|
@ -623,7 +623,7 @@ restconf_terminate(clicon_handle h)
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
if ((fs = clicon_socket_get(h)) != -1)
|
if ((fs = clicon_socket_get(h)) != -1)
|
||||||
close(fs);
|
close(fs);
|
||||||
clixon_plugin_exit(h);
|
clixon_plugin_exit_all(h);
|
||||||
rpc_callback_delete_all(h);
|
rpc_callback_delete_all(h);
|
||||||
clicon_rpc_close_session(h);
|
clicon_rpc_close_session(h);
|
||||||
if ((yspec = clicon_dbspec_yang(h)) != NULL)
|
if ((yspec = clicon_dbspec_yang(h)) != NULL)
|
||||||
|
|
|
||||||
|
|
@ -409,7 +409,7 @@ api_restconf(clicon_handle h,
|
||||||
/* If present, check credentials. See "plugin_credentials" in plugin
|
/* If present, check credentials. See "plugin_credentials" in plugin
|
||||||
* See RFC 8040 section 2.5
|
* See RFC 8040 section 2.5
|
||||||
*/
|
*/
|
||||||
if ((authenticated = clixon_plugin_auth(h, r)) < 0)
|
if ((authenticated = clixon_plugin_auth_all(h, r)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
clicon_debug(1, "%s auth:%d %s", __FUNCTION__, authenticated, clicon_username_get(h));
|
clicon_debug(1, "%s auth:%d %s", __FUNCTION__, authenticated, clicon_username_get(h));
|
||||||
|
|
||||||
|
|
@ -781,7 +781,7 @@ main(int argc,
|
||||||
|
|
||||||
/* Call start function in all plugins before we go interactive
|
/* Call start function in all plugins before we go interactive
|
||||||
*/
|
*/
|
||||||
if (clixon_plugin_start(h) < 0)
|
if (clixon_plugin_start_all(h) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if ((sockpath = clicon_option_str(h, "CLICON_RESTCONF_PATH")) == NULL){
|
if ((sockpath = clicon_option_str(h, "CLICON_RESTCONF_PATH")) == NULL){
|
||||||
|
|
|
||||||
|
|
@ -411,7 +411,7 @@ api_stream(clicon_handle h,
|
||||||
/* If present, check credentials. See "plugin_credentials" in plugin
|
/* If present, check credentials. See "plugin_credentials" in plugin
|
||||||
* See RFC 8040 section 2.5
|
* See RFC 8040 section 2.5
|
||||||
*/
|
*/
|
||||||
if ((authenticated = clixon_plugin_auth(h, r)) < 0)
|
if ((authenticated = clixon_plugin_auth_all(h, r)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
clicon_debug(1, "%s auth:%d %s", __FUNCTION__, authenticated, clicon_username_get(h));
|
clicon_debug(1, "%s auth:%d %s", __FUNCTION__, authenticated, clicon_username_get(h));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -159,6 +159,15 @@ main_commit(clicon_handle h,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main_commit_done(clicon_handle h,
|
||||||
|
transaction_data td)
|
||||||
|
{
|
||||||
|
if (_transaction_log)
|
||||||
|
transaction_log(h, td, LOG_NOTICE, __FUNCTION__);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main_revert(clicon_handle h,
|
main_revert(clicon_handle h,
|
||||||
transaction_data td)
|
transaction_data td)
|
||||||
|
|
@ -802,6 +811,18 @@ example_start(clicon_handle h)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Plugin daemon.
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
*
|
||||||
|
* plugin_daemon is called once after damonization has been made but before lowering of privileges
|
||||||
|
* the main event loop is entered.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
example_daemon(clicon_handle h)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
example_exit(clicon_handle h)
|
example_exit(clicon_handle h)
|
||||||
{
|
{
|
||||||
|
|
@ -816,12 +837,14 @@ static clixon_plugin_api api = {
|
||||||
example_start, /* start */
|
example_start, /* start */
|
||||||
example_exit, /* exit */
|
example_exit, /* exit */
|
||||||
.ca_extension=example_extension, /* yang extensions */
|
.ca_extension=example_extension, /* yang extensions */
|
||||||
|
.ca_daemon=example_daemon, /* daemon */
|
||||||
.ca_reset=example_reset, /* reset */
|
.ca_reset=example_reset, /* reset */
|
||||||
.ca_statedata=example_statedata, /* statedata */
|
.ca_statedata=example_statedata, /* statedata */
|
||||||
.ca_trans_begin=main_begin, /* trans begin */
|
.ca_trans_begin=main_begin, /* trans begin */
|
||||||
.ca_trans_validate=main_validate, /* trans validate */
|
.ca_trans_validate=main_validate, /* trans validate */
|
||||||
.ca_trans_complete=main_complete, /* trans complete */
|
.ca_trans_complete=main_complete, /* trans complete */
|
||||||
.ca_trans_commit=main_commit, /* trans commit */
|
.ca_trans_commit=main_commit, /* trans commit */
|
||||||
|
.ca_trans_commit_done=main_commit_done, /* trans commit done */
|
||||||
.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 */
|
||||||
|
|
|
||||||
|
|
@ -126,6 +126,15 @@ nacm_commit(clicon_handle h,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
nacm_commit_done(clicon_handle h,
|
||||||
|
transaction_data td)
|
||||||
|
{
|
||||||
|
if (_transaction_log)
|
||||||
|
transaction_log(h, td, LOG_NOTICE, __FUNCTION__);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
nacm_revert(clicon_handle h,
|
nacm_revert(clicon_handle h,
|
||||||
transaction_data td)
|
transaction_data td)
|
||||||
|
|
@ -199,6 +208,7 @@ static clixon_plugin_api api = {
|
||||||
.ca_trans_validate=nacm_validate, /* trans validate */
|
.ca_trans_validate=nacm_validate, /* trans validate */
|
||||||
.ca_trans_complete=nacm_complete, /* trans complete */
|
.ca_trans_complete=nacm_complete, /* trans complete */
|
||||||
.ca_trans_commit=nacm_commit, /* trans commit */
|
.ca_trans_commit=nacm_commit, /* trans commit */
|
||||||
|
.ca_trans_commit_done=nacm_commit_done, /* trans commit done */
|
||||||
.ca_trans_revert=nacm_revert, /* trans revert */
|
.ca_trans_revert=nacm_revert, /* trans revert */
|
||||||
.ca_trans_end=nacm_end, /* trans end */
|
.ca_trans_end=nacm_end, /* trans end */
|
||||||
.ca_trans_abort=nacm_abort /* trans abort */
|
.ca_trans_abort=nacm_abort /* trans abort */
|
||||||
|
|
|
||||||
|
|
@ -98,3 +98,6 @@
|
||||||
*/
|
*/
|
||||||
#define STATE_ORDERED_BY_SYSTEM
|
#define STATE_ORDERED_BY_SYSTEM
|
||||||
|
|
||||||
|
/*! Restart specific backend plugins
|
||||||
|
*/
|
||||||
|
#undef RESTART_PLUGIN_RPC
|
||||||
|
|
|
||||||
|
|
@ -270,7 +270,7 @@ typedef struct clixon_plugin clixon_plugin;
|
||||||
* Prototypes
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*! Plugin initialization function. Must appear in all plugins
|
/*! Plugin initialization function. Must appear in all plugins, not a clixon system function
|
||||||
* @param[in] h Clixon handle
|
* @param[in] h Clixon handle
|
||||||
* @retval api Pointer to API struct
|
* @retval api Pointer to API struct
|
||||||
* @retval NULL Failure (if clixon_err() called), module disabled otherwise.
|
* @retval NULL Failure (if clixon_err() called), module disabled otherwise.
|
||||||
|
|
@ -288,15 +288,20 @@ int clixon_plugins_load(clicon_handle h, char *function, char *dir, char *regexp
|
||||||
|
|
||||||
int clixon_pseudo_plugin(clicon_handle h, char *name, clixon_plugin **cpp);
|
int clixon_pseudo_plugin(clicon_handle h, char *name, clixon_plugin **cpp);
|
||||||
|
|
||||||
int clixon_plugin_start(clicon_handle h);
|
int clixon_plugin_start_one(clixon_plugin *cp, clicon_handle h);
|
||||||
|
int clixon_plugin_start_all(clicon_handle h);
|
||||||
|
|
||||||
int clixon_plugin_exit(clicon_handle h);
|
int clixon_plugin_exit_one(clixon_plugin *cp, clicon_handle h);
|
||||||
|
int clixon_plugin_exit_all(clicon_handle h);
|
||||||
|
|
||||||
int clixon_plugin_auth(clicon_handle h, void *arg);
|
int clixon_plugin_auth_one(clixon_plugin *cp, clicon_handle h, void *arg);
|
||||||
|
int clixon_plugin_auth_all(clicon_handle h, void *arg);
|
||||||
|
|
||||||
int clixon_plugin_extension(clicon_handle h, yang_stmt *yext, yang_stmt *ys);
|
int clixon_plugin_extension_one(clixon_plugin *cp, clicon_handle h, yang_stmt *yext, yang_stmt *ys);
|
||||||
|
int clixon_plugin_extension_all(clicon_handle h, yang_stmt *yext, yang_stmt *ys);
|
||||||
|
|
||||||
int clixon_plugin_datastore_upgrade(clicon_handle h, char *db, cxobj *xt, modstate_diff_t *msd);
|
int clixon_plugin_datastore_upgrade_one(clixon_plugin *cp, clicon_handle h, char *db, cxobj *xt, modstate_diff_t *msd);
|
||||||
|
int clixon_plugin_datastore_upgrade_all(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);
|
||||||
|
|
|
||||||
|
|
@ -348,65 +348,111 @@ done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Call plugin_start in all plugins
|
/*! Call single plugin start callback
|
||||||
* @param[in] h Clicon handle
|
* @param[in] cp Plugin handle
|
||||||
* Call plugin start functions (if defined)
|
* @param[in] h Clixon handle
|
||||||
* @note Start functions used to have argc/argv. Use clicon_argv_get() instead
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clixon_plugin_start(clicon_handle h)
|
clixon_plugin_start_one(clixon_plugin *cp,
|
||||||
|
clicon_handle h)
|
||||||
{
|
{
|
||||||
clixon_plugin *cp;
|
int retval = -1;
|
||||||
int i;
|
plgstart_t *fn; /* Plugin start */
|
||||||
plgstart_t *startfn; /* Plugin start */
|
|
||||||
|
|
||||||
for (i = 0; i < _clixon_nplugins; i++) {
|
if ((fn = cp->cp_api.ca_start) != NULL){
|
||||||
cp = &_clixon_plugins[i];
|
if (fn(h) < 0) {
|
||||||
if ((startfn = cp->cp_api.ca_start) == NULL)
|
if (clicon_errno < 0)
|
||||||
continue;
|
clicon_log(LOG_WARNING, "%s: Internal error: Start callback in plugin: %s returned -1 but did not make a clicon_err call",
|
||||||
if (startfn(h) < 0) {
|
__FUNCTION__, cp->cp_name);
|
||||||
clicon_debug(1, "%s() failed", __FUNCTION__);
|
goto done;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Call plugin_start in all plugins
|
||||||
|
* @param[in] h Clixon handle
|
||||||
|
* Call plugin start functions (if defined)
|
||||||
|
* @note Start functions can use clicon_argv_get() to get -- command line options
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
clixon_plugin_start_all(clicon_handle h)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
clixon_plugin *cp = NULL;
|
||||||
|
|
||||||
|
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
|
||||||
|
if (clixon_plugin_start_one(cp, h) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Unload all plugins: call exit function and close shared handle
|
/*! Unload all plugins: call exit function and close shared handle
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] cp Plugin handle
|
||||||
|
* @param[in] h Clixon handle
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clixon_plugin_exit(clicon_handle h)
|
clixon_plugin_exit_one(clixon_plugin *cp,
|
||||||
|
clicon_handle h)
|
||||||
{
|
{
|
||||||
clixon_plugin *cp;
|
int retval = -1;
|
||||||
plgexit_t *exitfn;
|
char *error;
|
||||||
int i;
|
plgexit_t *fn;
|
||||||
char *error;
|
|
||||||
|
|
||||||
for (i = 0; i < _clixon_nplugins; i++) {
|
if ((fn = cp->cp_api.ca_exit) != NULL){
|
||||||
cp = &_clixon_plugins[i];
|
if (fn(h) < 0) {
|
||||||
if ((exitfn = cp->cp_api.ca_exit) == NULL)
|
if (clicon_errno < 0)
|
||||||
continue;
|
clicon_log(LOG_WARNING, "%s: Internal error: Exit callback in plugin: %s returned -1 but did not make a clicon_err call",
|
||||||
if (exitfn(h) < 0) {
|
__FUNCTION__, cp->cp_name);
|
||||||
clicon_debug(1, "%s() failed", __FUNCTION__);
|
goto done;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
if (dlclose(cp->cp_handle) != 0) {
|
if (dlclose(cp->cp_handle) != 0) {
|
||||||
error = (char*)dlerror();
|
error = (char*)dlerror();
|
||||||
clicon_err(OE_PLUGIN, errno, "dlclose: %s", error ? error : "Unknown error");
|
clicon_err(OE_PLUGIN, errno, "dlclose: %s", error ? error : "Unknown error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Unload all plugins: call exit function and close shared handle
|
||||||
|
* @param[in] h Clixon handle
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
clixon_plugin_exit_all(clicon_handle h)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
clixon_plugin *cp = NULL;
|
||||||
|
|
||||||
|
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
|
||||||
|
if (clixon_plugin_exit_one(cp, h) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
if (_clixon_plugins){
|
if (_clixon_plugins){
|
||||||
free(_clixon_plugins);
|
free(_clixon_plugins);
|
||||||
_clixon_plugins = NULL;
|
_clixon_plugins = NULL;
|
||||||
}
|
}
|
||||||
_clixon_nplugins = 0;
|
_clixon_nplugins = 0;
|
||||||
return 0;
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Run the restconf user-defined credentials callback if present
|
/*! Run the restconf user-defined credentials callback
|
||||||
* Find first authentication callback and call that, then return.
|
* @param[in] cp Plugin handle
|
||||||
* The callback is to set the authenticated user
|
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] arg Argument, such as fastcgi handler for restconf
|
* @param[in] arg Argument, such as fastcgi handler for restconf
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
|
|
@ -416,28 +462,97 @@ clixon_plugin_exit(clicon_handle h)
|
||||||
* Or no callback was found.
|
* Or no callback was found.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clixon_plugin_auth(clicon_handle h,
|
clixon_plugin_auth_one(clixon_plugin *cp,
|
||||||
void *arg)
|
clicon_handle h,
|
||||||
|
void *arg)
|
||||||
{
|
{
|
||||||
clixon_plugin *cp;
|
int retval = 1; /* Authenticated */
|
||||||
int i;
|
plgauth_t *fn; /* Plugin auth */
|
||||||
plgauth_t *authfn; /* Plugin auth */
|
|
||||||
int retval = 1;
|
|
||||||
|
|
||||||
for (i = 0; i < _clixon_nplugins; i++) {
|
if ((fn = cp->cp_api.ca_auth) != NULL){
|
||||||
cp = &_clixon_plugins[i];
|
if ((retval = fn(h, arg)) < 0) {
|
||||||
if ((authfn = cp->cp_api.ca_auth) == NULL)
|
if (clicon_errno < 0)
|
||||||
continue;
|
clicon_log(LOG_WARNING, "%s: Internal error: Auth callback in plugin: %s returned -1 but did not make a clicon_err call",
|
||||||
if ((retval = authfn(h, arg)) < 0) {
|
__FUNCTION__, cp->cp_name);
|
||||||
clicon_debug(1, "%s() failed", __FUNCTION__);
|
goto done;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Callback for a yang extension (unknown) statement
|
/*! Run the restconf user-defined credentials callback for all plugins
|
||||||
|
* Find first authentication callback and call that, then return.
|
||||||
|
* The callback is to set the authenticated user
|
||||||
|
* @param[in] cp Plugin handle
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] arg Argument, such as fastcgi handler for restconf
|
||||||
|
* @retval -1 Error
|
||||||
|
* @retval 0 Not authenticated
|
||||||
|
* @retval 1 Authenticated
|
||||||
|
* @note If authenticated either a callback was called and clicon_username_set()
|
||||||
|
* Or no callback was found.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
clixon_plugin_auth_all(clicon_handle h,
|
||||||
|
void *arg)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
clixon_plugin *cp = NULL;
|
||||||
|
int i = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
|
||||||
|
i++;
|
||||||
|
if ((ret = clixon_plugin_auth_one(cp, h, arg)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (ret == 1)
|
||||||
|
goto authenticated;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i==0)
|
||||||
|
retval = 1;
|
||||||
|
else
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
authenticated:
|
||||||
|
retval = 1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Callback for a yang extension (unknown) statement single plugin
|
||||||
|
* extension can be made.
|
||||||
|
* @param[in] cp Plugin handle
|
||||||
|
* @param[in] h Clixon handle
|
||||||
|
* @param[in] yext Yang node of extension
|
||||||
|
* @param[in] ys Yang node of (unknown) statement belonging to extension
|
||||||
|
* @retval 0 OK,
|
||||||
|
* @retval -1 Error
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
clixon_plugin_extension_one(clixon_plugin *cp,
|
||||||
|
clicon_handle h,
|
||||||
|
yang_stmt *yext,
|
||||||
|
yang_stmt *ys)
|
||||||
|
{
|
||||||
|
int retval = 1;
|
||||||
|
plgextension_t *fn; /* Plugin extension fn */
|
||||||
|
|
||||||
|
if ((fn = cp->cp_api.ca_extension) != NULL){
|
||||||
|
if (fn(h, yext, ys) < 0) {
|
||||||
|
if (clicon_errno < 0)
|
||||||
|
clicon_log(LOG_WARNING, "%s: Internal error: Extension callback in plugin: %s returned -1 but did not make a clicon_err call",
|
||||||
|
__FUNCTION__, cp->cp_name);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Callback for a yang extension (unknown) statement in all plugins
|
||||||
* Called at parsing of yang module containing a statement of an extension.
|
* Called at parsing of yang module containing a statement of an extension.
|
||||||
* A plugin may identify the extension and perform actions
|
* A plugin may identify the extension and perform actions
|
||||||
* on the yang statement, such as transforming the yang.
|
* on the yang statement, such as transforming the yang.
|
||||||
|
|
@ -450,24 +565,54 @@ clixon_plugin_auth(clicon_handle h,
|
||||||
* @retval -1 Error in one callback
|
* @retval -1 Error in one callback
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clixon_plugin_extension(clicon_handle h,
|
clixon_plugin_extension_all(clicon_handle h,
|
||||||
yang_stmt *yext,
|
yang_stmt *yext,
|
||||||
yang_stmt *ys)
|
yang_stmt *ys)
|
||||||
{
|
{
|
||||||
clixon_plugin *cp;
|
int retval = -1;
|
||||||
int i;
|
clixon_plugin *cp = NULL;
|
||||||
plgextension_t *extfn; /* Plugin extension fn */
|
|
||||||
int retval = 1;
|
|
||||||
|
|
||||||
for (i = 0; i < _clixon_nplugins; i++) {
|
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
|
||||||
cp = &_clixon_plugins[i];
|
if (clixon_plugin_extension_one(cp, h, yext, ys) < 0)
|
||||||
if ((extfn = cp->cp_api.ca_extension) == NULL)
|
goto done;
|
||||||
continue;
|
}
|
||||||
if ((retval = extfn(h, yext, ys)) < 0) {
|
retval = 0;
|
||||||
clicon_debug(1, "%s() failed", __FUNCTION__);
|
done:
|
||||||
return -1;
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Call plugin general-purpose datastore upgrade in one plugin
|
||||||
|
*
|
||||||
|
* @param[in] cp Plugin handle
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
clixon_plugin_datastore_upgrade_one(clixon_plugin *cp,
|
||||||
|
clicon_handle h,
|
||||||
|
char *db,
|
||||||
|
cxobj *xt,
|
||||||
|
modstate_diff_t *msd)
|
||||||
|
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
datastore_upgrade_t *fn;
|
||||||
|
|
||||||
|
if ((fn = cp->cp_api.ca_datastore_upgrade) != NULL){
|
||||||
|
if (fn(h, db, xt, msd) < 0) {
|
||||||
|
if (clicon_errno < 0)
|
||||||
|
clicon_log(LOG_WARNING, "%s: Internal error: Datastore upgrade callback in plugin: %s returned -1 but did not make a clicon_err call",
|
||||||
|
__FUNCTION__, cp->cp_name);
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -480,30 +625,23 @@ clixon_plugin_extension(clicon_handle h,
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
* Upgrade datastore on load before or as an alternative to module-specific upgrading mechanism
|
* Upgrade datastore on load before or as an alternative to module-specific upgrading mechanism
|
||||||
* @param[in] h Clicon handle
|
|
||||||
* Call plugin start functions (if defined)
|
|
||||||
* @note Start functions used to have argc/argv. Use clicon_argv_get() instead
|
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clixon_plugin_datastore_upgrade(clicon_handle h,
|
clixon_plugin_datastore_upgrade_all(clicon_handle h,
|
||||||
char *db,
|
char *db,
|
||||||
cxobj *xt,
|
cxobj *xt,
|
||||||
modstate_diff_t *msd)
|
modstate_diff_t *msd)
|
||||||
{
|
{
|
||||||
clixon_plugin *cp;
|
int retval = -1;
|
||||||
int i;
|
clixon_plugin *cp = NULL;
|
||||||
datastore_upgrade_t *repairfn;
|
|
||||||
|
|
||||||
for (i = 0; i < _clixon_nplugins; i++) {
|
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
|
||||||
cp = &_clixon_plugins[i];
|
if (clixon_plugin_datastore_upgrade_one(cp, h, db, xt, msd) < 0)
|
||||||
if ((repairfn = cp->cp_api.ca_datastore_upgrade) == NULL)
|
goto done;
|
||||||
continue;
|
|
||||||
if (repairfn(h, db, xt, msd) < 0) {
|
|
||||||
clicon_debug(1, "%s() failed", __FUNCTION__);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0;
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*--------------------------------------------------------------------
|
/*--------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -1882,7 +1882,7 @@ ys_populate_unknown(clicon_handle h,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/* Make extension callbacks that may alter yang structure */
|
/* Make extension callbacks that may alter yang structure */
|
||||||
if (clixon_plugin_extension(h, yext, ys) < 0)
|
if (clixon_plugin_extension_all(h, yext, ys) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
|
||||||
|
|
@ -346,6 +346,7 @@ expecteq(){
|
||||||
# - evaluated expression
|
# - evaluated expression
|
||||||
# - expected command return value (0 if OK)
|
# - expected command return value (0 if OK)
|
||||||
# - expected stdout outcome*
|
# - expected stdout outcome*
|
||||||
|
# @note need to escape \[\]
|
||||||
expectpart(){
|
expectpart(){
|
||||||
r=$?
|
r=$?
|
||||||
ret=$1
|
ret=$1
|
||||||
|
|
|
||||||
|
|
@ -222,18 +222,21 @@ if [ $BE -ne 0 ]; then
|
||||||
fi
|
fi
|
||||||
new "start backend"
|
new "start backend"
|
||||||
start_backend -s running -f $cfg
|
start_backend -s running -f $cfg
|
||||||
|
fi
|
||||||
fi
|
|
||||||
|
|
||||||
new "kill old restconf daemon"
|
|
||||||
sudo pkill -u www-data -f "/www-data/clixon_restconf"
|
|
||||||
|
|
||||||
new "start restconf daemon"
|
|
||||||
start_restconf -f $cfg
|
|
||||||
|
|
||||||
new "waiting"
|
new "waiting"
|
||||||
wait_backend
|
wait_backend
|
||||||
wait_restconf
|
|
||||||
|
if [ $RC -ne 0 ]; then
|
||||||
|
new "kill old restconf daemon"
|
||||||
|
sudo pkill -u www-data -f "/www-data/clixon_restconf"
|
||||||
|
|
||||||
|
new "start restconf daemon"
|
||||||
|
start_restconf -f $cfg
|
||||||
|
|
||||||
|
new "waiting"
|
||||||
|
wait_restconf
|
||||||
|
fi
|
||||||
|
|
||||||
XML='<c xmlns="urn:example:api"><y3><k>2</k></y3><y3><k>3</k></y3><y3><k>5</k><val>zorro</val></y3><y3><k>7</k></y3></c>'
|
XML='<c xmlns="urn:example:api"><y3><k>2</k></y3><y3><k>3</k></y3><y3><k>5</k><val>zorro</val></y3><y3><k>7</k></y3></c>'
|
||||||
|
|
||||||
|
|
@ -247,6 +250,11 @@ expectpart "$(curl -si -X GET http://localhost/restconf/data/example-api:c -H 'A
|
||||||
new "Send a trigger"
|
new "Send a trigger"
|
||||||
expectpart "$(curl -si -X POST http://localhost/restconf/operations/example-api:trigger -H 'Accept: application/yang-data+json')" 0 'HTTP/1.1 204 No Content'
|
expectpart "$(curl -si -X POST http://localhost/restconf/operations/example-api:trigger -H 'Accept: application/yang-data+json')" 0 'HTTP/1.1 204 No Content'
|
||||||
|
|
||||||
|
if [ $RC -ne 0 ]; then
|
||||||
|
new "Kill restconf daemon"
|
||||||
|
stop_restconf
|
||||||
|
fi
|
||||||
|
|
||||||
if [ $BE -eq 0 ]; then
|
if [ $BE -eq 0 ]; then
|
||||||
exit # BE
|
exit # BE
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
|
|
@ -62,36 +62,32 @@ if [ $RC -ne 0 ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new "restconf root discovery. RFC 8040 3.1 (xml+xrd)"
|
new "restconf root discovery. RFC 8040 3.1 (xml+xrd)"
|
||||||
expecteq "$(curl -s -X GET http://localhost/.well-known/host-meta)" 0 "<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>
|
expectpart "$(curl -si -X GET http://localhost/.well-known/host-meta)" 0 'HTTP/1.1 200 OK' "<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>" "<Link rel='restconf' href='/restconf'/>" "</XRD>"
|
||||||
<Link rel='restconf' href='/restconf'/>
|
|
||||||
</XRD>
"
|
|
||||||
|
|
||||||
new "restconf get restconf resource. RFC 8040 3.3 (json)"
|
new "restconf get restconf resource. RFC 8040 3.3 (json)"
|
||||||
expecteq "$(curl -sG -H "Accept: application/yang-data+json" http://localhost/restconf)" 0 '{"ietf-restconf:restconf":{"data":{},"operations":{},"yang-library-version":"2016-06-21"}}
|
expectpart "$(curl -si -X GET -H "Accept: application/yang-data+json" http://localhost/restconf)" 0 'HTTP/1.1 200 OK' '{"ietf-restconf:restconf":{"data":{},"operations":{},"yang-library-version":"2016-06-21"}}'
|
||||||
'
|
|
||||||
|
|
||||||
new "restconf get restconf resource. RFC 8040 3.3 (xml)"
|
new "restconf get restconf resource. RFC 8040 3.3 (xml)"
|
||||||
# Get XML instead of JSON?
|
# Get XML instead of JSON?
|
||||||
expecteq "$(curl -s -H 'Accept: application/yang-data+xml' -G http://localhost/restconf)" 0 '<restconf xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf"><data/><operations/><yang-library-version>2016-06-21</yang-library-version></restconf>
|
expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+xml' http://localhost/restconf)" 0 'HTTP/1.1 200 OK' '<restconf xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf"><data/><operations/><yang-library-version>2016-06-21</yang-library-version></restconf>'
|
||||||
'
|
|
||||||
|
|
||||||
# Should be alphabetically ordered
|
# Should be alphabetically ordered
|
||||||
new "restconf get restconf/operations. RFC8040 3.3.2 (json)"
|
new "restconf get restconf/operations. RFC8040 3.3.2 (json)"
|
||||||
expectpart "$(curl -siG http://localhost/restconf/operations)" 0 'HTTP/1.1 200 OK' '{"operations":{"clixon-example:client-rpc":\[null\],"clixon-example:empty":\[null\],"clixon-example:optional":\[null\],"clixon-example:example":\[null\],"clixon-lib:debug":\[null\],"clixon-lib:ping":\[null\],"clixon-lib:datastats":\[null\],"ietf-netconf:get-config":\[null\],"ietf-netconf:edit-config":\[null\],"ietf-netconf:copy-config":\[null\],"ietf-netconf:delete-config":\[null\],"ietf-netconf:lock":\[null\],"ietf-netconf:unlock":\[null\],"ietf-netconf:get":\[null\],"ietf-netconf:close-session":\[null\],"ietf-netconf:kill-session":\[null\],"ietf-netconf:commit":\[null\],"ietf-netconf:discard-changes":\[null\],"ietf-netconf:validate":\[null\],"clixon-rfc5277:create-subscription":\[null\]}}'
|
expectpart "$(curl -si -X GET http://localhost/restconf/operations)" 0 'HTTP/1.1 200 OK' '{"operations":{"clixon-example:client-rpc":\[null\],"clixon-example:empty":\[null\],"clixon-example:optional":\[null\],"clixon-example:example":\[null\],"clixon-lib:debug":\[null\],"clixon-lib:ping":\[null\],"clixon-lib:stats":\[null\],"clixon-lib:restart-plugin":\[null\],"ietf-netconf:get-config":\[null\],"ietf-netconf:edit-config":\[null\],"ietf-netconf:copy-config":\[null\],"ietf-netconf:delete-config":\[null\],"ietf-netconf:lock":\[null\],"ietf-netconf:unlock":\[null\],"ietf-netconf:get":\[null\],"ietf-netconf:close-session":\[null\],"ietf-netconf:kill-session":\[null\],"ietf-netconf:commit":\[null\],"ietf-netconf:discard-changes":\[null\],"ietf-netconf:validate":\[null\],"clixon-rfc5277:create-subscription":\[null\]}}'
|
||||||
|
|
||||||
new "restconf get restconf/operations. RFC8040 3.3.2 (xml)"
|
new "restconf get restconf/operations. RFC8040 3.3.2 (xml)"
|
||||||
ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/operations)
|
ret=$(curl -s -X GET -H "Accept: application/yang-data+xml" http://localhost/restconf/operations)
|
||||||
expect='<operations><client-rpc xmlns="urn:example:clixon"/><empty xmlns="urn:example:clixon"/><optional xmlns="urn:example:clixon"/><example xmlns="urn:example:clixon"/><debug xmlns="http://clicon.org/lib"/><ping xmlns="http://clicon.org/lib"/><datastats xmlns="http://clicon.org/lib"/><get-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><edit-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><copy-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><delete-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><lock xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><unlock xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><get xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><close-session xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><kill-session xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><commit xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><discard-changes xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><validate xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"/></operations>'
|
expect='<operations><client-rpc xmlns="urn:example:clixon"/><empty xmlns="urn:example:clixon"/><optional xmlns="urn:example:clixon"/><example xmlns="urn:example:clixon"/><debug xmlns="http://clicon.org/lib"/><ping xmlns="http://clicon.org/lib"/><stats xmlns="http://clicon.org/lib"/><restart-plugin xmlns="http://clicon.org/lib"/><get-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><edit-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><copy-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><delete-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><lock xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><unlock xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><get xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><close-session xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><kill-session xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><commit xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><discard-changes xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><validate xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"/></operations>'
|
||||||
match=`echo $ret | grep --null -Eo "$expect"`
|
match=`echo $ret | grep --null -Eo "$expect"`
|
||||||
if [ -z "$match" ]; then
|
if [ -z "$match" ]; then
|
||||||
err "$expect" "$ret"
|
err "$expect" "$ret"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new "restconf get restconf/yang-library-version. RFC8040 3.3.3"
|
new "restconf get restconf/yang-library-version. RFC8040 3.3.3"
|
||||||
expecteq "$(curl -sG http://localhost/restconf/yang-library-version)" 0 '{"yang-library-version":"2016-06-21"}'
|
expectpart "$(curl -si -X GET http://localhost/restconf/yang-library-version)" 0 'HTTP/1.1 200 OK' '{"yang-library-version":"2016-06-21"}'
|
||||||
|
|
||||||
new "restconf get restconf/yang-library-version. RFC8040 3.3.3 (xml)"
|
new "restconf get restconf/yang-library-version. RFC8040 3.3.3 (xml)"
|
||||||
ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/yang-library-version)
|
ret=$(curl -s -X GET -H "Accept: application/yang-data+xml" http://localhost/restconf/yang-library-version)
|
||||||
expect="<yang-library-version>2016-06-21</yang-library-version>"
|
expect="<yang-library-version>2016-06-21</yang-library-version>"
|
||||||
match=`echo $ret | grep --null -Eo "$expect"`
|
match=`echo $ret | grep --null -Eo "$expect"`
|
||||||
if [ -z "$match" ]; then
|
if [ -z "$match" ]; then
|
||||||
|
|
@ -99,8 +95,7 @@ if [ -z "$match" ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new "restconf schema resource, RFC 8040 sec 3.7 according to RFC 7895 (explicit resource)"
|
new "restconf schema resource, RFC 8040 sec 3.7 according to RFC 7895 (explicit resource)"
|
||||||
expecteq "$(curl -s -H 'Accept: application/yang-data+json' -G http://localhost/restconf/data/ietf-yang-library:modules-state/module=ietf-interfaces,2018-02-20)" 0 '{"ietf-yang-library:module":[{"name":"ietf-interfaces","revision":"2018-02-20","namespace":"urn:ietf:params:xml:ns:yang:ietf-interfaces","conformance-type":"implement"}]}
|
expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/ietf-yang-library:modules-state/module=ietf-interfaces,2018-02-20)" 0 'HTTP/1.1 200 OK' '{"ietf-yang-library:module":\[{"name":"ietf-interfaces","revision":"2018-02-20","namespace":"urn:ietf:params:xml:ns:yang:ietf-interfaces","conformance-type":"implement"}\]}'
|
||||||
'
|
|
||||||
|
|
||||||
new "restconf options. RFC 8040 4.1"
|
new "restconf options. RFC 8040 4.1"
|
||||||
expectpart "$(curl -is -X OPTIONS http://localhost/restconf/data)" 0 "HTTP/1.1 200 OK" "Allow: OPTIONS,HEAD,GET,POST,PUT,PATCH,DELETE"
|
expectpart "$(curl -is -X OPTIONS http://localhost/restconf/data)" 0 "HTTP/1.1 200 OK" "Allow: OPTIONS,HEAD,GET,POST,PUT,PATCH,DELETE"
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ checklog(){
|
||||||
s=$1 # statement
|
s=$1 # statement
|
||||||
l0=$2 # linenr
|
l0=$2 # linenr
|
||||||
new "Check $s in log"
|
new "Check $s in log"
|
||||||
# echo "grep \"transaction_log $s\" $flog"
|
# echo "grep \"transaction_log $s line:$l0\" $flog"
|
||||||
t=$(grep -n "transaction_log $s" $flog)
|
t=$(grep -n "transaction_log $s" $flog)
|
||||||
if [ -z "$t" ]; then
|
if [ -z "$t" ]; then
|
||||||
echo -e "\e[31m\nError in Test$testnr [$testname]:"
|
echo -e "\e[31m\nError in Test$testnr [$testname]:"
|
||||||
|
|
@ -133,7 +133,7 @@ expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><edit-config><target><candidate/></
|
||||||
new "Commit base"
|
new "Commit base"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><commit/></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><commit/></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
let line=12 # Skipping basic transaction
|
let line=14 # Skipping basic transaction
|
||||||
|
|
||||||
# 1. validate(-only) transaction
|
# 1. validate(-only) transaction
|
||||||
let nr++
|
let nr++
|
||||||
|
|
@ -164,7 +164,7 @@ new "Commit transaction: commit"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><commit/></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><commit/></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
xml="<y><a>$nr</a></y>"
|
xml="<y><a>$nr</a></y>"
|
||||||
for op in begin validate complete commit end; do
|
for op in begin validate complete commit commit_done end; do
|
||||||
checklog "$nr main_$op add: $xml" $line
|
checklog "$nr main_$op add: $xml" $line
|
||||||
let line++
|
let line++
|
||||||
checklog "$nr nacm_$op add: $xml" $line
|
checklog "$nr nacm_$op add: $xml" $line
|
||||||
|
|
@ -227,12 +227,13 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><commit/></rpc>]]>]]>' '^<rpc-reply
|
||||||
new "Commit user-error discard-changes"
|
new "Commit user-error discard-changes"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
for op in begin validate complete commit; do
|
for op in begin validate complete commit ; do
|
||||||
checklog "$nr main_$op add: <y><a>$errnr</a></y>" $line
|
checklog "$nr main_$op add: <y><a>$errnr</a></y>" $line
|
||||||
let line++
|
let line++
|
||||||
checklog "$nr nacm_$op add: <y><a>$errnr</a></y>" $line
|
checklog "$nr nacm_$op add: <y><a>$errnr</a></y>" $line
|
||||||
let line++
|
let line++
|
||||||
done
|
done
|
||||||
|
|
||||||
let line++ # error message
|
let line++ # error message
|
||||||
checklog "$nr main_revert add: <y><a>$errnr</a></y>" $line
|
checklog "$nr main_revert add: <y><a>$errnr</a></y>" $line
|
||||||
let line++
|
let line++
|
||||||
|
|
@ -252,7 +253,7 @@ expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><edit-config><target><candidate/></
|
||||||
new "netconf commit base"
|
new "netconf commit base"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><commit/></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><commit/></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
#Ignore
|
#Ignore
|
||||||
let line+=10
|
let line+=12
|
||||||
|
|
||||||
let nr++
|
let nr++
|
||||||
new "6. netconf mixed change: change b, del c, add d"
|
new "6. netconf mixed change: change b, del c, add d"
|
||||||
|
|
@ -262,7 +263,7 @@ new "netconf commit change"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><commit/></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><commit/></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
# Check complete transaction $nr:
|
# Check complete transaction $nr:
|
||||||
for op in begin validate complete commit; do
|
for op in begin validate complete commit commit_done; do
|
||||||
checklog "$nr main_$op add: <d>0</d>" $line
|
checklog "$nr main_$op add: <d>0</d>" $line
|
||||||
let line++
|
let line++
|
||||||
checklog "$nr main_$op change: <b>0</b><b>42</b>" $line
|
checklog "$nr main_$op change: <b>0</b><b>42</b>" $line
|
||||||
|
|
@ -287,7 +288,7 @@ expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><edit-config><target><candidate/></
|
||||||
|
|
||||||
new "netconf commit base"
|
new "netconf commit base"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><commit/></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><commit/></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
let line+=10
|
let line+=12
|
||||||
|
|
||||||
# Variant check that only b,c
|
# Variant check that only b,c
|
||||||
let nr++
|
let nr++
|
||||||
|
|
@ -298,7 +299,7 @@ new "netconf commit base"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><commit/></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><commit/></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
# check complete
|
# check complete
|
||||||
for op in begin validate complete commit end; do
|
for op in begin validate complete commit commit_done end; do
|
||||||
checklog "$nr main_$op add: <b>1</b><c>1</c>" $line
|
checklog "$nr main_$op add: <b>1</b><c>1</c>" $line
|
||||||
let line++
|
let line++
|
||||||
checklog "$nr nacm_$op add: <b>1</b><c>1</c>" $line
|
checklog "$nr nacm_$op add: <b>1</b><c>1</c>" $line
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,8 @@ module clixon-lib {
|
||||||
|
|
||||||
revision 2020-04-23 {
|
revision 2020-04-23 {
|
||||||
description
|
description
|
||||||
"Added: clixon-stats state for clixon XML and memory statistics.";
|
"Added: stats RPC for clixon XML and memory statistics.
|
||||||
|
Added: restart-plugin RPC for restarting individual plugins without restarting backend.";
|
||||||
}
|
}
|
||||||
revision 2019-08-13 {
|
revision 2019-08-13 {
|
||||||
description
|
description
|
||||||
|
|
@ -68,13 +69,13 @@ module clixon-lib {
|
||||||
rpc ping {
|
rpc ping {
|
||||||
description "Check aliveness of backend daemon.";
|
description "Check aliveness of backend daemon.";
|
||||||
}
|
}
|
||||||
rpc datastats {
|
rpc stats {
|
||||||
description "Clixon XML statistics.";
|
description "Clixon XML statistics.";
|
||||||
output {
|
output {
|
||||||
container global{
|
container global{
|
||||||
description "Clixon global statistics";
|
description "Clixon global statistics";
|
||||||
leaf xmlnr{
|
leaf xmlnr{
|
||||||
description "Number of XML objects. That is number of residing xml/json objects
|
description "Number of XML objects: number of residing xml/json objects
|
||||||
in the internal 'cxobj' representation.";
|
in the internal 'cxobj' representation.";
|
||||||
type uint64;
|
type uint64;
|
||||||
}
|
}
|
||||||
|
|
@ -99,4 +100,13 @@ module clixon-lib {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
rpc restart-plugin {
|
||||||
|
description "Restart specific backend plugins.";
|
||||||
|
input {
|
||||||
|
leaf-list plugin {
|
||||||
|
description "Name of plugin to restart";
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue