Backend daemon startup modes

This commit is contained in:
Olof hagsand 2017-11-19 11:52:30 +01:00
parent 23e40384f7
commit 496d676ad3
26 changed files with 769 additions and 280 deletions

View file

@ -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 * 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. longer silently exits. Instead a log is printed and an RPC error is returned.
* Added Floating point and negative number support to JSON * 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: * Support for non-line scrolling in CLI, eg wrap lines. Set with:
CLICON_CLI_LINESCROLLING 0 CLICON_CLI_LINESCROLLING 0
## 3.3.2 Aug 27 2017 # 3.3.2 (Aug 27 2017)
### Known issues ### Known issues
* Please use text datastore, key-value datastore no up-to-date * 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. * 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. * 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 xpath support for predicate: current(), eg /interface[name=current()/../name]
* Added prefix parsing of xpath, allowing eg /p:x/p:y, but prefix ignored. * 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. * 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() * Removed vector return values from xmldb_get()
* Generalized yang type resolution to all included (sub)modules not just the topmost * 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. * 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 * Strings in xmldb_put not properly encoded, eg eth/0 became eth.00000
## 3.3.0 # 3.3.0 (May 2017)
May 2017
* Datastore text module is now default. * Datastore text module is now default.
@ -205,7 +211,7 @@ May 2017
Instead use the rpc calls in clixon_proto_client.[ch] Instead use the rpc calls in clixon_proto_client.[ch]
In clients (eg cli/netconf) replace xmldb_get() in client code with In clients (eg cli/netconf) replace xmldb_get() in client code with
clicon_rpc_get_config(). 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); xmldb_get(h, db, api_path, &xt, &xvec, &xlen);
with with
clicon_rpc_get_config(h, dbstr, api_path, &xt); 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 * Added union type check for non-cli (eg xml) input
* Empty yang type. Relaxed yang types for unions, eg two strings with different length. * 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

View file

@ -73,7 +73,11 @@
#include "backend_handle.h" #include "backend_handle.h"
/* Command line options to be passed to getopt(3) */ /* 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 */ /*! Terminate. Cannot use h after this */
static int static int
@ -114,8 +118,7 @@ backend_sig_term(int arg)
clicon_exit_set(); /* checked in event_loop() */ clicon_exit_set(); /* checked in event_loop() */
} }
/* /*! usage
* usage
*/ */
static void static void
usage(char *argv0, clicon_handle h) 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" " -1\t\tRun once and then quit (dont wait for events)\n"
" -u <path>\tConfig UNIX domain path / ip address (default: %s)\n" " -u <path>\tConfig UNIX domain path / ip address (default: %s)\n"
" -P <file>\tPid filename (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" " -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" " -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\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" " -r\t\tReload running database\n"
#endif /* BACKEND_STARTUP_BACKWARD_COMPAT */
" -p \t\tPrint database yang specification\n" " -p \t\tPrint database yang specification\n"
" -g <group>\tClient membership required to this group (default: %s)\n" " -g <group>\tClient membership required to this group (default: %s)\n"
" -y <file>\tOverride yang spec file (dont include .yang suffix)\n" " -y <file>\tOverride yang spec file (dont include .yang suffix)\n"
@ -166,69 +172,26 @@ db_reset(clicon_handle h,
return 0; return 0;
} }
/*! Initialize running-config from file application configuration /*! Merge db1 into db2 without commit
*
* @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
*/ */
static int static int
rundb_main(clicon_handle h, db_merge(clicon_handle h,
char *app_config_file) const char *db1,
const char *db2)
{ {
int retval = -1; int retval = -1;
int fd = -1; cxobj *xt = NULL;
cxobj *xt = NULL;
cxobj *xn;
if (xmldb_create(h, "tmp") < 0) /* Get data as xml from db1 */
if (xmldb_get(h, (char*)db1, NULL, 1, &xt) < 0)
goto done; goto done;
if (xmldb_copy(h, "running", "tmp") < 0){ /* Merge xml into db2. WIthout commit */
clicon_err(OE_UNIX, errno, "file copy"); if (xmldb_put(h, (char*)db2, OP_MERGE, xt) < 0)
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)
goto done; goto done;
retval = 0; retval = 0;
done: done:
if (xt) if (xt)
xml_free(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; return retval;
} }
@ -291,6 +254,337 @@ backend_log_cb(int level,
return retval; 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 int
main(int argc, char **argv) main(int argc, char **argv)
{ {
@ -298,14 +592,16 @@ main(int argc, char **argv)
int zap; int zap;
int foreground; int foreground;
int once; int once;
int init_rundb; enum startup_mode_t startup_mode;
int reload_running; #ifdef BACKEND_STARTUP_BACKWARD_COMPAT
int reset_state_running; int init_rundb = 0;
int reset_state_candidate; int reset_state_running = 0;
char *app_config_file = NULL; int reset_state_candidate = 0;
int reload_running = 0;
#endif
char *extraxml_file;
char *config_group; char *config_group;
char *argv0 = argv[0]; char *argv0 = argv[0];
char *tmp;
struct stat st; struct stat st;
clicon_handle h; clicon_handle h;
int help = 0; int help = 0;
@ -317,7 +613,6 @@ main(int argc, char **argv)
char *xmldb_plugin; char *xmldb_plugin;
/* In the startup, logs to stderr & syslog and debug flag set later */ /* In the startup, logs to stderr & syslog and debug flag set later */
clicon_log_init(__PROGRAM__, LOG_INFO, CLICON_LOG_STDERR|CLICON_LOG_SYSLOG); clicon_log_init(__PROGRAM__, LOG_INFO, CLICON_LOG_STDERR|CLICON_LOG_SYSLOG);
/* Initiate CLICON handle */ /* Initiate CLICON handle */
if ((h = backend_handle_init()) == NULL) if ((h = backend_handle_init()) == NULL)
@ -327,10 +622,7 @@ main(int argc, char **argv)
foreground = 0; foreground = 0;
once = 0; once = 0;
zap = 0; zap = 0;
init_rundb = 0; extraxml_file = NULL;
reload_running = 0;
reset_state_running = 0;
reset_state_candidate = 0;
/* /*
* Command-line options for help, debug, and config-file * Command-line options for help, debug, and config-file
@ -402,32 +694,41 @@ main(int argc, char **argv)
case 'z': /* Zap other process */ case 'z': /* Zap other process */
zap++; zap++;
break; break;
case 'u': /* config unix domain path / ip address */ case 'u': /* config unix domain path / ip address */
if (!strlen(optarg)) if (!strlen(optarg))
usage(argv[0], h); usage(argv[0], h);
clicon_option_str_set(h, "CLICON_SOCK", optarg); clicon_option_str_set(h, "CLICON_SOCK", optarg);
break; break;
case 'P': /* pidfile */ case 'P': /* pidfile */
clicon_option_str_set(h, "CLICON_BACKEND_PIDFILE", optarg); clicon_option_str_set(h, "CLICON_BACKEND_PIDFILE", optarg);
break; break;
case 'I': /* Initiate running db */ case 's' : /* startup mode */
init_rundb++; clicon_option_str_set(h, "CLICON_STARTUP_MODE", optarg);
break; if (clicon_startup_mode(h) < 0){
case 'R': /* Reset state directly into running */ fprintf(stderr, "Invalid startup mode: %s\n", optarg);
reset_state_running++; usage(argv[0], h);
break; }
case 'C': /* Reset state into candidate and then commit it */ break;
reset_state_candidate++; case 'c': /* Load application config */
break; extraxml_file = optarg;
case 'c': /* Load application config */ break;
app_config_file = optarg; #ifdef BACKEND_STARTUP_BACKWARD_COMPAT
break; case 'I': /* Initiate running db */
case 'r': /* Reload running */ init_rundb++;
reload_running++; break;
break; case 'R': /* Reset state directly into running */
case 'g': /* config socket group */ reset_state_running++;
clicon_option_str_set(h, "CLICON_SOCK_GROUP", optarg); break;
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 */ case 'p' : /* Print spec */
printspec++; printspec++;
break; break;
@ -522,87 +823,52 @@ main(int argc, char **argv)
goto done; goto done;
if (xmldb_setopt(h, "yangspec", clicon_dbspec_yang(h)) < 0) if (xmldb_setopt(h, "yangspec", clicon_dbspec_yang(h)) < 0)
goto done; goto done;
/* If startup mode is not defined, eg via OPTION or -s, assume old method */
/* First check for startup config startup_mode = clicon_startup_mode(h);
XXX the options below have become out-of-hand. if (startup_mode == -1){ /* Old style, fragmented mode, phase out */
Too complex, need to simplify*/ #ifdef BACKEND_STARTUP_BACKWARD_COMPAT
if (clicon_option_int(h, "CLICON_USE_STARTUP_CONFIG") > 0){ if (fragmented_startup_mode(h,
if (xmldb_exists(h, "startup") == 1){ argv0, argc, argv,
/* copy startup config -> running */ reload_running, init_rundb,
if (xmldb_copy(h, "startup", "running") < 0) reset_state_candidate, reset_state_running,
goto done; extraxml_file
} ) < 0)
else
if (db_reset(h, "running") < 0)
goto done;
if (xmldb_create(h, "candidate") < 0)
goto done; 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) if (xmldb_copy(h, "running", "candidate") < 0)
goto done; goto done;
} /* Call plugin_start with user -- options */
/* If running exists and reload_running set, make a copy to candidate */ if (plugin_start_useroptions(h, argv0, argc, argv) <0)
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; 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) if (once)
goto done; goto done;

View file

@ -71,7 +71,7 @@
* @note the following should match the prototypes in clixon_backend.h * @note the following should match the prototypes in clixon_backend.h
*/ */
#define PLUGIN_RESET "plugin_reset" #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 /*! Plugin callback, if defined called to get state data from plugin
* @param[in] h Clicon handle * @param[in] h Clicon handle
@ -253,19 +253,18 @@ backend_plugin_load (clicon_handle h,
* @retval -1 Error * @retval -1 Error
*/ */
int int
plugin_reset_state(clicon_handle h, plugin_reset_state(clicon_handle h,
char *dbname) const char *db)
{ {
int i; int i;
struct plugin *p; struct plugin *p;
for (i = 0; i < _nplugins; i++) { for (i = 0; i < _nplugins; i++) {
p = &_plugins[i]; p = &_plugins[i];
if (p->p_reset) { if (p->p_reset) {
clicon_debug(1, "Calling plugin_reset() for %s\n", clicon_debug(1, "Calling plugin_reset() for %s\n",
p->p_name); 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", clicon_err(OE_FATAL, 0, "plugin_reset() failed for %s\n",
p->p_name); p->p_name);
return -1; return -1;
@ -283,7 +282,7 @@ plugin_reset_state(clicon_handle h,
* @retval -1 Error * @retval -1 Error
*/ */
int int
plugin_start_hooks(clicon_handle h, plugin_start_argv(clicon_handle h,
int argc, int argc,
char **argv) char **argv)
{ {

View file

@ -66,8 +66,8 @@ int backend_plugin_init(clicon_handle h);
int plugin_initiate(clicon_handle h); int plugin_initiate(clicon_handle h);
int plugin_finish(clicon_handle h); int plugin_finish(clicon_handle h);
int plugin_reset_state(clicon_handle h, char *dbname); int plugin_reset_state(clicon_handle h, const char *db);
int plugin_start_hooks(clicon_handle h, int argc, char **argv); int plugin_start_argv(clicon_handle h, int argc, char **argv);
int backend_statedata_call(clicon_handle h, char *xpath, cxobj *xml); int backend_statedata_call(clicon_handle h, char *xpath, cxobj *xml);

View file

@ -70,7 +70,7 @@ int plugin_exit(clicon_handle h);
/*! Reset system state to original state. Eg at reboot before running thru config. /*! Reset system state to original state. Eg at reboot before running thru config.
* @see plgreset_t * @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 /*! Retreive statedata, add statedata to XML tree
* @see plgstatedata_ t * @see plgstatedata_ t

View file

@ -150,8 +150,8 @@ static int _startup_locked = 0;
*/ */
static int static int
kv_db2file(struct kv_handle *kh, kv_db2file(struct kv_handle *kh,
char *db, const char *db,
char **filename) char **filename)
{ {
int retval = -1; int retval = -1;
cbuf *cb; cbuf *cb;
@ -565,7 +565,7 @@ kv_setopt(xmldb_handle xh,
*/ */
int int
kv_get(xmldb_handle xh, kv_get(xmldb_handle xh,
char *db, const char *db,
char *xpath, char *xpath,
int config, int config,
cxobj **xtop) cxobj **xtop)
@ -783,7 +783,7 @@ put(char *dbfile,
*/ */
int int
kv_put(xmldb_handle xh, kv_put(xmldb_handle xh,
char *db, const char *db,
enum operation_type op, enum operation_type op,
cxobj *xt) cxobj *xt)
{ {
@ -836,8 +836,8 @@ kv_put(xmldb_handle xh,
*/ */
int int
kv_copy(xmldb_handle xh, kv_copy(xmldb_handle xh,
char *from, const char *from,
char *to) const char *to)
{ {
int retval = -1; int retval = -1;
struct kv_handle *kh = handle(xh); struct kv_handle *kh = handle(xh);
@ -869,8 +869,8 @@ kv_copy(xmldb_handle xh,
*/ */
int int
kv_lock(xmldb_handle xh, kv_lock(xmldb_handle xh,
char *db, const char *db,
int pid) int pid)
{ {
int retval = -1; int retval = -1;
// struct kv_handle *kh = handle(xh); // struct kv_handle *kh = handle(xh);
@ -900,7 +900,7 @@ kv_lock(xmldb_handle xh,
*/ */
int int
kv_unlock(xmldb_handle xh, kv_unlock(xmldb_handle xh,
char *db) const char *db)
{ {
int retval = -1; int retval = -1;
// struct kv_handle *kh = handle(xh); // struct kv_handle *kh = handle(xh);
@ -949,7 +949,7 @@ kv_unlock_all(xmldb_handle xh,
*/ */
int int
kv_islocked(xmldb_handle xh, kv_islocked(xmldb_handle xh,
char *db) const char *db)
{ {
int retval = -1; int retval = -1;
// struct kv_handle *kh = handle(xh); // struct kv_handle *kh = handle(xh);
@ -974,7 +974,7 @@ kv_islocked(xmldb_handle xh,
*/ */
int int
kv_exists(xmldb_handle xh, kv_exists(xmldb_handle xh,
char *db) const char *db)
{ {
int retval = -1; int retval = -1;
struct kv_handle *kh = handle(xh); struct kv_handle *kh = handle(xh);
@ -1001,7 +1001,7 @@ kv_exists(xmldb_handle xh,
*/ */
int int
kv_delete(xmldb_handle xh, kv_delete(xmldb_handle xh,
char *db) const char *db)
{ {
int retval = -1; int retval = -1;
struct kv_handle *kh = handle(xh); struct kv_handle *kh = handle(xh);
@ -1026,7 +1026,7 @@ kv_delete(xmldb_handle xh,
*/ */
int int
kv_create(xmldb_handle xh, kv_create(xmldb_handle xh,
char *db) const char *db)
{ {
int retval = -1; int retval = -1;
struct kv_handle *kh = handle(xh); struct kv_handle *kh = handle(xh);

View file

@ -39,16 +39,16 @@
/* /*
* Prototypes * Prototypes
*/ */
int kv_get(xmldb_handle h, char *db, char *xpath, int config, cxobj **xtop); int kv_get(xmldb_handle h, const char *db, char *xpath, int config, cxobj **xtop);
int kv_put(xmldb_handle h, char *db, enum operation_type op, cxobj *xt); 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_dump(FILE *f, char *dbfilename, char *rxkey);
int kv_copy(xmldb_handle h, char *from, char *to); int kv_copy(xmldb_handle h, const char *from, const char *to);
int kv_lock(xmldb_handle h, char *db, int pid); int kv_lock(xmldb_handle h, const char *db, int pid);
int kv_unlock(xmldb_handle h, char *db); int kv_unlock(xmldb_handle h, const char *db);
int kv_unlock_all(xmldb_handle h, int pid); int kv_unlock_all(xmldb_handle h, int pid);
int kv_islocked(xmldb_handle h, char *db); int kv_islocked(xmldb_handle h, const char *db);
int kv_exists(xmldb_handle h, char *db); int kv_exists(xmldb_handle h, const char *db);
int kv_delete(xmldb_handle h, char *db); int kv_delete(xmldb_handle h, const char *db);
int kv_init(xmldb_handle h, char *db); int kv_init(xmldb_handle h, const char *db);
#endif /* _CLIXON_KEYVALUE_H */ #endif /* _CLIXON_KEYVALUE_H */

View file

@ -99,7 +99,7 @@ text_handle_check(xmldb_handle xh)
*/ */
static int static int
text_db2file(struct text_handle *th, text_db2file(struct text_handle *th,
char *db, const char *db,
char **filename) char **filename)
{ {
int retval = -1; int retval = -1;
@ -281,7 +281,7 @@ singleconfigroot(cxobj *xt,
*/ */
int int
text_get(xmldb_handle xh, text_get(xmldb_handle xh,
char *db, const char *db,
char *xpath, char *xpath,
int config, int config,
cxobj **xtop) cxobj **xtop)
@ -681,7 +681,7 @@ xml_container_presence(cxobj *x,
*/ */
int int
text_put(xmldb_handle xh, text_put(xmldb_handle xh,
char *db, const char *db,
enum operation_type op, enum operation_type op,
cxobj *x1) cxobj *x1)
{ {
@ -807,8 +807,8 @@ text_put(xmldb_handle xh,
*/ */
int int
text_copy(xmldb_handle xh, text_copy(xmldb_handle xh,
char *from, const char *from,
char *to) const char *to)
{ {
int retval = -1; int retval = -1;
struct text_handle *th = handle(xh); struct text_handle *th = handle(xh);
@ -840,7 +840,7 @@ text_copy(xmldb_handle xh,
*/ */
int int
text_lock(xmldb_handle xh, text_lock(xmldb_handle xh,
char *db, const char *db,
int pid) int pid)
{ {
struct text_handle *th = handle(xh); struct text_handle *th = handle(xh);
@ -860,7 +860,7 @@ text_lock(xmldb_handle xh,
*/ */
int int
text_unlock(xmldb_handle xh, text_unlock(xmldb_handle xh,
char *db) const char *db)
{ {
struct text_handle *th = handle(xh); struct text_handle *th = handle(xh);
int zero = 0; int zero = 0;
@ -905,7 +905,7 @@ text_unlock_all(xmldb_handle xh,
*/ */
int int
text_islocked(xmldb_handle xh, text_islocked(xmldb_handle xh,
char *db) const char *db)
{ {
struct text_handle *th = handle(xh); struct text_handle *th = handle(xh);
size_t vlen; size_t vlen;
@ -926,7 +926,7 @@ text_islocked(xmldb_handle xh,
*/ */
int int
text_exists(xmldb_handle xh, text_exists(xmldb_handle xh,
char *db) const char *db)
{ {
int retval = -1; int retval = -1;
@ -954,7 +954,7 @@ text_exists(xmldb_handle xh,
*/ */
int int
text_delete(xmldb_handle xh, text_delete(xmldb_handle xh,
char *db) const char *db)
{ {
int retval = -1; int retval = -1;
char *filename = NULL; char *filename = NULL;
@ -974,6 +974,7 @@ text_delete(xmldb_handle xh,
} }
/*! Create / init database /*! Create / init database
* If it exists dont change.
* @param[in] xh XMLDB handle * @param[in] xh XMLDB handle
* @param[in] db Database * @param[in] db Database
* @retval 0 OK * @retval 0 OK
@ -981,7 +982,7 @@ text_delete(xmldb_handle xh,
*/ */
int int
text_create(xmldb_handle xh, text_create(xmldb_handle xh,
char *db) const char *db)
{ {
int retval = -1; int retval = -1;
struct text_handle *th = handle(xh); struct text_handle *th = handle(xh);

View file

@ -39,16 +39,16 @@
/* /*
* Prototypes * Prototypes
*/ */
int text_get(xmldb_handle h, char *db, char *xpath, int config, cxobj **xtop); int text_get(xmldb_handle h, const char *db, char *xpath, int config, cxobj **xtop);
int text_put(xmldb_handle h, char *db, enum operation_type op, cxobj *xt); 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_dump(FILE *f, char *dbfilename, char *rxkey);
int text_copy(xmldb_handle h, char *from, char *to); int text_copy(xmldb_handle h, const char *from, const char *to);
int text_lock(xmldb_handle h, char *db, int pid); int text_lock(xmldb_handle h, const char *db, int pid);
int text_unlock(xmldb_handle h, char *db); int text_unlock(xmldb_handle h, const char *db);
int text_unlock_all(xmldb_handle h, int pid); int text_unlock_all(xmldb_handle h, int pid);
int text_islocked(xmldb_handle h, char *db); int text_islocked(xmldb_handle h, const char *db);
int text_exists(xmldb_handle h, char *db); int text_exists(xmldb_handle h, const char *db);
int text_delete(xmldb_handle h, char *db); int text_delete(xmldb_handle h, const char *db);
int text_init(xmldb_handle h, char *db); int text_init(xmldb_handle h, const char *db);
#endif /* _CLIXON_XMLDB_TEXT_H */ #endif /* _CLIXON_XMLDB_TEXT_H */

View file

@ -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 Clixon is written in C. The plugins are written in C. The CLI
specification uses cligen (http://cligen.se) specification uses cligen (http://cligen.se)
There is a project for writing plugins in Python. It is reasonable It is possible ro write plugins in Python. It is reasonable
simple to spawn an external script from a backend. simple to spawn an external script from a backend (but needs to be done).
## How to best understand Clixon? ## How to best understand Clixon?
Run the ietf yang routing example, in the example directory. Run the ietf yang routing example, in the example directory.

View file

@ -179,8 +179,10 @@ plugin_statedata(clicon_handle h,
return retval; return retval;
} }
/* /*! Plugin initialization. Create rpc callbacks
* Plugin initialization * 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 int
plugin_init(clicon_handle h) plugin_init(clicon_handle h)
@ -205,3 +207,57 @@ plugin_init(clicon_handle h)
return retval; 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;
}

View file

@ -47,3 +47,10 @@ int strverscmp (__const char *__s1, __const char *__s2);
* Experimental * Experimental
*/ */
#define XML_CHILD_HASH 1 #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

View file

@ -63,6 +63,13 @@ enum genmodel_type{
GT_ALL, /* Keywords on all variables */ 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 * Prototypes
@ -93,6 +100,7 @@ char *clicon_clispec_dir(clicon_handle h);
char *clicon_netconf_dir(clicon_handle h); char *clicon_netconf_dir(clicon_handle h);
char *clicon_restconf_dir(clicon_handle h); char *clicon_restconf_dir(clicon_handle h);
char *clicon_xmldb_plugin(clicon_handle h); char *clicon_xmldb_plugin(clicon_handle h);
int clicon_startup_mode(clicon_handle h);
int clicon_sock_family(clicon_handle h); int clicon_sock_family(clicon_handle h);
char *clicon_sock(clicon_handle h); char *clicon_sock(clicon_handle h);
int clicon_sock_port(clicon_handle h); int clicon_sock_port(clicon_handle h);

View file

@ -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); typedef int (xmldb_setopt_t)(xmldb_handle xh, char *optname, void *value);
/* Type of xmldb get function */ /* 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 */ /* 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 */ /* 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 */ /* 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 */ /* 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 */ /* Type of xmldb unlock_all function */
typedef int (xmldb_unlock_all_t)(xmldb_handle xh, int pid); typedef int (xmldb_unlock_all_t)(xmldb_handle xh, int pid);
/* Type of xmldb islocked function */ /* 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 */ /* 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 */ /* 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 */ /* 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 */ /* plugin init struct for the api */
struct xmldb_api{ struct xmldb_api{
@ -133,20 +133,20 @@ struct xmldb_api{
int xmldb_plugin_load(clicon_handle h, char *filename); int xmldb_plugin_load(clicon_handle h, char *filename);
int xmldb_plugin_unload(clicon_handle h); 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_connect(clicon_handle h);
int xmldb_disconnect(clicon_handle h); int xmldb_disconnect(clicon_handle h);
int xmldb_getopt(clicon_handle h, char *optname, void **value); int xmldb_getopt(clicon_handle h, char *optname, void **value);
int xmldb_setopt(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_get(clicon_handle h, const char *db, char *xpath, int config, cxobj **xtop);
int xmldb_put(clicon_handle h, char *db, enum operation_type op, cxobj *xt); int xmldb_put(clicon_handle h, const char *db, enum operation_type op, cxobj *xt);
int xmldb_copy(clicon_handle h, char *from, char *to); int xmldb_copy(clicon_handle h, const char *from, const char *to);
int xmldb_lock(clicon_handle h, char *db, int pid); int xmldb_lock(clicon_handle h, const char *db, int pid);
int xmldb_unlock(clicon_handle h, char *db); int xmldb_unlock(clicon_handle h, const char *db);
int xmldb_unlock_all(clicon_handle h, int pid); int xmldb_unlock_all(clicon_handle h, int pid);
int xmldb_islocked(clicon_handle h, char *db); int xmldb_islocked(clicon_handle h, const char *db);
int xmldb_exists(clicon_handle h, char *db); int xmldb_exists(clicon_handle h, const char *db);
int xmldb_delete(clicon_handle h, char *db); int xmldb_delete(clicon_handle h, const char *db);
int xmldb_create(clicon_handle h, char *db); int xmldb_create(clicon_handle h, const char *db);
#endif /* _CLIXON_XML_DB_H */ #endif /* _CLIXON_XML_DB_H */

View file

@ -185,7 +185,7 @@ quit:
return retval; return retval;
} }
/*! Make a copy of file src /*! Make a copy of file src. Overwrite existing
* @retval 0 OK * @retval 0 OK
* @retval -1 Error * @retval -1 Error
*/ */

View file

@ -58,6 +58,7 @@
/* clicon */ /* clicon */
#include "clixon_err.h" #include "clixon_err.h"
#include "clixon_string.h"
#include "clixon_queue.h" #include "clixon_queue.h"
#include "clixon_hash.h" #include "clixon_hash.h"
#include "clixon_handle.h" #include "clixon_handle.h"
@ -69,6 +70,16 @@
#include "clixon_xsl.h" #include "clixon_xsl.h"
#include "clixon_xml_map.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. /*! Print registry on file. For debugging.
*/ */
void void
@ -332,7 +343,6 @@ clicon_option_sanity(clicon_hash_t *copt)
return retval; return retval;
} }
/*! Initialize option values /*! Initialize option values
* *
* Set default options, Read config-file, Check that all values are set. * 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 /*! Check if a clicon option has a value
* @param[in] h clicon_handle
* @param[in] name option name
*/ */
int 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); 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. * supply a defualt value as shown in the example.
*/ */
int int
clicon_option_int(clicon_handle h, const char *name) clicon_option_int(clicon_handle h,
const char *name)
{ {
char *s; char *s;
@ -461,7 +475,9 @@ clicon_option_int(clicon_handle h, const char *name)
/*! Set option given as int. /*! Set option given as int.
*/ */
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]; char s[64];
@ -473,7 +489,8 @@ clicon_option_int_set(clicon_handle h, const char *name, int val)
/*! Delete option /*! Delete option
*/ */
int 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); 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"); 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 */ /*! Get family of backend socket: AF_UNIX, AF_INET or AF_INET6 */
int int
clicon_sock_family(clicon_handle h) clicon_sock_family(clicon_handle h)

View file

@ -175,7 +175,7 @@ xmldb_plugin_unload(clicon_handle h)
* @retval -1 Failed validate, xret set to error * @retval -1 Failed validate, xret set to error
*/ */
int int
xmldb_validate_db(char *db) xmldb_validate_db(const char *db)
{ {
if (strcmp(db, "running") != 0 && if (strcmp(db, "running") != 0 &&
strcmp(db, "candidate") != 0 && strcmp(db, "candidate") != 0 &&
@ -336,7 +336,7 @@ xmldb_setopt(clicon_handle h,
*/ */
int int
xmldb_get(clicon_handle h, xmldb_get(clicon_handle h,
char *db, const char *db,
char *xpath, char *xpath,
int config, int config,
cxobj **xtop) cxobj **xtop)
@ -393,7 +393,7 @@ xmldb_get(clicon_handle h,
*/ */
int int
xmldb_put(clicon_handle h, xmldb_put(clicon_handle h,
char *db, const char *db,
enum operation_type op, enum operation_type op,
cxobj *xt) cxobj *xt)
{ {
@ -439,8 +439,8 @@ xmldb_put(clicon_handle h,
*/ */
int int
xmldb_copy(clicon_handle h, xmldb_copy(clicon_handle h,
char *from, const char *from,
char *to) const char *to)
{ {
int retval = -1; int retval = -1;
xmldb_handle xh; xmldb_handle xh;
@ -472,7 +472,7 @@ xmldb_copy(clicon_handle h,
*/ */
int int
xmldb_lock(clicon_handle h, xmldb_lock(clicon_handle h,
char *db, const char *db,
int pid) int pid)
{ {
int retval = -1; int retval = -1;
@ -506,7 +506,7 @@ xmldb_lock(clicon_handle h,
*/ */
int int
xmldb_unlock(clicon_handle h, xmldb_unlock(clicon_handle h,
char *db) const char *db)
{ {
int retval = -1; int retval = -1;
xmldb_handle xh; xmldb_handle xh;
@ -569,7 +569,7 @@ xmldb_unlock_all(clicon_handle h,
*/ */
int int
xmldb_islocked(clicon_handle h, xmldb_islocked(clicon_handle h,
char *db) const char *db)
{ {
int retval = -1; int retval = -1;
xmldb_handle xh; xmldb_handle xh;
@ -601,7 +601,7 @@ xmldb_islocked(clicon_handle h,
*/ */
int int
xmldb_exists(clicon_handle h, xmldb_exists(clicon_handle h,
char *db) const char *db)
{ {
int retval = -1; int retval = -1;
xmldb_handle xh; xmldb_handle xh;
@ -632,7 +632,7 @@ xmldb_exists(clicon_handle h,
*/ */
int int
xmldb_delete(clicon_handle h, xmldb_delete(clicon_handle h,
char *db) const char *db)
{ {
int retval = -1; int retval = -1;
xmldb_handle xh; xmldb_handle xh;
@ -663,7 +663,7 @@ xmldb_delete(clicon_handle h,
*/ */
int int
xmldb_create(clicon_handle h, xmldb_create(clicon_handle h,
char *db) const char *db)
{ {
int retval = -1; int retval = -1;
xmldb_handle xh; xmldb_handle xh;

View file

@ -22,7 +22,7 @@ if [ $? -ne 0 ]; then
fi fi
new "start backend" new "start backend"
# start new backend # start new backend
sudo clixon_backend -If $clixon_cf sudo clixon_backend -s init -f $clixon_cf
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
err err
fi fi

View file

@ -55,7 +55,7 @@ fi
new "start backend" new "start backend"
# start new 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 if [ $? -ne 0 ]; then
err err
fi fi

View file

@ -16,7 +16,7 @@ if [ $? -ne 0 ]; then
fi fi
new "start backend" new "start backend"
# start new backend # start new backend
sudo clixon_backend -If $clixon_cf sudo clixon_backend -s init -f $clixon_cf
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
err err
fi fi

View file

@ -50,7 +50,7 @@ fi
new "start backend" new "start backend"
# start new 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 if [ $? -ne 0 ]; then
err err
fi fi

View file

@ -12,7 +12,7 @@ if [ $? -ne 0 ]; then
err err
fi fi
new "start backend" new "start backend"
sudo clixon_backend -If $clixon_cf sudo clixon_backend -s init -f $clixon_cf
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
err err
fi fi

90
test/test_startup.sh Executable file
View 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>'

View file

@ -69,7 +69,7 @@ if [ $? -ne 0 ]; then
fi fi
new "start backend" new "start backend"
# start new 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 if [ $? -ne 0 ]; then
err err
fi fi

View file

@ -70,7 +70,7 @@ fi
new "start backend" new "start backend"
# start new 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 if [ $? -ne 0 ]; then
err err
fi fi

View file

@ -38,9 +38,32 @@
***** END LICENSE BLOCK *****"; ***** END LICENSE BLOCK *****";
revision 2017-07-02 { revision 2017-11-12 {
description 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 { container config {
leaf CLICON_CONFIGFILE{ leaf CLICON_CONFIGFILE{
@ -185,12 +208,17 @@
type int32; type int32;
default 0; default 0;
description "Enabled uses \"startup\" configuration on boot. It is called 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 { leaf CLICON_XMLDB_PLUGIN {
type string; type string;
mandatory true; mandatory true;
description "XMLDB datastore plugin filename (see datastore/ and clixon_xml_db.[ch])"; 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";
}
} }
} }