diff --git a/CHANGELOG.md b/CHANGELOG.md
index 740a3c60..350bc6aa 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -24,9 +24,12 @@ Expected: January 2025
* New `CLICON_XMLDB_SYSTEM_ONLY_CONFIG` configuration option
* New `system-only-config` extension
* New `ca_system_only` backend callback for reading system-only data
+ * Changed C-API: add `system-only` parameter with default value `0` last:
+ * `clixon_json2file()` -> `clixon_json2file(,0)`
+ * `clixon_json2cbuf()` -> `clixon_json2cbuf(,0)`
### Corrected Bugs
-
+
* Fixed: [string length validation doesn't work for the entry "" in case it has default value specified](https://github.com/clicon/clixon/issues/563)
* Fixed: [SNMP: snmpwalk is slow and can timeout](https://github.com/clicon/clixon/issues/404)
diff --git a/apps/backend/backend_commit.c b/apps/backend/backend_commit.c
index 913c76cc..87704db8 100644
--- a/apps/backend/backend_commit.c
+++ b/apps/backend/backend_commit.c
@@ -172,13 +172,22 @@ startup_common(clixon_handle h,
cxobj *xret = NULL;
cxobj *xerr = NULL;
+ clixon_debug(CLIXON_DBG_BACKEND, "Reading initial config from %s", db);
/* If CLICON_XMLDB_MODSTATE is enabled, then get the db XML with
* potentially non-matching module-state in msdiff
*/
if (clicon_option_bool(h, "CLICON_XMLDB_MODSTATE"))
if ((msdiff = modstate_diff_new()) == NULL)
goto done;
- clixon_debug(CLIXON_DBG_BACKEND, "Reading initial config from %s", db);
+ /* Add system-only config to running */
+ if (clicon_option_bool(h, "CLICON_XMLDB_SYSTEM_ONLY_CONFIG")){
+ if ((ret = xmldb_get0(h, "running", YB_MODULE, NULL, "/", 0, 0, &xt, NULL, NULL)) < 0)
+ goto done;
+ if (xmldb_system_only_config(h, "/", NULL, &xt) < 0)
+ goto done;
+ td->td_src = xt;
+ xt = NULL;
+ }
if (clicon_option_bool(h, "CLICON_XMLDB_UPGRADE_CHECKOLD")){
if ((ret = xmldb_get0(h, db, YB_MODULE, NULL, "/", 0, 0, &xt, msdiff, &xerr)) < 0)
goto done;
@@ -659,6 +668,7 @@ candidate_validate(clixon_handle h,
* @retval 1 Validation OK
* @retval 0 Validation failed (with cbret set)
* @retval -1 Error - or validation failed
+ * @see startup_commit for commit on startup
*/
int
candidate_commit(clixon_handle h,
diff --git a/apps/cli/cli_common.c b/apps/cli/cli_common.c
index f2293b26..5f0ddcca 100644
--- a/apps/cli/cli_common.c
+++ b/apps/cli/cli_common.c
@@ -1461,7 +1461,7 @@ save_config_file(clixon_handle h,
goto done;
break;
case FORMAT_JSON:
- if (clixon_json2file(f, xt, pretty, fprintf, 0, 1) < 0)
+ if (clixon_json2file(f, xt, pretty, fprintf, 0, 1, 0) < 0)
goto done;
break;
case FORMAT_TEXT:
@@ -1587,7 +1587,7 @@ cli_notification_cb(int s,
goto done;
switch (format){
case FORMAT_JSON:
- if (clixon_json2file(stdout, xt, 1, cligen_output, 1, 1) < 0)
+ if (clixon_json2file(stdout, xt, 1, cligen_output, 1, 1, 0) < 0)
goto done;
case FORMAT_TEXT:
if (clixon_text2file(stdout, xt, 0, cligen_output, 1, 1) < 0)
diff --git a/apps/cli/cli_pipe.c b/apps/cli/cli_pipe.c
index f2759027..7e35b812 100644
--- a/apps/cli/cli_pipe.c
+++ b/apps/cli/cli_pipe.c
@@ -318,7 +318,7 @@ pipe_showas_fn(clixon_handle h,
goto done;
break;
case FORMAT_JSON:
- if (clixon_json2file(stdout, xt, pretty, cligen_output, 1, 0) < 0)
+ if (clixon_json2file(stdout, xt, pretty, cligen_output, 1, 0, 0) < 0)
goto done;
break;
case FORMAT_TEXT:
diff --git a/apps/cli/cli_show.c b/apps/cli/cli_show.c
index 10a2df81..2dd5ba97 100644
--- a/apps/cli/cli_show.c
+++ b/apps/cli/cli_show.c
@@ -1434,7 +1434,7 @@ cli_pagination(clixon_handle h,
goto done;
break;
case FORMAT_JSON:
- if (clixon_json2file(stdout, xc, 1, cligen_output, 0, 1) < 0)
+ if (clixon_json2file(stdout, xc, 1, cligen_output, 0, 1, 0) < 0)
goto done;
break;
case FORMAT_TEXT:
diff --git a/apps/restconf/restconf_err.c b/apps/restconf/restconf_err.c
index 28f55196..e7b9371f 100644
--- a/apps/restconf/restconf_err.c
+++ b/apps/restconf/restconf_err.c
@@ -308,14 +308,14 @@ api_return_err(clixon_handle h,
clixon_debug(CLIXON_DBG_RESTCONF, "code:%d", code);
if (pretty){
cprintf(cb, "{\n\"ietf-restconf:errors\" : ");
- if (clixon_json2cbuf(cb, xerr, pretty, 0, 0) < 0)
+ if (clixon_json2cbuf(cb, xerr, pretty, 0, 0, 0) < 0)
goto done;
cprintf(cb, "\n}\r\n");
}
else{
cprintf(cb, "{");
cprintf(cb, "\"ietf-restconf:errors\":");
- if (clixon_json2cbuf(cb, xerr, pretty, 0, 0) < 0)
+ if (clixon_json2cbuf(cb, xerr, pretty, 0, 0, 0) < 0)
goto done;
cprintf(cb, "}\r\n");
}
diff --git a/apps/restconf/restconf_methods_get.c b/apps/restconf/restconf_methods_get.c
index 1027bb4c..6e00d0ec 100644
--- a/apps/restconf/restconf_methods_get.c
+++ b/apps/restconf/restconf_methods_get.c
@@ -237,7 +237,7 @@ api_data_get2(clixon_handle h,
goto done;
break;
case YANG_DATA_JSON:
- if (clixon_json2cbuf(cbx, xret, pretty, 0, 0) < 0)
+ if (clixon_json2cbuf(cbx, xret, pretty, 0, 0, 0) < 0)
goto done;
break;
default:
diff --git a/apps/restconf/restconf_methods_patch.c b/apps/restconf/restconf_methods_patch.c
index 8bbf552d..90ef027d 100644
--- a/apps/restconf/restconf_methods_patch.c
+++ b/apps/restconf/restconf_methods_patch.c
@@ -120,7 +120,7 @@ yang_patch_xml2json_modified_cbuf(cxobj *x_simple_patch)
if (json_simple_patch == NULL)
return NULL;
cb = cbuf_new();
- if (clixon_json2cbuf(cb, x_simple_patch, 0, 0) < 0)
+ if (clixon_json2cbuf(cb, x_simple_patch, 0, 0, 0) < 0)
goto done;
// Insert a '[' after the first '{' to get the JSON to match what api_data_post/write() expect
@@ -271,7 +271,7 @@ yang_patch_do_replace(clixon_handle h,
}
}
// Convert the data to json
- if (clixon_json2cbuf(json_simple_patch, x_simple_patch, 0, 0) < 0)
+ if (clixon_json2cbuf(json_simple_patch, x_simple_patch, 0, 0, 0) < 0)
goto done;
// Send the POST request
@@ -336,7 +336,7 @@ yang_patch_do_create(clixon_handle h,
xml_addsub(x_simple_patch, value_vec_tmp);
}
}
- if (clixon_json2cbuf(cb, x_simple_patch, 0, 0) < 0)
+ if (clixon_json2cbuf(cb, x_simple_patch, 0, 0, 0) < 0)
goto done;
if (api_data_post(h, req, cbuf_get(simple_patch_request_uri),
pi, qvec,
@@ -492,7 +492,7 @@ yang_patch_do_merge(clixon_handle h,
xml_addsub(x_simple_patch, value_vec_tmp);
}
cbuf_reset(cb); /* reuse cb */
- if (clixon_json2cbuf(cb, x_simple_patch, 0, 0) < 0)
+ if (clixon_json2cbuf(cb, x_simple_patch, 0, 0, 0) < 0)
goto done;
if ((json_simple_patch = yang_patch_xml2json_modified_cbuf(x_simple_patch)) == NULL)
diff --git a/apps/restconf/restconf_methods_post.c b/apps/restconf/restconf_methods_post.c
index 6a5ee2de..90737864 100644
--- a/apps/restconf/restconf_methods_post.c
+++ b/apps/restconf/restconf_methods_post.c
@@ -884,7 +884,7 @@ api_operations_post(clixon_handle h,
/* xoutput should now look: */
break;
case YANG_DATA_JSON:
- if (clixon_json2cbuf(cbret, xoutput, pretty, 0, 0) < 0)
+ if (clixon_json2cbuf(cbret, xoutput, pretty, 0, 0, 0) < 0)
goto done;
/* xoutput should now look: {"example:output": {"x":0,"y":42}} */
break;
diff --git a/apps/restconf/restconf_root.c b/apps/restconf/restconf_root.c
index 83dcc036..353bed99 100644
--- a/apps/restconf/restconf_root.c
+++ b/apps/restconf/restconf_root.c
@@ -213,7 +213,7 @@ api_root_restconf_exact(clixon_handle h,
break;
case YANG_DATA_JSON:
case YANG_PATCH_JSON:
- if (clixon_json2cbuf(cb, xt, pretty, 0, 0) < 0)
+ if (clixon_json2cbuf(cb, xt, pretty, 0, 0, 0) < 0)
goto done;
break;
default:
@@ -299,7 +299,7 @@ api_yang_library_version(clixon_handle h,
break;
case YANG_DATA_JSON:
case YANG_PATCH_JSON:
- if (clixon_json2cbuf(cb, xt, pretty, 0, 0) < 0)
+ if (clixon_json2cbuf(cb, xt, pretty, 0, 0, 0) < 0)
goto done;
break;
default:
diff --git a/lib/clixon/clixon_json.h b/lib/clixon/clixon_json.h
index 3477df81..939c3b7d 100644
--- a/lib/clixon/clixon_json.h
+++ b/lib/clixon/clixon_json.h
@@ -44,9 +44,9 @@
* Prototypes
*/
int json2xml_decode(cxobj *x, cxobj **xerr);
-int clixon_json2cbuf(cbuf *cb, cxobj *x, int pretty, int skiptop, int autocliext);
+int clixon_json2cbuf(cbuf *cb, cxobj *x, int pretty, int skiptop, int autocliext, int system_only);
int xml2json_cbuf_vec(cbuf *cb, cxobj **vec, size_t veclen, int pretty, int skiptop);
-int clixon_json2file(FILE *f, cxobj *x, int pretty, clicon_output_cb *fn, int skiptop, int autocliext);
+int clixon_json2file(FILE *f, cxobj *x, int pretty, clicon_output_cb *fn, int skiptop, int autocliext, int system_only);
int json_print(FILE *f, cxobj *x);
int xml2json_vec(FILE *f, cxobj **vec, size_t veclen, int pretty, clicon_output_cb *fn, int skiptop);
int clixon_json_parse_string(char *str, int rfc7951, yang_bind yb, yang_stmt *yspec, cxobj **xt, cxobj **xret);
diff --git a/lib/src/clixon_datastore_read.c b/lib/src/clixon_datastore_read.c
index 51239373..2ff81357 100644
--- a/lib/src/clixon_datastore_read.c
+++ b/lib/src/clixon_datastore_read.c
@@ -887,7 +887,7 @@ xmldb_get_cache(clixon_handle h,
goto done;
}
if (clicon_option_bool(h, "CLICON_XMLDB_SYSTEM_ONLY_CONFIG") &&
- strcmp(db, "running") == 0){
+ (strcmp(db, "candidate") != 0)) {
if (xmldb_system_only_config(h, xpath?xpath:"/", nsc, &x1t) < 0)
goto done;
}
diff --git a/lib/src/clixon_datastore_write.c b/lib/src/clixon_datastore_write.c
index 42a221e3..7286441b 100644
--- a/lib/src/clixon_datastore_write.c
+++ b/lib/src/clixon_datastore_write.c
@@ -1628,8 +1628,7 @@ xmldb_dump(clixon_handle h,
switch (format){
case FORMAT_XML:
if (clixon_xml2file1(f, xt, 0, pretty, NULL, fprintf, 0, 0, wdef, multi,
- clicon_option_bool(h, "CLICON_XMLDB_SYSTEM_ONLY_CONFIG")
- ) < 0)
+ clicon_option_bool(h, "CLICON_XMLDB_SYSTEM_ONLY_CONFIG")) < 0)
goto done;
if (multi){
mw.mw_h = h;
@@ -1646,7 +1645,8 @@ xmldb_dump(clixon_handle h,
clixon_err(OE_CFG, errno, "JSON+multi not supported");
goto done;
}
- if (clixon_json2file(f, xt, pretty, fprintf, 0, 0) < 0)
+ if (clixon_json2file(f, xt, pretty, fprintf, 0, 0,
+ clicon_option_bool(h, "CLICON_XMLDB_SYSTEM_ONLY_CONFIG")) < 0)
goto done;
break;
default:
diff --git a/lib/src/clixon_json.c b/lib/src/clixon_json.c
index 06bbf825..7f5778e0 100644
--- a/lib/src/clixon_json.c
+++ b/lib/src/clixon_json.c
@@ -789,6 +789,7 @@ xml2json_encode_attr(cxobj *xa,
* @param[in] level Indentation level
* @param[in] pretty Pretty-print output (2 means debug)
* @param[in] flat Dont print NO_ARRAY object name (for _vec call)
+ * @param[in] system_only Enable checks for system-only-config extension
* @param[in] modname0
* @param[out] metacbp Meta encoding of attribute
* @retval 0 OK
@@ -829,6 +830,7 @@ xml2json1_cbuf(cbuf *cb,
int level,
int pretty,
int flat,
+ int system_only,
char *modname0,
cbuf *metacbp)
{
@@ -838,11 +840,13 @@ xml2json1_cbuf(cbuf *cb,
cxobj *xp;
enum childtype childt;
enum array_element_type xc_arraytype;
+ yang_stmt *yc;
yang_stmt *ys;
yang_stmt *ymod = NULL; /* yang module */
int commas;
char *modname = NULL;
cbuf *metacbc = NULL;
+ int exist;
if ((ys = xml_spec(x)) != NULL){
if (ys_real_module(ys, &ymod) < 0)
@@ -957,21 +961,29 @@ xml2json1_cbuf(cbuf *cb,
xc_arraytype = array_eval(i?xml_child_i(x,i-1):NULL,
xc,
xml_child_i(x, i+1));
- if (xml2json1_cbuf(cb,
- xc,
- xc_arraytype,
- level+1, pretty, 0, modname0,
- metacbc) < 0)
- goto done;
- if (commas > 0) {
- cprintf(cb, ",%s", pretty?"\n":"");
- --commas;
+ exist = 0;
+ if ((yc = xml_spec(xc)) != NULL && system_only){
+ if (yang_extension_value(yc, "system-only-config", CLIXON_LIB_NS, &exist, NULL) < 0)
+ goto done;
+ if (exist && commas)
+ commas--;
+ }
+ if (!exist) {
+ if (xml2json1_cbuf(cb,
+ xc,
+ xc_arraytype,
+ level+1, pretty, 0, system_only, modname0,
+ metacbc) < 0)
+ goto done;
+ if (commas > 0) {
+ cprintf(cb, ",%s", pretty?"\n":"");
+ --commas;
+ }
}
}
if (cbuf_len(metacbc)){
cprintf(cb, "%s", cbuf_get(metacbc));
}
-
switch (arraytype){
case BODY_ARRAY:
break;
@@ -1041,21 +1053,23 @@ xml2json1_cbuf(cbuf *cb,
* XML-style namespace notation in tree, but RFC7951 in output assume yang
* populated
*
- * @param[in,out] cb Cligen buffer to write to
- * @param[in] x XML tree to translate from
- * @param[in] pretty Set if output is pretty-printed
- * @param[in] autocliext How to handle autocli extensions: 0: ignore 1: follow
- * @retval 0 OK
- * @retval -1 Error
+ * @param[in,out] cb Cligen buffer to write to
+ * @param[in] x XML tree to translate from
+ * @param[in] pretty Set if output is pretty-printed
+ * @param[in] autocliext How to handle autocli extensions: 0: ignore 1: follow
+ * @param[in] system_only Enable checks for system-only-config extension
+ * @retval 0 OK
+ * @retval -1 Error
*
* @see clixon_xml2cbuf XML corresponding function
* @see xml2json_cbuf_vec Top symbol is list
*/
static int
-xml2json_cbuf1(cbuf *cb,
- cxobj *x,
- int pretty,
- int autocliext)
+xml2json_cbuf1(cbuf *cb,
+ cxobj *x,
+ int pretty,
+ int autocliext,
+ int system_only)
{
int retval = 1;
int level = 0;
@@ -1070,6 +1084,7 @@ xml2json_cbuf1(cbuf *cb,
if (exist)
goto ok;
}
+
cprintf(cb, "%*s{%s",
pretty?level*PRETTYPRINT_INDENT:0,"",
pretty?"\n":"");
@@ -1090,6 +1105,7 @@ xml2json_cbuf1(cbuf *cb,
level+1,
pretty,
0,
+ system_only,
NULL, /* ancestor modname / namespace */
NULL) < 0)
goto done;
@@ -1108,13 +1124,14 @@ xml2json_cbuf1(cbuf *cb,
* XML-style namespace notation in tree, but RFC7951 in output assume yang
* populated
*
- * @param[in,out] cb Cligen buffer to write to
- * @param[in] xt Top-level xml object
- * @param[in] pretty Set if output is pretty-printed
- * @param[in] skiptop 0: Include top object 1: Skip top-object, only children,
- * @param[in] autocliext How to handle autocli extensions: 0: ignore 1: follow
- * @retval 0 OK
- * @retval -1 Error
+ * @param[in,out] cb Cligen buffer to write to
+ * @param[in] xt Top-level xml object
+ * @param[in] pretty Set if output is pretty-printed
+ * @param[in] skiptop 0: Include top object 1: Skip top-object, only children,
+ * @param[in] autocliext How to handle autocli extensions: 0: ignore 1: follow
+ * @param[in] system_only Enable checks for system-only-config extension
+ * @retval 0 OK
+ * @retval -1 Error
* @code
* cbuf *cb = cbuf_new();
* if (xml2json_cbuf(cb, xn, 0, 0, 0) < 0)
@@ -1128,7 +1145,8 @@ clixon_json2cbuf(cbuf *cb,
cxobj *xt,
int pretty,
int skiptop,
- int autocliext)
+ int autocliext,
+ int system_only)
{
int retval = -1;
cxobj *xc;
@@ -1139,12 +1157,12 @@ clixon_json2cbuf(cbuf *cb,
while ((xc = xml_child_each(xt, xc, CX_ELMNT)) != NULL){
if (i++)
cprintf(cb, ",");
- if (xml2json_cbuf1(cb, xc, pretty, autocliext) < 0)
+ if (xml2json_cbuf1(cb, xc, pretty, autocliext, system_only) < 0)
goto done;
}
}
else {
- if (xml2json_cbuf1(cb, xt, pretty, autocliext) < 0)
+ if (xml2json_cbuf1(cb, xt, pretty, autocliext, system_only) < 0)
goto done;
}
retval = 0;
@@ -1217,7 +1235,7 @@ xml2json_cbuf_vec(cbuf *cb,
NO_ARRAY,
level,
pretty,
- 1, NULL, NULL) < 0)
+ 1, 0, NULL, NULL) < 0)
goto done;
if (0){
@@ -1237,19 +1255,20 @@ xml2json_cbuf_vec(cbuf *cb,
/*! Translate from xml tree to JSON and print to file using a callback
*
- * @param[in] f File to print to
- * @param[in] xn XML tree to translate from
- * @param[in] pretty Set if output is pretty-printed
- * @param[in] fn File print function
- * @param[in] skiptop 0: Include top object 1: Skip top-object, only children,
- * @param[in] autocliext How to handle autocli extensions: 0: ignore 1: follow
- * @retval 0 OK
- * @retval -1 Error
+ * @param[in] f File to print to
+ * @param[in] xn XML tree to translate from
+ * @param[in] pretty Set if output is pretty-printed
+ * @param[in] fn File print function
+ * @param[in] skiptop 0: Include top object 1: Skip top-object, only children,
+ * @param[in] autocliext How to handle autocli extensions: 0: ignore 1: follow
+ * @param[in] system_only Enable checks for system-only-config extension
+ * @retval 0 OK
+ * @retval -1 Error
*
* @note yang is necessary to translate to one-member lists,
* eg if a is a yang LIST 0 -> {"a":["0"]} and not {"a":"0"}
* @code
- * if (clixon_json2file(stderr, xn, 0, fprintf, 0, 0) < 0)
+ * if (clixon_json2file(stderr, xn, 0, fprintf, 0, 0, 0) < 0)
* goto err;
* @endcode
*/
@@ -1259,7 +1278,8 @@ clixon_json2file(FILE *f,
int pretty,
clicon_output_cb *fn,
int skiptop,
- int autocliext)
+ int autocliext,
+ int system_only)
{
int retval = 1;
cbuf *cb = NULL;
@@ -1270,7 +1290,7 @@ clixon_json2file(FILE *f,
clixon_err(OE_XML, errno, "cbuf_new");
goto done;
}
- if (clixon_json2cbuf(cb, xn, pretty, skiptop, autocliext) < 0)
+ if (clixon_json2cbuf(cb, xn, pretty, skiptop, autocliext, system_only) < 0)
goto done;
(*fn)(f, "%s", cbuf_get(cb));
retval = 0;
@@ -1289,7 +1309,7 @@ int
json_print(FILE *f,
cxobj *x)
{
- return clixon_json2file(f, x, 1, fprintf, 0, 0);
+ return clixon_json2file(f, x, 1, fprintf, 0, 0, 0);
}
/*! Translate a vector of xml objects to JSON File.
diff --git a/lib/src/clixon_options.c b/lib/src/clixon_options.c
index 93fa2ce4..51f905fd 100644
--- a/lib/src/clixon_options.c
+++ b/lib/src/clixon_options.c
@@ -253,7 +253,7 @@ clicon_option_dump1(clixon_handle h,
goto done;
break;
case FORMAT_JSON:
- if (clixon_json2file(f, xc, pretty, cligen_output, 0, 0) < 0)
+ if (clixon_json2file(f, xc, pretty, cligen_output, 0, 0, 0) < 0)
goto done;
break;
case FORMAT_TEXT:
diff --git a/test/config.sh.in b/test/config.sh.in
index f4816ae3..b9fc13e7 100755
--- a/test/config.sh.in
+++ b/test/config.sh.in
@@ -73,7 +73,7 @@ DATASTORE_TOP="config"
# clixon yang revisions occuring in tests (see eg yang/clixon/Makefile.in)
CLIXON_AUTOCLI_REV="2024-08-01"
-CLIXON_LIB_REV="2024-04-01"
+CLIXON_LIB_REV="2024-08-01"
CLIXON_CONFIG_REV="2024-08-01"
CLIXON_RESTCONF_REV="2022-08-01"
CLIXON_EXAMPLE_REV="2022-11-01"
diff --git a/test/test_datastore_system_only.sh b/test/test_datastore_system_only.sh
index b789d0a5..43fef970 100755
--- a/test/test_datastore_system_only.sh
+++ b/test/test_datastore_system_only.sh
@@ -21,8 +21,13 @@ test -d $CFD || mkdir -p $CFD
AUTOCLI=$(autocli_config clixon-\* kw-nokey false)
+# Define default restconfig config: RESTCONFIG
+RESTCONFIG=$(restconf_config none false)
+
cat < $cfg
+ ietf-netconf:startup
+ clixon-restconf:allow-auth-none
$cfg
$CFD
${YANG_INSTALLDIR}
@@ -41,6 +46,7 @@ cat < $cfg
true
true
true
+ $RESTCONFIG
EOF
@@ -74,6 +80,11 @@ module clixon-standard{
"System-only config data";
type string;
}
+ leaf normal-data {
+ description
+ "Normal config data";
+ type string;
+ }
}
grouping store-grouping {
container keys {
@@ -95,7 +106,7 @@ EOF
# A "local" YANG
cat < $flocal
-module clixon-mount1{
+module clixon-local{
yang-version 1.1;
namespace "urn:example:local";
prefix local;
@@ -140,19 +151,45 @@ show("Show a particular state of the system"){
}
EOF
-# Two reference files: What is expected in the datastore
-cat < $dir/x_db
+# Reference files: What is expected in the datastore
+cat < $dir/x_db_xml
a
+ otherdata
EOF
+# Same in JSON (but broken)
+cat < $dir/x_db_json
+{
+ "config": {
+ "clixon-standard:store": {
+ "keys": {
+ "key": [
+ {
+ "name": "a",
+ "normal-data": "otherdata"
+ }
+ ]
+ }
+ },
+ "ietf-netconf-acm:nacm": {
+ "enable-nacm": true,
+ "read-default": "permit",
+ "write-default": "deny",
+ "exec-default": "permit",
+ "enable-external-groups": true
+ }
+ }
+}
+EOF
+
# What is expected in the system-only-config file (simulated system)
cat < $dir/y_db
@@ -165,22 +202,23 @@ cat < $dir/y_db
EOF
-
# Check content of db
# Args:
-# 0: dbname
-# 1: system true/false check in system or not (only after commit)
+# 1: dbname
+# 2: system true/false check in system or not (only after commit)
+# 3: format xml/json
function check_db()
{
dbname=$1
system=$2
+ format=$3
sudo chmod 755 $dir/${dbname}_db
new "Check not in ${dbname}_db"
- ret=$(diff $dir/x_db $dir/${dbname}_db)
+ ret=$(diff $dir/x_db_$format $dir/${dbname}_db)
if [ $? -ne 0 ]; then
- err "$(cat $dir/x_db)" "$(cat $dir/${dbname}_db)"
+ err "$(cat $dir/x_db_$format)" "$(cat $dir/${dbname}_db)"
fi
if $system; then
@@ -205,6 +243,11 @@ if [ $BE -ne 0 ]; then
if [ $? -ne 0 ]; then
err
fi
+fi
+
+sudo rm -f $dir/system-only.xml
+
+if [ $BE -ne 0 ]; then
new "start backend -s init -f $cfg -- -o store/keys/key/system-only-data -O $dir/system-only.xml"
start_backend -s init -f $cfg -- -o store/keys/key/system-only-data -O $dir/system-only.xml
fi
@@ -212,40 +255,41 @@ fi
new "wait backend 1"
wait_backend
-sudo rm -f $dir/system-only.xml
-
new "Add mydata"
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "amydata" ""
+new "Add normal data"
+expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "aotherdata" ""
+
new "Check mydata present, but not in candidate datastore"
-check_db candidate false
+check_db candidate false xml
new "Get mydata from candidate"
-expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "amydata"
+expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "amydataotherdata"
new "Commit 1"
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" ""
new "Check mydata present, but not in running datastore"
-check_db running true
+check_db running true xml
new "Get mydata from running"
-expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "amydata"
+expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "amydataotherdata"
new "Remove mydata"
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "amydatanone" ""
new "Check mydata present, but not in candidate datastore"
-check_db candidate true
+check_db candidate true xml
new "Commit 2"
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" ""
-new "Get mydata from running, expected not"
-expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "a"
+new "Get mydata from running, expecte no system-nly"
+expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "aotherdata"
new "Check mydata not present, but not in running datastore"
-check_db running false
+check_db running false xml
new "Add mydata again"
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "amydata" ""
@@ -271,10 +315,10 @@ new "wait backend 2"
wait_backend
new "Check mydata present, but not in running datastore"
-check_db running true
+check_db running true xml
new "Get mydata from running"
-expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "amydata"
+expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "amydataotherdata"
new "Remove mydata"
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "amydatanone" ""
@@ -282,11 +326,118 @@ expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "
new "Commit 4"
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" ""
-new "Get mydata from running, expected not"
-expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "a"
+new "Get mydata from running, expected no system-only"
+expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "aotherdata"
new "Check mydata not present, but not in running datastore"
-check_db running false
+check_db running false xml
+
+new "Restart"
+if [ $BE -ne 0 ]; then
+ new "kill old backend"
+ sudo clixon_backend -zf $cfg
+ if [ $? -ne 0 ]; then
+ err
+ fi
+fi
+
+# Setup startup and saved system-only
+sudo cp $dir/x_db_xml $dir/startup_db
+sudo cp $dir/y_db $dir/system-only.xml
+
+if [ $BE -ne 0 ]; then
+ new "start backend -s startup -f $cfg -- -o store/keys/key/system-only-data -O $dir/system-only.xml"
+ start_backend -s startup -f $cfg -- -o store/keys/key/system-only-data -O $dir/system-only.xml
+fi
+
+new "wait backend 3"
+wait_backend
+
+new "Get mydata from running after startup"
+expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "amydataotherdata"
+
+new "Restart"
+if [ $BE -ne 0 ]; then
+ new "kill old backend"
+ sudo clixon_backend -zf $cfg
+ if [ $? -ne 0 ]; then
+ err
+ fi
+fi
+
+sudo rm -f $dir/system-only.xml
+
+if [ $BE -ne 0 ]; then
+ new "start backend -s init -f $cfg -o CLICON_XMLDB_FORMAT=json -- -o store/keys/key/system-only-data -O $dir/system-only.xml"
+ start_backend -s init -f $cfg -o CLICON_XMLDB_FORMAT=json -- -o store/keys/key/system-only-data -O $dir/system-only.xml
+fi
+
+new "wait backend 4"
+wait_backend
+
+new "Add mydata"
+expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "amydata" ""
+
+new "Add normal data"
+expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "aotherdata" ""
+
+new "Check mydata present, but not in candidate datastore"
+check_db candidate false json
+
+new "Get mydata from candidate"
+expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "amydataotherdata"
+
+new "Restart"
+if [ $BE -ne 0 ]; then
+ new "kill old backend"
+ sudo clixon_backend -zf $cfg
+ if [ $? -ne 0 ]; then
+ err
+ fi
+fi
+
+# restconf
+
+sudo rm -f $dir/system-only.xml
+
+if [ $BE -ne 0 ]; then
+ new "start backend -s init -f $cfg -- -o store/keys/key/system-only-data -O $dir/system-only.xml"
+ start_backend -s init -f $cfg -- -o store/keys/key/system-only-data -O $dir/system-only.xml
+fi
+
+new "wait backend 5"
+wait_backend
+
+if [ $RC -ne 0 ]; then
+ new "kill old restconf daemon"
+ stop_restconf_pre
+
+ new "start restconf daemon"
+ start_restconf -f $cfg
+fi
+
+new "wait restconf"
+wait_restconf
+
+new "Add mydata"
+expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-standard:store":{"keys":{"key":[{"name":"a","system-only-data":"mydata"}]}}}' $RCPROTO://localhost/restconf/data)" 0 "HTTP/$HVER 201"
+
+new "Add normal data"
+expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-standard:normal-data":"otherdata"}' $RCPROTO://localhost/restconf/data/clixon-standard:store/keys/key=a)" 0 "HTTP/$HVER 201"
+
+new "Check mydata present, but not in running datastore"
+check_db running true xml
+
+new "Check mydata present, but not in candidate datastore"
+check_db candidate true xml
+
+new "get"
+expectpart "$(curl $CURLOPTS -X GET -H "Content-Type: application/yang-data+json" $RCPROTO://localhost/restconf/data/clixon-standard:store)" 0 "HTTP/$HVER 200" '{"clixon-standard:store":{"keys":{"key":\[{"name":"a","system-only-data":"mydata","normal-data":"otherdata"}\]}}}'
+
+if [ $RC -ne 0 ]; then
+ new "Kill restconf daemon"
+ stop_restconf
+fi
if [ $BE -ne 0 ]; then
new "Kill backend"
diff --git a/yang/clixon/Makefile.in b/yang/clixon/Makefile.in
index 79fd2c47..1e2d9e79 100644
--- a/yang/clixon/Makefile.in
+++ b/yang/clixon/Makefile.in
@@ -43,7 +43,7 @@ YANG_INSTALLDIR = @YANG_INSTALLDIR@
# Note: mirror these to test/config.sh.in
YANGSPECS = clixon-config@2024-08-01.yang # 7.2
-YANGSPECS += clixon-lib@2024-04-01.yang # 7.1
+YANGSPECS += clixon-lib@2024-08-01.yang # 7.2
YANGSPECS += clixon-rfc5277@2008-07-01.yang
YANGSPECS += clixon-xml-changelog@2019-03-21.yang
YANGSPECS += clixon-restconf@2022-08-01.yang # 5.9
diff --git a/yang/clixon/clixon-lib@2024-08-01.yang b/yang/clixon/clixon-lib@2024-08-01.yang
index 8c3cc4d7..faa8304f 100644
--- a/yang/clixon/clixon-lib@2024-08-01.yang
+++ b/yang/clixon/clixon-lib@2024-08-01.yang
@@ -71,8 +71,7 @@ module clixon-lib {
revision 2024-08-01 {
description
- "Added: list-pagination-partial-state
- Added: system-only-config extension (tentative)
+ "Added: system-only-config extension (tentative)
Released in Clixon 7.2";
}
revision 2024-04-01 {
@@ -323,18 +322,6 @@ module clixon-lib {
"A CLI session";
base ncm:transport;
}
- extension list-pagination-partial-state {
- description
- "List should be partially read according to the clixon_pagination_cb_register API.
- This is a performance enhancement of pagination state data.
- This means that a special callback is used for retreiving list state which is aware of
- offset/limit attributes.
- In this way the non-config data can be partially read by the server, instead of reading
- the whole state on every pagination request.
- It affects only the server/backend-side
- It only handles the offset and limit attributes, all other attributes,
- such as where, sort-by, direction, etc, are ignored";
- }
extension ignore-compare {
description
"The object should be ignored when comparing device configs for equality.