Added state data

This commit is contained in:
Olof hagsand 2017-07-01 17:42:39 +02:00
parent 43c39160a5
commit f5c19d8586
24 changed files with 512 additions and 224 deletions

View file

@ -291,7 +291,7 @@ hash_del(clicon_hash_t *hash,
return 0;
}
/*! Return vector of keys in has table
/*! Return vector of keys in hash table
*
* @param[in] hash Hash table
* @param[out] nkeys Size of key vector

View file

@ -1345,6 +1345,10 @@ cxvec_append(cxobj *x,
* @param[in] type matching type or -1 for any
* @param[in] fn Callback
* @param[in] arg Argument
* @retval -1 Error, aborted at first error encounter
* @retval 0 OK, all nodes traversed
* @retval n OK, aborted at first encounter of first match
*
* @code
* int x_fn(cxobj *x, void *arg)
* {
@ -1353,7 +1357,7 @@ cxvec_append(cxobj *x,
* xml_apply(xn, CX_ELMNT, x_fn, NULL);
* @endcode
* @note do not delete or move around any children during this function
* @note It does not apply fn to the root node,..
* @note return value > 0 aborts the traversal
* @see xml_apply0 including top object
*/
int
@ -1363,13 +1367,19 @@ xml_apply(cxobj *xn,
void *arg)
{
int retval = -1;
cxobj *x = NULL;
cxobj *x;
int ret;
x = NULL;
while ((x = xml_child_each(xn, x, type)) != NULL) {
if (fn(x, arg) < 0)
goto done;
if (xml_apply(x, type, fn, arg) < 0)
if ((ret = xml_apply(x, type, fn, arg)) < 0)
goto done;
if (ret > 0){
retval = ret;
goto done;
}
}
retval = 0;
done:
@ -1377,7 +1387,11 @@ xml_apply(cxobj *xn,
}
/*! Apply a function call on top object and all xml node children recursively
* @retval -1 Error, aborted at first error encounter
* @retval 0 OK, all nodes traversed
* @retval n OK, aborted at first encounter of first match
* @see xml_apply not including top object
*/
int
xml_apply0(cxobj *xn,
@ -1386,10 +1400,14 @@ xml_apply0(cxobj *xn,
void *arg)
{
int retval = -1;
int ret;
if (fn(xn, arg) < 0)
if ((ret = fn(xn, arg)) < 0)
goto done;
retval = xml_apply(xn, type, fn, arg);
if (ret > 0)
retval = ret;
else
retval = xml_apply(xn, type, fn, arg);
done:
return retval;
}
@ -1402,6 +1420,9 @@ xml_apply0(cxobj *xn,
* @param[in] xn XML node
* @param[in] fn Callback
* @param[in] arg Argument
* @retval -1 Error, aborted at first error encounter
* @retval 0 OK, all nodes traversed
* @retval n OK, aborted at first encounter of first match
* @code
* int x_fn(cxobj *x, void *arg)
* {
@ -1420,12 +1441,17 @@ xml_apply_ancestor(cxobj *xn,
{
int retval = -1;
cxobj *xp = NULL;
int ret;
while ((xp = xml_parent(xn)) != NULL) {
if (fn(xp, arg) < 0)
goto done;
if (xml_apply_ancestor(xp, fn, arg) < 0)
if ((ret = xml_apply_ancestor(xp, fn, arg)) < 0)
goto done;
if (ret > 0){
retval = ret;
goto done;
}
xn = xp;
}
retval = 0;

View file

@ -322,12 +322,13 @@ xmldb_setopt(clicon_handle h,
* @param[in] h Clicon handle
* @param[in] dbname Name of database to search in (filename including dir path
* @param[in] xpath String with XPATH syntax. or NULL for all
* @param[in] config If set only configuration data, else also state
* @param[out] xtop Single XML tree which xvec points to. Free with xml_free()
* @retval 0 OK
* @retval -1 Error
* @code
* cxobj *xt;
* if (xmldb_get(xh, "running", "/interfaces/interface[name="eth"]", &xt) < 0)
* if (xmldb_get(xh, "running", "/interfaces/interface[name="eth"]", 1, &xt) < 0)
* err;
* for (i=0; i<xlen; i++){
* xn = xv[i];
@ -343,6 +344,7 @@ int
xmldb_get(clicon_handle h,
char *db,
char *xpath,
int config,
cxobj **xtop)
{
int retval = -1;
@ -361,7 +363,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, xtop);
retval = xa->xa_get_fn(xh, db, xpath, config, xtop);
#if DEBUG
if (retval == 0) {
cbuf *cb = cbuf_new();
@ -391,6 +393,9 @@ xmldb_get(clicon_handle h,
* if (xmldb_put(xh, "running", OP_MERGE, xt) < 0)
* err;
* @endcode
* @note that you can add both config data and state data. In comparison,
* xmldb_get has a parameter to get config data only.
*
*/
int
xmldb_put(clicon_handle h,

View file

@ -1084,23 +1084,25 @@ api_path_fmt2xpath(char *api_path_fmt,
return retval;
}
/*! Prune everything that does not pass test
/*! Prune everything that does not pass test or have at least a child* does not
* @param[in] xt XML tree with some node marked
* @param[in] flag Which flag to test for
* @param[in] test 1: test that flag is set, 0: test that flag is not set
* @param[out] upmark Set if a child (recursively) has marked set.
* The function removes all branches that does not a child that pass the test
* The function removes all branches that does not pass the test
* Purge all nodes that dont have MARK flag set recursively.
* Save all nodes that is MARK:ed or have at least one (grand*)child that is MARKed
* @code
* xml_tree_prune_flagged(xt, XML_FLAG_MARK, 1, NULL);
* xml_tree_prune_flagged_sub(xt, XML_FLAG_MARK, 1, NULL);
* @endcode
* @note This function seems a little too complex semantics
* @see xml_tree_prune_flagged for a simpler variant
*/
int
xml_tree_prune_flagged(cxobj *xt,
int flag,
int test,
int *upmark)
xml_tree_prune_flagged_sub(cxobj *xt,
int flag,
int test,
int *upmark)
{
int retval = -1;
int submark;
@ -1117,6 +1119,7 @@ xml_tree_prune_flagged(cxobj *xt,
xprev = x = NULL;
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
if (xml_flag(x, flag) == test?flag:0){
/* Pass test */
mark++;
xprev = x;
continue; /* mark and stop here */
@ -1131,7 +1134,7 @@ xml_tree_prune_flagged(cxobj *xt,
continue;
}
}
if (xml_tree_prune_flagged(x, flag, test, &submark) < 0)
if (xml_tree_prune_flagged_sub(x, flag, test, &submark) < 0)
goto done;
/* if xt is list and submark anywhere, then key subs are also marked
*/
@ -1167,6 +1170,43 @@ xml_tree_prune_flagged(cxobj *xt,
return retval;
}
/*! Prune everything that passes test
* @param[in] xt XML tree with some node marked
* @param[in] flag Which flag to test for
* @param[in] test 1: test that flag is set, 0: test that flag is not set
* The function removes all branches that does not pass test
* @code
* xml_tree_prune_flagged(xt, XML_FLAG_MARK, 1, NULL);
* @endcode
*/
int
xml_tree_prune_flagged(cxobj *xt,
int flag,
int test)
{
int retval = -1;
cxobj *x;
cxobj *xprev;
x = NULL;
xprev = x = 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)
goto done;
x = xprev;
continue;
}
if (xml_tree_prune_flagged(x, flag, test) < 0)
goto done;
xprev = x;
}
retval = 0;
done:
return retval;
}
/*! Add default values (if not set)
* @param[in] xt XML tree with some node marked
*/
@ -1293,10 +1333,6 @@ xml_sanity(cxobj *xt,
goto done;
}
name = xml_name(xt);
if (ys==NULL){
clicon_err(OE_XML, 0, "No spec for xml node %s", name);
goto done;
}
if (strstr(ys->ys_argument, name)==NULL){
clicon_err(OE_XML, 0, "xml node name '%s' does not match yang spec arg '%s'",
name, ys->ys_argument);
@ -1307,6 +1343,69 @@ xml_sanity(cxobj *xt,
return retval;
}
/*! Mark all nodes that are not configure data and set return
* @param[in] xt XML tree
* @param[out] arg If set, set to 1 as int* if not config data
*/
int
xml_non_config_data(cxobj *xt,
void *arg) /* Set to 1 if state node */
{
int retval = -1;
yang_stmt *ys;
if ((ys = (yang_stmt*)xml_spec(xt)) == NULL){
clicon_log(LOG_WARNING, "%s: no xml_spec(%s)", __FUNCTION__, xml_name(xt));
retval = 0;
goto done;
}
if (!yang_config(ys)){ /* config == false means state data: mark for remove */
xml_flag_set(xt, XML_FLAG_MARK);
if (arg)
(*(int*)arg) = 1;
}
retval = 0;
done:
return retval;
}
/*! Add yang specification backpoint to XML node
* @param[in] xt XML tree node
* @note This should really be unnecessary since yspec should be set on creation
* @code
* xml_apply(xc, CX_ELMNT, xml_spec_populate, yspec)
* @endcode
*/
int
xml_spec_populate(cxobj *x,
void *arg)
{
int retval = -1;
yang_spec *yspec = (yang_spec*)arg;
char *name;
yang_stmt *y; /* yang node */
cxobj *xp; /* xml parent */
yang_stmt *yp; /* parent yang */
name = xml_name(x);
if ((xp = xml_parent(x)) != NULL &&
(yp = xml_spec(xp)) != NULL)
y = yang_find_syntax((yang_node*)yp, xml_name(x));
else
y = yang_find_topnode(yspec, name); /* still NULL for config */
if (y==NULL){
clicon_err(OE_XML, EBADF, "yang spec not found for xml node '%s' xml parent name: '%s' yangspec:'%s']",
name,
xp?xml_name(xp):"", yp?yp->ys_argument:"");
goto done;
}
xml_spec_set(x, y);
retval = 0;
done:
return retval;
}
/*! Translate from restconf api-path in cvv form to xml xpath
* eg a/b=c -> a/[b=c]
* @param[in] yspec Yang spec
@ -1618,83 +1717,5 @@ api_path2xml(char *api_path,
return retval;
}
/* See RFC 8040 Section 7: Mapping from NETCONF<error-tag> to Status Code
* and RFC 6241 Appendix A. NETCONF Error list
*/
const map_str2int netconf_restconf_map[] = {
{"in-use", 409},
{"invalid-value", 400},
{"invalid-value", 404},
{"invalid-value", 406},
{"too-big", 413}, /* request */
{"too-big", 400}, /* response */
{"missing-attribute", 400},
{"bad-attribute", 400},
{"unknown-attribute", 400},
{"bad-element", 400},
{"unknown-element", 400},
{"unknown-namespace", 400},
{"access-denied", 401},
{"access-denied", 403},
{"lock-denied", 409},
{"resource-denied", 409},
{"rollback-failed", 500},
{"data-exists", 409},
{"data-missing", 409},
{"operation-not-supported",405},
{"operation-not-supported",501},
{"operation-failed", 412},
{"operation-failed", 500},
{"partial-operation", 500},
{"malformed-message", 400},
{NULL, -1}
};
/* See 7231 Section 6.1
*/
const map_str2int http_reason_phrase_map[] = {
{"Continue", 100},
{"Switching Protocols", 101},
{"OK", 200},
{"Created", 201},
{"Accepted", 202},
{"Non-Authoritative Information", 203},
{"No Content", 204},
{"Reset Content", 205},
{"Partial Content", 206},
{"Multiple Choices", 300},
{"Moved Permanently", 301},
{"Found", 302},
{"See Other", 303},
{"Not Modified", 304},
{"Use Proxy", 305},
{"Temporary Redirect", 307},
{"Bad Request", 400},
{"Unauthorized", 401},
{"Payment Required", 402},
{"Forbidden", 403},
{"Not Found", 404},
{"Method Not Allowed", 405},
{"Not Acceptable", 406},
{"Proxy Authentication Required", 407},
{"Request Timeout", 408},
{"Conflict", 409},
{"Gone", 410},
{"Length Required", 411},
{"Precondition Failed", 412},
{"Payload Too Large", 413},
{"URI Too Long", 414},
{"Unsupported Media Type", 415},
{"Range Not Satisfiable", 416},
{"Expectation Failed", 417},
{"Upgrade Required", 426},
{"Internal Server Error", 500},
{"Not Implemented", 501},
{"Bad Gateway", 502},
{"Service Unavailable", 503},
{"Gateway Timeout", 504},
{"HTTP Version Not Supported", 505},
{NULL, -1}
};

View file

@ -132,7 +132,7 @@ enum axis_type{
};
/* Mapping between axis type string <--> int */
static const map_str2int atmap[] = {
static const map_str2int axismap[] = {
{"self", A_SELF},
{"child", A_CHILD},
{"parent", A_PARENT},
@ -163,7 +163,7 @@ xpath_print(FILE *f, struct xpath_element *xplist)
struct xpath_predicate *xp;
for (xe=xplist; xe; xe=xe->xe_next){
fprintf(f, "\t:%s %s ", clicon_int2str(atmap, xe->xe_type),
fprintf(f, "\t:%s %s ", clicon_int2str(axismap, xe->xe_type),
xe->xe_str?xe->xe_str:"");
for (xp=xe->xe_predicate; xp; xp=xp->xp_next)
fprintf(f, "[%s]", xp->xp_expr);
@ -581,7 +581,7 @@ xpath_find(struct xpath_element *xe,
}
#if 0
fprintf(stderr, "%s: %s: \"%s\"\n", __FUNCTION__,
clicon_int2str(atmap, xe->xe_type), xe->xe_str?xe->xe_str:"");
clicon_int2str(axismap, xe->xe_type), xe->xe_str?xe->xe_str:"");
#endif
switch (xe->xe_type){
case A_SELF:

View file

@ -103,12 +103,14 @@ static const map_str2int ytmap[] = {
static int
yang_builtin(char *type)
{
if (clicon_str2int(ytmap, type) != -1)
return 1;
#if 0
const struct map_str2int *yt;
/* built-in types */
for (yt = &ytmap[0]; yt->ms_str; yt++)
if (strcmp(yt->ms_str, type) == 0)
return 1;
#endif
return 0;
}