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:
parent
8abcda6f85
commit
11eccd5478
16 changed files with 177 additions and 349 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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_ */
|
||||
|
|
|
|||
|
|
@ -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_ */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
/*
|
||||
* t
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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&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&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&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&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"
|
||||
|
|
|
|||
|
|
@ -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&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&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&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&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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue