Confirmed commit: lock check on running
This commit is contained in:
parent
7976303ef2
commit
a9d1ab006c
5 changed files with 63 additions and 25 deletions
|
|
@ -52,8 +52,6 @@ Expected: End of 2022
|
||||||
* Added support for relevant arguments to CLI commit
|
* Added support for relevant arguments to CLI commit
|
||||||
* See [example_cli.cli](https://github.com/clicon/clixon/blob/master/example/main/example_cli.cli)
|
* See [example_cli.cli](https://github.com/clicon/clixon/blob/master/example/main/example_cli.cli)
|
||||||
* See [Netconf Confirmed Commit Capability](https://github.com/clicon/clixon/issues/255)
|
* See [Netconf Confirmed Commit Capability](https://github.com/clicon/clixon/issues/255)
|
||||||
* Known issues
|
|
||||||
* Lock check, see RFC 6241 7.5
|
|
||||||
|
|
||||||
### API changes on existing protocol/config features
|
### API changes on existing protocol/config features
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -716,9 +716,15 @@ from_client_lock(clicon_handle h,
|
||||||
struct client_entry *ce = (struct client_entry *)arg;
|
struct client_entry *ce = (struct client_entry *)arg;
|
||||||
uint32_t id = ce->ce_id;
|
uint32_t id = ce->ce_id;
|
||||||
uint32_t iddb;
|
uint32_t iddb;
|
||||||
|
uint32_t otherid;
|
||||||
char *db;
|
char *db;
|
||||||
cbuf *cbx = NULL; /* Assist cbuf */
|
cbuf *cbx = NULL; /* Assist cbuf */
|
||||||
|
yang_stmt *yspec;
|
||||||
|
|
||||||
|
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||||
|
clicon_err(OE_YANG, ENOENT, "No yang spec9");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
if ((db = netconf_db_find(xe, "target")) == NULL){
|
if ((db = netconf_db_find(xe, "target")) == NULL){
|
||||||
if (netconf_missing_element(cbret, "protocol", "target", NULL) < 0)
|
if (netconf_missing_element(cbret, "protocol", "target", NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -754,6 +760,20 @@ from_client_lock(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
goto ok;
|
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)
|
if (xmldb_lock(h, db, id) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* user callback */
|
/* user callback */
|
||||||
|
|
|
||||||
|
|
@ -761,6 +761,19 @@ candidate_commit(clicon_handle h,
|
||||||
* configuration datastore that are actually different and only check
|
* configuration datastore that are actually different and only check
|
||||||
* "create", "update", and "delete" access permissions for this set of
|
* "create", "update", and "delete" access permissions for this set of
|
||||||
* nodes, which could be empty.
|
* nodes, which could be empty.
|
||||||
|
*
|
||||||
|
* Handling of the first phase of confirmed-commit:
|
||||||
|
* First, it must be determined if the given <commit> RPC constitutes a "confirming-commit", roughly meaning:
|
||||||
|
* 1) it was issued in the same session as a prior confirmed-commit
|
||||||
|
* 2) it bears a <persist-id> element matching the <persist> element that accompanied the prior confirmed-commit
|
||||||
|
*
|
||||||
|
* If it is a valid "confirming-commit" and this RPC does not bear another <confirmed/> element, then the
|
||||||
|
* confirmed-commit is complete, the rollback event can be cancelled and the rollback database deleted.
|
||||||
|
*
|
||||||
|
* No further action is necessary as the candidate configuration was already copied to the running configuration.
|
||||||
|
*
|
||||||
|
* If the RPC does bear another <confirmed/> element, that will be handled in phase two, from within the
|
||||||
|
* candidate_commit() method.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
from_client_commit(clicon_handle h,
|
from_client_commit(clicon_handle h,
|
||||||
|
|
@ -777,20 +790,6 @@ from_client_commit(clicon_handle h,
|
||||||
int ret;
|
int ret;
|
||||||
yang_stmt *yspec;
|
yang_stmt *yspec;
|
||||||
|
|
||||||
/* Handle the first phase of confirmed-commit
|
|
||||||
*
|
|
||||||
* First, it must be determined if the given <commit> RPC constitutes a "confirming-commit", roughly meaning:
|
|
||||||
* 1) it was issued in the same session as a prior confirmed-commit
|
|
||||||
* 2) it bears a <persist-id> element matching the <persist> element that accompanied the prior confirmed-commit
|
|
||||||
*
|
|
||||||
* If it is a valid "confirming-commit" and this RPC does not bear another <confirmed/> element, then the
|
|
||||||
* confirmed-commit is complete, the rollback event can be cancelled and the rollback database deleted.
|
|
||||||
*
|
|
||||||
* No further action is necessary as the candidate configuration was already copied to the running configuration.
|
|
||||||
*
|
|
||||||
* If the RPC does bear another <confirmed/> element, that will be handled in phase two, from within the
|
|
||||||
* candidate_commit() method.
|
|
||||||
*/
|
|
||||||
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;
|
||||||
|
|
@ -810,8 +809,7 @@ from_client_commit(clicon_handle h,
|
||||||
clicon_err(OE_XML, errno, "cbuf_new");
|
clicon_err(OE_XML, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
cprintf(cbx, "<session-id>%u</session-id>", iddb);
|
if (netconf_in_use(cbret, "protocol", "Operation failed, lock is already held") < 0)
|
||||||
if (netconf_in_use(cbret, cbuf_get(cbx), "Operation failed, lock is already held") < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -312,7 +312,8 @@ PIDS=($(jobs -l % | cut -c 6- | awk '{print $1}'))
|
||||||
assert_config_equals "running" "$CONFIGB" # assert config twice to prove it surives disconnect
|
assert_config_equals "running" "$CONFIGB" # assert config twice to prove it surives disconnect
|
||||||
assert_config_equals "running" "$CONFIGB" # of ephemeral sessions
|
assert_config_equals "running" "$CONFIGB" # of ephemeral sessions
|
||||||
|
|
||||||
kill -9 ${PIDS[0]} # kill the while loop above to close STDIN on 1st
|
new "soft kill ${PIDS[0]}"
|
||||||
|
kill ${PIDS[0]} # kill the while loop above to close STDIN on 1st
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
|
|
@ -433,15 +434,11 @@ expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+xml
|
||||||
|
|
||||||
assert_config_equals "running" "$CONFIGBPLUSC"
|
assert_config_equals "running" "$CONFIGBPLUSC"
|
||||||
|
|
||||||
new "soft kill"
|
new "soft kill ${PIDS[0]}"
|
||||||
kill ${PIDS[0]} # kill the while loop above to close STDIN on 1st
|
kill ${PIDS[0]} # kill the while loop above to close STDIN on 1st
|
||||||
|
|
||||||
assert_config_equals "running" "$CONFIGBPLUSC"
|
assert_config_equals "running" "$CONFIGBPLUSC"
|
||||||
|
|
||||||
kill -9 ${PIDS[0]} 2> /dev/null # kill the while loop above to close STDIN on 1st
|
|
||||||
|
|
||||||
assert_config_equals "running" "$CONFIGBPLUSC"
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
new "restconf persistid expect fail"
|
new "restconf persistid expect fail"
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ cat <<EOF > $cfg
|
||||||
<clixon-config xmlns="http://clicon.org/config">
|
<clixon-config xmlns="http://clicon.org/config">
|
||||||
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
|
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
|
||||||
<CLICON_FEATURE>ietf-netconf:startup</CLICON_FEATURE>
|
<CLICON_FEATURE>ietf-netconf:startup</CLICON_FEATURE>
|
||||||
|
<CLICON_FEATURE>ietf-netconf:confirmed-commit</CLICON_FEATURE>
|
||||||
<CLICON_MODULE_SET_ID>42</CLICON_MODULE_SET_ID>
|
<CLICON_MODULE_SET_ID>42</CLICON_MODULE_SET_ID>
|
||||||
<CLICON_YANG_DIR>$dir</CLICON_YANG_DIR>
|
<CLICON_YANG_DIR>$dir</CLICON_YANG_DIR>
|
||||||
<CLICON_YANG_DIR>${YANG_INSTALLDIR}</CLICON_YANG_DIR>
|
<CLICON_YANG_DIR>${YANG_INSTALLDIR}</CLICON_YANG_DIR>
|
||||||
|
|
@ -356,6 +357,30 @@ expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS>
|
||||||
new "kill-session using prefix xx"
|
new "kill-session using prefix xx"
|
||||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<xx:rpc xmlns:xx=\"urn:ietf:params:xml:ns:netconf:base:1.0\" xx:message-id=\"42\"><xx:kill-session><xx:session-id>44</xx:session-id></xx:kill-session></xx:rpc>" "" "<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" xmlns:xx=\"urn:ietf:params:xml:ns:netconf:base:1.0\" xx:message-id=\"42\"><ok/></rpc-reply>"
|
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<xx:rpc xmlns:xx=\"urn:ietf:params:xml:ns:netconf:base:1.0\" xx:message-id=\"42\"><xx:kill-session><xx:session-id>44</xx:session-id></xx:kill-session></xx:rpc>" "" "<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" xmlns:xx=\"urn:ietf:params:xml:ns:netconf:base:1.0\" xx:message-id=\"42\"><ok/></rpc-reply>"
|
||||||
|
|
||||||
|
new "asynchronous lock running"
|
||||||
|
sleep 60 | cat <(echo "$HELLONO11<rpc $DEFAULTNS><lock><target><running/></target></lock></rpc>]]>]]>") -| $clixon_netconf -qf $cfg >> /dev/null &
|
||||||
|
|
||||||
|
PIDS=($(jobs -l % | cut -c 6- | awk '{print $1}'))
|
||||||
|
|
||||||
|
new "try commit should fail"
|
||||||
|
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><commit/></rpc>" "" "<rpc-reply $DEFAULTNS><rpc-error><error-type>protocol</error-type><error-tag>in-use</error-tag><error-severity>error</error-severity><error-message>Operation failed, lock is already held</error-message></rpc-error></rpc-reply>"
|
||||||
|
|
||||||
|
new "soft kill ${PIDS[0]}"
|
||||||
|
kill ${PIDS[0]} # kill the while loop above to close STDIN on 1st
|
||||||
|
|
||||||
|
new "asynchronous confirmed commit"
|
||||||
|
sleep 60 | cat <(echo "$HELLONO11<rpc $DEFAULTNS><commit><confirmed/><confirm-timeout>60</confirm-timeout></commit></rpc>]]>]]>") -| $clixon_netconf -qf $cfg >> /dev/null &
|
||||||
|
PIDS=($(jobs -l % | cut -c 6- | awk '{print $1}'))
|
||||||
|
|
||||||
|
new "try lock should fail"
|
||||||
|
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><lock><target><running/></target></lock></rpc>" "<rpc-reply $DEFAULTNS><rpc-error><error-type>protocol</error-type><error-tag>lock-denied</error-tag><error-info><session-id>[0-9]*</session-id></error-info><error-severity>error</error-severity><error-message>Operation failed, another session has an ongoing confirmed commit</error-message></rpc-error></rpc-reply>"
|
||||||
|
|
||||||
|
new "soft kill ${PIDS[0]}"
|
||||||
|
kill ${PIDS[0]} # kill the while loop above to close STDIN on 1st
|
||||||
|
|
||||||
|
new "netconf discard-changes"
|
||||||
|
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><discard-changes/></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||||
|
|
||||||
# modify candidate, then lock, should fail.
|
# modify candidate, then lock, should fail.
|
||||||
new "netconf edit config"
|
new "netconf edit config"
|
||||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><table xmlns=\"urn:example:clixon\"><parameter><name>a</name></parameter></table></config></edit-config></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><table xmlns=\"urn:example:clixon\"><parameter><name>a</name></parameter></table></config></edit-config></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue