* Ensured you can add multiple callbacks for any RPC, including basic ones.

* Extra RPC:s will be called _after_ the basic ones.
  * One specific usecase is hook for `copy-config` (see [doc/ROADMAP.md] that can be implemented thus way.
* `rpc_callback_register` added a namespace parameter. Example:
   ```
     rpc_callback_register(h, empty_rpc, NULL, "urn:example:clixon", "empty");
   ```
This commit is contained in:
Olof hagsand 2019-03-10 17:27:52 +01:00
parent 748c7282ea
commit b1c74b5f1f
18 changed files with 755 additions and 514 deletions

File diff suppressed because it is too large Load diff

View file

@ -60,5 +60,6 @@ struct client_entry{
*/
int backend_client_rm(clicon_handle h, struct client_entry *ce);
int from_client(int fd, void *arg);
int backend_rpc_init(clicon_handle h);
#endif /* _BACKEND_CLIENT_H_ */

View file

@ -330,8 +330,6 @@ startup_validate(clicon_handle h,
goto done;
}
/*! Do a diff between candidate and running, then start a commit transaction
*
* The code reverts changes if the commit fails. But if the revert
@ -408,25 +406,33 @@ candidate_commit(clicon_handle h,
goto done;
}
/*! Commit changes from candidate to running
* @param[in] h Clicon handle
* @param[out] cbret Return xml value cligen buffer
* @retval 0 OK. This may indicate both ok and err msg back to client
* @retval -1 (Local) Error
* NACM: The server MUST determine the exact nodes in the running
/*! Commit the candidate configuration as the device's new current configuration
*
* @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
* @note NACM: The server MUST determine the exact nodes in the running
* configuration datastore that are actually different and only check
* "create", "update", and "delete" access permissions for this set of
* nodes, which could be empty.
*/
int
from_client_commit(clicon_handle h,
int mypid,
cbuf *cbret)
cxobj *xe,
cbuf *cbret,
void *arg,
void *regarg)
{
int retval = -1;
int piddb;
cbuf *cbx = NULL; /* Assist cbuf */
int ret;
int retval = -1;
struct client_entry *ce = (struct client_entry *)arg;
int mypid = ce->ce_pid;
int piddb;
cbuf *cbx = NULL; /* Assist cbuf */
int ret;
/* Check if target locked by other client */
piddb = xmldb_islocked(h, "running");
@ -457,22 +463,30 @@ from_client_commit(clicon_handle h,
return retval; /* may be zero if we ignoring errors from commit */
} /* from_client_commit */
/*! Discard all changes in candidate / revert to running
* @param[in] h Clicon handle
* @param[in] mypid Process/session id of calling client
* @param[out] cbret Return xml value cligen buffer
/*! Revert the candidate configuration to the current running configuration.
*
* @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. This may indicate both ok and err msg back to client
* @retval -1 (Local) Error
* @retval 0 OK
* @retval -1 Error
* NACM: No datastore permissions are needed.
*/
int
from_client_discard_changes(clicon_handle h,
int mypid,
cbuf *cbret)
cxobj *xe,
cbuf *cbret,
void *arg,
void *regarg)
{
int retval = -1;
int piddb;
cbuf *cbx = NULL; /* Assist cbuf */
int retval = -1;
struct client_entry *ce = (struct client_entry *)arg;
int mypid = ce->ce_pid;
int piddb;
cbuf *cbx = NULL; /* Assist cbuf */
/* Check if target locked by other client */
piddb = xmldb_islocked(h, "candidate");
@ -500,22 +514,60 @@ from_client_discard_changes(clicon_handle h,
return retval; /* may be zero if we ignoring errors from commit */
}
/*! Handle an incoming validate message from a client.
* @param[in] h Clicon handle
* @param[in] db Database name
* @param[out] cbret Return xml value cligen buffer
* @retval 0 OK. This may indicate both ok and err msg back to client (eg invalid)
* @retval -1 (Local) Error
/*! Cancel an ongoing confirmed commit.
* If the confirmed commit is persistent, the parameter 'persist-id' must be
* given, and it must match the value of the 'persist' parameter.
*
* @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. This may indicate both ok and err msg back to client
* @retval 0 OK
* @retval -1 Error
* @see RFC 6241 Sec 8.4
*/
int
from_client_cancel_commit(clicon_handle h,
cxobj *xe,
cbuf *cbret,
void *arg,
void *regarg)
{
int retval = -1;
retval = 0;
// done:
return retval;
}
/*! Validates the contents of the specified configuration.
* @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. This may indicate both ok and err msg back to client
* (eg invalid)
* @retval -1 Error
*/
int
from_client_validate(clicon_handle h,
char *db,
cbuf *cbret)
cxobj *xe,
cbuf *cbret,
void *arg,
void *regarg)
{
int retval = -1;
transaction_data_t *td = NULL;
int ret;
char *db;
if ((db = netconf_db_find(xe, "source")) == NULL){
if (netconf_missing_element(cbret, "protocol", "source", NULL) < 0)
goto done;
goto ok;
}
if (strcmp(db, "candidate") != 0 && strcmp(db, "tmp") != 0){
if (netconf_invalid_value(cbret, "protocol", "No such database")< 0)
goto done;
@ -552,3 +604,4 @@ from_client_validate(clicon_handle h,
transaction_free(td);
return retval;
} /* from_client_validate */

View file

@ -40,10 +40,12 @@
/*
* Prototypes
*/
int from_client_validate(clicon_handle h, char *db, cbuf *cbret);
int from_client_commit(clicon_handle h, int pid, cbuf *cbret);
int from_client_discard_changes(clicon_handle h, int pid, cbuf *cbret);
int startup_validate(clicon_handle h, char *db, cbuf *cbret);
int candidate_commit(clicon_handle h, char *db, cbuf *cbret);
int from_client_commit(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_validate(clicon_handle h, cxobj *xe, cbuf *cbret, void *arg, void *regarg);
#endif /* _BACKEND_COMMIT_H_ */

View file

@ -635,6 +635,10 @@ main(int argc,
if (xmldb_setopt(h, "nacm_xtree", (void*)clicon_nacm_ext(h)) < 0)
goto done;
/* Initialize server socket and save it to handle */
if (backend_rpc_init(h) < 0)
goto done;
/* Save modules state of the backend (server). Compare with startup XML */
if (startup_module_state(h, yspec) < 0)
goto done;

View file

@ -603,7 +603,7 @@ netconf_application_rpc(clicon_handle h,
/* Look for local (client-side) netconf plugins. */
if ((ret = rpc_callback_call(h, xn, cbret, NULL)) < 0)
goto done;
if (ret == 1){ /* Handled locally */
if (ret > 0){ /* Handled locally */
if (xml_parse_string(cbuf_get(cbret), NULL, xret) < 0)
goto done;
}
@ -692,6 +692,7 @@ netconf_rpc_dispatch(clicon_handle h,
strcmp(xml_name(xe), "kill-session") == 0 ||
strcmp(xml_name(xe), "validate") == 0 || /* :validate */
strcmp(xml_name(xe), "commit") == 0 || /* :candidate */
strcmp(xml_name(xe), "cancel-commit") == 0 ||
strcmp(xml_name(xe), "discard-changes") == 0){
if (clicon_rpc_netconf_xml(h, xml_parent(xe), xret, NULL) < 0)
goto done;

View file

@ -1674,7 +1674,7 @@ api_operations_post(clicon_handle h,
*/
if ((ret = rpc_callback_call(h, xbot, cbret, r)) < 0)
goto done;
if (ret == 1){ /* Handled locally */
if (ret > 0){ /* Handled locally */
if (xml_parse_string(cbuf_get(cbret), NULL, &xret) < 0)
goto done;
/* Local error: return it and quit */