From 6bf2a74e2453621485143c05d846823a00d0e961 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Fri, 26 Apr 2019 12:12:55 +0200 Subject: [PATCH] * Restconf with startup feature will now copy all edit changes to startup db (as it should according to RFC 8040) * See [Restconf does not handle startup datastore according to the RFC](https://github.com/clicon/clixon/issues/74) * Netconf Startup feature is no longer hardcoded, you need to explicitly enable it (See RFC 6241, Section 8.7) * Enable in config file with: `ietf-netconf:startup`, or use `*:*` --- CHANGELOG.md | 6 +- README.md | 4 +- apps/backend/backend_main.c | 7 ++ apps/cli/cli_main.c | 4 + apps/restconf/restconf_main.c | 10 +++ apps/restconf/restconf_methods.c | 55 ++++++++++++++ doc/FAQ.md | 11 +++ example/main/example.xml | 2 +- lib/clixon/clixon_data.h | 12 --- lib/clixon/clixon_yang.h | 1 + lib/src/clixon_data.c | 98 ------------------------ lib/src/clixon_netconf_lib.c | 6 -- lib/src/clixon_yang.c | 36 ++++++++- test/test_copy_config.sh | 1 + test/test_feature.sh | 2 +- test/test_nacm_default.sh | 1 + test/test_nacm_protocol.sh | 1 + test/test_netconf.sh | 1 + test/test_restconf.sh | 4 +- test/test_restconf_startup.sh | 126 +++++++++++++++++++++++++++++++ test/test_rpc.sh | 2 +- test/test_startup.sh | 4 +- test/test_upgrade.sh | 1 + test/test_upgrade_auto.sh | 1 + test/test_upgrade_interfaces.sh | 1 + test/test_upgrade_repair.sh | 1 + 26 files changed, 270 insertions(+), 128 deletions(-) create mode 100755 test/test_restconf_startup.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index 1aaa51a1..4c95cb23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,9 @@ ### API changes on existing features (you may need to change your code) +* Restconf with startup feature will now copy all edit changes to startup db (as it should according to RFC 8040) +* Netconf Startup feature is no longer hardcoded, you need to explicitly enable it (See RFC 6241, Section 8.7) + * Enable in config file with: `ietf-netconf:startup`, or use `*:*` * The directory `docker/system` has been moved to `docker/main`, to reflect that it runs the main example. * xmldb_get() removed "config" parameter: * Change all calls to dbget from: `xmldb_get(h, db, xpath, 0|1, &xret, msd)` to `xmldb_get(h, db, xpath, &xret, msd)` @@ -111,7 +114,7 @@ ### Minor changes -* A new "hello world" example is added +* A new minimal "hello world" example has been added * Experimental customized error output strings, see [lib/clixon/clixon_err_string.h] * Empty leaf values, eg are now checked at validation. * Empty values were skipped in validation. @@ -138,6 +141,7 @@ * Added libgen.h for baseline() ### Corrected Bugs +* [Restconf does not handle startup datastore according to the RFC](https://github.com/clicon/clixon/issues/74) * Failure in startup with -m startup or running left running_db cleared. * Running-db should not be changed on failure. Unless failure-db defined. Or if SEGV, etc. In those cases, tmp_db should include the original running-db. * Backend plugin returning NULL was still installed - is now logged and skipped. diff --git a/README.md b/README.md index b26a32d2..5d195282 100644 --- a/README.md +++ b/README.md @@ -162,10 +162,12 @@ Clixon implements the following NETCONF proposals or standards: The following RFC6241 capabilities/features are hardcoded in Clixon: - :candidate (RFC6241 8.3) - :validate (RFC6241 8.6) -- :startup (RFC6241 8.7) - :xpath (RFC6241 8.9) - :notification: (RFC5277) +The following features are optional and can be enabled by setting CLICON_FEATURE: +- :startup (RFC6241 8.7) + Clixon does not support the following netconf features: - :url capability diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c index 658447e8..e132435e 100644 --- a/apps/backend/backend_main.c +++ b/apps/backend/backend_main.c @@ -616,6 +616,13 @@ main(int argc, clicon_log(LOG_ERR, "Startup mode undefined. Specify option CLICON_STARTUP_MODE or specify -s option to clicon_backend."); goto done; } + /* Check that netconf :startup is enabled */ + if (startup_mode == SM_STARTUP && + !if_feature(yspec, "ietf-netconf", "startup")){ + clicon_log(LOG_ERR, "Startup mode selected but Netconf :startup feature is not enabled. Enable with option: ietf-netconf:startup"); + goto done; + } + /* Init running db if it is not there */ if (xmldb_exists(h, "running") != 1) diff --git a/apps/cli/cli_main.c b/apps/cli/cli_main.c index 7b4c5205..cc0ab648 100644 --- a/apps/cli/cli_main.c +++ b/apps/cli/cli_main.c @@ -485,6 +485,10 @@ main(int argc, char **argv) if (yang_modules_init(h) < 0) goto done; + /* Add netconf yang spec, used as internal protocol */ + if (netconf_module_load(h) < 0) + goto done; + /* Create tree generated from dataspec. If no other trees exists, this is * the only one. * The following code creates the tree @datamodel diff --git a/apps/restconf/restconf_main.c b/apps/restconf/restconf_main.c index 6d8e8082..92822e80 100644 --- a/apps/restconf/restconf_main.c +++ b/apps/restconf/restconf_main.c @@ -668,6 +668,11 @@ main(int argc, /* Load yang module library, RFC7895 */ if (yang_modules_init(h) < 0) goto done; + + /* Add netconf yang spec, used as internal protocol */ + if (netconf_module_load(h) < 0) + goto done; + /* Add system modules */ if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC8040") && yang_spec_parse_module(h, "ietf-restconf-monitoring", NULL, yspec)< 0) @@ -675,6 +680,11 @@ main(int argc, if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC5277") && yang_spec_parse_module(h, "clixon-rfc5277", NULL, yspec)< 0) goto done; + + /* Dump configuration options on debug */ + if (debug) + clicon_option_dump(h, debug); + /* Call start function in all plugins before we go interactive */ if (clixon_plugin_start(h) < 0) diff --git a/apps/restconf/restconf_methods.c b/apps/restconf/restconf_methods.c index c9277e91..d9df89cd 100644 --- a/apps/restconf/restconf_methods.c +++ b/apps/restconf/restconf_methods.c @@ -588,6 +588,25 @@ api_data_post(clicon_handle h, goto done; goto ok; } + if (if_feature(yspec, "ietf-netconf", "startup")){ + /* RFC8040 Sec 1.4: + * If the NETCONF server supports :startup, the RESTCONF server MUST + * automatically update the non-volatile startup configuration + * datastore, after the "running" datastore has been altered as a + * consequence of a RESTCONF edit operation. + */ + cbuf_reset(cbx); + cprintf(cbx, "", NACM_RECOVERY_USER); + cprintf(cbx, ""); + if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0) + goto done; + /* If copy-config failed, log and ignore (already committed) */ + if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){ + + clicon_log(LOG_WARNING, "%s: copy-config running->startup failed", __FUNCTION__); + } + } + FCGX_SetExitStatus(201, r->out); /* Created */ FCGX_FPrintF(r->out, "Content-Type: text/plain\r\n"); FCGX_FPrintF(r->out, "\r\n"); @@ -914,6 +933,24 @@ api_data_put(clicon_handle h, goto done; goto ok; } + if (if_feature(yspec, "ietf-netconf", "startup")){ + /* RFC8040 Sec 1.4: + * If the NETCONF server supports :startup, the RESTCONF server MUST + * automatically update the non-volatile startup configuration + * datastore, after the "running" datastore has been altered as a + * consequence of a RESTCONF edit operation. + */ + cbuf_reset(cbx); + cprintf(cbx, "", NACM_RECOVERY_USER); + cprintf(cbx, ""); + if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0) + goto done; + /* If copy-config failed, log and ignore (already committed) */ + if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){ + + clicon_log(LOG_WARNING, "%s: copy-config running->startup failed", __FUNCTION__); + } + } FCGX_SetExitStatus(201, r->out); /* Created */ FCGX_FPrintF(r->out, "Content-Type: text/plain\r\n"); FCGX_FPrintF(r->out, "\r\n"); @@ -1071,6 +1108,24 @@ api_data_delete(clicon_handle h, goto done; goto ok; } + if (if_feature(yspec, "ietf-netconf", "startup")){ + /* RFC8040 Sec 1.4: + * If the NETCONF server supports :startup, the RESTCONF server MUST + * automatically update the non-volatile startup configuration + * datastore, after the "running" datastore has been altered as a + * consequence of a RESTCONF edit operation. + */ + cbuf_reset(cbx); + cprintf(cbx, "", NACM_RECOVERY_USER); + cprintf(cbx, ""); + if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0) + goto done; + /* If copy-config failed, log and ignore (already committed) */ + if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){ + + clicon_log(LOG_WARNING, "%s: copy-config running->startup failed", __FUNCTION__); + } + } FCGX_SetExitStatus(201, r->out); FCGX_FPrintF(r->out, "Content-Type: text/plain\r\n"); FCGX_FPrintF(r->out, "\r\n"); diff --git a/doc/FAQ.md b/doc/FAQ.md index a5c81437..24aaf048 100644 --- a/doc/FAQ.md +++ b/doc/FAQ.md @@ -298,6 +298,17 @@ The example below shows enabling a specific feature; enabling all features in mo Features can be probed by using RFC 7895 Yang module library which provides information on all modules and which features are enabled. +Clixon have three hardcoded features: +- :candidate (RFC6241 8.3) +- :validate (RFC6241 8.6) +- :xpath (RFC6241 8.9) + +You can select the startup feature by including it in the config file: +``` + ietf-netconf:startup +``` +(or just `ietf-netconf:*`). + ## Can I run Clixon as a container? Yes, Clixon has two examples on how to build docker containers. A [base](../docker/base) image and a complete [example system](../docker/system). diff --git a/example/main/example.xml b/example/main/example.xml index a7c13214..85c751bf 100644 --- a/example/main/example.xml +++ b/example/main/example.xml @@ -1,6 +1,6 @@ /usr/local/etc/example.xml - *:* + ietf-netconf:startup /usr/local/share/clixon clixon-example example diff --git a/lib/clixon/clixon_data.h b/lib/clixon/clixon_data.h index 6f4872b6..54537008 100644 --- a/lib/clixon/clixon_data.h +++ b/lib/clixon/clixon_data.h @@ -70,18 +70,6 @@ int clicon_config_yang_set(clicon_handle h, yang_stmt *ys); cxobj *clicon_conf_xml(clicon_handle h); int clicon_conf_xml_set(clicon_handle h, cxobj *x); -#ifdef XXX -plghndl_t clicon_xmldb_plugin_get(clicon_handle h); -int clicon_xmldb_plugin_set(clicon_handle h, plghndl_t handle); - -void *clicon_xmldb_api_get(clicon_handle h); -int clicon_xmldb_api_set(clicon_handle h, void *xa_api); - - -void *clicon_xmldb_handle_get(clicon_handle h); -int clicon_xmldb_handle_set(clicon_handle h, void *xh); -#endif - db_elmnt *clicon_db_elmnt_get(clicon_handle h, const char *db); int clicon_db_elmnt_set(clicon_handle h, const char *db, db_elmnt *xc); diff --git a/lib/clixon/clixon_yang.h b/lib/clixon/clixon_yang.h index 8f5c775a..76e49980 100644 --- a/lib/clixon/clixon_yang.h +++ b/lib/clixon/clixon_yang.h @@ -184,6 +184,7 @@ yang_stmt *yang_choice(yang_stmt *y); int yang_order(yang_stmt *y); int yang_print(FILE *f, yang_stmt *yn); int yang_print_cbuf(cbuf *cb, yang_stmt *yn, int marginal); +int if_feature(yang_stmt *yspec, char *module, char *feature); int ys_populate(yang_stmt *ys, void *arg); yang_stmt *yang_parse_file(int fd, const char *name, yang_stmt *ysp); int yang_apply(yang_stmt *yn, enum rfc_6020 key, yang_applyfn_t fn, diff --git a/lib/src/clixon_data.c b/lib/src/clixon_data.c index 98521bff..56871268 100644 --- a/lib/src/clixon_data.c +++ b/lib/src/clixon_data.c @@ -214,104 +214,6 @@ clicon_conf_xml_set(clicon_handle h, return 0; } -#ifdef XXX -/*! Get xmldb datastore plugin handle, as used by dlopen/dlsym/dlclose */ -plghndl_t -clicon_xmldb_plugin_get(clicon_handle h) -{ - clicon_hash_t *cdat = clicon_data(h); - size_t len; - void *p; - - if ((p = hash_value(cdat, "xmldb_plugin", &len)) != NULL) - return *(plghndl_t*)p; - return NULL; -} - -/*! Set xmldb datastore plugin handle, as used by dlopen/dlsym/dlclose */ -int -clicon_xmldb_plugin_set(clicon_handle h, - plghndl_t handle) -{ - clicon_hash_t *cdat = clicon_data(h); - - if (hash_add(cdat, "xmldb_plugin", &handle, sizeof(void*)) == NULL) - return -1; - return 0; -} - - -/*! Get XMLDB API struct pointer - * @param[in] h Clicon handle - * @retval xa XMLDB API struct - * @note xa is really of type struct xmldb_api* - */ -void * -clicon_xmldb_api_get(clicon_handle h) -{ - clicon_hash_t *cdat = clicon_data(h); - size_t len; - void *xa; - - if ((xa = hash_value(cdat, "xmldb_api", &len)) != NULL) - return *(void**)xa; - return NULL; -} - -/*! Set or reset XMLDB API struct pointer - * @param[in] h Clicon handle - * @param[in] xa XMLDB API struct - * @note xa is really of type struct xmldb_api* - */ -int -clicon_xmldb_api_set(clicon_handle h, - void *xa) -{ - clicon_hash_t *cdat = clicon_data(h); - - /* It is the pointer to xa_api that should be copied by hash, - so we send a ptr to the ptr to indicate what to copy. - */ - if (hash_add(cdat, "xmldb_api", &xa, sizeof(void*)) == NULL) - return -1; - return 0; -} - - -/*! Get XMLDB storage handle - * @param[in] h Clicon handle - * @retval xh XMLDB storage handle. If not connected return NULL - */ -void * -clicon_xmldb_handle_get(clicon_handle h) -{ - clicon_hash_t *cdat = clicon_data(h); - size_t len; - void *xh; - - if ((xh = hash_value(cdat, "xmldb_handle", &len)) != NULL) - return *(void**)xh; - return NULL; -} - -/*! Set or reset XMLDB storage handle - * @param[in] h Clicon handle - * @param[in] xh XMLDB storage handle. If NULL reset it - * @note Just keep note of it, dont allocate it or so. - */ -int -clicon_xmldb_handle_set(clicon_handle h, - void *xh) -{ - clicon_hash_t *cdat = clicon_data(h); - - if (hash_add(cdat, "xmldb_handle", &xh, sizeof(void*)) == NULL) - return -1; - return 0; -} -#endif /* XXX */ - - /*! Get authorized user name * @param[in] h Clicon handle * @retval xh XMLDB storage handle. If not connected return NULL diff --git a/lib/src/clixon_netconf_lib.c b/lib/src/clixon_netconf_lib.c index 87763b85..45956aa9 100644 --- a/lib/src/clixon_netconf_lib.c +++ b/lib/src/clixon_netconf_lib.c @@ -1030,14 +1030,8 @@ netconf_module_load(clicon_handle h) goto done; if (xml_parse_string("ietf-netconf:validate", yspec, &xc) < 0) goto done; - if (xml_parse_string("ietf-netconf:startup", yspec, &xc) < 0) - goto done; if (xml_parse_string("ietf-netconf:xpath", yspec, &xc) < 0) goto done; -#ifdef NYI - if (xml_parse_string("ietf-netconf:confirmed-commit", yspec, &xc) < 0) - goto done; -#endif /* Load yang spec */ if (yang_spec_parse_module(h, "ietf-netconf", NULL, yspec)< 0) goto done; diff --git a/lib/src/clixon_yang.c b/lib/src/clixon_yang.c index 7a816bdd..525fc51b 100644 --- a/lib/src/clixon_yang.c +++ b/lib/src/clixon_yang.c @@ -1591,6 +1591,33 @@ ys_populate_identity(yang_stmt *ys, return retval; } +/*! Return 1 if feature is enabled, 0 if not using the populated yang tree + * + * @param[in] yspec yang specification + * @param[in] module Name of module + * @param[in] feature Name of feature + * @retval 0 Not found or not set + * @retval 1 Found and set + * XXX: should the in-param be h, ymod, or yspec? + */ +int +if_feature(yang_stmt *yspec, + char *module, + char *feature) +{ + yang_stmt *ym; /* module */ + yang_stmt *yf; /* feature */ + cg_var *cv; + + if ((ym = yang_find_module_by_name(yspec, module)) == NULL) + return 0; + if ((yf = yang_find(ym, Y_FEATURE, feature)) == NULL) + return 0; + if ((cv = yang_cv_get(yf)) == NULL) + return 0; + return cv_bool_get(cv); +} + /*! Populate yang feature statement - set cv to 1 if enabled * * @param[in] ys Feature yang statement to populate. @@ -1608,6 +1635,8 @@ ys_populate_feature(clicon_handle h, char *module; char *feature; cxobj *xc; + char *m; + char *f; /* get clicon config file in xml form */ if ((x = clicon_conf_xml(h)) == NULL) @@ -1620,11 +1649,12 @@ ys_populate_feature(clicon_handle h, feature = ys->ys_argument; xc = NULL; while ((xc = xml_child_each(x, xc, CX_ELMNT)) != NULL && found == 0) { - char *m = NULL; - char *f = NULL; + m = NULL; + f = NULL; if (strcmp(xml_name(xc), "CLICON_FEATURE") != 0) continue; - /* get m and f from configuration feature rules */ + /* CLICON_FEATURE is on the form :. + * Split on colon to get module(m) and feature(f) respectively */ if (nodeid_split(xml_body(xc), &m, &f) < 0) goto done; if (m && f && diff --git a/test/test_copy_config.sh b/test/test_copy_config.sh index ee1d60d1..75e3eea9 100755 --- a/test/test_copy_config.sh +++ b/test/test_copy_config.sh @@ -32,6 +32,7 @@ cfg=$dir/conf_yang.xml cat < $cfg $cfg + ietf-netconf:startup 42 /usr/local/share/clixon $IETFRFC diff --git a/test/test_feature.sh b/test/test_feature.sh index 463b0555..d441b3e7 100755 --- a/test/test_feature.sh +++ b/test/test_feature.sh @@ -158,7 +158,7 @@ fi # Note order of features in ietf-netconf yang is alphabetically: candidate, startup, validate, xpath new "netconf module ietf-netconf" -expect="ietf-netconf2011-06-01urn:ietf:params:xml:ns:netconf:base:1.0candidatevalidatestartupxpathimplement" +expect="ietf-netconf2011-06-01urn:ietf:params:xml:ns:netconf:base:1.0candidatevalidatexpathimplement" match=`echo "$ret" | grep -GZo "$expect"` if [ -z "$match" ]; then err "$expect" "$ret" diff --git a/test/test_nacm_default.sh b/test/test_nacm_default.sh index b0dd3e60..cc457c60 100755 --- a/test/test_nacm_default.sh +++ b/test/test_nacm_default.sh @@ -13,6 +13,7 @@ fyang=$dir/nacm-example.yang cat < $cfg $cfg + ietf-netconf:startup /usr/local/share/clixon $IETFRFC $fyang diff --git a/test/test_nacm_protocol.sh b/test/test_nacm_protocol.sh index a6af2124..3e6089ce 100755 --- a/test/test_nacm_protocol.sh +++ b/test/test_nacm_protocol.sh @@ -37,6 +37,7 @@ fyang=$dir/nacm-example.yang cat < $cfg $cfg + ietf-netconf:startup /usr/local/share/clixon $IETFRFC $fyang diff --git a/test/test_netconf.sh b/test/test_netconf.sh index 9738345d..3b369875 100755 --- a/test/test_netconf.sh +++ b/test/test_netconf.sh @@ -14,6 +14,7 @@ tmp=$dir/tmp.x cat < $cfg $cfg + ietf-netconf:startup 42 /usr/local/share/clixon $IETFRFC diff --git a/test/test_restconf.sh b/test/test_restconf.sh index 1d71e78b..be4f73b0 100755 --- a/test/test_restconf.sh +++ b/test/test_restconf.sh @@ -73,12 +73,12 @@ expecteq "$(curl -s -H 'Accept: application/yang-data+xml' -G http://localhost/r # Should be alphabetically ordered new "restconf get restconf/operations. RFC8040 3.3.2 (json)" -expecteq "$(curl -sG http://localhost/restconf/operations)" 0 '{"operations": {"clixon-example:client-rpc": null,"clixon-example:empty": null,"clixon-example:optional": null,"clixon-example:example": null,"clixon-lib:debug": null}} +expecteq "$(curl -sG http://localhost/restconf/operations)" 0 '{"operations": {"clixon-example:client-rpc": null,"clixon-example:empty": null,"clixon-example:optional": null,"clixon-example:example": null,"clixon-lib:debug": null,"ietf-netconf:get-config": null,"ietf-netconf:edit-config": null,"ietf-netconf:copy-config": null,"ietf-netconf:delete-config": null,"ietf-netconf:lock": null,"ietf-netconf:unlock": null,"ietf-netconf:get": null,"ietf-netconf:close-session": null,"ietf-netconf:kill-session": null,"ietf-netconf:commit": null,"ietf-netconf:discard-changes": null,"ietf-netconf:validate": null,"clixon-rfc5277:create-subscription": null}} ' new "restconf get restconf/operations. RFC8040 3.3.2 (xml)" ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/operations) -expect='' +expect='' match=`echo $ret | grep -EZo "$expect"` if [ -z "$match" ]; then err "$expect" "$ret" diff --git a/test/test_restconf_startup.sh b/test/test_restconf_startup.sh new file mode 100755 index 00000000..36037af8 --- /dev/null +++ b/test/test_restconf_startup.sh @@ -0,0 +1,126 @@ +#!/bin/bash +# Test restconf :startup +# RFC 8040 Sec 1.4 says: +# the NETCONF server supports :startup, the RESTCONF server MUST +# automatically update the non-volatile startup configuration +# datastore, after the "running" datastore has been altered as a +# consequence of a RESTCONF edit operation. +# Magic line must be first in script (see README.md) +s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi + +APPNAME=example + +cfg=$dir/conf.xml +fyang=$dir/example.yang + +cat < $fyang +module example{ + yang-version 1.1; + namespace "urn:example:clixon"; + prefix ip; + container x { + list y { + key "a"; + leaf a { + type string; + } + leaf b { + type string; + } + } + } +} +EOF + +# Use yang in example + +cat < $cfg + + $cfg + /usr/local/share/clixon + /usr/local/lib/$APPNAME/backend + example_backend.so$ + /usr/local/lib/$APPNAME/restconf + /usr/local/var/$APPNAME/$APPNAME.sock + /usr/local/var/$APPNAME/$APPNAME.pidfile + $dir + +EOF + +testrun(){ + option=$1 + + new "test params: -f $cfg -y $fyang $option" + if [ $BE -ne 0 ]; then + new "kill old backend" + sudo clixon_backend -zf $cfg + if [ $? -ne 0 ]; then + err + fi + new "start backend -s init -f $cfg -y $fyang $option" + start_backend -s init -f $cfg -y $fyang $option + fi + + new "kill old restconf daemon" + sudo pkill -u www-data clixon_restconf + + new "start restconf daemon" + start_restconf -f $cfg -y $fyang $option + + new "waiting" + sleep $RCWAIT + + new "restconf put 42" + expecteq "$(curl -s -X PUT http://localhost/restconf/data/example:x/y=42 -d '{"example:y":{"a":"42","b":"42"}}')" 0 "" + + new "restconf put 99" + expecteq "$(curl -s -X PUT http://localhost/restconf/data/example:x/y=99 -d '{"example:y":{"a":"99","b":"99"}}')" 0 "" + + new "restconf post 123" + expecteq "$(curl -s -X POST http://localhost/restconf/data/example:x -d '{"example:y":{"a":"123","b":"123"}}')" 0 "" + + new "restconf delete 42" + expecteq "$(curl -s -X DELETE http://localhost/restconf/data/example:x/y=42)" 0 "" + + new "Kill restconf daemon" + stop_restconf + + if [ $BE -ne 0 ]; then + new "Kill backend" + # Check if premature kill + pid=`pgrep -u root -f clixon_backend` + if [ -z "$pid" ]; then + err "backend already dead" + fi + # kill backend + stop_backend -f $cfg + fi +} + +# clear startup +sudo rm -f $dir/startup_db; + +new "Run with startup option, check running is copied" +testrun "-o CLICON_FEATURE=ietf-netconf:startup" + +new "Check running and startup exists and are same" +if [ ! -f $dir/startup_db ]; then + err "startup should exist but does not" +fi +echo "diff $dir/startup_db $dir/running_db" +d=$(sudo diff $dir/startup_db $dir/running_db) +if [ -n "$d" ]; then + err "running and startup should be equal" "$d" +fi + +# clear startup +sudo rm -f $dir/startup_db; + +new "Run without startup option, check running is copied" +testrun "" + +new "Check startup should not exist" +if [ -f $dir/startup_db ]; then + err "startup should not exist" +fi +rm -rf $dir diff --git a/test/test_rpc.sh b/test/test_rpc.sh index 3c2a44ee..d78ec54e 100755 --- a/test/test_rpc.sh +++ b/test/test_rpc.sh @@ -127,7 +127,7 @@ new "restconf wrong method" expecteq "$(curl -s -X POST -d '{"clixon-example:input":{"x":"0"}}' http://localhost/restconf/operations/clixon-example:wrong)" 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "missing-element","error-info": {"bad-element": "wrong"},"error-severity": "error","error-message": "RPC not defined"}}} ' new "restconf example missing input" -expecteq "$(curl -s -X POST -d '{"clixon-example:input":null}' http://localhost/restconf/operations/ietf-netconf:edit-config)" 0 '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "yang module not found"}}} ' +expecteq "$(curl -s -X POST -d '{"clixon-example:input":null}' http://localhost/restconf/operations/ietf-netconf:edit-config)" 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "missing-element","error-info": {"bad-element": "target"},"error-severity": "error","error-message": "Mandatory variable"}}} ' new "netconf kill-session missing session-id mandatory" expecteof "$clixon_netconf -qf $cfg" 0 ']]>]]>' '^applicationmissing-elementsession-iderrorMandatory variable]]>]]>$' diff --git a/test/test_startup.sh b/test/test_startup.sh index 8ec21156..cd36277c 100755 --- a/test/test_startup.sh +++ b/test/test_startup.sh @@ -8,7 +8,7 @@ # - startup db starts with a "start" interface # There is also an "invalid" XML and a "broken" XML # There are two steps, first run through everything OK -# Then try with invalid and borken XML and ensure the backend quits and all is untouched +# Then try with invalid and broken XML and ensure the backend quits and all is untouched # Magic line must be first in script (see README.md) s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi @@ -20,6 +20,7 @@ cfg=$dir/conf_startup.xml cat < $cfg $cfg + ietf-netconf:startup /usr/local/share/clixon $IETFRFC clixon-example @@ -65,7 +66,6 @@ testrun(){ edb=$4 # extradb at start exprun=$5 # expected running_db after startup - sudo rm -f $dir/*_db echo "$rdb" > $dir/running_db echo "$sdb" > $dir/startup_db diff --git a/test/test_upgrade.sh b/test/test_upgrade.sh index d33dbaf1..03b59f7b 100755 --- a/test/test_upgrade.sh +++ b/test/test_upgrade.sh @@ -94,6 +94,7 @@ EOF cat < $cfg $cfg + ietf-netconf:startup /usr/local/share/clixon $dir /usr/local/var/$APPNAME/$APPNAME.sock diff --git a/test/test_upgrade_auto.sh b/test/test_upgrade_auto.sh index 9827848f..7991864c 100755 --- a/test/test_upgrade_auto.sh +++ b/test/test_upgrade_auto.sh @@ -173,6 +173,7 @@ XML='dont change merename me $cfg $cfg + ietf-netconf:startup /usr/local/share/clixon $dir /usr/local/var/$APPNAME/$APPNAME.sock diff --git a/test/test_upgrade_interfaces.sh b/test/test_upgrade_interfaces.sh index 2ec3b230..c72e7b2c 100755 --- a/test/test_upgrade_interfaces.sh +++ b/test/test_upgrade_interfaces.sh @@ -232,6 +232,7 @@ EOF cat < $cfg $cfg + ietf-netconf:startup /usr/local/share/clixon interfaces:if-mib $dir diff --git a/test/test_upgrade_repair.sh b/test/test_upgrade_repair.sh index c6cc4dda..e752d1d5 100755 --- a/test/test_upgrade_repair.sh +++ b/test/test_upgrade_repair.sh @@ -57,6 +57,7 @@ EOF cat < $cfg $cfg + ietf-netconf:startup /usr/local/share/clixon $dir /usr/local/var/$APPNAME/$APPNAME.sock