This commit is contained in:
Olof Hagsand 2019-02-28 13:11:22 +01:00
commit a529546c88
45 changed files with 1913 additions and 708 deletions

View file

@ -878,7 +878,7 @@ nacm_access_pre(clicon_handle h,
goto done;
}
else if (strcmp(mode, "internal")==0){
if (xmldb_get(h, "running", "nacm", 0, &xnacm0) < 0)
if (xmldb_get(h, "running", "nacm", 0, &xnacm0, NULL) < 0)
goto done;
}
}

View file

@ -889,6 +889,36 @@ clicon_username_set(clicon_handle h,
return hash_add(cdat, "username", username, strlen(username)+1)==NULL?-1:0;
}
/*! Get backend daemon startup status
* @param[in] h Clicon handle
* @retval status Startup status
*/
enum startup_status
clicon_startup_status_get(clicon_handle h)
{
clicon_hash_t *cdat = clicon_data(h);
void *p;
if ((p = hash_value(cdat, "startup_status", NULL)) != NULL)
return *(enum startup_status *)p;
return STARTUP_ERR;
}
/*! Set backend daemon startup status
* @param[in] h Clicon handle
* @param[in] status Startup status
* @retval 0 OK
* @retval -1 Error (when setting value)
*/
int
clicon_startup_status_set(clicon_handle h,
enum startup_status status)
{
clicon_hash_t *cdat = clicon_data(h);
if (hash_add(cdat, "startup_status", &status, sizeof(status))==NULL)
return -1;
return 0;
}
/*! Get socket fd (ie backend server socket / restconf fcgx socket)
* @param[in] h Clicon handle

View file

@ -210,7 +210,7 @@ plugin_load_one(clicon_handle h,
clicon_err_reset();
if ((api = initfn(h)) == NULL) {
if (!clicon_errno){ /* if clicon_err() is not called then log and continue */
clicon_log(LOG_WARNING, "Warning: failed to initiate %s", strrchr(file,'/')?strchr(file, '/'):file);
clicon_log(LOG_DEBUG, "Warning: failed to initiate %s", strrchr(file,'/')?strchr(file, '/'):file);
dlclose(handle);
}
else{

View file

@ -133,10 +133,13 @@ struct xml{
/*
* Variables
*/
/* Iterate through modules to find the matching datanode
/* If set to 1 which is default, strict namespace checking of XML is made.
* If set to 0, "loose" namespace semantics is applied.
* This means: iterate through all yang modules to find matching datanode
* or rpc if no xmlns attribute specifies namespace.
* This is loose semantics of finding namespaces.
* And it is wrong, but is the way Clixon originally was written."
* This is _wrong_, but is the way Clixon originally was written, and some
* code still relies on it.
* This, of course, should change.
* @see CLICON_XML_NS_STRICT clixon configure option
*/
int _CLICON_XML_NS_STRICT = 1;
@ -1129,6 +1132,7 @@ xml_find_type_value(cxobj *xt,
* @code
* cxobj *x = xml_find_type(x, "prefix", "name", CX_ATTR);
* @endcode
* @see xml_find which finds any child given name
* @see xml_find_value where a body can be found as well
*/
cxobj *
@ -1708,7 +1712,7 @@ xml_parse_file(int fd,
* cxobj *xt = NULL;
* if (xml_parse_string(str, yspec, &xt) < 0)
* err;
* if (xml_root_child(xt, 0, &xt) < 0) # If you want to remove TOP
* if (xml_rootchild(xt, 0, &xt) < 0) # If you want to remove TOP
* err;
* @endcode
* @see xml_parse_file
@ -1778,7 +1782,11 @@ xml_parse_va(cxobj **xtop,
return retval;
}
/*! Copy single xml node frm x0 to x1 without copying children
/*! Copy single xml node from x0 to x1 without copying children
* @param[in] x0 Source XML tree
* @param[in] x1 Destination XML tree (must exist)
* @retval 0 OK
* @retval -1 Error
*/
int
xml_copy_one(cxobj *x0,
@ -1806,6 +1814,10 @@ xml_copy_one(cxobj *x0,
*
* x1 should be a created placeholder. If x1 is non-empty,
* the copied tree is appended to the existing tree.
* @param[in] x0 Source XML tree
* @param[in] x1 Destination XML tree (must exist)
* @retval 0 OK
* @retval -1 Error
* @code
* x1 = xml_new("new", xparent, NULL);
* if (xml_copy(x0, x1) < 0)

View file

@ -325,11 +325,12 @@ xmldb_setopt(clicon_handle h,
* @param[in] xpath String with XPATH syntax. or NULL for all
* @param[in] config If set only configuration data, else also state
* @param[out] xret Single return XML tree. Free with xml_free()
* @param[out] xms If set, return modules-state differences
* @retval 0 OK
* @retval -1 Error
* @code
* cxobj *xt;
* if (xmldb_get(xh, "running", "/interfaces/interface[name="eth"]", 1, &xt) < 0)
* if (xmldb_get(xh, "running", "/interfaces/interface[name="eth"]", 1, &xt, NULL) < 0)
* err;
* xml_free(xt);
* @endcode
@ -341,7 +342,8 @@ xmldb_get(clicon_handle h,
const char *db,
char *xpath,
int config,
cxobj **xret)
cxobj **xret,
cxobj **xms)
{
int retval = -1;
xmldb_handle xh;
@ -359,7 +361,7 @@ xmldb_get(clicon_handle h,
clicon_err(OE_DB, 0, "Not connected to datastore plugin");
goto done;
}
retval = xa->xa_get_fn(xh, db, xpath, config, xret);
retval = xa->xa_get_fn(xh, db, xpath, config, xret, xms);
#if DEBUG
if (retval == 0) {
cbuf *cb = cbuf_new();

View file

@ -228,8 +228,10 @@ xml2cli(FILE *f,
if (ys->ys_keyword == Y_LIST){
if ((match = yang_key_match((yang_node*)ys, xml_name(xe))) < 0)
goto done;
if (match)
continue;
if (match){
fprintf(f, "%s\n", cbuf_get(cbpre));
continue; /* Not key itself */
}
}
if (xml2cli(f, xe, cbuf_get(cbpre), gt) < 0)
goto done;
@ -1135,8 +1137,8 @@ xml_diff1(yang_stmt *ys,
/*! Compute differences between two xml trees
* @param[in] yspec Yang specification
* @param[in] x1 First XML tree
* @param[in] x2 Second XML tree
* @param[in] x1 First XML tree
* @param[in] x2 Second XML tree
* @param[out] first Pointervector to XML nodes existing in only first tree
* @param[out] firstlen Length of first vector
* @param[out] second Pointervector to XML nodes existing in only second tree
@ -1572,7 +1574,7 @@ xml_tree_prune_flagged(cxobj *xt,
cxobj *xprev;
x = NULL;
xprev = x = NULL;
xprev = NULL;
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
if (xml_flag(x, flag) == test?flag:0){ /* Pass test means purge */
if (xml_purge(x) < 0)

View file

@ -81,7 +81,7 @@
void
clixon_xml_parseerror(void *_ya, char *s)
{
clicon_err(OE_XML, 0, "xml_parse: line %d: %s: at or before: %s",
clicon_err(OE_XML, XMLPARSE_ERRNO, "xml_parse: line %d: %s: at or before: %s",
_YA->ya_linenum, s, clixon_xml_parsetext);
return;
}
@ -117,7 +117,7 @@ xml_parse_version(struct xml_parse_yacc_arg *ya,
char *ver)
{
if(strcmp(ver, "1.0")){
clicon_err(OE_XML, errno, "Wrong XML version %s expected 1.0", ver);
clicon_err(OE_XML, XMLPARSE_ERRNO, "Wrong XML version %s expected 1.0", ver);
free(ver);
return -1;
}
@ -224,12 +224,12 @@ xml_parse_bslash1(struct xml_parse_yacc_arg *ya,
cxobj *xc;
if (strcmp(xml_name(x), name)){
clicon_err(OE_XML, 0, "XML parse sanity check failed: %s vs %s",
clicon_err(OE_XML, XMLPARSE_ERRNO, "XML parse sanity check failed: %s vs %s",
xml_name(x), name);
goto done;
}
if (xml_prefix(x)!=NULL){
clicon_err(OE_XML, 0, "XML parse sanity check failed: %s:%s vs %s",
clicon_err(OE_XML, XMLPARSE_ERRNO, "XML parse sanity check failed: %s:%s vs %s",
xml_prefix(x), xml_name(x), name);
goto done;
}
@ -267,7 +267,7 @@ xml_parse_bslash2(struct xml_parse_yacc_arg *ya,
cxobj *xc;
if (strcmp(xml_name(x), name)){
clicon_err(OE_XML, 0, "Sanity check failed: %s:%s vs %s:%s",
clicon_err(OE_XML, XMLPARSE_ERRNO, "Sanity check failed: %s:%s vs %s:%s",
xml_prefix(x),
xml_name(x),
namespace,
@ -276,7 +276,7 @@ xml_parse_bslash2(struct xml_parse_yacc_arg *ya,
}
if (xml_prefix(x)==NULL ||
strcmp(xml_prefix(x), namespace)){
clicon_err(OE_XML, 0, "Sanity check failed: %s:%s vs %s:%s",
clicon_err(OE_XML, XMLPARSE_ERRNO, "Sanity check failed: %s:%s vs %s:%s",
xml_prefix(x),
xml_name(x),
namespace,

View file

@ -189,6 +189,7 @@ modules_state_cache_set(clicon_handle h,
* @param[in] h Clicon handle
* @param[in] yspec Yang spec
* @param[in] xpath XML Xpath
* @param[in] brief Just name,revision and uri (no cache)
* @param[in,out] xret Existing XML tree, merge x into this
* @retval -1 Error (fatal)
* @retval 0 OK
@ -212,10 +213,149 @@ x +--ro namespace inet:uri
+--ro schema? inet:uri
* @see netconf_create_hello
*/
#if 1
/*! Actually build the yang modules state XML tree
*/
static int
yms_build(clicon_handle h,
yang_spec *yspec,
char *msid,
int brief,
cbuf *cb)
{
int retval = -1;
yang_stmt *ylib = NULL; /* ietf-yang-library */
char *module = "ietf-yang-library";
yang_stmt *ys;
yang_stmt *yc;
yang_stmt *ymod; /* generic module */
yang_stmt *yns = NULL; /* namespace */
if ((ylib = yang_find((yang_node*)yspec, Y_MODULE, module)) == NULL &&
(ylib = yang_find((yang_node*)yspec, Y_SUBMODULE, module)) == NULL){
clicon_err(OE_YANG, 0, "%s not found", module);
goto done;
}
if ((yns = yang_find((yang_node*)ylib, Y_NAMESPACE, NULL)) == NULL){
clicon_err(OE_YANG, 0, "%s yang namespace not found", module);
goto done;
}
cprintf(cb,"<modules-state xmlns=\"%s\">", yns->ys_argument);
cprintf(cb,"<module-set-id>%s</module-set-id>", msid);
ymod = NULL;
while ((ymod = yn_each((yang_node*)yspec, ymod)) != NULL) {
if (ymod->ys_keyword != Y_MODULE &&
ymod->ys_keyword != Y_SUBMODULE)
continue;
cprintf(cb,"<module>");
cprintf(cb,"<name>%s</name>", ymod->ys_argument);
if ((ys = yang_find((yang_node*)ymod, Y_REVISION, NULL)) != NULL)
cprintf(cb,"<revision>%s</revision>", ys->ys_argument);
else
cprintf(cb,"<revision></revision>");
if ((ys = yang_find((yang_node*)ymod, Y_NAMESPACE, NULL)) != NULL)
cprintf(cb,"<namespace>%s</namespace>", ys->ys_argument);
else
cprintf(cb,"<namespace></namespace>");
/* This follows order in rfc 7895: feature, conformance-type,
submodules */
if (!brief){
yc = NULL;
while ((yc = yn_each((yang_node*)ymod, yc)) != NULL) {
switch(yc->ys_keyword){
case Y_FEATURE:
if (yc->ys_cv && cv_bool_get(yc->ys_cv))
cprintf(cb,"<feature>%s</feature>", yc->ys_argument);
break;
default:
break;
}
}
cprintf(cb, "<conformance-type>implement</conformance-type>");
}
yc = NULL;
while ((yc = yn_each((yang_node*)ymod, yc)) != NULL) {
switch(yc->ys_keyword){
case Y_SUBMODULE:
cprintf(cb,"<submodule>");
cprintf(cb,"<name>%s</name>", yc->ys_argument);
if ((ys = yang_find((yang_node*)yc, Y_REVISION, NULL)) != NULL)
cprintf(cb,"<revision>%s</revision>", ys->ys_argument);
else
cprintf(cb,"<revision></revision>");
cprintf(cb,"</submodule>");
break;
default:
break;
}
}
cprintf(cb,"</module>");
}
cprintf(cb,"</modules-state>");
retval = 0;
done:
return retval;
}
int
yang_modules_state_get(clicon_handle h,
yang_spec *yspec,
char *xpath,
int brief,
cxobj **xret)
{
int retval = -1;
cxobj *x = NULL;
char *msid; /* modules-set-id */
cxobj *x1;
cbuf *cb = NULL;
msid = clicon_option_str(h, "CLICON_MODULE_SET_ID");
if (!brief && modules_state_cache_get(h, msid, &x) < 0)
goto done;
if (x != NULL){ /* Yes a cache (but no duplicate) */
if (xpath_first(x, "%s", xpath)){
if ((x1 = xml_dup(x)) == NULL)
goto done;
x = x1;
}
else
x = NULL;
}
else { /* No cache -> build the tree */
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, 0, "clicon buffer");
goto done;
}
if (yms_build(h, yspec, msid, brief, cb) < 0)
goto done;
if (xml_parse_string(cbuf_get(cb), yspec, &x) < 0){
if (netconf_operation_failed_xml(xret, "protocol", clicon_err_reason)< 0)
goto done;
retval = 1;
goto done;
}
if (!brief && modules_state_cache_set(h, x) < 0) /* move to fn above? */
goto done;
}
if (x && netconf_trymerge(x, yspec, xret) < 0)
goto done;
retval = 0;
done:
if (cb)
cbuf_free(cb);
if (x)
xml_free(x);
return retval;
}
#else
int
yang_modules_state_get(clicon_handle h,
yang_spec *yspec,
char *xpath,
int brief,
cxobj **xret)
{
int retval = -1;
@ -259,6 +399,7 @@ yang_modules_state_get(clicon_handle h,
cprintf(cb,"<modules-state xmlns=\"%s\">", yns->ys_argument);
cprintf(cb,"<module-set-id>%s</module-set-id>", msid);
<<<<<<< HEAD
ymod = NULL;
while ((ymod = yn_each((yang_node*)yspec, ymod)) != NULL) {
if (ymod->ys_keyword != Y_MODULE &&
@ -270,12 +411,33 @@ yang_modules_state_get(clicon_handle h,
cprintf(cb,"<revision>%s</revision>", ys->ys_argument);
else
cprintf(cb,"<revision></revision>");
=======
ymod = NULL;
while ((ymod = yn_each((yang_node*)yspec, ymod)) != NULL) {
if (ymod->ys_keyword != Y_MODULE &&
ymod->ys_keyword != Y_SUBMODULE)
continue;
cprintf(cb,"<module>");
cprintf(cb,"<name>%s</name>", ymod->ys_argument);
if ((ys = yang_find((yang_node*)ymod, Y_REVISION, NULL)) != NULL)
cprintf(cb,"<revision>%s</revision>", ys->ys_argument);
else
cprintf(cb,"<revision></revision>");
if (!brief){
>>>>>>> modules-state
if ((ys = yang_find((yang_node*)ymod, Y_NAMESPACE, NULL)) != NULL)
cprintf(cb,"<namespace>%s</namespace>", ys->ys_argument);
else
cprintf(cb,"<namespace></namespace>");
<<<<<<< HEAD
/* This follows order in rfc 7895: feature, conformance-type, submodules */
yc = NULL;
=======
}
/* This follows order in rfc 7895: feature, conformance-type, submodules */
yc = NULL;
if (!brief)
>>>>>>> modules-state
while ((yc = yn_each((yang_node*)ymod, yc)) != NULL) {
switch(yc->ys_keyword){
case Y_FEATURE:
@ -286,6 +448,7 @@ yang_modules_state_get(clicon_handle h,
break;
}
}
<<<<<<< HEAD
cprintf(cb, "<conformance-type>implement</conformance-type>");
yc = NULL;
while ((yc = yn_each((yang_node*)ymod, yc)) != NULL) {
@ -302,6 +465,25 @@ yang_modules_state_get(clicon_handle h,
default:
break;
}
=======
if (!brief)
cprintf(cb, "<conformance-type>implement</conformance-type>");
yc = NULL;
if (!brief)
while ((yc = yn_each((yang_node*)ymod, yc)) != NULL) {
switch(yc->ys_keyword){
case Y_SUBMODULE:
cprintf(cb,"<submodule>");
cprintf(cb,"<name>%s</name>", yc->ys_argument);
if ((ys = yang_find((yang_node*)yc, Y_REVISION, NULL)) != NULL)
cprintf(cb,"<revision>%s</revision>", ys->ys_argument);
else
cprintf(cb,"<revision></revision>");
cprintf(cb,"</submodule>");
break;
default:
break;
>>>>>>> modules-state
}
cprintf(cb,"</module>");
}
@ -326,3 +508,4 @@ yang_modules_state_get(clicon_handle h,
cbuf_free(cb);
return retval;
}
#endif