System-only-config
* Fix startup diff * Add system-only to running on startup * JSON support:
This commit is contained in:
parent
3a656fac07
commit
69b65ad13d
19 changed files with 276 additions and 105 deletions
|
|
@ -24,6 +24,9 @@ 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
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -884,7 +884,7 @@ api_operations_post(clixon_handle h,
|
|||
/* xoutput should now look: <output xmlns="uri"><x>0</x></output> */
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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 <a>0</a> -> {"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.
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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 <<EOF > $cfg
|
||||
<clixon-config xmlns="http://clicon.org/config">
|
||||
<CLICON_FEATURE>ietf-netconf:startup</CLICON_FEATURE>
|
||||
<CLICON_FEATURE>clixon-restconf:allow-auth-none</CLICON_FEATURE> <!-- Use auth-type=none -->
|
||||
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
|
||||
<CLICON_CONFIGDIR>$CFD</CLICON_CONFIGDIR>
|
||||
<CLICON_YANG_DIR>${YANG_INSTALLDIR}</CLICON_YANG_DIR>
|
||||
|
|
@ -41,6 +46,7 @@ cat <<EOF > $cfg
|
|||
<CLICON_VALIDATE_STATE_XML>true</CLICON_VALIDATE_STATE_XML>
|
||||
<CLICON_STREAM_DISCOVERY_RFC5277>true</CLICON_STREAM_DISCOVERY_RFC5277>
|
||||
<CLICON_YANG_SCHEMA_MOUNT>true</CLICON_YANG_SCHEMA_MOUNT>
|
||||
$RESTCONFIG
|
||||
</clixon-config>
|
||||
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 <<EOF > $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 <<EOF > $dir/x_db
|
||||
# Reference files: What is expected in the datastore
|
||||
cat <<EOF > $dir/x_db_xml
|
||||
<config>
|
||||
<store xmlns="urn:example:std">
|
||||
<keys>
|
||||
<key>
|
||||
<name>a</name>
|
||||
<normal-data>otherdata</normal-data>
|
||||
</key>
|
||||
</keys>
|
||||
</store>
|
||||
</config>
|
||||
EOF
|
||||
|
||||
# Same in JSON (but broken)
|
||||
cat <<EOF > $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 <<EOF > $dir/y_db
|
||||
<store xmlns="urn:example:std">
|
||||
|
|
@ -165,22 +202,23 @@ cat <<EOF > $dir/y_db
|
|||
</store>
|
||||
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" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><store xmlns=\"urn:example:std\"><keys><key><name>a</name><system-only-data>mydata</system-only-data></key></keys></store></config></edit-config></rpc>" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||
|
||||
new "Add normal data"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><store xmlns=\"urn:example:std\"><keys><key><name>a</name><normal-data>otherdata</normal-data></key></keys></store></config></edit-config></rpc>" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||
|
||||
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" "<rpc $DEFAULTNS><get-config><source><candidate/></source></get-config></rpc>" "<rpc-reply $DEFAULTNS><data><store xmlns=\"urn:example:std\"><keys><key><name>a</name><system-only-data>mydata</system-only-data></key></keys></store></data></rpc-reply>"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get-config><source><candidate/></source></get-config></rpc>" "<rpc-reply $DEFAULTNS><data><store xmlns=\"urn:example:std\"><keys><key><name>a</name><system-only-data>mydata</system-only-data><normal-data>otherdata</normal-data></key></keys></store></data></rpc-reply>"
|
||||
|
||||
new "Commit 1"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><commit/></rpc>" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||
|
||||
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" "<rpc $DEFAULTNS><get-config><source><running/></source></get-config></rpc>" "<rpc-reply $DEFAULTNS><data><store xmlns=\"urn:example:std\"><keys><key><name>a</name><system-only-data>mydata</system-only-data></key></keys></store></data></rpc-reply>"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get-config><source><running/></source></get-config></rpc>" "<rpc-reply $DEFAULTNS><data><store xmlns=\"urn:example:std\"><keys><key><name>a</name><system-only-data>mydata</system-only-data><normal-data>otherdata</normal-data></key></keys></store></data></rpc-reply>"
|
||||
|
||||
new "Remove mydata"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><store xmlns=\"urn:example:std\"><keys><key><name>a</name><system-only-data nc:operation=\"delete\" xmlns:nc=\"${BASENS}\">mydata</system-only-data></key></keys></store></config><default-operation>none</default-operation></edit-config></rpc>" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||
|
||||
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" "<rpc $DEFAULTNS><commit/></rpc>" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||
|
||||
new "Get mydata from running, expected not"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get-config><source><running/></source></get-config></rpc>" "<rpc-reply $DEFAULTNS><data><store xmlns=\"urn:example:std\"><keys><key><name>a</name></key></keys></store></data></rpc-reply>"
|
||||
new "Get mydata from running, expecte no system-nly"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get-config><source><running/></source></get-config></rpc>" "<rpc-reply $DEFAULTNS><data><store xmlns=\"urn:example:std\"><keys><key><name>a</name><normal-data>otherdata</normal-data></key></keys></store></data></rpc-reply>"
|
||||
|
||||
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" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><store xmlns=\"urn:example:std\"><keys><key><name>a</name><system-only-data>mydata</system-only-data></key></keys></store></config></edit-config></rpc>" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||
|
|
@ -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" "<rpc $DEFAULTNS><get-config><source><running/></source></get-config></rpc>" "<rpc-reply $DEFAULTNS><data><store xmlns=\"urn:example:std\"><keys><key><name>a</name><system-only-data>mydata</system-only-data></key></keys></store></data></rpc-reply>"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get-config><source><running/></source></get-config></rpc>" "<rpc-reply $DEFAULTNS><data><store xmlns=\"urn:example:std\"><keys><key><name>a</name><system-only-data>mydata</system-only-data><normal-data>otherdata</normal-data></key></keys></store></data></rpc-reply>"
|
||||
|
||||
new "Remove mydata"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><store xmlns=\"urn:example:std\"><keys><key><name>a</name><system-only-data nc:operation=\"delete\" xmlns:nc=\"${BASENS}\">mydata</system-only-data></key></keys></store></config><default-operation>none</default-operation></edit-config></rpc>" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||
|
|
@ -282,11 +326,118 @@ expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS>
|
|||
new "Commit 4"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><commit/></rpc>" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||
|
||||
new "Get mydata from running, expected not"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get-config><source><running/></source></get-config></rpc>" "<rpc-reply $DEFAULTNS><data><store xmlns=\"urn:example:std\"><keys><key><name>a</name></key></keys></store></data></rpc-reply>"
|
||||
new "Get mydata from running, expected no system-only"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get-config><source><running/></source></get-config></rpc>" "<rpc-reply $DEFAULTNS><data><store xmlns=\"urn:example:std\"><keys><key><name>a</name><normal-data>otherdata</normal-data></key></keys></store></data></rpc-reply>"
|
||||
|
||||
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" "<rpc $DEFAULTNS><get-config><source><running/></source></get-config></rpc>" "<rpc-reply $DEFAULTNS><data><store xmlns=\"urn:example:std\"><keys><key><name>a</name><system-only-data>mydata</system-only-data><normal-data>otherdata</normal-data></key></keys></store></data></rpc-reply>"
|
||||
|
||||
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" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><store xmlns=\"urn:example:std\"><keys><key><name>a</name><system-only-data>mydata</system-only-data></key></keys></store></config></edit-config></rpc>" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||
|
||||
new "Add normal data"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><store xmlns=\"urn:example:std\"><keys><key><name>a</name><normal-data>otherdata</normal-data></key></keys></store></config></edit-config></rpc>" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||
|
||||
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" "<rpc $DEFAULTNS><get-config><source><candidate/></source></get-config></rpc>" "<rpc-reply $DEFAULTNS><data><store xmlns=\"urn:example:std\"><keys><key><name>a</name><system-only-data>mydata</system-only-data><normal-data>otherdata</normal-data></key></keys></store></data></rpc-reply>"
|
||||
|
||||
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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue