Backend daemon startup modes
This commit is contained in:
parent
23e40384f7
commit
496d676ad3
26 changed files with 769 additions and 280 deletions
30
CHANGELOG.md
30
CHANGELOG.md
|
|
@ -1,7 +1,15 @@
|
|||
# Clixon CHANGELOG
|
||||
# 3.3.3 (Upcoming)
|
||||
|
||||
## 3.3.3 Upcoming
|
||||
### Known issues
|
||||
### Major changes:
|
||||
* Introducing backend daemon startup modes. The flags -IRCr and option CLICON_USE_STARTUP_CONFIG are replaced with command-line option -s <mode> and option CLICON_STARTUP_MODE. You need to replace the starting of clixon_backend as follows:
|
||||
-I replace with "init" (as -s command line option or CLICON_STARTUP_MODE option)
|
||||
-CIr replace with "running"
|
||||
null replace with "none"
|
||||
CLICON_USE_STARTUP_CONFIG=1 replace with "startup"
|
||||
Backward compatibility is enabled by defining BACKEND_STARTUP_BACKWARD_COMPAT in include/clixon_custom.h
|
||||
|
||||
### Minor changes:
|
||||
* When user callbacks such as statedata() call returns -1, clixon_backend no
|
||||
longer silently exits. Instead a log is printed and an RPC error is returned.
|
||||
* Added Floating point and negative number support to JSON
|
||||
|
|
@ -45,7 +53,7 @@ clixon_cli -f /usr/local/etc/routing.conf -1x
|
|||
* Support for non-line scrolling in CLI, eg wrap lines. Set with:
|
||||
CLICON_CLI_LINESCROLLING 0
|
||||
|
||||
## 3.3.2 Aug 27 2017
|
||||
# 3.3.2 (Aug 27 2017)
|
||||
|
||||
### Known issues
|
||||
* Please use text datastore, key-value datastore no up-to-date
|
||||
|
|
@ -138,7 +146,7 @@ If you submit "nopresence" without a leaf, it will automatically be removed:
|
|||
* Restconf GET will return state data also, if defined.
|
||||
* You need to define state data in a backend callback. See the example and documentation for more details.
|
||||
|
||||
### Minor changes:
|
||||
### Minor Changes
|
||||
* Added xpath support for predicate: current(), eg /interface[name=current()/../name]
|
||||
* Added prefix parsing of xpath, allowing eg /p:x/p:y, but prefix ignored.
|
||||
* Corrected Yang union CLI generation and type validation. Recursive unions did not work.
|
||||
|
|
@ -154,7 +162,7 @@ If you submit "nopresence" without a leaf, it will automatically be removed:
|
|||
* Removed vector return values from xmldb_get()
|
||||
* Generalized yang type resolution to all included (sub)modules not just the topmost
|
||||
|
||||
## 3.3.1 June 7 2017
|
||||
# 3.3.1 (June 7 2017)
|
||||
|
||||
* Fixed yang leafref cli completion for absolute paths.
|
||||
|
||||
|
|
@ -162,9 +170,7 @@ If you submit "nopresence" without a leaf, it will automatically be removed:
|
|||
|
||||
* Strings in xmldb_put not properly encoded, eg eth/0 became eth.00000
|
||||
|
||||
## 3.3.0
|
||||
|
||||
May 2017
|
||||
# 3.3.0 (May 2017)
|
||||
|
||||
* Datastore text module is now default.
|
||||
|
||||
|
|
@ -205,7 +211,7 @@ May 2017
|
|||
Instead use the rpc calls in clixon_proto_client.[ch]
|
||||
In clients (eg cli/netconf) replace xmldb_get() in client code with
|
||||
clicon_rpc_get_config().
|
||||
If you use the vector arguments of xmldb_get(), replace as follows:
|
||||
pIf you use the vector arguments of xmldb_get(), replace as follows:
|
||||
xmldb_get(h, db, api_path, &xt, &xvec, &xlen);
|
||||
with
|
||||
clicon_rpc_get_config(h, dbstr, api_path, &xt);
|
||||
|
|
@ -273,7 +279,9 @@ May 2017
|
|||
* Added union type check for non-cli (eg xml) input
|
||||
* Empty yang type. Relaxed yang types for unions, eg two strings with different length.
|
||||
|
||||
Dec 2016: Dual license: both GPLv3 and APLv2
|
||||
# (Dec 2016)
|
||||
* Dual license: both GPLv3 and APLv2
|
||||
|
||||
Feb 2016: Forked new clixon repository from clicon
|
||||
# (Feb 2016)
|
||||
* Forked new clixon repository from clicon
|
||||
|
||||
|
|
|
|||
|
|
@ -73,7 +73,11 @@
|
|||
#include "backend_handle.h"
|
||||
|
||||
/* Command line options to be passed to getopt(3) */
|
||||
#define BACKEND_OPTS "hD:f:d:b:Fzu:P:1IRCc:rg:py:x:"
|
||||
#ifdef BACKEND_STARTUP_BACKWARD_COMPAT
|
||||
#define BACKEND_OPTS "hD:f:d:b:Fzu:P:1s:c:IRCrg:py:x:" /* substitute s: for IRCc:r */
|
||||
#else
|
||||
#define BACKEND_OPTS "hD:f:d:b:Fzu:P:1s:c:g:py:x:" /* substitute s: for IRCc:r */
|
||||
#endif
|
||||
|
||||
/*! Terminate. Cannot use h after this */
|
||||
static int
|
||||
|
|
@ -114,8 +118,7 @@ backend_sig_term(int arg)
|
|||
clicon_exit_set(); /* checked in event_loop() */
|
||||
}
|
||||
|
||||
/*
|
||||
* usage
|
||||
/*! usage
|
||||
*/
|
||||
static void
|
||||
usage(char *argv0, clicon_handle h)
|
||||
|
|
@ -137,11 +140,14 @@ usage(char *argv0, clicon_handle h)
|
|||
" -1\t\tRun once and then quit (dont wait for events)\n"
|
||||
" -u <path>\tConfig UNIX domain path / ip address (default: %s)\n"
|
||||
" -P <file>\tPid filename (default: %s)\n"
|
||||
" -s <mode>\tSpecify backend startup mode: none|startup|running|init (replaces -IRCc:r:\n"
|
||||
" -c <file>\tLoad extra xml configuration, but don't commit.\n"
|
||||
#ifdef BACKEND_STARTUP_BACKWARD_COMPAT
|
||||
" -I\t\tInitialize running state database\n"
|
||||
" -R\t\tCall plugin_reset() in plugins to reset system state in running db (use with -I)\n"
|
||||
" -C\t\tCall plugin_reset() in plugins to reset system state in candidate db (use with -I)\n"
|
||||
" -c <file>\tLoad specified application config.\n"
|
||||
" -r\t\tReload running database\n"
|
||||
#endif /* BACKEND_STARTUP_BACKWARD_COMPAT */
|
||||
" -p \t\tPrint database yang specification\n"
|
||||
" -g <group>\tClient membership required to this group (default: %s)\n"
|
||||
" -y <file>\tOverride yang spec file (dont include .yang suffix)\n"
|
||||
|
|
@ -166,69 +172,26 @@ db_reset(clicon_handle h,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*! Initialize running-config from file application configuration
|
||||
*
|
||||
* @param[in] h clicon handle
|
||||
* @param[in] app_config_file clicon application configuration file
|
||||
* @param[in] running_db Name of running db
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error. clicon_err set
|
||||
/*! Merge db1 into db2 without commit
|
||||
*/
|
||||
static int
|
||||
rundb_main(clicon_handle h,
|
||||
char *app_config_file)
|
||||
db_merge(clicon_handle h,
|
||||
const char *db1,
|
||||
const char *db2)
|
||||
{
|
||||
int retval = -1;
|
||||
int fd = -1;
|
||||
cxobj *xt = NULL;
|
||||
cxobj *xn;
|
||||
int retval = -1;
|
||||
cxobj *xt = NULL;
|
||||
|
||||
if (xmldb_create(h, "tmp") < 0)
|
||||
/* Get data as xml from db1 */
|
||||
if (xmldb_get(h, (char*)db1, NULL, 1, &xt) < 0)
|
||||
goto done;
|
||||
if (xmldb_copy(h, "running", "tmp") < 0){
|
||||
clicon_err(OE_UNIX, errno, "file copy");
|
||||
goto done;
|
||||
}
|
||||
if ((fd = open(app_config_file, O_RDONLY)) < 0){
|
||||
clicon_err(OE_UNIX, errno, "open(%s)", app_config_file);
|
||||
goto done;
|
||||
}
|
||||
if (clicon_xml_parse_file(fd, &xt, "</clicon>") < 0)
|
||||
goto done;
|
||||
if ((xn = xml_child_i(xt, 0)) != NULL)
|
||||
if (xmldb_put(h, "tmp", OP_MERGE, xn) < 0)
|
||||
goto done;
|
||||
if (candidate_commit(h, "tmp") < 0)
|
||||
goto done;
|
||||
if (xmldb_delete(h, "tmp") < 0)
|
||||
/* Merge xml into db2. WIthout commit */
|
||||
if (xmldb_put(h, (char*)db2, OP_MERGE, xt) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
done:
|
||||
if (xt)
|
||||
xml_free(xt);
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
candb_reset(clicon_handle h)
|
||||
{
|
||||
int retval = -1;
|
||||
|
||||
if (xmldb_copy(h, "running", "tmp") < 0){
|
||||
clicon_err(OE_UNIX, errno, "file copy");
|
||||
goto done;
|
||||
}
|
||||
/* Request plugins to reset system state, eg initiate running from system
|
||||
* -R
|
||||
*/
|
||||
if (plugin_reset_state(h, "tmp") < 0)
|
||||
goto done;
|
||||
if (candidate_commit(h, "tmp") < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -291,6 +254,337 @@ backend_log_cb(int level,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Call plugin_start with -- user options */
|
||||
static int
|
||||
plugin_start_useroptions(clicon_handle h,
|
||||
char *argv0,
|
||||
int argc,
|
||||
char **argv)
|
||||
{
|
||||
char *tmp;
|
||||
|
||||
tmp = *(argv-1);
|
||||
*(argv-1) = argv0;
|
||||
if (plugin_start_argv(h, argc+1, argv-1) < 0)
|
||||
return -1;
|
||||
*(argv-1) = tmp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef BACKEND_STARTUP_BACKWARD_COMPAT
|
||||
/*! Initialize running-config from file application configuration
|
||||
*
|
||||
* @param[in] h clicon handle
|
||||
* @param[in] extraxml_file clicon application configuration file
|
||||
* @param[in] running_db Name of running db
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error. clicon_err set
|
||||
*/
|
||||
static int
|
||||
rundb_main(clicon_handle h,
|
||||
char *extraxml_file)
|
||||
{
|
||||
int retval = -1;
|
||||
int fd = -1;
|
||||
cxobj *xt = NULL;
|
||||
cxobj *xn;
|
||||
|
||||
if (xmldb_create(h, "tmp") < 0)
|
||||
goto done;
|
||||
if (xmldb_copy(h, "running", "tmp") < 0)
|
||||
goto done;
|
||||
if ((fd = open(extraxml_file, O_RDONLY)) < 0){
|
||||
clicon_err(OE_UNIX, errno, "open(%s)", extraxml_file);
|
||||
goto done;
|
||||
}
|
||||
if (clicon_xml_parse_file(fd, &xt, "</clicon>") < 0)
|
||||
goto done;
|
||||
if ((xn = xml_child_i(xt, 0)) != NULL)
|
||||
if (xmldb_put(h, "tmp", OP_MERGE, xn) < 0)
|
||||
goto done;
|
||||
if (candidate_commit(h, "tmp") < 0)
|
||||
goto done;
|
||||
if (xmldb_delete(h, "tmp") < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
if (xt)
|
||||
xml_free(xt);
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
candb_reset(clicon_handle h)
|
||||
{
|
||||
int retval = -1;
|
||||
|
||||
if (xmldb_copy(h, "running", "tmp") < 0)
|
||||
goto done;
|
||||
/* Request plugins to reset system state, eg initiate running from system
|
||||
* -R
|
||||
*/
|
||||
if (plugin_reset_state(h, "tmp") < 0)
|
||||
goto done;
|
||||
if (candidate_commit(h, "tmp") < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Legacy (old-style) startup mode where flags -IRCcr was used
|
||||
*/
|
||||
static int
|
||||
fragmented_startup_mode(clicon_handle h,
|
||||
char *argv0,
|
||||
int argc,
|
||||
char *argv[],
|
||||
int reload_running,
|
||||
int init_rundb,
|
||||
int reset_state_candidate,
|
||||
int reset_state_running,
|
||||
char *extraxml_file)
|
||||
{
|
||||
int retval = -1;
|
||||
|
||||
/* First check for startup config */
|
||||
if (clicon_option_int(h, "CLICON_USE_STARTUP_CONFIG") > 0){
|
||||
if (xmldb_exists(h, "startup") == 1){
|
||||
/* copy startup config -> running */
|
||||
if (xmldb_copy(h, "startup", "running") < 0)
|
||||
goto done;
|
||||
}
|
||||
else
|
||||
if (db_reset(h, "running") < 0)
|
||||
goto done;
|
||||
if (xmldb_create(h, "candidate") < 0)
|
||||
goto done;
|
||||
if (xmldb_copy(h, "running", "candidate") < 0)
|
||||
goto done;
|
||||
}
|
||||
/* If running exists and reload_running set, make a copy to candidate */
|
||||
if (reload_running){
|
||||
if (xmldb_exists(h, "running") != 1){
|
||||
clicon_log(LOG_NOTICE, "%s: -r (reload running) option given but no running_db found, proceeding without", __PROGRAM__);
|
||||
reload_running = 0; /* void it, so we dont commit candidate below */
|
||||
}
|
||||
else
|
||||
if (xmldb_copy(h, "running", "candidate") < 0)
|
||||
goto done;
|
||||
}
|
||||
/* Init running db
|
||||
* -I or if it isnt there
|
||||
*/
|
||||
if (init_rundb || xmldb_exists(h, "running") != 1){
|
||||
if (db_reset(h, "running") < 0)
|
||||
goto done;
|
||||
}
|
||||
/* If candidate does not exist, create it from running */
|
||||
if (xmldb_exists(h, "candidate") != 1){
|
||||
if (xmldb_create(h, "candidate") < 0)
|
||||
goto done;
|
||||
if (xmldb_copy(h, "running", "candidate") < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Load plugins and call plugin_init() */
|
||||
if (plugin_initiate(h) != 0)
|
||||
goto done;
|
||||
|
||||
if (reset_state_candidate){
|
||||
if (candb_reset(h) < 0)
|
||||
goto done;
|
||||
}
|
||||
else
|
||||
if (reset_state_running){
|
||||
if (plugin_reset_state(h, "running") < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (plugin_start_useroptions(h, argv0, argc, argv) <0)
|
||||
goto done;
|
||||
|
||||
if (reload_running){
|
||||
/* This could be a failed validation, and we should not fail for that */
|
||||
(void)candidate_commit(h, "candidate");
|
||||
}
|
||||
|
||||
/* Have we specified a config file to load? eg
|
||||
* -c [<file>]
|
||||
*/
|
||||
if (extraxml_file)
|
||||
if (rundb_main(h, extraxml_file) < 0)
|
||||
goto done;
|
||||
/* Initiate the shared candidate. */
|
||||
if (xmldb_copy(h, "running", "candidate") < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
#endif /* BACKEND_STARTUP_BACKWARD_COMPAT */
|
||||
|
||||
/*! Merge xml in filename into database
|
||||
*/
|
||||
static int
|
||||
load_extraxml(clicon_handle h,
|
||||
char *filename,
|
||||
const char *db)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *xt = NULL;
|
||||
int fd = -1;
|
||||
|
||||
if (filename == NULL)
|
||||
return 0;
|
||||
if ((fd = open(filename, O_RDONLY)) < 0){
|
||||
clicon_err(OE_UNIX, errno, "open(%s)", filename);
|
||||
goto done;
|
||||
}
|
||||
if (clicon_xml_parse_file(fd, &xt, "</config>") < 0)
|
||||
goto done;
|
||||
/* Replace parent w first child */
|
||||
if (xml_rootchild(xt, 0, &xt) < 0)
|
||||
goto done;
|
||||
/* Merge user reset state */
|
||||
if (xmldb_put(h, (char*)db, OP_MERGE, xt) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
if (xt)
|
||||
xml_free(xt);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Clixon none startup modes Do not touch running state
|
||||
*/
|
||||
static int
|
||||
startup_mode_none(clicon_handle h)
|
||||
{
|
||||
int retval = -1;
|
||||
|
||||
/* If it is not there, create candidate from running */
|
||||
if (xmldb_exists(h, "candidate") != 1)
|
||||
if (xmldb_copy(h, "running", "candidate") < 0)
|
||||
goto done;
|
||||
/* Load plugins and call plugin_init() */
|
||||
if (plugin_initiate(h) != 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Clixon init startup modes Start with a completely clean running state
|
||||
*/
|
||||
static int
|
||||
startup_mode_init(clicon_handle h)
|
||||
{
|
||||
int retval = -1;
|
||||
|
||||
/* Reset running, regardless */
|
||||
if (db_reset(h, "running") < 0)
|
||||
goto done;
|
||||
/* If it is not there, create candidate from running */
|
||||
if (xmldb_exists(h, "candidate") != 1)
|
||||
if (xmldb_copy(h, "running", "candidate") < 0)
|
||||
goto done;
|
||||
/* Load plugins and call plugin_init() */
|
||||
if (plugin_initiate(h) != 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Clixon running startup mode: Commit running db configuration into running
|
||||
*
|
||||
copy reset commit merge
|
||||
running----+ |--------------------+-----+------>
|
||||
\ / /
|
||||
candidate +--------------------+ /
|
||||
/
|
||||
tmp |-------+-----+---------+
|
||||
reset extra file
|
||||
*/
|
||||
static int
|
||||
startup_mode_running(clicon_handle h,
|
||||
char *extraxml_file)
|
||||
{
|
||||
int retval = -1;
|
||||
|
||||
/* Stash original running to candidate for later commit */
|
||||
if (xmldb_copy(h, "running", "candidate") < 0)
|
||||
goto done;
|
||||
/* Load plugins and call plugin_init() */
|
||||
if (plugin_initiate(h) != 0)
|
||||
goto done;
|
||||
/* Clear tmp db */
|
||||
if (db_reset(h, "tmp") < 0)
|
||||
goto done;
|
||||
/* Application may define extra xml in its reset function*/
|
||||
if (plugin_reset_state(h, "tmp") < 0)
|
||||
goto done;
|
||||
/* Get application extra xml from file */
|
||||
if (load_extraxml(h, extraxml_file, "tmp") < 0)
|
||||
goto done;
|
||||
/* Commit original running */
|
||||
if (candidate_commit(h, "candidate") < 0)
|
||||
goto done;
|
||||
/* Merge user reset state and extra xml file (no commit) */
|
||||
if (db_merge(h, "tmp", "running") < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Clixon startup startup mode: Commit startup configuration into running state
|
||||
reset commit merge
|
||||
running |--------------------+-----+------>
|
||||
/ /
|
||||
startup --------------------+ /
|
||||
/
|
||||
tmp |-------+-----+---------+
|
||||
reset extra file
|
||||
*/
|
||||
static int
|
||||
startup_mode_startup(clicon_handle h,
|
||||
char *extraxml_file)
|
||||
{
|
||||
int retval = -1;
|
||||
|
||||
/* If startup does not exist, clear it */
|
||||
if (xmldb_exists(h, "startup") != 1) /* diff */
|
||||
if (xmldb_create(h, "startup") < 0) /* diff */
|
||||
return -1;
|
||||
/* Load plugins and call plugin_init() */
|
||||
if (plugin_initiate(h) != 0)
|
||||
goto done;
|
||||
/* Clear tmp db */
|
||||
if (db_reset(h, "tmp") < 0)
|
||||
goto done;
|
||||
/* Application may define extra xml in its reset function*/
|
||||
if (plugin_reset_state(h, "tmp") < 0)
|
||||
goto done;
|
||||
/* Get application extra xml from file */
|
||||
if (load_extraxml(h, extraxml_file, "tmp") < 0)
|
||||
goto done;
|
||||
/* Commit startup */
|
||||
if (candidate_commit(h, "startup") < 0) /* diff */
|
||||
goto done;
|
||||
/* Merge user reset state and extra xml file (no commit) */
|
||||
if (db_merge(h, "tmp", "running") < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
|
|
@ -298,14 +592,16 @@ main(int argc, char **argv)
|
|||
int zap;
|
||||
int foreground;
|
||||
int once;
|
||||
int init_rundb;
|
||||
int reload_running;
|
||||
int reset_state_running;
|
||||
int reset_state_candidate;
|
||||
char *app_config_file = NULL;
|
||||
enum startup_mode_t startup_mode;
|
||||
#ifdef BACKEND_STARTUP_BACKWARD_COMPAT
|
||||
int init_rundb = 0;
|
||||
int reset_state_running = 0;
|
||||
int reset_state_candidate = 0;
|
||||
int reload_running = 0;
|
||||
#endif
|
||||
char *extraxml_file;
|
||||
char *config_group;
|
||||
char *argv0 = argv[0];
|
||||
char *tmp;
|
||||
struct stat st;
|
||||
clicon_handle h;
|
||||
int help = 0;
|
||||
|
|
@ -317,7 +613,6 @@ main(int argc, char **argv)
|
|||
char *xmldb_plugin;
|
||||
|
||||
/* In the startup, logs to stderr & syslog and debug flag set later */
|
||||
|
||||
clicon_log_init(__PROGRAM__, LOG_INFO, CLICON_LOG_STDERR|CLICON_LOG_SYSLOG);
|
||||
/* Initiate CLICON handle */
|
||||
if ((h = backend_handle_init()) == NULL)
|
||||
|
|
@ -327,10 +622,7 @@ main(int argc, char **argv)
|
|||
foreground = 0;
|
||||
once = 0;
|
||||
zap = 0;
|
||||
init_rundb = 0;
|
||||
reload_running = 0;
|
||||
reset_state_running = 0;
|
||||
reset_state_candidate = 0;
|
||||
extraxml_file = NULL;
|
||||
|
||||
/*
|
||||
* Command-line options for help, debug, and config-file
|
||||
|
|
@ -402,32 +694,41 @@ main(int argc, char **argv)
|
|||
case 'z': /* Zap other process */
|
||||
zap++;
|
||||
break;
|
||||
case 'u': /* config unix domain path / ip address */
|
||||
case 'u': /* config unix domain path / ip address */
|
||||
if (!strlen(optarg))
|
||||
usage(argv[0], h);
|
||||
clicon_option_str_set(h, "CLICON_SOCK", optarg);
|
||||
break;
|
||||
case 'P': /* pidfile */
|
||||
clicon_option_str_set(h, "CLICON_BACKEND_PIDFILE", optarg);
|
||||
break;
|
||||
case 'I': /* Initiate running db */
|
||||
init_rundb++;
|
||||
break;
|
||||
case 'R': /* Reset state directly into running */
|
||||
reset_state_running++;
|
||||
break;
|
||||
case 'C': /* Reset state into candidate and then commit it */
|
||||
reset_state_candidate++;
|
||||
break;
|
||||
case 'c': /* Load application config */
|
||||
app_config_file = optarg;
|
||||
break;
|
||||
case 'r': /* Reload running */
|
||||
reload_running++;
|
||||
break;
|
||||
case 'g': /* config socket group */
|
||||
clicon_option_str_set(h, "CLICON_SOCK_GROUP", optarg);
|
||||
break;
|
||||
break;
|
||||
case 'P': /* pidfile */
|
||||
clicon_option_str_set(h, "CLICON_BACKEND_PIDFILE", optarg);
|
||||
break;
|
||||
case 's' : /* startup mode */
|
||||
clicon_option_str_set(h, "CLICON_STARTUP_MODE", optarg);
|
||||
if (clicon_startup_mode(h) < 0){
|
||||
fprintf(stderr, "Invalid startup mode: %s\n", optarg);
|
||||
usage(argv[0], h);
|
||||
}
|
||||
break;
|
||||
case 'c': /* Load application config */
|
||||
extraxml_file = optarg;
|
||||
break;
|
||||
#ifdef BACKEND_STARTUP_BACKWARD_COMPAT
|
||||
case 'I': /* Initiate running db */
|
||||
init_rundb++;
|
||||
break;
|
||||
case 'R': /* Reset state directly into running */
|
||||
reset_state_running++;
|
||||
break;
|
||||
case 'C': /* Reset state into candidate and then commit it */
|
||||
reset_state_candidate++;
|
||||
break;
|
||||
case 'r': /* Reload running */
|
||||
reload_running++;
|
||||
break;
|
||||
#endif /* BACKEND_STARTUP_BACKWARD_COMPAT */
|
||||
case 'g': /* config socket group */
|
||||
clicon_option_str_set(h, "CLICON_SOCK_GROUP", optarg);
|
||||
break;
|
||||
case 'p' : /* Print spec */
|
||||
printspec++;
|
||||
break;
|
||||
|
|
@ -522,87 +823,52 @@ main(int argc, char **argv)
|
|||
goto done;
|
||||
if (xmldb_setopt(h, "yangspec", clicon_dbspec_yang(h)) < 0)
|
||||
goto done;
|
||||
|
||||
/* First check for startup config
|
||||
XXX the options below have become out-of-hand.
|
||||
Too complex, need to simplify*/
|
||||
if (clicon_option_int(h, "CLICON_USE_STARTUP_CONFIG") > 0){
|
||||
if (xmldb_exists(h, "startup") == 1){
|
||||
/* copy startup config -> running */
|
||||
if (xmldb_copy(h, "startup", "running") < 0)
|
||||
goto done;
|
||||
}
|
||||
else
|
||||
if (db_reset(h, "running") < 0)
|
||||
goto done;
|
||||
if (xmldb_create(h, "candidate") < 0)
|
||||
/* If startup mode is not defined, eg via OPTION or -s, assume old method */
|
||||
startup_mode = clicon_startup_mode(h);
|
||||
if (startup_mode == -1){ /* Old style, fragmented mode, phase out */
|
||||
#ifdef BACKEND_STARTUP_BACKWARD_COMPAT
|
||||
if (fragmented_startup_mode(h,
|
||||
argv0, argc, argv,
|
||||
reload_running, init_rundb,
|
||||
reset_state_candidate, reset_state_running,
|
||||
extraxml_file
|
||||
) < 0)
|
||||
goto done;
|
||||
#else
|
||||
clicon_log(LOG_ERR, "Startup mode indefined. Specify option CLICON_STARTUP_MODE or specify -s option to clicon_backend.\n");
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
/* Init running db if it is not there
|
||||
*/
|
||||
if (xmldb_exists(h, "running") != 1)
|
||||
if (xmldb_create(h, "running") < 0)
|
||||
return -1;
|
||||
switch (startup_mode){
|
||||
case SM_NONE:
|
||||
if (startup_mode_none(h) < 0)
|
||||
goto done;
|
||||
break;
|
||||
case SM_INIT: /* -I */
|
||||
if (startup_mode_init(h) < 0)
|
||||
goto done;
|
||||
break;
|
||||
case SM_RUNNING: /* -CIr */
|
||||
if (startup_mode_running(h, extraxml_file) < 0)
|
||||
goto done;
|
||||
break;
|
||||
case SM_STARTUP: /* startup configuration */
|
||||
if (startup_mode_startup(h, extraxml_file) < 0)
|
||||
goto done;
|
||||
break;
|
||||
}
|
||||
/* Initiate the shared candidate. */
|
||||
if (xmldb_copy(h, "running", "candidate") < 0)
|
||||
goto done;
|
||||
}
|
||||
/* If running exists and reload_running set, make a copy to candidate */
|
||||
if (reload_running){
|
||||
if (xmldb_exists(h, "running") != 1){
|
||||
clicon_log(LOG_NOTICE, "%s: -r (reload running) option given but no running_db found, proceeding without", __PROGRAM__);
|
||||
reload_running = 0; /* void it, so we dont commit candidate below */
|
||||
}
|
||||
else
|
||||
if (xmldb_copy(h, "running", "candidate") < 0)
|
||||
goto done;
|
||||
}
|
||||
/* Init running db
|
||||
* -I or if it isnt there
|
||||
*/
|
||||
if (init_rundb || xmldb_exists(h, "running") != 1){
|
||||
if (db_reset(h, "running") < 0)
|
||||
/* Call plugin_start with user -- options */
|
||||
if (plugin_start_useroptions(h, argv0, argc, argv) <0)
|
||||
goto done;
|
||||
}
|
||||
/* If candidate does not exist, create it from running */
|
||||
if (xmldb_exists(h, "candidate") != 1){
|
||||
if (xmldb_create(h, "candidate") < 0)
|
||||
goto done;
|
||||
if (xmldb_copy(h, "running", "candidate") < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Initialize plugins
|
||||
(also calls plugin_init() and plugin_start(argc,argv) in each plugin */
|
||||
if (plugin_initiate(h) != 0)
|
||||
goto done;
|
||||
|
||||
if (reset_state_candidate){
|
||||
if (candb_reset(h) < 0)
|
||||
goto done;
|
||||
}
|
||||
else
|
||||
if (reset_state_running){
|
||||
if (plugin_reset_state(h, "running") < 0)
|
||||
goto done;
|
||||
}
|
||||
/* Call plugin_start */
|
||||
tmp = *(argv-1);
|
||||
*(argv-1) = argv0;
|
||||
if (plugin_start_hooks(h, argc+1, argv-1) < 0)
|
||||
goto done;
|
||||
*(argv-1) = tmp;
|
||||
|
||||
if (reload_running){
|
||||
/* This could be a failed validation, and we should not fail for that */
|
||||
(void)candidate_commit(h, "candidate");
|
||||
}
|
||||
|
||||
/* Have we specified a config file to load? eg
|
||||
* -c [<file>]
|
||||
*/
|
||||
if (app_config_file)
|
||||
if (rundb_main(h, app_config_file) < 0)
|
||||
goto done;
|
||||
|
||||
/* Initiate the shared candidate. Maybe we should not do this?
|
||||
* Too strict access
|
||||
*/
|
||||
if (xmldb_copy(h, "running", "candidate") < 0)
|
||||
goto done;
|
||||
if (once)
|
||||
goto done;
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@
|
|||
* @note the following should match the prototypes in clixon_backend.h
|
||||
*/
|
||||
#define PLUGIN_RESET "plugin_reset"
|
||||
typedef int (plgreset_t)(clicon_handle h, char *dbname); /* Reset system status */
|
||||
typedef int (plgreset_t)(clicon_handle h, const char *db); /* Reset system status */
|
||||
|
||||
/*! Plugin callback, if defined called to get state data from plugin
|
||||
* @param[in] h Clicon handle
|
||||
|
|
@ -253,19 +253,18 @@ backend_plugin_load (clicon_handle h,
|
|||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
plugin_reset_state(clicon_handle h,
|
||||
char *dbname)
|
||||
plugin_reset_state(clicon_handle h,
|
||||
const char *db)
|
||||
{
|
||||
int i;
|
||||
struct plugin *p;
|
||||
|
||||
|
||||
for (i = 0; i < _nplugins; i++) {
|
||||
p = &_plugins[i];
|
||||
if (p->p_reset) {
|
||||
clicon_debug(1, "Calling plugin_reset() for %s\n",
|
||||
p->p_name);
|
||||
if (((p->p_reset)(h, dbname)) < 0) {
|
||||
if (((p->p_reset)(h, db)) < 0) {
|
||||
clicon_err(OE_FATAL, 0, "plugin_reset() failed for %s\n",
|
||||
p->p_name);
|
||||
return -1;
|
||||
|
|
@ -283,7 +282,7 @@ plugin_reset_state(clicon_handle h,
|
|||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
plugin_start_hooks(clicon_handle h,
|
||||
plugin_start_argv(clicon_handle h,
|
||||
int argc,
|
||||
char **argv)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -66,8 +66,8 @@ int backend_plugin_init(clicon_handle h);
|
|||
int plugin_initiate(clicon_handle h);
|
||||
int plugin_finish(clicon_handle h);
|
||||
|
||||
int plugin_reset_state(clicon_handle h, char *dbname);
|
||||
int plugin_start_hooks(clicon_handle h, int argc, char **argv);
|
||||
int plugin_reset_state(clicon_handle h, const char *db);
|
||||
int plugin_start_argv(clicon_handle h, int argc, char **argv);
|
||||
|
||||
int backend_statedata_call(clicon_handle h, char *xpath, cxobj *xml);
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ int plugin_exit(clicon_handle h);
|
|||
/*! Reset system state to original state. Eg at reboot before running thru config.
|
||||
* @see plgreset_t
|
||||
*/
|
||||
int plugin_reset(clicon_handle h, char *dbname);
|
||||
int plugin_reset(clicon_handle h, const char *db);
|
||||
|
||||
/*! Retreive statedata, add statedata to XML tree
|
||||
* @see plgstatedata_ t
|
||||
|
|
|
|||
|
|
@ -150,8 +150,8 @@ static int _startup_locked = 0;
|
|||
*/
|
||||
static int
|
||||
kv_db2file(struct kv_handle *kh,
|
||||
char *db,
|
||||
char **filename)
|
||||
const char *db,
|
||||
char **filename)
|
||||
{
|
||||
int retval = -1;
|
||||
cbuf *cb;
|
||||
|
|
@ -565,7 +565,7 @@ kv_setopt(xmldb_handle xh,
|
|||
*/
|
||||
int
|
||||
kv_get(xmldb_handle xh,
|
||||
char *db,
|
||||
const char *db,
|
||||
char *xpath,
|
||||
int config,
|
||||
cxobj **xtop)
|
||||
|
|
@ -783,7 +783,7 @@ put(char *dbfile,
|
|||
*/
|
||||
int
|
||||
kv_put(xmldb_handle xh,
|
||||
char *db,
|
||||
const char *db,
|
||||
enum operation_type op,
|
||||
cxobj *xt)
|
||||
{
|
||||
|
|
@ -836,8 +836,8 @@ kv_put(xmldb_handle xh,
|
|||
*/
|
||||
int
|
||||
kv_copy(xmldb_handle xh,
|
||||
char *from,
|
||||
char *to)
|
||||
const char *from,
|
||||
const char *to)
|
||||
{
|
||||
int retval = -1;
|
||||
struct kv_handle *kh = handle(xh);
|
||||
|
|
@ -869,8 +869,8 @@ kv_copy(xmldb_handle xh,
|
|||
*/
|
||||
int
|
||||
kv_lock(xmldb_handle xh,
|
||||
char *db,
|
||||
int pid)
|
||||
const char *db,
|
||||
int pid)
|
||||
{
|
||||
int retval = -1;
|
||||
// struct kv_handle *kh = handle(xh);
|
||||
|
|
@ -900,7 +900,7 @@ kv_lock(xmldb_handle xh,
|
|||
*/
|
||||
int
|
||||
kv_unlock(xmldb_handle xh,
|
||||
char *db)
|
||||
const char *db)
|
||||
{
|
||||
int retval = -1;
|
||||
// struct kv_handle *kh = handle(xh);
|
||||
|
|
@ -949,7 +949,7 @@ kv_unlock_all(xmldb_handle xh,
|
|||
*/
|
||||
int
|
||||
kv_islocked(xmldb_handle xh,
|
||||
char *db)
|
||||
const char *db)
|
||||
{
|
||||
int retval = -1;
|
||||
// struct kv_handle *kh = handle(xh);
|
||||
|
|
@ -974,7 +974,7 @@ kv_islocked(xmldb_handle xh,
|
|||
*/
|
||||
int
|
||||
kv_exists(xmldb_handle xh,
|
||||
char *db)
|
||||
const char *db)
|
||||
{
|
||||
int retval = -1;
|
||||
struct kv_handle *kh = handle(xh);
|
||||
|
|
@ -1001,7 +1001,7 @@ kv_exists(xmldb_handle xh,
|
|||
*/
|
||||
int
|
||||
kv_delete(xmldb_handle xh,
|
||||
char *db)
|
||||
const char *db)
|
||||
{
|
||||
int retval = -1;
|
||||
struct kv_handle *kh = handle(xh);
|
||||
|
|
@ -1026,7 +1026,7 @@ kv_delete(xmldb_handle xh,
|
|||
*/
|
||||
int
|
||||
kv_create(xmldb_handle xh,
|
||||
char *db)
|
||||
const char *db)
|
||||
{
|
||||
int retval = -1;
|
||||
struct kv_handle *kh = handle(xh);
|
||||
|
|
|
|||
|
|
@ -39,16 +39,16 @@
|
|||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
int kv_get(xmldb_handle h, char *db, char *xpath, int config, cxobj **xtop);
|
||||
int kv_put(xmldb_handle h, char *db, enum operation_type op, cxobj *xt);
|
||||
int kv_get(xmldb_handle h, const char *db, char *xpath, int config, cxobj **xtop);
|
||||
int kv_put(xmldb_handle h, const char *db, enum operation_type op, cxobj *xt);
|
||||
int kv_dump(FILE *f, char *dbfilename, char *rxkey);
|
||||
int kv_copy(xmldb_handle h, char *from, char *to);
|
||||
int kv_lock(xmldb_handle h, char *db, int pid);
|
||||
int kv_unlock(xmldb_handle h, char *db);
|
||||
int kv_copy(xmldb_handle h, const char *from, const char *to);
|
||||
int kv_lock(xmldb_handle h, const char *db, int pid);
|
||||
int kv_unlock(xmldb_handle h, const char *db);
|
||||
int kv_unlock_all(xmldb_handle h, int pid);
|
||||
int kv_islocked(xmldb_handle h, char *db);
|
||||
int kv_exists(xmldb_handle h, char *db);
|
||||
int kv_delete(xmldb_handle h, char *db);
|
||||
int kv_init(xmldb_handle h, char *db);
|
||||
int kv_islocked(xmldb_handle h, const char *db);
|
||||
int kv_exists(xmldb_handle h, const char *db);
|
||||
int kv_delete(xmldb_handle h, const char *db);
|
||||
int kv_init(xmldb_handle h, const char *db);
|
||||
|
||||
#endif /* _CLIXON_KEYVALUE_H */
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ text_handle_check(xmldb_handle xh)
|
|||
*/
|
||||
static int
|
||||
text_db2file(struct text_handle *th,
|
||||
char *db,
|
||||
const char *db,
|
||||
char **filename)
|
||||
{
|
||||
int retval = -1;
|
||||
|
|
@ -281,7 +281,7 @@ singleconfigroot(cxobj *xt,
|
|||
*/
|
||||
int
|
||||
text_get(xmldb_handle xh,
|
||||
char *db,
|
||||
const char *db,
|
||||
char *xpath,
|
||||
int config,
|
||||
cxobj **xtop)
|
||||
|
|
@ -681,7 +681,7 @@ xml_container_presence(cxobj *x,
|
|||
*/
|
||||
int
|
||||
text_put(xmldb_handle xh,
|
||||
char *db,
|
||||
const char *db,
|
||||
enum operation_type op,
|
||||
cxobj *x1)
|
||||
{
|
||||
|
|
@ -807,8 +807,8 @@ text_put(xmldb_handle xh,
|
|||
*/
|
||||
int
|
||||
text_copy(xmldb_handle xh,
|
||||
char *from,
|
||||
char *to)
|
||||
const char *from,
|
||||
const char *to)
|
||||
{
|
||||
int retval = -1;
|
||||
struct text_handle *th = handle(xh);
|
||||
|
|
@ -840,7 +840,7 @@ text_copy(xmldb_handle xh,
|
|||
*/
|
||||
int
|
||||
text_lock(xmldb_handle xh,
|
||||
char *db,
|
||||
const char *db,
|
||||
int pid)
|
||||
{
|
||||
struct text_handle *th = handle(xh);
|
||||
|
|
@ -860,7 +860,7 @@ text_lock(xmldb_handle xh,
|
|||
*/
|
||||
int
|
||||
text_unlock(xmldb_handle xh,
|
||||
char *db)
|
||||
const char *db)
|
||||
{
|
||||
struct text_handle *th = handle(xh);
|
||||
int zero = 0;
|
||||
|
|
@ -905,7 +905,7 @@ text_unlock_all(xmldb_handle xh,
|
|||
*/
|
||||
int
|
||||
text_islocked(xmldb_handle xh,
|
||||
char *db)
|
||||
const char *db)
|
||||
{
|
||||
struct text_handle *th = handle(xh);
|
||||
size_t vlen;
|
||||
|
|
@ -926,7 +926,7 @@ text_islocked(xmldb_handle xh,
|
|||
*/
|
||||
int
|
||||
text_exists(xmldb_handle xh,
|
||||
char *db)
|
||||
const char *db)
|
||||
{
|
||||
|
||||
int retval = -1;
|
||||
|
|
@ -954,7 +954,7 @@ text_exists(xmldb_handle xh,
|
|||
*/
|
||||
int
|
||||
text_delete(xmldb_handle xh,
|
||||
char *db)
|
||||
const char *db)
|
||||
{
|
||||
int retval = -1;
|
||||
char *filename = NULL;
|
||||
|
|
@ -974,6 +974,7 @@ text_delete(xmldb_handle xh,
|
|||
}
|
||||
|
||||
/*! Create / init database
|
||||
* If it exists dont change.
|
||||
* @param[in] xh XMLDB handle
|
||||
* @param[in] db Database
|
||||
* @retval 0 OK
|
||||
|
|
@ -981,7 +982,7 @@ text_delete(xmldb_handle xh,
|
|||
*/
|
||||
int
|
||||
text_create(xmldb_handle xh,
|
||||
char *db)
|
||||
const char *db)
|
||||
{
|
||||
int retval = -1;
|
||||
struct text_handle *th = handle(xh);
|
||||
|
|
|
|||
|
|
@ -39,16 +39,16 @@
|
|||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
int text_get(xmldb_handle h, char *db, char *xpath, int config, cxobj **xtop);
|
||||
int text_put(xmldb_handle h, char *db, enum operation_type op, cxobj *xt);
|
||||
int text_get(xmldb_handle h, const char *db, char *xpath, int config, cxobj **xtop);
|
||||
int text_put(xmldb_handle h, const char *db, enum operation_type op, cxobj *xt);
|
||||
int text_dump(FILE *f, char *dbfilename, char *rxkey);
|
||||
int text_copy(xmldb_handle h, char *from, char *to);
|
||||
int text_lock(xmldb_handle h, char *db, int pid);
|
||||
int text_unlock(xmldb_handle h, char *db);
|
||||
int text_copy(xmldb_handle h, const char *from, const char *to);
|
||||
int text_lock(xmldb_handle h, const char *db, int pid);
|
||||
int text_unlock(xmldb_handle h, const char *db);
|
||||
int text_unlock_all(xmldb_handle h, int pid);
|
||||
int text_islocked(xmldb_handle h, char *db);
|
||||
int text_exists(xmldb_handle h, char *db);
|
||||
int text_delete(xmldb_handle h, char *db);
|
||||
int text_init(xmldb_handle h, char *db);
|
||||
int text_islocked(xmldb_handle h, const char *db);
|
||||
int text_exists(xmldb_handle h, const char *db);
|
||||
int text_delete(xmldb_handle h, const char *db);
|
||||
int text_init(xmldb_handle h, const char *db);
|
||||
|
||||
#endif /* _CLIXON_XMLDB_TEXT_H */
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ APIs. There are currently plugins for: CLI, Netconf, Restconf, the datastore an
|
|||
Clixon is written in C. The plugins are written in C. The CLI
|
||||
specification uses cligen (http://cligen.se)
|
||||
|
||||
There is a project for writing plugins in Python. It is reasonable
|
||||
simple to spawn an external script from a backend.
|
||||
It is possible ro write plugins in Python. It is reasonable
|
||||
simple to spawn an external script from a backend (but needs to be done).
|
||||
|
||||
## How to best understand Clixon?
|
||||
Run the ietf yang routing example, in the example directory.
|
||||
|
|
|
|||
|
|
@ -179,8 +179,10 @@ plugin_statedata(clicon_handle h,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Plugin initialization
|
||||
/*! Plugin initialization. Create rpc callbacks
|
||||
* plugin_init is called as soon as the plugin has been loaded and is
|
||||
* assumed initialize the plugin's internal state if any as well as register
|
||||
* any callbacks, configuration dependencies.
|
||||
*/
|
||||
int
|
||||
plugin_init(clicon_handle h)
|
||||
|
|
@ -205,3 +207,57 @@ plugin_init(clicon_handle h)
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Plugin state reset. Add xml or set state in backend machine.
|
||||
* Called in each backend plugin. plugin_reset is called after all plugins
|
||||
* have been initialized. This give the application a chance to reset
|
||||
* system state back to a base state.
|
||||
* This is generally done when a system boots up to
|
||||
* make sure the initial system state is well defined. This can be creating
|
||||
* default configuration files for various daemons, set interface flags etc.
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] db Name of database. Not may be other than "running"
|
||||
* In this example, a loopback interface is added
|
||||
*/
|
||||
int
|
||||
plugin_reset(clicon_handle h,
|
||||
const char *db)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *xt = NULL;
|
||||
|
||||
if (clicon_xml_parse_str("<config><interfaces><interface>"
|
||||
"<name>lo</name><type>local</type>"
|
||||
"</interface></interfaces></config>", &xt) < 0)
|
||||
goto done;
|
||||
/* Replace parent w fiorst child */
|
||||
if (xml_rootchild(xt, 0, &xt) < 0)
|
||||
goto done;
|
||||
/* Merge user reset state */
|
||||
if (xmldb_put(h, (char*)db, OP_MERGE, xt) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
if (xt != NULL)
|
||||
free(xt);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Plugin start.
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] argc Argument vector length (args after -- to backend_main)
|
||||
* @param[in] argv Argument vector
|
||||
*
|
||||
* plugin_start is called once everything has been initialized, right before
|
||||
* the main event loop is entered. Command line options can be passed to the
|
||||
* plugins by using "-- <args>" where <args> is any choice of
|
||||
* options specific to the application. These options are passed to the
|
||||
* plugin_start function via the argc and argv arguments which
|
||||
* can be processed with the standard getopt(3).
|
||||
*/
|
||||
int
|
||||
plugin_start(clicon_handle h,
|
||||
int argc,
|
||||
char **argv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,3 +47,10 @@ int strverscmp (__const char *__s1, __const char *__s2);
|
|||
* Experimental
|
||||
*/
|
||||
#define XML_CHILD_HASH 1
|
||||
|
||||
/* Backward compatible clixon backend daemon startup sequences
|
||||
* This has been replaced with -s <mode> and CLICON_STARTUP_MODE
|
||||
* define if enable backward compatible behaviour
|
||||
* Remove in 3.3.4
|
||||
*/
|
||||
#undef BACKEND_STARTUP_BACKWARD_COMPAT
|
||||
|
|
|
|||
|
|
@ -63,6 +63,13 @@ enum genmodel_type{
|
|||
GT_ALL, /* Keywords on all variables */
|
||||
};
|
||||
|
||||
/*! See clixon-config.yang type startup_mode */
|
||||
enum startup_mode_t{
|
||||
SM_NONE=0,
|
||||
SM_STARTUP,
|
||||
SM_RUNNING,
|
||||
SM_INIT
|
||||
};
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
|
|
@ -93,6 +100,7 @@ char *clicon_clispec_dir(clicon_handle h);
|
|||
char *clicon_netconf_dir(clicon_handle h);
|
||||
char *clicon_restconf_dir(clicon_handle h);
|
||||
char *clicon_xmldb_plugin(clicon_handle h);
|
||||
int clicon_startup_mode(clicon_handle h);
|
||||
int clicon_sock_family(clicon_handle h);
|
||||
char *clicon_sock(clicon_handle h);
|
||||
int clicon_sock_port(clicon_handle h);
|
||||
|
|
|
|||
|
|
@ -75,34 +75,34 @@ typedef int (xmldb_getopt_t)(xmldb_handle xh, char *optname, void **value);
|
|||
typedef int (xmldb_setopt_t)(xmldb_handle xh, char *optname, void *value);
|
||||
|
||||
/* Type of xmldb get function */
|
||||
typedef int (xmldb_get_t)(xmldb_handle xh, char *db, char *xpath, int config, cxobj **xtop);
|
||||
typedef int (xmldb_get_t)(xmldb_handle xh, const char *db, char *xpath, int config, cxobj **xtop);
|
||||
|
||||
/* Type of xmldb put function */
|
||||
typedef int (xmldb_put_t)(xmldb_handle xh, char *db, enum operation_type op, cxobj *xt);
|
||||
typedef int (xmldb_put_t)(xmldb_handle xh, const char *db, enum operation_type op, cxobj *xt);
|
||||
|
||||
/* Type of xmldb copy function */
|
||||
typedef int (xmldb_copy_t)(xmldb_handle xh, char *from, char *to);
|
||||
typedef int (xmldb_copy_t)(xmldb_handle xh, const char *from, const char *to);
|
||||
|
||||
/* Type of xmldb lock function */
|
||||
typedef int (xmldb_lock_t)(xmldb_handle xh, char *db, int pid);
|
||||
typedef int (xmldb_lock_t)(xmldb_handle xh, const char *db, int pid);
|
||||
|
||||
/* Type of xmldb unlock function */
|
||||
typedef int (xmldb_unlock_t)(xmldb_handle xh, char *db);
|
||||
typedef int (xmldb_unlock_t)(xmldb_handle xh, const char *db);
|
||||
|
||||
/* Type of xmldb unlock_all function */
|
||||
typedef int (xmldb_unlock_all_t)(xmldb_handle xh, int pid);
|
||||
|
||||
/* Type of xmldb islocked function */
|
||||
typedef int (xmldb_islocked_t)(xmldb_handle xh, char *db);
|
||||
typedef int (xmldb_islocked_t)(xmldb_handle xh, const char *db);
|
||||
|
||||
/* Type of xmldb exists function */
|
||||
typedef int (xmldb_exists_t)(xmldb_handle xh, char *db);
|
||||
typedef int (xmldb_exists_t)(xmldb_handle xh, const char *db);
|
||||
|
||||
/* Type of xmldb delete function */
|
||||
typedef int (xmldb_delete_t)(xmldb_handle xh, char *db);
|
||||
typedef int (xmldb_delete_t)(xmldb_handle xh, const char *db);
|
||||
|
||||
/* Type of xmldb init function */
|
||||
typedef int (xmldb_create_t)(xmldb_handle xh, char *db);
|
||||
typedef int (xmldb_create_t)(xmldb_handle xh, const char *db);
|
||||
|
||||
/* plugin init struct for the api */
|
||||
struct xmldb_api{
|
||||
|
|
@ -133,20 +133,20 @@ struct xmldb_api{
|
|||
int xmldb_plugin_load(clicon_handle h, char *filename);
|
||||
int xmldb_plugin_unload(clicon_handle h);
|
||||
|
||||
int xmldb_validate_db(char *db);
|
||||
int xmldb_validate_db(const char *db);
|
||||
int xmldb_connect(clicon_handle h);
|
||||
int xmldb_disconnect(clicon_handle h);
|
||||
int xmldb_getopt(clicon_handle h, char *optname, void **value);
|
||||
int xmldb_setopt(clicon_handle h, char *optname, void *value);
|
||||
int xmldb_get(clicon_handle h, char *db, char *xpath, int config, cxobj **xtop);
|
||||
int xmldb_put(clicon_handle h, char *db, enum operation_type op, cxobj *xt);
|
||||
int xmldb_copy(clicon_handle h, char *from, char *to);
|
||||
int xmldb_lock(clicon_handle h, char *db, int pid);
|
||||
int xmldb_unlock(clicon_handle h, char *db);
|
||||
int xmldb_get(clicon_handle h, const char *db, char *xpath, int config, cxobj **xtop);
|
||||
int xmldb_put(clicon_handle h, const char *db, enum operation_type op, cxobj *xt);
|
||||
int xmldb_copy(clicon_handle h, const char *from, const char *to);
|
||||
int xmldb_lock(clicon_handle h, const char *db, int pid);
|
||||
int xmldb_unlock(clicon_handle h, const char *db);
|
||||
int xmldb_unlock_all(clicon_handle h, int pid);
|
||||
int xmldb_islocked(clicon_handle h, char *db);
|
||||
int xmldb_exists(clicon_handle h, char *db);
|
||||
int xmldb_delete(clicon_handle h, char *db);
|
||||
int xmldb_create(clicon_handle h, char *db);
|
||||
int xmldb_islocked(clicon_handle h, const char *db);
|
||||
int xmldb_exists(clicon_handle h, const char *db);
|
||||
int xmldb_delete(clicon_handle h, const char *db);
|
||||
int xmldb_create(clicon_handle h, const char *db);
|
||||
|
||||
#endif /* _CLIXON_XML_DB_H */
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ quit:
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Make a copy of file src
|
||||
/*! Make a copy of file src. Overwrite existing
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@
|
|||
|
||||
/* clicon */
|
||||
#include "clixon_err.h"
|
||||
#include "clixon_string.h"
|
||||
#include "clixon_queue.h"
|
||||
#include "clixon_hash.h"
|
||||
#include "clixon_handle.h"
|
||||
|
|
@ -69,6 +70,16 @@
|
|||
#include "clixon_xsl.h"
|
||||
#include "clixon_xml_map.h"
|
||||
|
||||
/* Mapping between Clicon startup modes string <--> constants,
|
||||
see clixon-config.yang type startup_mode */
|
||||
static const map_str2int startup_mode_map[] = {
|
||||
{"none", SM_NONE},
|
||||
{"running", SM_RUNNING},
|
||||
{"startup", SM_STARTUP},
|
||||
{"init", SM_INIT},
|
||||
{NULL, -1}
|
||||
};
|
||||
|
||||
/*! Print registry on file. For debugging.
|
||||
*/
|
||||
void
|
||||
|
|
@ -332,7 +343,6 @@ clicon_option_sanity(clicon_hash_t *copt)
|
|||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*! Initialize option values
|
||||
*
|
||||
* Set default options, Read config-file, Check that all values are set.
|
||||
|
|
@ -387,9 +397,12 @@ clicon_options_main(clicon_handle h)
|
|||
}
|
||||
|
||||
/*! Check if a clicon option has a value
|
||||
* @param[in] h clicon_handle
|
||||
* @param[in] name option name
|
||||
*/
|
||||
int
|
||||
clicon_option_exists(clicon_handle h, const char *name)
|
||||
clicon_option_exists(clicon_handle h,
|
||||
const char *name)
|
||||
{
|
||||
clicon_hash_t *copt = clicon_options(h);
|
||||
|
||||
|
|
@ -449,7 +462,8 @@ clicon_option_str_set(clicon_handle h,
|
|||
* supply a defualt value as shown in the example.
|
||||
*/
|
||||
int
|
||||
clicon_option_int(clicon_handle h, const char *name)
|
||||
clicon_option_int(clicon_handle h,
|
||||
const char *name)
|
||||
{
|
||||
char *s;
|
||||
|
||||
|
|
@ -461,7 +475,9 @@ clicon_option_int(clicon_handle h, const char *name)
|
|||
/*! Set option given as int.
|
||||
*/
|
||||
int
|
||||
clicon_option_int_set(clicon_handle h, const char *name, int val)
|
||||
clicon_option_int_set(clicon_handle h,
|
||||
const char *name,
|
||||
int val)
|
||||
{
|
||||
char s[64];
|
||||
|
||||
|
|
@ -473,7 +489,8 @@ clicon_option_int_set(clicon_handle h, const char *name, int val)
|
|||
/*! Delete option
|
||||
*/
|
||||
int
|
||||
clicon_option_del(clicon_handle h, const char *name)
|
||||
clicon_option_del(clicon_handle h,
|
||||
const char *name)
|
||||
{
|
||||
clicon_hash_t *copt = clicon_options(h);
|
||||
|
||||
|
|
@ -550,6 +567,15 @@ clicon_xmldb_plugin(clicon_handle h)
|
|||
return clicon_option_str(h, "CLICON_XMLDB_PLUGIN");
|
||||
}
|
||||
|
||||
int
|
||||
clicon_startup_mode(clicon_handle h)
|
||||
{
|
||||
char *mode;
|
||||
if ((mode = clicon_option_str(h, "CLICON_STARTUP_MODE")) == NULL)
|
||||
return -1;
|
||||
return clicon_str2int(startup_mode_map, mode);
|
||||
}
|
||||
|
||||
/*! Get family of backend socket: AF_UNIX, AF_INET or AF_INET6 */
|
||||
int
|
||||
clicon_sock_family(clicon_handle h)
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ xmldb_plugin_unload(clicon_handle h)
|
|||
* @retval -1 Failed validate, xret set to error
|
||||
*/
|
||||
int
|
||||
xmldb_validate_db(char *db)
|
||||
xmldb_validate_db(const char *db)
|
||||
{
|
||||
if (strcmp(db, "running") != 0 &&
|
||||
strcmp(db, "candidate") != 0 &&
|
||||
|
|
@ -336,7 +336,7 @@ xmldb_setopt(clicon_handle h,
|
|||
*/
|
||||
int
|
||||
xmldb_get(clicon_handle h,
|
||||
char *db,
|
||||
const char *db,
|
||||
char *xpath,
|
||||
int config,
|
||||
cxobj **xtop)
|
||||
|
|
@ -393,7 +393,7 @@ xmldb_get(clicon_handle h,
|
|||
*/
|
||||
int
|
||||
xmldb_put(clicon_handle h,
|
||||
char *db,
|
||||
const char *db,
|
||||
enum operation_type op,
|
||||
cxobj *xt)
|
||||
{
|
||||
|
|
@ -439,8 +439,8 @@ xmldb_put(clicon_handle h,
|
|||
*/
|
||||
int
|
||||
xmldb_copy(clicon_handle h,
|
||||
char *from,
|
||||
char *to)
|
||||
const char *from,
|
||||
const char *to)
|
||||
{
|
||||
int retval = -1;
|
||||
xmldb_handle xh;
|
||||
|
|
@ -472,7 +472,7 @@ xmldb_copy(clicon_handle h,
|
|||
*/
|
||||
int
|
||||
xmldb_lock(clicon_handle h,
|
||||
char *db,
|
||||
const char *db,
|
||||
int pid)
|
||||
{
|
||||
int retval = -1;
|
||||
|
|
@ -506,7 +506,7 @@ xmldb_lock(clicon_handle h,
|
|||
*/
|
||||
int
|
||||
xmldb_unlock(clicon_handle h,
|
||||
char *db)
|
||||
const char *db)
|
||||
{
|
||||
int retval = -1;
|
||||
xmldb_handle xh;
|
||||
|
|
@ -569,7 +569,7 @@ xmldb_unlock_all(clicon_handle h,
|
|||
*/
|
||||
int
|
||||
xmldb_islocked(clicon_handle h,
|
||||
char *db)
|
||||
const char *db)
|
||||
{
|
||||
int retval = -1;
|
||||
xmldb_handle xh;
|
||||
|
|
@ -601,7 +601,7 @@ xmldb_islocked(clicon_handle h,
|
|||
*/
|
||||
int
|
||||
xmldb_exists(clicon_handle h,
|
||||
char *db)
|
||||
const char *db)
|
||||
{
|
||||
int retval = -1;
|
||||
xmldb_handle xh;
|
||||
|
|
@ -632,7 +632,7 @@ xmldb_exists(clicon_handle h,
|
|||
*/
|
||||
int
|
||||
xmldb_delete(clicon_handle h,
|
||||
char *db)
|
||||
const char *db)
|
||||
{
|
||||
int retval = -1;
|
||||
xmldb_handle xh;
|
||||
|
|
@ -663,7 +663,7 @@ xmldb_delete(clicon_handle h,
|
|||
*/
|
||||
int
|
||||
xmldb_create(clicon_handle h,
|
||||
char *db)
|
||||
const char *db)
|
||||
{
|
||||
int retval = -1;
|
||||
xmldb_handle xh;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ if [ $? -ne 0 ]; then
|
|||
fi
|
||||
new "start backend"
|
||||
# start new backend
|
||||
sudo clixon_backend -If $clixon_cf
|
||||
sudo clixon_backend -s init -f $clixon_cf
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ fi
|
|||
|
||||
new "start backend"
|
||||
# start new backend
|
||||
sudo clixon_backend -If $clixon_cf -y /tmp/leafref.yang
|
||||
sudo clixon_backend -s init -f $clixon_cf -y /tmp/leafref.yang
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ if [ $? -ne 0 ]; then
|
|||
fi
|
||||
new "start backend"
|
||||
# start new backend
|
||||
sudo clixon_backend -If $clixon_cf
|
||||
sudo clixon_backend -s init -f $clixon_cf
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ fi
|
|||
|
||||
new "start backend"
|
||||
# start new backend
|
||||
sudo clixon_backend -If $clixon_cf -y $fyang
|
||||
sudo clixon_backend -s init -f $clixon_cf -y $fyang
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ if [ $? -ne 0 ]; then
|
|||
err
|
||||
fi
|
||||
new "start backend"
|
||||
sudo clixon_backend -If $clixon_cf
|
||||
sudo clixon_backend -s init -f $clixon_cf
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
|
|
|
|||
90
test/test_startup.sh
Executable file
90
test/test_startup.sh
Executable file
|
|
@ -0,0 +1,90 @@
|
|||
#!/bin/bash
|
||||
# Startup test: Start clicon daemon in the (four) different startup modes
|
||||
# and the dbs and files are setup as follows:
|
||||
# - The example reset_state callback adds "lo" interface
|
||||
# - An extra xml configuration file starts with an "extra" interface
|
||||
# - running db starts with a "run" interface
|
||||
# - startup db starts with a "start" interface
|
||||
|
||||
# include err() and new() functions
|
||||
. ./lib.sh
|
||||
|
||||
# For memcheck
|
||||
# clixon_netconf="valgrind --leak-check=full --show-leak-kinds=all clixon_netconf"
|
||||
clixon_netconf=clixon_netconf
|
||||
clixon_cli=clixon_cli
|
||||
|
||||
run(){
|
||||
mode=$1
|
||||
expect=$2
|
||||
|
||||
cat <<EOF > /tmp/db
|
||||
<config>
|
||||
<interfaces>
|
||||
<interface>
|
||||
<name>run</name>
|
||||
<type>eth</type>
|
||||
</interface>
|
||||
</interfaces>
|
||||
</config>
|
||||
EOF
|
||||
sudo mv /tmp/db /usr/local/var/routing/running_db
|
||||
|
||||
cat <<EOF > /tmp/db
|
||||
<config>
|
||||
<interfaces>
|
||||
<interface>
|
||||
<name>startup</name>
|
||||
<type>eth</type>
|
||||
</interface>
|
||||
</interfaces>
|
||||
</config>
|
||||
EOF
|
||||
sudo mv /tmp/db /usr/local/var/routing/startup_db
|
||||
|
||||
cat <<EOF > /tmp/config
|
||||
<config>
|
||||
<interfaces>
|
||||
<interface>
|
||||
<name>extra</name>
|
||||
<type>eth</type>
|
||||
</interface>
|
||||
</interfaces>
|
||||
</config>
|
||||
EOF
|
||||
|
||||
# kill old backend (if any)
|
||||
new "kill old backend"
|
||||
sudo clixon_backend -zf $clixon_cf $yang
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
|
||||
new "start backend"
|
||||
# start new backend
|
||||
sudo clixon_backend -f $clixon_cf $yang -s $mode -c /tmp/config
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
|
||||
new "Check $mode"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf $yang" '<rpc><get-config><source><running/></source></get-config></rpc>]]>]]>' "^<rpc-reply>$expect</rpc-reply>]]>]]>$"
|
||||
|
||||
new "Kill backend"
|
||||
# Check if still alive
|
||||
pid=`pgrep clixon_backend`
|
||||
if [ -z "$pid" ]; then
|
||||
err "backend already dead"
|
||||
fi
|
||||
# kill backend
|
||||
sudo clixon_backend -zf $clixon_cf
|
||||
if [ $? -ne 0 ]; then
|
||||
err "kill backend"
|
||||
fi
|
||||
}
|
||||
|
||||
run init '<data/>'
|
||||
run none '<data><interfaces><interface><name>run</name><type>eth</type><enabled>true</enabled></interface></interfaces></data>'
|
||||
run running '<data><interfaces><interface><name>run</name><type>eth</type><enabled>true</enabled></interface><interface><name>lo</name><type>local</type><enabled>true</enabled></interface><interface><name>extra</name><type>eth</type><enabled>true</enabled></interface></interfaces></data>'
|
||||
run startup '<data><interfaces><interface><name>startup</name><type>eth</type><enabled>true</enabled></interface><interface><name>lo</name><type>local</type><enabled>true</enabled></interface><interface><name>extra</name><type>eth</type><enabled>true</enabled></interface></interfaces></data>'
|
||||
|
||||
|
|
@ -69,7 +69,7 @@ if [ $? -ne 0 ]; then
|
|||
fi
|
||||
new "start backend"
|
||||
# start new backend
|
||||
sudo clixon_backend -If $clixon_cf -y /tmp/type.yang
|
||||
sudo clixon_backend -s init -f $clixon_cf -y /tmp/type.yang
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ fi
|
|||
|
||||
new "start backend"
|
||||
# start new backend
|
||||
sudo clixon_backend -If $clixon_cf -y /tmp/test.yang
|
||||
sudo clixon_backend -s init -f $clixon_cf -y /tmp/test.yang
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -38,9 +38,32 @@
|
|||
|
||||
***** END LICENSE BLOCK *****";
|
||||
|
||||
revision 2017-07-02 {
|
||||
revision 2017-11-12 {
|
||||
description
|
||||
"Initial revision";
|
||||
"Added startup config";
|
||||
}
|
||||
typedef startup_mode{
|
||||
description "Which method to boot/start clicon backend.
|
||||
The methods differ in how they reach a running state
|
||||
Which source database to commit from, if any.";
|
||||
type enumeration{
|
||||
enum none{
|
||||
description "Do not touch running state
|
||||
Typical after crash when running state and db are synched";
|
||||
}
|
||||
enum init{
|
||||
description "Initialize running state.
|
||||
Start with a completely clean running state";
|
||||
}
|
||||
enum running{
|
||||
description "Commit running db configuration into running state
|
||||
Usecase: after reboot if a persistent running db exists";
|
||||
}
|
||||
enum startup{
|
||||
description "Commit startup configuration into running state
|
||||
Usecase: after reboot when no persistent running db exists";
|
||||
}
|
||||
}
|
||||
}
|
||||
container config {
|
||||
leaf CLICON_CONFIGFILE{
|
||||
|
|
@ -185,12 +208,17 @@
|
|||
type int32;
|
||||
default 0;
|
||||
description "Enabled uses \"startup\" configuration on boot. It is called
|
||||
startup_db and exists in XMLDB_DIR";
|
||||
startup_db and exists in XMLDB_DIR. NOTE: Obsolete with CLICON_STARTUP_MODE";
|
||||
}
|
||||
leaf CLICON_XMLDB_PLUGIN {
|
||||
type string;
|
||||
mandatory true;
|
||||
description "XMLDB datastore plugin filename (see datastore/ and clixon_xml_db.[ch])";
|
||||
}
|
||||
leaf CLICON_STARTUP_MODE {
|
||||
type startup_mode;
|
||||
description "Which method to boot/start clicon backend";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue