Netconf startup configuration support. Set CLICON_USE_STARTUP_CONFIG to 1 to

enable. Eg, if backend_main is started with -CIr startup will be copied to
  running.
 Added .. as valid step in xpath
This commit is contained in:
Olof hagsand 2017-02-10 11:54:34 +01:00
parent 30a479de68
commit 4461cc9598
20 changed files with 116 additions and 159 deletions

View file

@ -297,16 +297,10 @@ from_client_commit(clicon_handle h,
int retval = -1;
char *candidate;
char *running;
uint32_t snapshot;
uint32_t startup;
char *archive_dir;
char *startup_config;
if (clicon_msg_commit_decode(msg,
&candidate,
&running,
&snapshot,
&startup,
label) < 0)
goto err;
@ -325,30 +319,6 @@ from_client_commit(clicon_handle h,
goto err;
}
clicon_debug(1, "Commit %s", candidate);
if (snapshot){
if ((archive_dir = clicon_archive_dir(h)) == NULL){
clicon_err(OE_PLUGIN, 0, "snapshot set and clicon_archive_dir not defined");
goto err;
}
if (config_snapshot(h, running, archive_dir) < 0)
goto err;
}
if (startup){
if ((archive_dir = clicon_archive_dir(h)) == NULL){
clicon_err(OE_PLUGIN, 0, "startup set but clicon_archive_dir not defined");
goto err;
}
if ((startup_config = clicon_startup_config(h)) == NULL){
clicon_err(OE_PLUGIN, 0, "startup set but startup_config not defined");
goto err;
}
if (clicon_file_copy("snapshot", "startup") < 0){
clicon_err(OE_PROTO, errno, "%s: Error when creating startup",
__FUNCTION__);
goto err;
}
}
retval = 0;
if (send_msg_ok(s) < 0)
goto done;

View file

@ -72,7 +72,7 @@
#include "backend_handle.h"
/* Command line options to be passed to getopt(3) */
#define BACKEND_OPTS "hD:f:d:Fzu:P:1IRCc::rg:ptx:"
#define BACKEND_OPTS "hD:f:d:Fzu:P:1IRCc:rg:ptx:"
/*! Terminate. Cannot use h after this */
static int
@ -121,7 +121,6 @@ usage(char *argv0, clicon_handle h)
char *plgdir = clicon_backend_dir(h);
char *confsock = clicon_sock(h);
char *confpid = clicon_backend_pidfile(h);
char *startup = clicon_startup_config(h);
char *group = clicon_sock_group(h);
fprintf(stderr, "usage:%s\n"
@ -138,8 +137,7 @@ usage(char *argv0, clicon_handle h)
" -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. Default is\n"
" \t\"CLICON_STARTUP_CONFIG\" = %s\n"
" -c <file>\tLoad specified application config.\n"
" -r\t\tReload running database\n"
" -p \t\tPrint database yang specification\n"
" -t \t\tPrint alternate spec translation (eg if YANG print KEY, if KEY print YANG)\n"
@ -149,7 +147,6 @@ usage(char *argv0, clicon_handle h)
plgdir ? plgdir : "none",
confsock ? confsock : "none",
confpid ? confpid : "none",
startup ? startup : "none",
group ? group : "none"
);
exit(-1);
@ -415,11 +412,7 @@ main(int argc, char **argv)
reset_state_candidate++;
break;
case 'c': /* Load application config */
app_config_file = optarg ? optarg : clicon_startup_config(h);
if (app_config_file == NULL) {
fprintf(stderr, "Option \"CLICON_STARTUP_CONFIG\" not set\n");
return -1;
}
app_config_file = optarg;
break;
case 'r': /* Reload running */
reload_running++;
@ -510,6 +503,19 @@ main(int argc, char **argv)
if (yang_spec_main(h, stdout, printspec) < 0)
goto done;
/* First check for starup 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 (rundb_init(h) < 0)
goto done;
}
/* If running exists and reload_running set, make a copy to candidate */
if (reload_running){
if (xmldb_exists(h, "running") != 1){
@ -549,14 +555,13 @@ main(int argc, char **argv)
*(argv-1) = tmp;
if (reload_running){
if (candidate_commit(h, "candidate") < 0)
goto done;
/* This could be afailed validation, and we should not fail for that */
(void)candidate_commit(h, "candidate");
}
/* Have we specified a config file to load? eg
-c <file>
-r replace running (obsolete)
*/
* -c [<file>]
*/
if (app_config_file)
if (rundb_main(h, app_config_file) < 0)
goto done;

View file

@ -257,7 +257,7 @@ cli_dbxmlv(clicon_handle h,
if (clicon_rpc_change(h, "candidate", op, xk, str) < 0)
goto done;
if (clicon_autocommit(h)) {
if (clicon_rpc_commit(h, "candidate", "running", 0, 0) < 0)
if (clicon_rpc_commit(h, "candidate", "running") < 0)
goto done;
}
retval = 0;
@ -456,7 +456,7 @@ cli_quitv(clicon_handle h,
}
/*! Generic commit callback
* @param[in] arg If 1, then snapshot and copy to startup config
* @param[in] argv No arguments expected
*/
int
cli_commitv(clicon_handle h,
@ -464,21 +464,10 @@ cli_commitv(clicon_handle h,
cvec *argv)
{
int retval = -1;
int snapshot;
if (cvec_len(argv) > 1){
clicon_err(OE_PLUGIN, 0, "%s: Requires 0 or 1 element. If given: snapshot flag 0|1", __FUNCTION__);
goto done;
}
if (cvec_len(argv))
snapshot = cv_int32_get(cvec_i(argv, 0));
else
snapshot = 0;
if ((retval = clicon_rpc_commit(h,
"candidate",
"running",
snapshot, /* snapshot */
snapshot)) < 0){ /* startup */
"running")) < 0){ /* startup */
cli_output(stderr, "Commit failed. Edit and try again or discard changes");
goto done;
}
@ -702,8 +691,8 @@ load_config_filev(clicon_handle h,
* Utility function used by cligen spec file
* @param[in] h CLICON handle
* @param[in] cvv variable vector (containing <varname>)
* @param[in] arg a string: "<dbname> <varname>"
* <dbname> is running or candidate
* @param[in] argv a string: "<dbname> <varname>"
* <dbname> is running, candidate, or startup
* <varname> is name of cligen variable in the "cvv" vector containing file name
* Note that "filename" is local on client filesystem not backend.
* The function can run without a local database
@ -735,23 +724,11 @@ save_config_filev(clicon_handle h,
goto done;
}
#if 0
if (arg == NULL || (str = cv_string_get(arg)) == NULL){
clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__);
goto done;
}
if ((vec = clicon_strsplit(str, " ", &nvec, __FUNCTION__)) == NULL){
clicon_err(OE_PLUGIN, errno, "clicon_strsplit");
goto done;
}
if (nvec != 2){
clicon_err(OE_PLUGIN, 0, "Arg syntax is <dbname> <varname>");
goto done;
}
#endif
dbstr = cv_string_get(cvec_i(argv, 0));
varstr = cv_string_get(cvec_i(argv, 1));
if (strcmp(dbstr, "running") != 0 && strcmp(dbstr, "candidate") != 0) {
if (strcmp(dbstr, "running") != 0 &&
strcmp(dbstr, "candidate") != 0 &&
strcmp(dbstr, "startup") != 0) {
clicon_err(OE_PLUGIN, 0, "No such db name: %s", dbstr);
goto done;
}
@ -799,7 +776,9 @@ delete_allv(clicon_handle h,
goto done;
}
dbstr = cv_string_get(cvec_i(argv, 0));
if (strcmp(dbstr, "running") != 0 && strcmp(dbstr, "candidate") != 0){
if (strcmp(dbstr, "running") != 0 &&
strcmp(dbstr, "candidate") != 0 &&
strcmp(dbstr, "startup") != 0){
clicon_err(OE_PLUGIN, 0, "No such db name: %s", dbstr);
goto done;
}
@ -822,6 +801,22 @@ discard_changesv(clicon_handle h,
return clicon_rpc_copy(h, "running", "candidate");
}
/*! Copy from one database to another, eg running->startup
* @param[in] argv a string: "<db1> <db2>" Copy from db1 to db2
*/
int
db_copy(clicon_handle h,
cvec *cvv,
cvec *argv)
{
char *db1;
char *db2;
db1 = cv_string_get(cvec_i(argv, 0));
db2 = cv_string_get(cvec_i(argv, 1));
return clicon_rpc_copy(h, db1, db2);
}
/* These are strings that can be used as 3rd argument to cli_setlog */
static const char *SHOWAS_TXT = "txt";
static const char *SHOWAS_XML = "xml";

View file

@ -126,7 +126,8 @@ expandv_dbvar(void *h,
}
dbstr = cv_string_get(cv);
if (strcmp(dbstr, "running") != 0 &&
strcmp(dbstr, "candidate") != 0){
strcmp(dbstr, "candidate") != 0 &&
strcmp(dbstr, "startup") != 0){
clicon_err(OE_PLUGIN, 0, "No such db name: %s", dbstr);
goto done;
}
@ -407,7 +408,7 @@ xml2csv(FILE *f, cxobj *x, cvec *cvv)
* @param[in] arg A string: <dbname> <xpath> [<varname>]
* @param[out] xt Configuration as xml tree.
* Format of arg:
* <dbname> "running", "candidate"
* <dbname> "running", "candidate", "startup"
* <xpath> xpath expression
* <varname> optional name of variable in cvv. If set, xpath must have a '%s'
* @code
@ -440,7 +441,9 @@ show_confv_as(clicon_handle h,
}
/* Dont get attr here, take it from arg instead */
db = cv_string_get(cvec_i(argv, 0));
if (strcmp(db, "running") != 0 && strcmp(db, "candidate") != 0) {
if (strcmp(db, "running") != 0 &&
strcmp(db, "candidate") != 0 &&
strcmp(db, "startup") != 0) {
clicon_err(OE_PLUGIN, 0, "No such db name: %s", db);
goto done;
}
@ -703,8 +706,8 @@ show_confv_as_csv(clicon_handle h,
*/
int
show_confv_xpath(clicon_handle h,
cvec *cvv,
cvec *argv)
cvec *cvv,
cvec *argv)
{
int retval = -1;
char *str;
@ -721,7 +724,9 @@ show_confv_xpath(clicon_handle h,
}
str = cv_string_get(cvec_i(argv, 0));
/* Dont get attr here, take it from arg instead */
if (strcmp(str, "running") != 0 && strcmp(str, "candidate") != 0){
if (strcmp(str, "running") != 0 &&
strcmp(str, "candidate") != 0 &&
strcmp(str, "startup") != 0){
clicon_err(OE_PLUGIN, 0, "No such db name: %s", str);
goto done;
}
@ -790,7 +795,8 @@ expand_dbvar(void *h,
}
dbstr = vec[0];
if (strcmp(dbstr, "running") != 0 &&
strcmp(dbstr, "candidate") != 0){
strcmp(dbstr, "candidate") != 0 &&
strcmp(dbstr, "startup") != 0){
clicon_err(OE_PLUGIN, 0, "No such db name: %s", dbstr);
goto done;
}
@ -869,7 +875,7 @@ expand_dbvar(void *h,
* @param[in] arg A string: <dbname> <xpath> [<varname>]
* @param[out] xt Configuration as xml tree.
* Format of arg:
* <dbname> "running", "candidate"
* <dbname> "running", "candidate", "startup"
* <xpath> xpath expression
* <varname> optional name of variable in cvv. If set, xpath must have a '%s'
* @code
@ -909,7 +915,9 @@ show_conf_as(clicon_handle h,
}
/* Dont get attr here, take it from arg instead */
db = vec[0];
if (strcmp(db, "running") != 0 && strcmp(db, "candidate") != 0) {
if (strcmp(db, "running") != 0 &&
strcmp(db, "candidate") != 0 &&
strcmp(db, "startup") != 0) {
clicon_err(OE_PLUGIN, 0, "No such db name: %s", db);
goto done;
}
@ -1178,7 +1186,9 @@ show_conf_xpath(clicon_handle h,
goto done;
}
/* Dont get attr here, take it from arg instead */
if (strcmp(str, "running") != 0 && strcmp(str, "candidate") != 0){
if (strcmp(str, "running") != 0 &&
strcmp(str, "candidate") != 0 &&
strcmp(str, "startup") != 0){
clicon_err(OE_PLUGIN, 0, "No such db name: %s", str);
goto done;
}

View file

@ -88,7 +88,7 @@ usage(char *argv0)
"\t-h\t\tHelp\n"
"\t-D\t\tDebug\n"
"\t-S\t\tLog on syslog\n"
"\t-d <db>\tDatabase name (default: running)\n"
"\t-d <db>\t\tDatabase name (default: running)\n"
"\t-p\t\tDump database on stdout\n"
"\t-b\t\tBrief output, just print keys. Combine with -p or -m\n"
"\t-n \"<key> <val>\" Add database entry\n"

View file

@ -120,9 +120,7 @@ netconf_create_hello(cbuf *xf, /* msg buffer */
cprintf(xf, "<capability>urn:ietf:params:xml:ns:netconf:capability:validate:1.0</capability>\n");
cprintf(xf, "<capability>urn:ietf:params:netconf:capability:xpath:1.0</capability>\n");
cprintf(xf, "<capability>urn:ietf:params:netconf:capability:notification:1.0</capability>\n");
// cprintf(xf, "<capability>urn:rnr:rnrapi:1:0</capability>");
cprintf(xf, "<capability>urn:ietf:params:netconf:capability:startup:1.0</capability>\n");
cprintf(xf, "</capabilities>");
cprintf(xf, "<session-id>%lu</session-id>", 42+session_id);
cprintf(xf, "</hello>");

View file

@ -204,6 +204,9 @@ netconf_get_target(clicon_handle h,
else
if (xpath_first(x, "running") != NULL)
target = "running";
else
if (xpath_first(x, "startup") != NULL)
target = "startup";
}
return target;

View file

@ -247,11 +247,11 @@ netconf_get_config(clicon_handle h,
cbuf *cb_err,
cxobj *xorig)
{
cxobj *xfilter; /* filter */
int retval = -1;
char *source;
cxobj *xfilter; /* filter */
int retval = -1;
char *source;
enum filter_option foption = FILTER_SUBTREE;
char *ftype = NULL;
char *ftype = NULL;
if ((source = netconf_get_target(h, xn, "source")) == NULL){
netconf_create_rpc_error(cb_err, xorig,
@ -568,7 +568,7 @@ netconf_delete_config(clicon_handle h,
"<bad-element>target</bad-element>");
goto done;
}
if (strcmp(target, "candidate")){
if (strcmp(target, "running") == 0){
netconf_create_rpc_error(cb_err, xorig,
"bad-element",
"protocol",
@ -577,7 +577,7 @@ netconf_delete_config(clicon_handle h,
"<bad-element>target</bad-element>");
goto done;
}
if (clicon_rpc_change(h, "candidate",
if (clicon_rpc_change(h, target,
OP_REMOVE,
"/", "") < 0){
netconf_create_rpc_error(cb_err, xorig,
@ -745,8 +745,7 @@ netconf_commit(clicon_handle h,
{
int retval = -1;
if (clicon_rpc_commit(h, "candidate", "running",
0, 0) < 0){
if (clicon_rpc_commit(h, "candidate", "running") < 0){
netconf_create_rpc_error(cb_err, xorig,
"operation-failed",
"protocol", "error",

View file

@ -273,8 +273,7 @@ api_data_delete(clicon_handle h,
api_path,
"") < 0)
goto done;
if (clicon_rpc_commit(h, "candidate", "running",
0, 0) < 0)
if (clicon_rpc_commit(h, "candidate", "running") < 0)
goto done;
FCGX_SetExitStatus(201, r->out);
FCGX_FPrintF(r->out, "Content-Type: text/plain\r\n");
@ -348,8 +347,7 @@ api_data_put(clicon_handle h,
api_path,
cbuf_get(cbx)) < 0)
goto done;
if (clicon_rpc_commit(h, "candidate", "running",
0, 0) < 0)
if (clicon_rpc_commit(h, "candidate", "running") < 0)
goto done;
FCGX_SetExitStatus(201, r->out); /* Created */
FCGX_FPrintF(r->out, "Content-Type: text/plain\r\n");