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
This commit is contained in:
Olof hagsand 2022-10-07 10:02:07 +02:00
parent 8abcda6f85
commit 11eccd5478
16 changed files with 177 additions and 349 deletions

View file

@ -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

View file

@ -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;
}

View file

@ -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 <stdlib.h>
#include <errno.h>
#include <syslog.h>
/* cligen */
#include <cligen/cligen.h>
/* clixon */
#include <clixon/clixon.h>
#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;
}

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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_ */

View file

@ -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_ */

View file

@ -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

View file

@ -1,5 +1,4 @@
/*
* t
*
***** BEGIN LICENSE BLOCK *****

View file

@ -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, "<capability>%s</capability>", 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, "<capability>urn:ietf:params:netconf:capability:candidate:1.0</capability>");
/* RFC6241 Sec 8.6. Validate Capability */
cprintf(cb, "<capability>urn:ietf:params:netconf:capability:validate:1.1</capability>");
cprintf(cb, "<capability>urn:ietf:params:netconf:capability:startup:1.0</capability>");
/* rfc 6241 Sec 8.7 Distinct Startup Capability */
if (if_feature(yspec, "ietf-netconf", "startup"))
cprintf(cb, "<capability>urn:ietf:params:netconf:capability:startup:1.0</capability>");
/* RFC6241 Sec 8.9. XPath Capability */
cprintf(cb, "<capability>urn:ietf:params:netconf:capability:xpath:1.0</capability>");
cprintf(cb, "<capability>urn:ietf:params:netconf:capability:notification:1.0</capability>");
/* rfc6243 with-defaults capability modes */
cprintf(cb, "<capability>");
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, "</capability>");
/* rfc 4741 and 6241 confirmed-commit capabilities */
if (if_feature(yspec, "ietf-netconf", "confirmed-commit")) {
cprintf(cb, "<capability>urn:ietf:params:netconf:capability:confirmed-commit:1.0</capability>");
/* RFC5277 Notification Capability */
cprintf(cb, "<capability>urn:ietf:params:netconf:capability:notification:1.0</capability>");
/* 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, "<capability>urn:ietf:params:netconf:capability:confirmed-commit:1.1</capability>");
}
cprintf(cb, "</capabilities>");
if (session_id)

View file

@ -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,

View file

@ -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

View file

@ -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 <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_FEATURE>ietf-netconf:startup</CLICON_FEATURE>
<CLICON_FEATURE>ietf-netconf:confirmed-commit</CLICON_FEATURE>
<CLICON_FEATURE>clixon-restconf:allow-auth-none</CLICON_FEATURE> <!-- Use auth-type=none -->
<CLICON_MODULE_SET_ID>42</CLICON_MODULE_SET_ID>
<CLICON_YANG_DIR>${YANG_INSTALLDIR}</CLICON_YANG_DIR>
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
@ -37,6 +44,7 @@ cat <<EOF > $cfg
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
<CLICON_BACKEND_USER>$USER</CLICON_BACKEND_USER>
<CLICON_BACKEND_PRIVILEGES>drop_perm</CLICON_BACKEND_PRIVILEGES>
$RESTCONFIG
</clixon-config>
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 "<get-config><source><$TARGET/></source></get-config>" "$(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="<interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\"><interface><name>eth0</name><type>ex:eth</type><enabled>true</enabled></interface></interfaces>"
CONFIGC="<interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\"><interface><name>eth1</name><type>ex:eth</type><enabled>true</enabled></interface></interfaces>"
CONFIGBPLUSC="<interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\"><interface><name>eth0</name><type>ex:eth</type><enabled>true</enabled></interface><interface><name>eth1</name><type>ex:eth</type><enabled>true</enabled></interface></interfaces>"
FAILSAFE_CFG="<interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\"><interface><name>eth99</name><type>ex:eth</type><enabled>true</enabled></interface></interfaces>"
CONFIGB="<table xmlns=\"urn:example:clixon\"><parameter><name>eth0</name></parameter></table>"
CONFIGC="<table xmlns=\"urn:example:clixon\"><parameter><name>eth1</name></parameter></table>"
CONFIGBPLUSC="<table xmlns=\"urn:example:clixon\"><parameter><name>eth0</name></parameter><parameter><name>eth1</name></parameter></table>"
FAILSAFE_CFG="<table xmlns=\"urn:example:clixon\"><parameter><name>eth99</name></parameter></table>"
# 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 "<?xml version=\"1.0\" encoding=\"UTF-8\"?><hello $DEFAULTONLY><capabilities><capability>urn:ietf:params:netconf:base:1.1</capability></capabilities></hello>]]>]]>" "<capability>urn:ietf:params:netconf:capability:confirmed-commit:1.1</capability>" '^$'
################################################################################
new "netconf ephemeral confirmed-commit rolls back after disconnect"
reset
edit_config "candidate" "$CONFIGB"
@ -305,13 +238,13 @@ commit "<persist>abcdefg</persist><confirmed/>"
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
</bar>
</foo>
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

View file

@ -106,7 +106,15 @@ new "Netconf snd hello with prefix"
expecteof "$clixon_netconf -qef $cfg" 0 "<?xml version=\"1.0\" encoding=\"UTF-8\"?><nc:hello xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\"><nc:capabilities><nc:capability>urn:ietf:params:netconf:base:1.1</nc:capability></nc:capabilities></nc:hello>]]>]]>" '^$'
new "netconf snd + rcv hello"
expecteof "$clixon_netconf -f $cfg" 0 "<?xml version=\"1.0\" encoding=\"UTF-8\"?><hello $DEFAULTONLY><capabilities><capability>urn:ietf:params:netconf:base:1.1</capability></capabilities></hello>]]>]]>" "^<hello $DEFAULTONLY><capabilities><capability>urn:ietf:params:netconf:base:1.1</capability><capability>urn:ietf:params:netconf:base:1.0</capability><capability>urn:ietf:params:netconf:capability:yang-library:1.0?revision=2019-01-04&amp;module-set-id=42</capability><capability>urn:ietf:params:netconf:capability:candidate:1.0</capability><capability>urn:ietf:params:netconf:capability:validate:1.1</capability><capability>urn:ietf:params:netconf:capability:startup:1.0</capability><capability>urn:ietf:params:netconf:capability:xpath:1.0</capability><capability>urn:ietf:params:netconf:capability:notification:1.0</capability><capability>urn:ietf:params:netconf:capability:with-defaults:1.0?basic-mode=explicit&amp;also-supported=report-all,trim,report-all-tagged</capability></capabilities><session-id>[0-9]*</session-id></hello>]]>]]>$" '^$'
expecteof "$clixon_netconf -f $cfg" 0 "<?xml version=\"1.0\" encoding=\"UTF-8\"?><hello $DEFAULTONLY><capabilities><capability>urn:ietf:params:netconf:base:1.1</capability></capabilities></hello>]]>]]>" "^<hello $DEFAULTONLY><capabilities><capability>urn:ietf:params:netconf:base:1.1</capability><capability>urn:ietf:params:netconf:base:1.0</capability>
<capability>urn:ietf:params:netconf:capability:yang-library:1.0?revision=2019-01-04&amp;module-set-id=42</capability>
<capability>urn:ietf:params:netconf:capability:candidate:1.0</capability>
<capability>urn:ietf:params:netconf:capability:validate:1.1</capability>
<capability>urn:ietf:params:netconf:capability:xpath:1.0</capability>
<capability>urn:ietf:params:netconf:capability:notification:1.0</capability>
<capability>urn:ietf:params:netconf:capability:startup:1.0</capability>
<capability>urn:ietf:params:netconf:capability:with-defaults:1.0?basic-mode=explicit&amp;also-supported=report-all,trim,report-all-tagged</capability>
</capabilities><session-id>[0-9]*</session-id></hello>]]>]]>$" '^$'
# Actually non-standard to reply on wrong hello with rpc-error, but may be useful
new "Netconf snd hello with extra element"

View file

@ -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 "<hello $DEFAULTONLY><capabilities><capability>urn:ietf:params:netconf:base:1.1</capability><capability>urn:ietf:params:netconf:base:1.0</capability><capability>urn:ietf:params:netconf:capability:yang-library:1.0?revision=2019-01-04&amp;module-set-id=42</capability><capability>urn:ietf:params:netconf:capability:candidate:1.0</capability><capability>urn:ietf:params:netconf:capability:validate:1.1</capability><capability>urn:ietf:params:netconf:capability:startup:1.0</capability><capability>urn:ietf:params:netconf:capability:xpath:1.0</capability><capability>urn:ietf:params:netconf:capability:notification:1.0</capability><capability>urn:ietf:params:netconf:capability:with-defaults:1.0?basic-mode=explicit&amp;also-supported=report-all,trim,report-all-tagged</capability></capabilities><session-id>2</session-id></hello>" "<rpc-reply $DEFAULTNS><data/></rpc-reply>"
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 "<hello $DEFAULTONLY><capabilities><capability>urn:ietf:params:netconf:base:1.1</capability><capability>urn:ietf:params:netconf:base:1.0</capability><capability>urn:ietf:params:netconf:capability:yang-library:1.0?revision=2019-01-04&amp;module-set-id=42</capability><capability>urn:ietf:params:netconf:capability:candidate:1.0</capability><capability>urn:ietf:params:netconf:capability:validate:1.1</capability><capability>urn:ietf:params:netconf:capability:xpath:1.0</capability><capability>urn:ietf:params:netconf:capability:with-defaults:1.0?basic-mode=explicit&amp;also-supported=report-all,trim,report-all-tagged</capability><capability>urn:ietf:params:netconf:capability:notification:1.0</capability></capabilities><session-id>2</session-id></hello>" "<rpc-reply $DEFAULTNS><data/></rpc-reply>"
# Wait
wait