* New backend startup and upgrade support, see [doc/startup.md] for details

* Datastore files contain RFC7895 module-state information
This commit is contained in:
Olof hagsand 2019-02-13 11:35:49 +01:00
parent 28bd698968
commit 560110b4e8
44 changed files with 1595 additions and 631 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

@ -882,4 +882,34 @@ 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;
}

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

@ -1135,8 +1135,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

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

@ -132,6 +132,7 @@ yang_modules_revision(clicon_handle h)
/*! Get modules state according to RFC 7895
* @param[in] h Clicon handle
* @param[in] yspec Yang spec
* @param[in] brief Just name and revision
* @param[in,out] xret Existing XML tree, merge x into this
* @retval -1 Error (fatal)
* @retval 0 OK
@ -158,6 +159,7 @@ x +--ro namespace inet:uri
int
yang_modules_state_get(clicon_handle h,
yang_spec *yspec,
int brief,
cxobj **xret)
{
int retval = -1;
@ -199,24 +201,29 @@ yang_modules_state_get(clicon_handle h,
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>");
if (!brief){
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 */
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;
if (!brief)
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>");
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: