Added option: `CLICON_AUTOLOCK`
This commit is contained in:
Olof hagsand 2024-04-12 12:40:03 +02:00
parent 331585f45b
commit 407b4703b3
4 changed files with 126 additions and 38 deletions

View file

@ -15,13 +15,14 @@ Expected: June 2024
### Features
* New: [Autolock](https://github.com/clicon/clixon/issues/508)
* CLI configurable format: [Default format should be configurable](https://github.com/clicon/clixon-controller/issues/87)
* CLI support for multiple inline commands separated by semi-colon
* New `clixon-config@2024-04-01.yang` revision
* Added options:
- `CLICON_NETCONF_DUPLICATE_ALLOW` - Disable duplicate check in NETCONF messages
- `CLICON_CLI_OUTPUT_FORMAT` - Default CLI output format
- `CLICON_AUTOLOCK` - Implicit locks
* New `clixon-lib@2024-04-01.yang` revision
- Added: Default format

View file

@ -175,6 +175,8 @@ ce_event_cb(clixon_handle h,
/*! Unlock all db:s of a client and call user unlock calback
*
* @param[in] h Clixon handle
* @param[in] id Session id
* @see xmldb_unlock_all unlocks, but does not call user callbacks which is a backend thing
*/
static int
@ -185,8 +187,15 @@ release_all_dbs(clixon_handle h,
char **keys = NULL;
size_t klen;
int i;
uint32_t iddb;
db_elmnt *de;
if (clicon_option_bool(h, "CLICON_AUTOLOCK") &&
(iddb = xmldb_islocked(h, "candidate")) == id){
if (xmldb_copy(h, "running", "candidate") < 0)
goto done;
xmldb_modified_set(h, "candidate", 0); /* reset dirty bit */
}
/* get all db:s */
if (clicon_hash_keys(clicon_db_elmnt(h), &keys, &klen) < 0)
goto done;
@ -195,6 +204,8 @@ release_all_dbs(clixon_handle h,
if ((de = clicon_db_elmnt_get(h, keys[i])) != NULL &&
de->de_id == id){
de->de_id = 0; /* unlock */
clicon_db_elmnt_set(h, keys[i], de);
if (clixon_plugin_lockdb_all(h, keys[i], 0, id) < 0)
goto done;
@ -432,6 +443,73 @@ clixon_stats_module_get(clixon_handle h,
return retval;
}
/*! Do lock checks and lock
* @param[in] h Clixon handle
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] db Datastore
* @retval 1 OK
* @retval 0 Failed
* @retval -1 Error
*/
static int
do_lock(clixon_handle h,
cbuf *cbret,
uint32_t id,
char *db)
{
int retval = -1;
uint32_t otherid;
cbuf *cbx = NULL; /* Assist cbuf */
yang_stmt *yspec;
if ((yspec = clicon_dbspec_yang(h)) == NULL){
clixon_err(OE_YANG, ENOENT, "No yang spec");
goto done;
}
if ((cbx = cbuf_new()) == NULL){
clixon_err(OE_XML, errno, "cbuf_new");
goto done;
}
/* 2) The target configuration is <candidate>, it has already been modified, and
* these changes have not been committed or rolled back.
*/
if (strcmp(db, "candidate") == 0 &&
xmldb_modified_get(h, db)){
if (netconf_lock_denied(cbret, "<session-id>0</session-id>",
"Operation failed, candidate has already been modified and the changes have not been committed or rolled back (RFC 6241 7.5)") < 0)
goto done;
goto failed;
}
/* 3) The target configuration is <running>, and another NETCONF
* session has an ongoing confirmed commit
*/
if (strcmp(db, "running") == 0 &&
if_feature(yspec, "ietf-netconf", "confirmed-commit") &&
confirmed_commit_state_get(h) != INACTIVE){
if ((otherid = confirmed_commit_session_id_get(h)) != 0){
cprintf(cbx, "<session-id>%u</session-id>", otherid);
if (netconf_lock_denied(cbret, cbuf_get(cbx),
"Operation failed, another session has an ongoing confirmed commit") < 0)
goto done;
goto failed;
}
}
if (xmldb_lock(h, db, id) < 0)
goto done;
/* user callback */
if (clixon_plugin_lockdb_all(h, db, 1, id) < 0)
goto done;
retval = 1;
done:
if (cbx)
cbuf_free(cbx);
return retval;
failed:
retval = 0;
goto done;
}
/*! Loads all or part of a specified configuration to target configuration
*
* @param[in] h Clixon handle
@ -499,6 +577,12 @@ from_client_edit_config(clixon_handle h,
goto done;
goto ok;
}
if (clicon_option_bool(h, "CLICON_AUTOLOCK")){
if ((ret = do_lock(h, cbret, myid, target)) < 0)
goto done;
if (ret == 0)
goto ok;
}
if (xml_nsctx_node(xn, &nsc) < 0)
goto done;
/* Get prefix of netconf base namespace in the incoming message */
@ -693,6 +777,7 @@ from_client_copy_config(clixon_handle h,
uint32_t myid = ce->ce_id;
cbuf *cbx = NULL; /* Assist cbuf */
cbuf *cbmsg = NULL;
int ret;
if ((source = netconf_db_find(xe, "source")) == NULL){
if (netconf_missing_element(cbret, "protocol", "source", NULL) < 0)
@ -716,6 +801,12 @@ from_client_copy_config(clixon_handle h,
goto done;
goto ok;
}
if (clicon_option_bool(h, "CLICON_AUTOLOCK")){
if ((ret = do_lock(h, cbret, myid, target)) < 0)
goto done;
if (ret == 0)
goto ok;
}
if (xmldb_copy(h, source, target) < 0){
if ((cbmsg = cbuf_new()) == NULL){
clixon_err(OE_UNIX, errno, "cbuf_new");
@ -834,16 +925,11 @@ from_client_lock(clixon_handle h,
int retval = -1;
struct client_entry *ce = (struct client_entry *)arg;
uint32_t id = ce->ce_id;
uint32_t iddb;
uint32_t otherid;
char *db;
int ret;
cbuf *cbx = NULL; /* Assist cbuf */
yang_stmt *yspec;
uint32_t iddb;
if ((yspec = clicon_dbspec_yang(h)) == NULL){
clixon_err(OE_YANG, ENOENT, "No yang spec");
goto done;
}
if ((db = netconf_db_find(xe, "target")) == NULL){
if (netconf_missing_element(cbret, "protocol", "target", NULL) < 0)
goto done;
@ -863,35 +949,10 @@ from_client_lock(clixon_handle h,
goto done;
goto ok;
}
/* 2) The target configuration is <candidate>, it has already been modified, and
* these changes have not been committed or rolled back.
*/
if (strcmp(db, "candidate") == 0 &&
xmldb_modified_get(h, db)){
if (netconf_lock_denied(cbret, "<session-id>0</session-id>",
"Operation failed, candidate has already been modified and the changes have not been committed or rolled back (RFC 6241 7.5)") < 0)
if ((ret = do_lock(h, cbret, id, db)) < 0)
goto done;
if (ret == 0)
goto ok;
}
/* 3) The target configuration is <running>, and another NETCONF
* session has an ongoing confirmed commi
*/
if (strcmp(db, "running") == 0 &&
if_feature(yspec, "ietf-netconf", "confirmed-commit") &&
confirmed_commit_state_get(h) != INACTIVE){
if ((otherid = confirmed_commit_session_id_get(h)) != 0){
cprintf(cbx, "<session-id>%u</session-id>", otherid);
if (netconf_lock_denied(cbret, cbuf_get(cbx),
"Operation failed, another session has an ongoing confirmed commit") < 0)
goto done;
goto ok;
}
}
if (xmldb_lock(h, db, id) < 0)
goto done;
/* user callback */
if (clixon_plugin_lockdb_all(h, db, 1, id) < 0)
goto done;
cprintf(cbret, "<rpc-reply xmlns=\"%s\"><ok/></rpc-reply>", NETCONF_BASE_NAMESPACE);
ok:
retval = 0;

View file

@ -801,6 +801,16 @@ from_client_commit(clixon_handle h,
goto ok;
}
/* Check if target locked by other client */
iddb = xmldb_islocked(h, "candidate");
if (iddb && myid != iddb){
if ((cbx = cbuf_new()) == NULL){
clixon_err(OE_XML, errno, "cbuf_new");
goto done;
}
if (netconf_in_use(cbret, "protocol", "Operation failed, lock is already held") < 0)
goto done;
goto ok;
}
iddb = xmldb_islocked(h, "running");
if (iddb && myid != iddb){
if ((cbx = cbuf_new()) == NULL){
@ -818,6 +828,8 @@ from_client_commit(clixon_handle h,
goto done;
goto ok;
}
if (clicon_option_bool(h, "CLICON_AUTOLOCK"))
xmldb_unlock(h, "candidate");
if (ret == 0)
clixon_debug(CLIXON_DBG_BACKEND, "Commit candidate failed");
else
@ -872,6 +884,9 @@ from_client_discard_changes(clixon_handle h,
goto ok;
}
xmldb_modified_set(h, "candidate", 0); /* reset dirty bit */
if (clicon_option_bool(h, "CLICON_AUTOLOCK")){
xmldb_unlock(h, "candidate");
}
cprintf(cbret, "<rpc-reply xmlns=\"%s\"><ok/></rpc-reply>", NETCONF_BASE_NAMESPACE);
ok:
retval = 0;

View file

@ -54,6 +54,7 @@ module clixon-config {
"Added options:
CLICON_NETCONF_DUPLICATE_ALLOW - Disable duplicate check in NETCONF messages.
CLICON_CLI_OUTPUT_FORMAT - Default CLI output format
CLICON_AUTOLOCK - Implicit locks
Released in Clixon 7.1";
}
revision 2024-01-01 {
@ -779,8 +780,8 @@ module clixon-config {
type int32;
default 1;
description
"Set to 0 if you want CLI to wrap to next line.
Set to 1 if you want CLI to scroll sideways when approaching
"Set to 0 if you want CLI INPUT to wrap to next line.
Set to 1 if you want CLI INPUT to scroll sideways when approaching
right margin";
}
leaf CLICON_CLI_LINES_DEFAULT {
@ -976,6 +977,16 @@ module clixon-config {
persistent confirming commit.
(consider boolean)";
}
leaf CLICON_AUTOLOCK {
type boolean;
default false;
description
"Set if all edit-config implicitly locks without the need of an explicit lock-db
In short, the lock is obtained by edit-config and copy-config and released by
discard and commit.
Also, any edits in candidate are discarded if the client closes the connection.
This effectively disables shared candidate";
}
leaf CLICON_XMLDB_DIR {
type string;
mandatory true;