From 11eccd5478eecebe8d428ce9bc86df72c1b64ea6 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Fri, 7 Oct 2022 10:02:07 +0200 Subject: [PATCH] Confirm commit: - Removed confirm-commit 1.0 capability (only 1.1 present) - Made startup capability conditional (as confirmed-commit) - Fixed startup error when rollback did not exist - Adjust snmp commit calls - Move failsafe to lib - Test: Minimized test application, test capability --- apps/backend/Makefile.in | 8 +- apps/backend/backend_commit.c | 56 ++++++++- apps/backend/backend_failsafe.c | 105 ---------------- apps/backend/backend_failsafe.h | 42 ------- apps/backend/backend_main.c | 2 +- apps/backend/backend_startup.c | 89 ++++---------- apps/backend/backend_startup.h | 1 - apps/backend/clixon_backend_commit.h | 1 + apps/snmp/snmp_handler.c | 4 +- lib/clixon/clixon_proto_client.h | 1 - lib/src/clixon_netconf_lib.c | 22 ++-- lib/src/clixon_proto_client.c | 10 +- test/site.sh | 1 - test/test_confirmed_commit.sh | 172 ++++++++++----------------- test/test_netconf_hello.sh | 10 +- test/test_netconf_ssh_callhome.sh | 2 +- 16 files changed, 177 insertions(+), 349 deletions(-) delete mode 100644 apps/backend/backend_failsafe.c delete mode 100644 apps/backend/backend_failsafe.h diff --git a/apps/backend/Makefile.in b/apps/backend/Makefile.in index 5e3a782a..9bfa8d92 100644 --- a/apps/backend/Makefile.in +++ b/apps/backend/Makefile.in @@ -87,10 +87,6 @@ INCLUDES = -I. -I$(top_srcdir)/lib/src -I$(top_srcdir)/lib -I$(top_srcdir)/inclu # Name of application APPL = clixon_backend -# Source / objects called from plugin and otherwise -COMMONSRC = backend_failsafe.c -COMMONOBJ = $(COMMONSRC:.c=.o) - # Not accessible from plugin APPSRC = backend_main.c APPSRC += backend_socket.c @@ -98,14 +94,14 @@ APPSRC += backend_client.c APPSRC += backend_get.c APPSRC += backend_plugin_restconf.c # Pseudo plugin for restconf daemon APPSRC += backend_startup.c -APPOBJ = $(APPSRC:.c=.o) $(COMMONOBJ) +APPOBJ = $(APPSRC:.c=.o) # Accessible from plugin LIBSRC = clixon_backend_transaction.c LIBSRC += clixon_backend_handle.c LIBSRC += backend_commit.c LIBSRC += backend_plugin.c -LIBOBJ = $(LIBSRC:.c=.o) $(COMMONOBJ) +LIBOBJ = $(LIBSRC:.c=.o) # Name of lib MYNAME = clixon_backend diff --git a/apps/backend/backend_commit.c b/apps/backend/backend_commit.c index 4ce995d8..8e689620 100644 --- a/apps/backend/backend_commit.c +++ b/apps/backend/backend_commit.c @@ -70,7 +70,6 @@ #include "backend_handle.h" #include "clixon_backend_commit.h" #include "backend_client.h" -#include "backend_failsafe.h" /* a global instance of the confirmed_commit struct for reference throughout the procedure */ struct confirmed_commit confirmed_commit = { @@ -1577,3 +1576,58 @@ from_client_restart_one(clicon_handle h, goto done; } +/*! Reset running and start in failsafe mode. If no failsafe then quit. + * + * param[in] h Clixon handle + * param[in] phase Debug string + Typically done when startup status is not OK so + +failsafe ----------------------+ + reset \ commit +running ----|-------+---------------> RUNNING FAILSAFE + \ +tmp |----------------------> + */ +int +load_failsafe(clicon_handle h, + char *phase) +{ + int retval = -1; + int ret; + char *db = "failsafe"; + cbuf *cbret = NULL; + + phase = phase == NULL ? "(unknown)" : phase; + + if ((cbret = cbuf_new()) == NULL){ + clicon_err(OE_XML, errno, "cbuf_new"); + goto done; + } + if ((ret = xmldb_exists(h, db)) < 0) + goto done; + if (ret == 0){ /* No it does not exist, fail */ + clicon_err(OE_DB, 0, "%s failed and no Failsafe database found, exiting", phase); + goto done; + } + /* Copy original running to tmp as backup (restore if error) */ + if (xmldb_copy(h, "running", "tmp") < 0) + goto done; + if (xmldb_db_reset(h, "running") < 0) + goto done; + ret = candidate_commit(h, db, cbret); + if (ret != 1) + if (xmldb_copy(h, "tmp", "running") < 0) + goto done; + if (ret < 0) + goto done; + if (ret == 0){ + clicon_err(OE_DB, 0, "%s failed, Failsafe database validation failed %s", phase, cbuf_get(cbret)); + goto done; + } + clicon_log(LOG_NOTICE, "%s failed, Failsafe database loaded ", phase); + retval = 0; + done: + if (cbret) + cbuf_free(cbret); + return retval; +} diff --git a/apps/backend/backend_failsafe.c b/apps/backend/backend_failsafe.c deleted file mode 100644 index 4c6f0966..00000000 --- a/apps/backend/backend_failsafe.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * - ***** BEGIN LICENSE BLOCK ***** - - Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren - Copyright (C) 2017-2019 Olof Hagsand - Copyright (C) 2020-2021 Olof Hagsand and Rubicon Communications, LLC(Netgate) - - This file is part of CLIXON. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - Alternatively, the contents of this file may be used under the terms of - the GNU General Public License Version 3 or later (the "GPL"), - in which case the provisions of the GPL are applicable instead - of those above. If you wish to allow use of your version of this file only - under the terms of the GPL, and not to allow others to - use your version of this file under the terms of Apache License version 2, - indicate your decision by deleting the provisions above and replace them with - the notice and other provisions required by the GPL. If you do not delete - the provisions above, a recipient may use your version of this file under - the terms of any one of the Apache License version 2 or the GPL. - - ***** END LICENSE BLOCK ***** - - */ - -#ifdef HAVE_CONFIG_H -#include "clixon_config.h" /* generated by config & autoconf */ -#endif - -#include -#include -#include - -/* cligen */ -#include - -/* clixon */ -#include - -#include "clixon_backend_commit.h" -#include "backend_failsafe.h" - -/*! Reset running and start in failsafe mode. If no failsafe then quit. - Typically done when startup status is not OK so - -failsafe ----------------------+ - reset \ commit -running ----|-------+---------------> RUNNING FAILSAFE - \ -tmp |----------------------> - */ -int -load_failsafe(clicon_handle h, char *phase) -{ - int retval = -1; - int ret; - char *db = "failsafe"; - cbuf *cbret = NULL; - - phase = phase == NULL ? "(unknown)" : phase; - - if ((cbret = cbuf_new()) == NULL){ - clicon_err(OE_XML, errno, "cbuf_new"); - goto done; - } - if ((ret = xmldb_exists(h, db)) < 0) - goto done; - if (ret == 0){ /* No it does not exist, fail */ - clicon_err(OE_DB, 0, "%s failed and no Failsafe database found, exiting", phase); - goto done; - } - /* Copy original running to tmp as backup (restore if error) */ - if (xmldb_copy(h, "running", "tmp") < 0) - goto done; - if (xmldb_db_reset(h, "running") < 0) - goto done; - ret = candidate_commit(h, db, cbret); - if (ret != 1) - if (xmldb_copy(h, "tmp", "running") < 0) - goto done; - if (ret < 0) - goto done; - if (ret == 0){ - clicon_err(OE_DB, 0, "%s failed, Failsafe database validation failed %s", phase, cbuf_get(cbret)); - goto done; - } - clicon_log(LOG_NOTICE, "%s failed, Failsafe database loaded ", phase); - retval = 0; - done: - if (cbret) - cbuf_free(cbret); - return retval; -} diff --git a/apps/backend/backend_failsafe.h b/apps/backend/backend_failsafe.h deleted file mode 100644 index 55e0dbf3..00000000 --- a/apps/backend/backend_failsafe.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * - ***** BEGIN LICENSE BLOCK ***** - - Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren - Copyright (C) 2017-2019 Olof Hagsand - Copyright (C) 2020-2021 Olof Hagsand and Rubicon Communications, LLC(Netgate) - - This file is part of CLIXON. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - Alternatively, the contents of this file may be used under the terms of - the GNU General Public License Version 3 or later (the "GPL"), - in which case the provisions of the GPL are applicable instead - of those above. If you wish to allow use of your version of this file only - under the terms of the GPL, and not to allow others to - use your version of this file under the terms of Apache License version 2, - indicate your decision by deleting the provisions above and replace them with - the notice and other provisions required by the GPL. If you do not delete - the provisions above, a recipient may use your version of this file under - the terms of any one of the Apache License version 2 or the GPL. - - ***** END LICENSE BLOCK ***** - - */ - -#ifndef CLIXON_BACKEND_FAILSAFE_H -#define CLIXON_BACKEND_FAILSAFE_H -int load_failsafe(clicon_handle h, char *phase); - -#endif //CLIXON_BACKEND_FAILSAFE_H diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c index fa0ac8ef..0b9a24ea 100644 --- a/apps/backend/backend_main.c +++ b/apps/backend/backend_main.c @@ -962,7 +962,7 @@ main(int argc, if (status != STARTUP_OK){ if (cbuf_len(cbret)) clicon_log(LOG_NOTICE, "%s: %u %s", __PROGRAM__, getpid(), cbuf_get(cbret)); - if (startup_failsafe(h) < 0){ + if (load_failsafe(h, "Startup") < 0){ goto done; } status = STARTUP_OK; diff --git a/apps/backend/backend_startup.c b/apps/backend/backend_startup.c index 0602d64f..c03f3b95 100644 --- a/apps/backend/backend_startup.c +++ b/apps/backend/backend_startup.c @@ -132,9 +132,10 @@ startup_mode_startup(clicon_handle h, char *db, cbuf *cbret) { - int retval = -1; - int ret = 0; - int db_exists; + int retval = -1; + int ret = 0; + int rollback_exists; + yang_stmt *yspec = clicon_dbspec_yang(h); if (strcmp(db, "running")==0){ clicon_err(OE_FATAL, 0, "Invalid startup db: %s", db); @@ -153,13 +154,12 @@ startup_mode_startup(clicon_handle h, * database was deleted, either clixon_backend crashed or the machine * rebooted. */ - yang_stmt *yspec = clicon_dbspec_yang(h); if (if_feature(yspec, "ietf-netconf", "confirmed-commit")) { - db_exists = xmldb_exists(h, "rollback"); - if (db_exists < 0) { + if ((rollback_exists = xmldb_exists(h, "rollback")) < 0) { clicon_err(OE_DAEMON, 0, "Error checking for the existence of the rollback database"); goto done; - } else if (db_exists == 1) { + } + if (rollback_exists == 1) { ret = startup_commit(h, "rollback", cbret); switch(ret) { case -1: @@ -170,23 +170,30 @@ startup_mode_startup(clicon_handle h, /* Rename the errored rollback database so that it is not tried on a subsequent startup */ xmldb_rename(h, db, NULL, ".error"); - - retval = 1; - goto done; + goto ok; case 1: /* validation ok */ - retval = 1; xmldb_delete(h, "rollback"); - goto done; + goto ok; default: /* Unexpected response */ goto fail; } } - } else if ((ret = startup_commit(h, db, cbret)) < 0) - goto done; - if (ret == 0) - goto fail; + else { + if ((ret = startup_commit(h, db, cbret)) < 0) + goto done; + if (ret == 0) + goto fail; + } + } + else { + if ((ret = startup_commit(h, db, cbret)) < 0) + goto done; + if (ret == 0) + goto fail; + } + ok: retval = 1; done: return retval; @@ -332,56 +339,6 @@ startup_extraxml(clicon_handle h, goto done; } -/*! Reset running and start in failsafe mode. If no failsafe then quit. - Typically done when startup status is not OK so - -failsafe ----------------------+ - reset \ commit -running ----|-------+---------------> RUNNING FAILSAFE - \ -tmp |----------------------> - */ -int -startup_failsafe(clicon_handle h) -{ - int retval = -1; - int ret; - char *db = "failsafe"; - cbuf *cbret = NULL; - - if ((cbret = cbuf_new()) == NULL){ - clicon_err(OE_XML, errno, "cbuf_new"); - goto done; - } - if ((ret = xmldb_exists(h, db)) < 0) - goto done; - if (ret == 0){ /* No it does not exist, fail */ - clicon_err(OE_DB, 0, "Startup failed and no Failsafe database found, exiting"); - goto done; - } - /* Copy original running to tmp as backup (restore if error) */ - if (xmldb_copy(h, "running", "tmp") < 0) - goto done; - if (xmldb_db_reset(h, "running") < 0) - goto done; - ret = candidate_commit(h, db, cbret); - if (ret != 1) - if (xmldb_copy(h, "tmp", "running") < 0) - goto done; - if (ret < 0) - goto done; - if (ret == 0){ - clicon_err(OE_DB, 0, "Startup failed, Failsafe database validation failed %s", cbuf_get(cbret)); - goto done; - } - clicon_log(LOG_NOTICE, "Startup failed, Failsafe database loaded "); - retval = 0; - done: - if (cbret) - cbuf_free(cbret); - return retval; -} - /*! Init modules state of the backend (server). To compare with startup XML * Set the modules state as setopt to the datastore module. * Only if CLICON_XMLDB_MODSTATE is enabled diff --git a/apps/backend/backend_startup.h b/apps/backend/backend_startup.h index 741bd2e0..7191f028 100644 --- a/apps/backend/backend_startup.h +++ b/apps/backend/backend_startup.h @@ -44,7 +44,6 @@ */ int startup_mode_startup(clicon_handle h, char *db, cbuf *cbret); int startup_extraxml(clicon_handle h, char *file, cbuf *cbret); -int startup_failsafe(clicon_handle h); int startup_module_state(clicon_handle h, yang_stmt *yspec); #endif /* _BACKEND_STARTUP_H_ */ diff --git a/apps/backend/clixon_backend_commit.h b/apps/backend/clixon_backend_commit.h index 2cd1c1a6..62785eef 100644 --- a/apps/backend/clixon_backend_commit.h +++ b/apps/backend/clixon_backend_commit.h @@ -83,5 +83,6 @@ int from_client_discard_changes(clicon_handle h, cxobj *xe, cbuf *cbret, void *a 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_restart_one(clicon_handle h, clixon_plugin_t *cp, cbuf *cbret); +int load_failsafe(clicon_handle h, char *phase); #endif /* _CLIXON_BACKEND_COMMIT_H_ */ diff --git a/apps/snmp/snmp_handler.c b/apps/snmp/snmp_handler.c index c113214d..fa981e41 100644 --- a/apps/snmp/snmp_handler.c +++ b/apps/snmp/snmp_handler.c @@ -750,7 +750,7 @@ clixon_snmp_scalar_handler1(netsnmp_mib_handler *handler, goto done; break; case MODE_SET_COMMIT: /* 3 */ - if (clicon_rpc_commit(sh->sh_h) < 0) + if (clicon_rpc_commit(sh->sh_h, 0, 0, 0, NULL, NULL) < 0) goto done; break; case MODE_SET_FREE: /* 4 */ @@ -1303,7 +1303,7 @@ clixon_snmp_table_handler1(netsnmp_mib_handler *handler, } break; case MODE_SET_COMMIT: // 3 - if (clicon_rpc_commit(sh->sh_h) < 0) + if (clicon_rpc_commit(sh->sh_h, 0, 0, 0, NULL, NULL) < 0) goto done; break; case MODE_SET_FREE: // 4 diff --git a/lib/clixon/clixon_proto_client.h b/lib/clixon/clixon_proto_client.h index 644c8d81..c13cafdb 100644 --- a/lib/clixon/clixon_proto_client.h +++ b/lib/clixon/clixon_proto_client.h @@ -1,5 +1,4 @@ /* - * t * ***** BEGIN LICENSE BLOCK ***** diff --git a/lib/src/clixon_netconf_lib.c b/lib/src/clixon_netconf_lib.c index e0e92d6d..2d15605a 100644 --- a/lib/src/clixon_netconf_lib.c +++ b/lib/src/clixon_netconf_lib.c @@ -1752,7 +1752,8 @@ netconf_content_int2str(netconf_content nr) * backend, and backend may implement more modules - please consider if using * library routines for detecting capabilities here. In contrast, yang module * list (RFC7895) is processed by the backend. - * @note encode bodies, see xml_chardata_encode() + * @note If you add new, remember to encode bodies if needed, see xml_chardata_encode() + * @note * @see yang_modules_state_get * @see netconf_module_load */ @@ -1779,6 +1780,7 @@ netconf_hello_server(clicon_handle h, /* A peer MAY include capabilities for previous NETCONF versions, to indicate that it supports multiple protocol versions. */ cprintf(cb, "%s", NETCONF_BASE_CAPABILITY_1_0); + /* Check if RFC7895 loaded and revision found */ if ((ietf_yang_library_revision = yang_modules_revision(h)) != NULL){ if (xml_chardata_encode(&encstr, "urn:ietf:params:netconf:capability:yang-library:1.0?revision=%s&module-set-id=%s", @@ -1791,21 +1793,25 @@ netconf_hello_server(clicon_handle h, encstr = NULL; } } + /* RFC6241 Sec 8.3. Candidate Configuration Capability */ cprintf(cb, "urn:ietf:params:netconf:capability:candidate:1.0"); + /* RFC6241 Sec 8.6. Validate Capability */ cprintf(cb, "urn:ietf:params:netconf:capability:validate:1.1"); - cprintf(cb, "urn:ietf:params:netconf:capability:startup:1.0"); + /* rfc 6241 Sec 8.7 Distinct Startup Capability */ + if (if_feature(yspec, "ietf-netconf", "startup")) + cprintf(cb, "urn:ietf:params:netconf:capability:startup:1.0"); + /* RFC6241 Sec 8.9. XPath Capability */ cprintf(cb, "urn:ietf:params:netconf:capability:xpath:1.0"); - cprintf(cb, "urn:ietf:params:netconf:capability:notification:1.0"); /* rfc6243 with-defaults capability modes */ cprintf(cb, ""); xml_chardata_cbuf_append(cb, "urn:ietf:params:netconf:capability:with-defaults:1.0?basic-mode=explicit&also-supported=report-all,trim,report-all-tagged"); cprintf(cb, ""); - - /* rfc 4741 and 6241 confirmed-commit capabilities */ - if (if_feature(yspec, "ietf-netconf", "confirmed-commit")) { - cprintf(cb, "urn:ietf:params:netconf:capability:confirmed-commit:1.0"); + /* RFC5277 Notification Capability */ + cprintf(cb, "urn:ietf:params:netconf:capability:notification:1.0"); + /* It is somewhat arbitrary why some features/capabilities are hardocded and why some are not + * rfc 6241 Sec 8.4 confirmed-commit capabilities */ + if (if_feature(yspec, "ietf-netconf", "confirmed-commit")) cprintf(cb, "urn:ietf:params:netconf:capability:confirmed-commit:1.1"); - } cprintf(cb, ""); if (session_id) diff --git a/lib/src/clixon_proto_client.c b/lib/src/clixon_proto_client.c index ee724a44..4b2b1c9b 100644 --- a/lib/src/clixon_proto_client.c +++ b/lib/src/clixon_proto_client.c @@ -1266,8 +1266,14 @@ clicon_rpc_validate(clicon_handle h, /*! Commit changes send a commit request to backend daemon * @param[in] h CLICON handle - * @retval 0 OK - * @retval -1 Error and logged to syslog + * @param[in] confirmed If set, send commit/confirmed + * @param[in] cancel If set, send cancle-commit + * @param[in] timeout For confirmed, a timeout in seconds (default 600s) + * @param[in] persist A persist identifier to use + * @param[in] persist_id If cancel or confirmed, the persist id + * @retval 0 OK + * @retval -1 Error and logged to syslog + * @see rfc6241 Sec 8.4 Confirmed Commit Capability */ int clicon_rpc_commit(clicon_handle h, diff --git a/test/site.sh b/test/site.sh index 480ef3bf..c01c7f26 100644 --- a/test/site.sh +++ b/test/site.sh @@ -10,7 +10,6 @@ # The SKIPLIST has precedence over the 'pattern' variable that you can use to # specify included file when running the various test scripts such as "all.sh". #SKIPLIST="test_[a-t]*\.sh test_openconfig.sh test_yangmodels.sh" -SKIPLIST="test_http_data.sh test_netconf_ssh_callhome.sh test_privileges.sh test_restconf.sh test_yang_models_ieee.sh" # # Parse yang openconfig models from https://github.com/openconfig/public OPENCONFIG=/usr/local/share/openconfig/public diff --git a/test/test_confirmed_commit.sh b/test/test_confirmed_commit.sh index 3f18fc86..9d109328 100755 --- a/test/test_confirmed_commit.sh +++ b/test/test_confirmed_commit.sh @@ -1,8 +1,11 @@ #!/usr/bin/env bash -# Basic Netconf functionality -# Mainly default/null prefix, but also xx: prefix -# XXX: could add tests for dual prefixes xx and xy with doppelganger names, ie xy:filter that is -# syntactic correct but wrong +# Netconf confirm commit capability +# See RFC 6241 Section 8.4 +# Test uses privileges drop +# TODO: +# - privileges drop +# - restconf +# - lock check # Magic line must be first in script (see README.md) s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi @@ -13,13 +16,17 @@ cfg=$dir/conf_yang.xml tmp=$dir/tmp.x fyang=$dir/clixon-example.yang -# Use yang in example +# Backend user for priv drop, otherwise root +USER=root #${BUSER} + +# Define default restconfig config: RESTCONFIG +RESTCONFIG=$(restconf_config none false) cat < $cfg $cfg - ietf-netconf:startup ietf-netconf:confirmed-commit + clixon-restconf:allow-auth-none 42 ${YANG_INSTALLDIR} $IETFRFC @@ -37,6 +44,7 @@ cat < $cfg /usr/local/var/$APPNAME $USER drop_perm + $RESTCONFIG EOF @@ -45,16 +53,7 @@ module clixon-example{ yang-version 1.1; namespace "urn:example:clixon"; prefix ex; - import ietf-interfaces { - prefix if; - } - import ietf-ip { - prefix ip; - } - /* Example interface type for tests, local callbacks, etc */ - identity eth { - base if:interface-type; - } + /* Generic config data */ container table{ list parameter{ @@ -64,74 +63,6 @@ module clixon-example{ } } } - /* State data (not config) for the example application*/ - container state { - config false; - description "state data for the example application (must be here for example get operation)"; - leaf-list op { - type string; - } - } - augment "/if:interfaces/if:interface" { - container my-status { - config false; - description "For testing augment+state"; - leaf int { - type int32; - } - leaf str { - type string; - } - } - } - rpc client-rpc { - description "Example local client-side RPC that is processed by the - the netconf/restconf and not sent to the backend. - This is a clixon implementation detail: some rpc:s - are better processed by the client for API or perf reasons"; - input { - leaf x { - type string; - } - } - output { - leaf x { - type string; - } - } - } - rpc empty { - description "Smallest possible RPC with no input or output sections"; - } - rpc example { - description "Some example input/output for testing RFC7950 7.14. - RPC simply echoes the input for debugging."; - input { - leaf x { - description - "If a leaf in the input tree has a 'mandatory' statement with - the value 'true', the leaf MUST be present in an RPC invocation."; - type string; - mandatory true; - } - leaf y { - description - "If a leaf in the input tree has a 'mandatory' statement with the - value 'true', the leaf MUST be present in an RPC invocation."; - type string; - default "42"; - } - } - output { - leaf x { - type string; - } - leaf y { - type string; - } - } - } - } EOF @@ -176,6 +107,7 @@ function edit_config() { function assert_config_equals() { TARGET="$1" EXPECTED="$2" +# new "get-config: $TARGET" rpc "<$TARGET/>" "$(data "$EXPECTED")" } @@ -191,15 +123,12 @@ RUNNING_PATH="/usr/local/var/$APPNAME/running_db" ROLLBACK_PATH="/usr/local/var/$APPNAME/rollback_db" FAILSAFE_PATH="/usr/local/var/$APPNAME/failsafe_db" -CONFIGB="eth0ex:ethtrue" -CONFIGC="eth1ex:ethtrue" -CONFIGBPLUSC="eth0ex:ethtrueeth1ex:ethtrue" -FAILSAFE_CFG="eth99ex:ethtrue" +CONFIGB="eth0
" +CONFIGC="eth1
" +CONFIGBPLUSC="eth0eth1
" +FAILSAFE_CFG="eth99
" -# TODO this test suite is somewhat brittle as it relies on the presence of the example configuration that one gets with -# make install-example in the Clixon distribution. It would be better if the dependencies were entirely self contained. - -new "test params: -f $cfg -- -s" +new "test params: -f $cfg" # Bring your own backend if [ $BE -ne 0 ]; then # kill old backend (if any) @@ -208,15 +137,19 @@ if [ $BE -ne 0 ]; then if [ $? -ne 0 ]; then err fi - new "start backend -s init -f $cfg -- -s" - start_backend -s init -f $cfg -- -s + new "start backend -s init -f $cfg" + start_backend -s init -f $cfg fi new "wait backend" wait_backend -################################################################################ + +new "Hello check confirm-commit capability" +expecteof "$clixon_netconf -f $cfg" 0 "urn:ietf:params:netconf:base:1.1]]>]]>" "urn:ietf:params:netconf:capability:confirmed-commit:1.1" '^$' + +################################################################################ new "netconf ephemeral confirmed-commit rolls back after disconnect" reset edit_config "candidate" "$CONFIGB" @@ -305,13 +238,13 @@ commit "abcdefg" assert_config_equals "running" "$CONFIGBPLUSC" stop_backend -f $cfg # kill backend and restart [ -f "$ROLLBACK_PATH" ] || err "rollback_db doesn't exist!" # assert rollback_db exists -start_backend -s running -f $cfg -- -s +start_backend -s running -f $cfg wait_backend assert_config_equals "running" "$CONFIGB" [ -f "ROLLBACK_PATH" ] && err "rollback_db still exists!" # assert rollback_db doesn't exist stop_backend -f $cfg -start_backend -s init -f $cfg -- -s +start_backend -s init -f $cfg ################################################################################ @@ -334,12 +267,12 @@ sudo tee "$ROLLBACK_PATH" > /dev/null << EOF EOF -start_backend -s running -f $cfg -- -s +start_backend -s running -f $cfg wait_backend assert_config_equals "running" "$FAILSAFE_CFG" stop_backend -f $cfg -start_backend -s init -f $cfg -lf/tmp/clixon.log -D1 -- -s +start_backend -s init -f $cfg -lf/tmp/clixon.log -D1 wait_backend ################################################################################ @@ -364,14 +297,15 @@ reset tmppipe=$(mktemp -u) mkfifo -m 600 "$tmppipe" + cat << EOF | clixon_cli -f $cfg >> /dev/null & -set interfaces interface eth0 type ex:eth -set interfaces interface eth0 enabled true +set table parameter eth0 commit confirmed 60 shell echo >> $tmppipe shell cat $tmppipe quit EOF + cat $tmppipe >> /dev/null assert_config_equals "running" "$CONFIGB" echo >> $tmppipe @@ -383,17 +317,17 @@ rm $tmppipe new "cli persistent confirmed-commit" reset + cat << EOF | clixon_cli -f $cfg >> /dev/null -set interfaces interface eth0 type ex:eth -set interfaces interface eth0 enabled true +set table parameter eth0 commit confirmed persist a quit EOF + assert_config_equals "running" "$CONFIGB" cat << EOF | clixon_cli -f $cfg >> /dev/null -set interfaces interface eth1 type ex:eth -set interfaces interface eth1 enabled true +set table parameter eth1 commit persist-id a confirmed persist ab quit EOF @@ -420,8 +354,7 @@ expectpart "$($clixon_cli -lo -1 -f $cfg commit persist-id ab cancel)" 255 "no c new "cli persistent confirmed-commit with timeout" reset cat << EOF | clixon_cli -f $cfg >> /dev/null -set interfaces interface eth0 type ex:eth -set interfaces interface eth0 enabled true +set table parameter eth0 commit confirmed persist abcd 2 EOF assert_config_equals "running" "$CONFIGB" @@ -433,16 +366,16 @@ assert_config_equals "running" "" new "cli persistent confirmed-commit with reset timeout" reset cat << EOF | clixon_cli -f $cfg >> /dev/null -set interfaces interface eth0 type ex:eth -set interfaces interface eth0 enabled true +set table parameter eth0 commit confirmed persist abcd 5 EOF + assert_config_equals "running" "$CONFIGB" cat << EOF | clixon_cli -f $cfg >> /dev/null -set interfaces interface eth1 type ex:eth -set interfaces interface eth1 enabled true +set table parameter eth1 commit persist-id abcd confirmed persist abcdef 10 EOF + sleep 6 assert_config_equals "running" "$CONFIGBPLUSC" # now sleep long enough for rollback to happen; get config, assert == A @@ -452,7 +385,21 @@ assert_config_equals "running" "" # TODO test restconf receives "409 conflict" when there is a persistent confirmed-commit active # TODO test restconf causes confirming-commit for ephemeral confirmed-commit +if [ $RC -ne 0 ]; then + new "kill old restconf daemon" + stop_restconf_pre + new "start restconf daemon" + start_restconf -f $cfg +fi + +new "wait restconf" +wait_restconf + +if [ $RC -ne 0 ]; then + new "Kill restconf daemon" + stop_restconf +fi if [ $BE -ne 0 ]; then new "Kill backend" @@ -465,5 +412,8 @@ if [ $BE -ne 0 ]; then stop_backend -f $cfg fi +# Set by restconf_config +unset RESTCONFIG + new "endtest" endtest diff --git a/test/test_netconf_hello.sh b/test/test_netconf_hello.sh index 93e81177..61eb4447 100755 --- a/test/test_netconf_hello.sh +++ b/test/test_netconf_hello.sh @@ -106,7 +106,15 @@ new "Netconf snd hello with prefix" expecteof "$clixon_netconf -qef $cfg" 0 "urn:ietf:params:netconf:base:1.1]]>]]>" '^$' new "netconf snd + rcv hello" -expecteof "$clixon_netconf -f $cfg" 0 "urn:ietf:params:netconf:base:1.1]]>]]>" "^urn:ietf:params:netconf:base:1.1urn:ietf:params:netconf:base:1.0urn:ietf:params:netconf:capability:yang-library:1.0?revision=2019-01-04&module-set-id=42urn:ietf:params:netconf:capability:candidate:1.0urn:ietf:params:netconf:capability:validate:1.1urn:ietf:params:netconf:capability:startup:1.0urn:ietf:params:netconf:capability:xpath:1.0urn:ietf:params:netconf:capability:notification:1.0urn:ietf:params:netconf:capability:with-defaults:1.0?basic-mode=explicit&also-supported=report-all,trim,report-all-tagged[0-9]*]]>]]>$" '^$' +expecteof "$clixon_netconf -f $cfg" 0 "urn:ietf:params:netconf:base:1.1]]>]]>" "^urn:ietf:params:netconf:base:1.1urn:ietf:params:netconf:base:1.0 +urn:ietf:params:netconf:capability:yang-library:1.0?revision=2019-01-04&module-set-id=42 +urn:ietf:params:netconf:capability:candidate:1.0 +urn:ietf:params:netconf:capability:validate:1.1 +urn:ietf:params:netconf:capability:xpath:1.0 +urn:ietf:params:netconf:capability:notification:1.0 +urn:ietf:params:netconf:capability:startup:1.0 +urn:ietf:params:netconf:capability:with-defaults:1.0?basic-mode=explicit&also-supported=report-all,trim,report-all-tagged +[0-9]*]]>]]>$" '^$' # Actually non-standard to reply on wrong hello with rpc-error, but may be useful new "Netconf snd hello with extra element" diff --git a/test/test_netconf_ssh_callhome.sh b/test/test_netconf_ssh_callhome.sh index 32a05415..8fc5469b 100755 --- a/test/test_netconf_ssh_callhome.sh +++ b/test/test_netconf_ssh_callhome.sh @@ -134,7 +134,7 @@ EOF new "Start Listener client" echo "ssh -s -F $sshcfg -v -i $key -o ProxyUseFdpass=yes -o ProxyCommand=\"clixon_netconf_ssh_callhome_client -a 127.0.0.1\" . netconf" #-F $sshcfg -expectpart "$(ssh -s -F $sshcfg -v -i $key -o ProxyUseFdpass=yes -o ProxyCommand="${clixon_netconf_ssh_callhome_client} -a 127.0.0.1" . netconf < $rpccmd)" 0 "urn:ietf:params:netconf:base:1.1urn:ietf:params:netconf:base:1.0urn:ietf:params:netconf:capability:yang-library:1.0?revision=2019-01-04&module-set-id=42urn:ietf:params:netconf:capability:candidate:1.0urn:ietf:params:netconf:capability:validate:1.1urn:ietf:params:netconf:capability:startup:1.0urn:ietf:params:netconf:capability:xpath:1.0urn:ietf:params:netconf:capability:notification:1.0urn:ietf:params:netconf:capability:with-defaults:1.0?basic-mode=explicit&also-supported=report-all,trim,report-all-tagged2" "" +expectpart "$(ssh -s -F $sshcfg -v -i $key -o ProxyUseFdpass=yes -o ProxyCommand="${clixon_netconf_ssh_callhome_client} -a 127.0.0.1" . netconf < $rpccmd)" 0 "urn:ietf:params:netconf:base:1.1urn:ietf:params:netconf:base:1.0urn:ietf:params:netconf:capability:yang-library:1.0?revision=2019-01-04&module-set-id=42urn:ietf:params:netconf:capability:candidate:1.0urn:ietf:params:netconf:capability:validate:1.1urn:ietf:params:netconf:capability:xpath:1.0urn:ietf:params:netconf:capability:with-defaults:1.0?basic-mode=explicit&also-supported=report-all,trim,report-all-taggedurn:ietf:params:netconf:capability:notification:1.02" "" # Wait wait