diff --git a/CHANGELOG.md b/CHANGELOG.md index b80e4c9e..5fd3cc39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,8 @@ Expected: February 2024 ### C/CLI-API changes on existing features Developers may need to change their code +* New `clixon-lib@2024-01-01.yang` revision + * Replaced container creators to grouping/uses * Changed ca_errmsg callback to a more generic variant * Includes all error, log and debug messages * See [Customized NETCONF error message](https://github.com/clicon/clixon/issues/454) diff --git a/lib/clixon/clixon_xml.h b/lib/clixon/clixon_xml.h index 9fdb3a6b..2aced51e 100644 --- a/lib/clixon/clixon_xml.h +++ b/lib/clixon/clixon_xml.h @@ -170,10 +170,10 @@ typedef struct xml cxobj; /* struct defined in clicon_xml.c */ * * @param[in] x XML node * @param[in] arg General-purpose argument - * @retval -1 Error, aborted at first error encounter, return -1 to end user - * @retval 0 OK, continue - * @retval 1 Abort, dont continue with others, return 1 to end user * @retval 2 Locally abort this subtree, continue with others + * @retval 1 Abort, dont continue with others, return 1 to end user + * @retval 0 OK, continue + * @retval -1 Error, aborted at first error encounter, return -1 to end user */ typedef int (xml_applyfn_t)(cxobj *x, void *arg); @@ -239,7 +239,6 @@ size_t xml_creator_len(cxobj *xn); cvec *xml_creator_get(cxobj *xn); int xml_creator_copy_one(cxobj *x0, cxobj *x1); int xml_creator_copy_all(cxobj *x0, cxobj *x1); -int xml_creator_print(FILE *f, cxobj *xn); char *xml_value(cxobj *xn); int xml_value_set(cxobj *xn, char *val); diff --git a/lib/clixon/clixon_xml_map.h b/lib/clixon/clixon_xml_map.h index 7d8d2c13..e3f84489 100644 --- a/lib/clixon/clixon_xml_map.h +++ b/lib/clixon/clixon_xml_map.h @@ -77,5 +77,6 @@ int xml_rpc_isaction(cxobj *xn); int xml_find_action(cxobj *xn, int top, cxobj **xap); int purge_tagged_nodes(cxobj *xn, char *ns, char *name, char *value, int keepnode); int clixon_compare_xmls(cxobj *xc1, cxobj *xc2, enum format_enum format); +int xml_creator_tree(cxobj *xt, cxobj **xcreator); #endif /* _CLIXON_XML_MAP_H_ */ diff --git a/lib/src/clixon_xml.c b/lib/src/clixon_xml.c index 7a211899..d06423b6 100644 --- a/lib/src/clixon_xml.c +++ b/lib/src/clixon_xml.c @@ -819,41 +819,6 @@ xml_creator_copy_all(cxobj *x0, return retval; } -/*! Print XML and creator tags where they exists, apply help function - * - * @param[in] x XML tree - * @param[in] arg FIle - * @retval see xml_apply - */ -static int -creator_print_fn(cxobj *x, - void *arg) -{ - FILE *f = (FILE *)arg; - cg_var *cv; - - if (x->x_creators == NULL) - return 0; - cv = NULL; - while ((cv = cvec_each(x->x_creators, cv)) != NULL){ - fprintf(f, "%s ", cv_name_get(cv)); - } - fprintf(f, ":\n"); - clixon_xml2file(f, x, 3, 1, NULL, cligen_output, 0, 0); - return 2; /* Locally abort this subtree, continue with others */ -} - -/*! Print XML and creator tags where they exists recursively, for debugging - * - * @param[in] xn XML tree - * @retval see xml_apply - */ -int -xml_creator_print(FILE *f, - cxobj *xn) -{ - return xml_apply0(xn, CX_ELMNT, creator_print_fn, f); -} /*! Get value of xnode * diff --git a/lib/src/clixon_xml_io.c b/lib/src/clixon_xml_io.c index 5ee9b0be..a9ae7ab8 100644 --- a/lib/src/clixon_xml_io.c +++ b/lib/src/clixon_xml_io.c @@ -81,6 +81,9 @@ /* Size of xml read buffer */ #define BUFLEN 1024 +/* Forward */ +static int xml_diff2cbuf(cbuf *cb, cxobj *x0, cxobj *x1, int level, int skiptop); + /*------------------------------------------------------------------------ * XML printing functions. Output a parse tree to file, string cligen buf *------------------------------------------------------------------------*/ @@ -1037,7 +1040,7 @@ xml_diff2cbuf_ordered_by_user(cbuf *cb, * @see clixon_compare_xmls which uses files and is independent of YANG * @see text_diff2cbuf */ -int +static int xml_diff2cbuf(cbuf *cb, cxobj *x0, cxobj *x1, diff --git a/lib/src/clixon_xml_map.c b/lib/src/clixon_xml_map.c index db1dd011..89bbffcd 100644 --- a/lib/src/clixon_xml_map.c +++ b/lib/src/clixon_xml_map.c @@ -2034,3 +2034,90 @@ clixon_compare_xmls(cxobj *xc1, unlink(filename2); return retval; } + +/*! Add creator data to metadata xml object on the form name:xpath* + * + * Callback function type for xml_apply + * @param[in] x XML node + * @param[in] arg General-purpose argument + * @retval 2 Locally abort this subtree, continue with others + * @retval 1 Abort, dont continue with others, return 1 to end user + * @retval 0 OK, continue + * @retval -1 Error, aborted at first error encounter, return -1 to end user + * On the form: + * + * testA[name='foo'] + * ... + * ... + * + */ +static int +xml_creator_one(cxobj *x, + void *arg) +{ + int retval = -1; + cxobj *xmeta = (cxobj*)arg; + cxobj *xmc; + cvec *cvv; + cg_var *cv; + char *val; + cvec *nsc = NULL; + char *xpath = NULL; + + if ((cvv = xml_creator_get(x)) == NULL){ + retval = 0; + goto done; + } + /* Note this requires x to have YANG spec */ + if (xml2xpath(x, nsc, 0, 0, &xpath) < 0) + goto done; + cv = NULL; + while ((cv = cvec_each(cvv, cv)) != NULL){ + val = cv_name_get(cv); + /* Find existing entry where name is val */ + xmc = NULL; + while ((xmc = xml_child_each(xmeta, xmc, CX_ELMNT)) != NULL){ + if (strcmp(xml_find_body(xmc, "name"), val) == 0) + break; + } + if (xmc != NULL){ + if (clixon_xml_parse_va(YB_NONE, NULL, &xmc, NULL, "%s", xpath) < 0) + goto done; + } + else { + if (clixon_xml_parse_va(YB_NONE, NULL, &xmeta, NULL, + "%s%s", + val, xpath) < 0) + goto done; + } + } + retval = 2; + done: + if (xpath) + free(xpath); + return retval; +} + +/*! Create creator data tree on the form (name:xpath*)* + * + * @param[in] xt XML top-level node, where to look for creator attributes + * @param[out] xcreators Created XML tree on the form ... + * @retval 0 OK + * @retval -1 Error + */ +int +xml_creator_tree(cxobj *xt, + cxobj **xcreators) +{ + int retval = -1; + + if ((*xcreators = xml_new("creators", NULL, CX_ELMNT)) == NULL) + goto done; + if (xmlns_set(*xcreators, NULL, CLIXON_LIB_NS) < 0) + goto done; + if (xml_apply(xt, CX_ELMNT, xml_creator_one, *xcreators) < 0) + goto done; + retval = 0; + done: + return retval; +} diff --git a/test/config.sh.in b/test/config.sh.in index aa0576a2..12a40d3f 100755 --- a/test/config.sh.in +++ b/test/config.sh.in @@ -76,7 +76,7 @@ DATASTORE_TOP="config" # clixon yang revisions occuring in tests (see eg yang/clixon/Makefile.in) CLIXON_AUTOCLI_REV="2023-09-01" -CLIXON_LIB_REV="2023-11-01" +CLIXON_LIB_REV="2024-01-01" CLIXON_CONFIG_REV="2023-05-01" CLIXON_RESTCONF_REV="2022-08-01" CLIXON_EXAMPLE_REV="2022-11-01" diff --git a/yang/clixon/Makefile.in b/yang/clixon/Makefile.in index b5615e34..07ca2873 100644 --- a/yang/clixon/Makefile.in +++ b/yang/clixon/Makefile.in @@ -44,6 +44,7 @@ YANG_INSTALLDIR = @YANG_INSTALLDIR@ # Note: mirror these to test/config.sh.in YANGSPECS = clixon-config@2023-11-01.yang # 6.5 YANGSPECS += clixon-lib@2023-11-01.yang # 6.5 +YANGSPECS += clixon-lib@2024-01-01.yang # 6.6 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@2023-05-01.yang b/yang/clixon/clixon-lib@2024-01-01.yang similarity index 90% rename from yang/clixon/clixon-lib@2023-05-01.yang rename to yang/clixon/clixon-lib@2024-01-01.yang index 04c689f5..6b46e019 100644 --- a/yang/clixon/clixon-lib@2023-05-01.yang +++ b/yang/clixon/clixon-lib@2024-01-01.yang @@ -68,6 +68,18 @@ module clixon-lib { - objectexisted "; + revision 2024-01-01 { + description + "Moved container creators to grouping/uses + Released in 6.6.0"; + } + revision 2023-11-01 { + description + "Added ignore-compare extension + Added creator meta configuration + Removed obsolete extension autocli-op + Released in 6.5.0"; + } revision 2023-05-01 { description "Restructured and extended stats rpc to schema mountpoints @@ -179,7 +191,7 @@ module clixon-lib { } identity restconf { description - "RESTCONF either as HTTP/1 or /2, TLS or not, reverese proxy (eg fcgi/nginx) or native"; + "RESTCONF either as HTTP/1 or /2, TLS or not, reverse proxy (eg fcgi/nginx) or native"; base ncm:transport; } identity cli { @@ -187,20 +199,12 @@ module clixon-lib { "A CLI session"; base ncm:transport; } - extension autocli-op { - description - "Takes an argument an operation defing how to modify the clispec at - this point in the YANG tree for the automated generated CLI. - Note that this extension is only used in clixon_cli. - Operations is expected to be extended, but the following operations are defined: - - hide This command is active but not shown by ? or TAB (meaning, it hides the auto-completion of commands) - - hide-database This command hides the database - - hide-database-auto-completion This command hides the database and the auto completion (meaning, this command acts as both commands above) - Obsolete: use clixon-autocli:hide and clixon-autocli:hide-show instead"; - argument cliop; - status obsolete; + extension ignore-compare { + description + "The object should be ignored when comparing device configs for equality. + One example is auto-created objects by the server, such as uid. + Another example is a plain-text password is changed to an encrypted by the server."; } - md:annotation creator { type string; description @@ -209,8 +213,26 @@ module clixon-lib { create the same object. When such a service is deleted (or changed) one needs to keep track of which service created what. Limitations: only objects that are actually added or deleted. - A sub-object wil not be noted"; + A sub-object will not be noted"; } + grouping clixon-creators{ + container creators{ + config false; + description "Meta-data for creator attribute."; + list creator { + key name; + leaf name { + description "Name of creator / service (instance) name"; + type string; + } + leaf-list path { + description "Path to object"; + type string; + } + } + } + } + uses clixon-creators; rpc debug { description "Set debug level of backend."; input {