diff --git a/CHANGELOG.md b/CHANGELOG.md index 19d71504..e528ef5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,8 @@ clixon_cli -f /usr/local/etc/routing.conf -1x Backward compatibility is enabled by defining BACKEND_STARTUP_BACKWARD_COMPAT in include/clixon_custom.h ### Minor changes: +* Disabled key-value datastore. Enable with --with-keyvalue +* Removed mandatory requirements for BACKEND, NETCONF, RESTCONF and CLI dirs. * 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 diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c index 971adcf0..efa8a8f0 100644 --- a/apps/backend/backend_main.c +++ b/apps/backend/backend_main.c @@ -140,7 +140,7 @@ usage(char *argv0, clicon_handle h) " -1\t\tRun once and then quit (dont wait for events)\n" " -u \tConfig UNIX domain path / ip address (default: %s)\n" " -P \tPid filename (default: %s)\n" - " -s \tSpecify backend startup mode: none|startup|running|init (replaces -IRCc:r:\n" + " -s \tSpecify backend startup mode: none|startup|running|init (replaces -IRCr\n" " -c \tLoad extra xml configuration, but don't commit.\n" #ifdef BACKEND_STARTUP_BACKWARD_COMPAT " -I\t\tInitialize running state database\n" @@ -835,7 +835,8 @@ main(int argc, char **argv) ) < 0) goto done; #else - clicon_log(LOG_ERR, "Startup mode indefined. Specify option CLICON_STARTUP_MODE or specify -s option to clicon_backend.\n"); + clicon_log(LOG_ERR, "Startup mode undefined. Specify option CLICON_STARTUP_MODE or specify -s option to clicon_backend.\n"); + goto done; #endif } else { diff --git a/apps/backend/backend_plugin.c b/apps/backend/backend_plugin.c index 8003013a..b194931d 100644 --- a/apps/backend/backend_plugin.c +++ b/apps/backend/backend_plugin.c @@ -431,11 +431,9 @@ plugin_initiate(clicon_handle h) return -1; /* Then load application plugins */ - if ((dir = clicon_backend_dir(h)) == NULL){ - clicon_err(OE_PLUGIN, 0, "backend_dir not defined"); - return -1; - } - if (backend_plugin_load_dir(h, dir) < 0) + dir = clicon_backend_dir(h); + /* If backend directory, load the backend plugisn */ + if (dir && backend_plugin_load_dir(h, dir) < 0) return -1; return 0; diff --git a/apps/cli/cli_main.c b/apps/cli/cli_main.c index a3cc885f..972ee5d9 100644 --- a/apps/cli/cli_main.c +++ b/apps/cli/cli_main.c @@ -400,12 +400,6 @@ main(int argc, char **argv) if (yang_spec_main(h, stdout, printspec) < 0) goto done; - /* Check plugin directory */ - if (clicon_cli_dir(h) == NULL){ - clicon_err(OE_PLUGIN, 0, "clicon_cli_dir not defined"); - goto done; - } - /* Create tree generated from dataspec. If no other trees exists, this is * the only one. */ diff --git a/apps/cli/cli_plugin.c b/apps/cli/cli_plugin.c index 18288125..ef3dfcaa 100644 --- a/apps/cli/cli_plugin.c +++ b/apps/cli/cli_plugin.c @@ -366,7 +366,9 @@ done: /*! Load plugins within a directory */ static int -cli_plugin_load_dir(clicon_handle h, char *dir, cli_syntax_t *stx) +cli_plugin_load_dir(clicon_handle h, + char *dir, + cli_syntax_t *stx) { int i; int ndp; @@ -452,10 +454,7 @@ cli_syntax_load (clicon_handle h) return 0; /* Format plugin directory path */ - if ((plugin_dir = clicon_cli_dir(h)) == NULL){ - clicon_err(OE_FATAL, 0, "clicon_cli_dir not set"); - goto quit; - } + plugin_dir = clicon_cli_dir(h); clispec_dir = clicon_clispec_dir(h); clispec_file = clicon_option_str(h, "CLICON_CLISPEC_FILE"); @@ -474,7 +473,7 @@ cli_syntax_load (clicon_handle h) goto quit; /* Then load application plugins */ - if (cli_plugin_load_dir(h, plugin_dir, stx) < 0) + if (plugin_dir && cli_plugin_load_dir(h, plugin_dir, stx) < 0) goto quit; if (clispec_file){ diff --git a/apps/netconf/netconf_main.c b/apps/netconf/netconf_main.c index 990e89b6..ed2f1373 100644 --- a/apps/netconf/netconf_main.c +++ b/apps/netconf/netconf_main.c @@ -286,8 +286,6 @@ static void usage(clicon_handle h, char *argv0) { - char *netconfdir = clicon_netconf_dir(h); - fprintf(stderr, "usage:%s\n" "where options are\n" "\t-h\t\tHelp\n" @@ -298,7 +296,7 @@ usage(clicon_handle h, "\t-S\t\tLog on syslog\n" "\t-y \tOverride yang spec file (dont include .yang suffix)\n", argv0, - netconfdir + clicon_netconf_dir(h) ); exit(0); } diff --git a/apps/netconf/netconf_plugin.c b/apps/netconf/netconf_plugin.c index cd169b77..64aa8e87 100644 --- a/apps/netconf/netconf_plugin.c +++ b/apps/netconf/netconf_plugin.c @@ -92,8 +92,9 @@ netconf_plugin_load(clicon_handle h) char filename[MAXPATHLEN]; plghndl_t *handle; + /* If no DIR defined, then dont load plugins */ if ((dir = clicon_netconf_dir(h)) == NULL){ - clicon_err(OE_PLUGIN, 0, "clicon_netconf_dir not defined"); + retval = 0; goto quit; } diff --git a/apps/restconf/restconf_lib.c b/apps/restconf/restconf_lib.c index 08383266..7fc1d0ac 100644 --- a/apps/restconf/restconf_lib.c +++ b/apps/restconf/restconf_lib.c @@ -316,7 +316,7 @@ restconf_plugin_load(clicon_handle h) char filename[MAXPATHLEN]; if ((dir = clicon_restconf_dir(h)) == NULL){ - clicon_err(OE_PLUGIN, 0, "clicon_restconf_dir not defined"); + retval = 0; goto quit; } /* Get plugin objects names from plugin directory */ diff --git a/apps/restconf/restconf_main.c b/apps/restconf/restconf_main.c index 17a0060e..70201edd 100644 --- a/apps/restconf/restconf_main.c +++ b/apps/restconf/restconf_main.c @@ -269,8 +269,6 @@ usage(clicon_handle h, char *argv0) { - char *restconfdir = clicon_restconf_dir(h); - fprintf(stderr, "usage:%s [options]\n" "where options are\n" "\t-h \t\tHelp\n" @@ -279,7 +277,7 @@ usage(clicon_handle h, "\t-d \tSpecify restconf plugin directory dir (default: %s)\n" "\t-y \tOverride yang spec file (dont include .yang suffix)\n", argv0, - restconfdir + clicon_restconf_dir(h) ); exit(0); } diff --git a/configure b/configure index f108d6eb..7412f276 100755 --- a/configure +++ b/configure @@ -1344,7 +1344,7 @@ Optional Packages: --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-cligen=dir Use CLIGEN here --without-restconf disable support for restconf - --without-keyvalue disable support for key-value xmldb datastore + --with-keyvalue enable support for key-value xmldb datastore --with-qdbm=dir Use QDBM here, if keyvalue Some influential environment variables: @@ -3943,10 +3943,10 @@ fi if test "${with_keyvalue+set}" = set; then : withval=$with_keyvalue; else - with_keyvalue=yes + with_keyvalue=no fi - +echo "keyvalue:${with_keyvalue}" if test "x${with_keyvalue}" == xyes; then echo "yes keyvalue" # This is for qdbm diff --git a/configure.ac b/configure.ac index fc423ddf..a5076d40 100644 --- a/configure.ac +++ b/configure.ac @@ -138,10 +138,10 @@ fi # This is for keyvalue datastore (and qdbm) AC_ARG_WITH([keyvalue], - [AS_HELP_STRING([--without-keyvalue],[disable support for key-value xmldb datastore])], - [], - [with_keyvalue=yes]) - + [AS_HELP_STRING([--with-keyvalue],[enable support for key-value xmldb datastore])], + [], + [with_keyvalue=no]) +echo "keyvalue:${with_keyvalue}" if test "x${with_keyvalue}" == xyes; then echo "yes keyvalue" # This is for qdbm diff --git a/datastore/text/clixon_xmldb_text.c b/datastore/text/clixon_xmldb_text.c index c0077221..4df8133b 100644 --- a/datastore/text/clixon_xmldb_text.c +++ b/datastore/text/clixon_xmldb_text.c @@ -881,7 +881,7 @@ text_unlock_all(xmldb_handle xh, int pid) { struct text_handle *th = handle(xh); - char **keys; + char **keys = NULL; size_t klen; int i; int *val; @@ -893,6 +893,8 @@ text_unlock_all(xmldb_handle xh, if ((val = hash_value(th->th_dbs, keys[i], &vlen)) != NULL && *val == pid) hash_del(th->th_dbs, keys[i]); + if (keys) + free(keys); return 0; } diff --git a/example/routing_backend.c b/example/routing_backend.c index e667b2d0..a0f23b0a 100644 --- a/example/routing_backend.c +++ b/example/routing_backend.c @@ -153,6 +153,8 @@ route_count(clicon_handle h, * @retval 0 OK * @retval -1 Error * @see xmldb_get + * @note this example code returns a static statedata used in testing. + * Real code would poll state */ int plugin_statedata(clicon_handle h, @@ -162,15 +164,11 @@ plugin_statedata(clicon_handle h, int retval = -1; cxobj **xvec = NULL; - fprintf(stderr, "%s xpath:%s\n", __FUNCTION__, xpath); /* Example of (static) statedata, real code would poll state */ if (xml_parse("" "eth0" "eth" - "up" - "up" "42" - "1000000000" "", xstate) < 0) goto done; retval = 0; @@ -218,6 +216,7 @@ plugin_init(clicon_handle h) * @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 + * @note This assumes example yang with interfaces/interface */ int plugin_reset(clicon_handle h, @@ -239,7 +238,7 @@ plugin_reset(clicon_handle h, retval = 0; done: if (xt != NULL) - free(xt); + xml_free(xt); return retval; } diff --git a/lib/src/clixon_options.c b/lib/src/clixon_options.c index 3d6ce6fb..e8eef2c2 100644 --- a/lib/src/clixon_options.c +++ b/lib/src/clixon_options.c @@ -178,6 +178,8 @@ clicon_option_readfile_xml(clicon_hash_t *copt, } retval = 0; done: + if (xt) + xml_free(xt); if (f) fclose(f); return retval; @@ -356,7 +358,7 @@ clicon_options_main(clicon_handle h) clicon_hash_t *copt = clicon_options(h); char *suffix; char xml = 0; /* Configfile is xml, otherwise legacy */ - yang_spec *yspec; + yang_spec *yspec = NULL; /* * Set configure file if not set by command-line above @@ -380,6 +382,8 @@ clicon_options_main(clicon_handle h) /* Read configfile */ if (clicon_option_readfile_xml(copt, configfile, yspec) < 0) goto done; + if (yspec) + yspec_free(yspec); } else { /* Set default options */ @@ -529,6 +533,7 @@ clicon_yang_module_revision(clicon_handle h) return clicon_option_str(h, "CLICON_YANG_MODULE_REVISION"); } +/*! Directory of backend plugins. If null, no plugins are loaded */ char * clicon_backend_dir(clicon_handle h) { diff --git a/lib/src/clixon_xml_db.c b/lib/src/clixon_xml_db.c index 383eb4fa..7e85f44c 100644 --- a/lib/src/clixon_xml_db.c +++ b/lib/src/clixon_xml_db.c @@ -555,7 +555,7 @@ xmldb_unlock_all(clicon_handle h, clicon_err(OE_DB, 0, "Not connected to datastore plugin"); goto done; } - retval =xa->xa_unlock_all_fn(xh, pid); + retval = xa->xa_unlock_all_fn(xh, pid); done: return retval; } diff --git a/test/test_netconf.sh b/test/test_netconf.sh index 3f1da8a1..67889412 100755 --- a/test/test_netconf.sh +++ b/test/test_netconf.sh @@ -96,7 +96,7 @@ new "netconf edit state operation should fail" expecteof "$clixon_netconf -qf $clixon_cf" "eth1eth]]>]]>" "^invalid-value" new "netconf get state operation" -expecteof "$clixon_netconf -qf $clixon_cf" "]]>]]>" "^]]>]]>$" +expecteof "$clixon_netconf -qf $clixon_cf" "]]>]]>" "^eth0eth42]]>]]>$" new "netconf lock/unlock" expecteof "$clixon_netconf -qf $clixon_cf" "]]>]]>]]>]]>" "^]]>]]>]]>]]>$" diff --git a/test/test_perf.sh b/test/test_perf.sh index 24f15e60..fa31f4d8 100755 --- a/test/test_perf.sh +++ b/test/test_perf.sh @@ -42,7 +42,6 @@ EOF # kill old backend (if any) new "kill old backend" -echo "clixon_backend -zf $clixon_cf -y $fyang" sudo clixon_backend -zf $clixon_cf -y $fyang if [ $? -ne 0 ]; then err diff --git a/test/test_restconf.sh b/test/test_restconf.sh index f77fd3bf..a8fc45d0 100755 --- a/test/test_restconf.sh +++ b/test/test_restconf.sh @@ -6,7 +6,7 @@ . ./lib.sh # This is a fixed 'state' implemented in routing_backend. It is always there -state='{"interfaces-state": {"interface": {"name": "eth0","type": "eth","admin-status": "up","oper-status": "up","if-index": "42","speed": "1000000000"}}}' +state='{"interfaces-state": {"interface": {"name": "eth0","type": "eth","if-index": "42"}}}' # kill old backend (if any) new "kill old backend" @@ -47,7 +47,7 @@ new "restconf Add subtree to datastore using POST" expectfn 'curl -sS -X POST -d {"interfaces":{"interface":{"name":"eth/0/0","type":"eth","enabled":"true"}}} http://localhost/restconf/data' "" new "restconf Check interfaces eth/0/0 added" -expectfn "curl -sS -G http://localhost/restconf/data" '{"interfaces": {"interface": {"name": "eth/0/0","type": "eth","enabled": "true"}},"interfaces-state": {"interface": {"name": "eth0","type": "eth","admin-status": "up","oper-status": "up","if-index": "42","speed": "1000000000"}}} +expectfn "curl -sS -G http://localhost/restconf/data" '{"interfaces": {"interface": {"name": "eth/0/0","type": "eth","enabled": "true"}},"interfaces-state": {"interface": {"name": "eth0","type": "eth","if-index": "42"}}} $' new "restconf delete interfaces" @@ -60,7 +60,7 @@ new "restconf Add interfaces subtree eth/0/0 using POST" expectfn 'curl -sS -X POST -d {"interface":{"name":"eth/0/0","type":"eth","enabled":"true"}} http://localhost/restconf/data/interfaces' "" new "restconf Check eth/0/0 added" -expectfn "curl -sS -G http://localhost/restconf/data" '{"interfaces": {"interface": {"name": "eth/0/0","type": "eth","enabled": "true"}},"interfaces-state": {"interface": {"name": "eth0","type": "eth","admin-status": "up","oper-status": "up","if-index": "42","speed": "1000000000"}}} +expectfn "curl -sS -G http://localhost/restconf/data" '{"interfaces": {"interface": {"name": "eth/0/0","type": "eth","enabled": "true"}},"interfaces-state": {"interface": {"name": "eth0","type": "eth","if-index": "42"}}} $' new "restconf Re-post eth/0/0 which should generate error" @@ -86,7 +86,7 @@ new "restconf Add subtree eth/0/0 using PUT" expectfn 'curl -sS -X PUT -d {"interface":{"name":"eth/0/0","type":"eth","enabled":"true"}} http://localhost/restconf/data/interfaces/interface=eth%2f0%2f0' "" new "restconf get subtree" -expectfn "curl -sS -G http://localhost/restconf/data" '{"interfaces": {"interface": {"name": "eth/0/0","type": "eth","enabled": "true"}},"interfaces-state": {"interface": {"name": "eth0","type": "eth","admin-status": "up","oper-status": "up","if-index": "42","speed": "1000000000"}}} +expectfn "curl -sS -G http://localhost/restconf/data" '{"interfaces": {"interface": {"name": "eth/0/0","type": "eth","enabled": "true"}},"interfaces-state": {"interface": {"name": "eth0","type": "eth","if-index": "42"}}} $' new "restconf operation rpc using POST json" diff --git a/test/test_startup.sh b/test/test_startup.sh index d568ab6b..99cf1afa 100755 --- a/test/test_startup.sh +++ b/test/test_startup.sh @@ -55,20 +55,20 @@ EOF # kill old backend (if any) new "kill old backend" - sudo clixon_backend -zf $clixon_cf $yang + sudo clixon_backend -zf $clixon_cf if [ $? -ne 0 ]; then err fi new "start backend" # start new backend - sudo clixon_backend -f $clixon_cf $yang -s $mode -c /tmp/config + sudo clixon_backend -f $clixon_cf -s $mode -c /tmp/config if [ $? -ne 0 ]; then err fi new "Check $mode" - expecteof "$clixon_netconf -qf $clixon_cf $yang" ']]>]]>' "^$expect]]>]]>$" + expecteof "$clixon_netconf -qf $clixon_cf" ']]>]]>' "^$expect]]>]]>$" new "Kill backend" # Check if still alive diff --git a/test/test_yang.sh b/test/test_yang.sh index 8c0b6dc3..779cb84a 100755 --- a/test/test_yang.sh +++ b/test/test_yang.sh @@ -3,12 +3,29 @@ # include err() and new() functions . ./lib.sh +clixon_cf=/tmp/conf_yang.xml # For memcheck # clixon_netconf="valgrind --leak-check=full --show-leak-kinds=all clixon_netconf" clixon_netconf=clixon_netconf clixon_cli=clixon_cli +cat < /tmp/conf_yang.xml + + /tmp/test_yang.xml + /usr/local/share/routing/yang + example + /usr/local/lib/routing/clispec + /usr/local/lib/routing/cli + routing + /usr/local/var/routing/routing.sock + /usr/local/var/routing/routing.pidfile + 1 + /usr/local/var/routing + /usr/local/lib/xmldb/text.so + +EOF + cat < /tmp/test.yang module example{ container x { diff --git a/yang/clixon-config@2017-07-02.yang b/yang/clixon-config@2017-07-02.yang index 2cb9a8a0..7998cc50 100644 --- a/yang/clixon-config@2017-07-02.yang +++ b/yang/clixon-config@2017-07-02.yang @@ -89,18 +89,15 @@ } leaf CLICON_BACKEND_DIR { type string; - mandatory true; description "Location of backend .so plugins. Load all .so plugins in this dir as backend plugins"; } leaf CLICON_NETCONF_DIR { type string; - mandatory true; description "Location of netconf (frontend) .so plugins"; } leaf CLICON_RESTCONF_DIR { type string; - mandatory true; description "Location of restconf (frontend) .so plugins. Load all .so plugins in this dir as restconf code plugins"; } @@ -112,7 +109,6 @@ } leaf CLICON_CLI_DIR { type string; - mandatory true; description "Location of cli frontend .so plugins. Load all .so plugins in this dir as CLI object plugins"; }