Refined netconf none semantics in tests and text datastore
This commit is contained in:
parent
2f30bda7d4
commit
69ff0e3891
19 changed files with 247 additions and 91 deletions
|
|
@ -29,6 +29,8 @@
|
||||||
#
|
#
|
||||||
# ***** END LICENSE BLOCK *****
|
# ***** END LICENSE BLOCK *****
|
||||||
|
|
||||||
|
- Refined netconf "none" semantics in tests and text datastore
|
||||||
|
|
||||||
- Moved apps/dbctrl to datastore/
|
- Moved apps/dbctrl to datastore/
|
||||||
|
|
||||||
- Added connect/disconnect/getopt/setopt and handle to xmldb API
|
- Added connect/disconnect/getopt/setopt and handle to xmldb API
|
||||||
|
|
|
||||||
15
README.md
15
README.md
|
|
@ -1,5 +1,4 @@
|
||||||
CLIXON
|
# CLIXON
|
||||||
======
|
|
||||||
|
|
||||||
CLIXON is an automatic configuration manager where you from a YANG
|
CLIXON is an automatic configuration manager where you from a YANG
|
||||||
specification generate interactive CLI, NETCONF, RESTCONF and embedded
|
specification generate interactive CLI, NETCONF, RESTCONF and embedded
|
||||||
|
|
@ -12,6 +11,8 @@ applications such as CLICON/ROST does not run on CLIXON.
|
||||||
Presentations and tutorial is found on the [CLICON project
|
Presentations and tutorial is found on the [CLICON project
|
||||||
page](http://www.clicon.org)
|
page](http://www.clicon.org)
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
A typical installation is as follows:
|
A typical installation is as follows:
|
||||||
|
|
||||||
> configure # Configure clixon to platform
|
> configure # Configure clixon to platform
|
||||||
|
|
@ -22,17 +23,27 @@ A typical installation is as follows:
|
||||||
One example applications is provided, the IETF IP YANG datamodel with generated CLI and configuration interface. It all origins from work at
|
One example applications is provided, the IETF IP YANG datamodel with generated CLI and configuration interface. It all origins from work at
|
||||||
[KTH](http://www.csc.kth.se/~olofh/10G_OSR)
|
[KTH](http://www.csc.kth.se/~olofh/10G_OSR)
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
[CLIgen](http://www.cligen.se) is required for building CLIXON. If you need
|
[CLIgen](http://www.cligen.se) is required for building CLIXON. If you need
|
||||||
to build and install CLIgen:
|
to build and install CLIgen:
|
||||||
|
|
||||||
git clone https://github.com/olofhagsand/cligen.git
|
git clone https://github.com/olofhagsand/cligen.git
|
||||||
cd cligen; configure; make; make install
|
cd cligen; configure; make; make install
|
||||||
|
|
||||||
|
## Licenses
|
||||||
|
|
||||||
CLIXON is dual license. Either Apache License, Version 2.0 or GNU
|
CLIXON is dual license. Either Apache License, Version 2.0 or GNU
|
||||||
General Public License Version 2. You choose.
|
General Public License Version 2. You choose.
|
||||||
|
|
||||||
See LICENSE.md for license, CHANGELOG for recent changes.
|
See LICENSE.md for license, CHANGELOG for recent changes.
|
||||||
|
|
||||||
|
## Client code
|
||||||
|
|
||||||
|
[CLI](apps/restconf).
|
||||||
|
[Restconf](apps/restconf).
|
||||||
|
[Netconf](apps/netconf).
|
||||||
|
[Netconf](apps/netconf).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -307,7 +307,6 @@ from_client_edit_config(clicon_handle h,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((xc = xpath_first(xn, "config")) != NULL){
|
if ((xc = xpath_first(xn, "config")) != NULL){
|
||||||
/* XXX see from_client_xmlput() */
|
|
||||||
if (xmldb_put(h, target, operation, api_path, xc) < 0){
|
if (xmldb_put(h, target, operation, api_path, xc) < 0){
|
||||||
cprintf(cbret, "<rpc-reply><rpc-error>"
|
cprintf(cbret, "<rpc-reply><rpc-error>"
|
||||||
"<error-tag>operation-failed</error-tag>"
|
"<error-tag>operation-failed</error-tag>"
|
||||||
|
|
|
||||||
|
|
@ -66,8 +66,8 @@ curl -sX POST -d '{"clicon":{"interfaces":{"interface":{"name":"eth1","type":"et
|
||||||
|
|
||||||
3. DEBUGGING
|
3. DEBUGGING
|
||||||
++++++++++++
|
++++++++++++
|
||||||
Start the restconf programs with debug flag:
|
Start the restconf fastcgi program with debug flag:
|
||||||
sudo su -c "/www-data/clixon_restconf -D" -s /bin/sh www-data
|
sudo su -c "/www-data/clixon_restconf -Df /usr/local/etc/routing.conf" -s /bin/sh www-data
|
||||||
|
|
||||||
Look at syslog:
|
Look at syslog:
|
||||||
tail -f /var/log/syslog | grep clixon_restconf
|
tail -f /var/log/syslog | grep clixon_restconf
|
||||||
|
|
@ -296,7 +296,7 @@ api_data_edit(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
cprintf(cbx, "</config>");
|
cprintf(cbx, "</config>");
|
||||||
clicon_debug(1, "%s cbx: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path);
|
clicon_debug(1, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path);
|
||||||
if (clicon_rpc_edit_config(h, "candidate",
|
if (clicon_rpc_edit_config(h, "candidate",
|
||||||
operation,
|
operation,
|
||||||
api_path,
|
api_path,
|
||||||
|
|
@ -337,7 +337,8 @@ api_data_edit(clicon_handle h,
|
||||||
|
|
||||||
If the data resource already exists, then the POST request MUST fail
|
If the data resource already exists, then the POST request MUST fail
|
||||||
and a "409 Conflict" status-line MUST be returned.
|
and a "409 Conflict" status-line MUST be returned.
|
||||||
* Netconf: <edit-config> (nc:operation="create") | invoke an RPC operation
|
* Netconf: <edit-config> (nc:operation="create") | invoke an RPC operation * @example
|
||||||
|
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
api_data_post(clicon_handle h,
|
api_data_post(clicon_handle h,
|
||||||
|
|
@ -359,8 +360,8 @@ api_data_post(clicon_handle h,
|
||||||
* @param[in] pi Offset, where to start pcvec
|
* @param[in] pi Offset, where to start pcvec
|
||||||
* @param[in] qvec Vector of query string (QUERY_STRING)
|
* @param[in] qvec Vector of query string (QUERY_STRING)
|
||||||
* @param[in] data Stream input data
|
* @param[in] data Stream input data
|
||||||
* Example:
|
* @example
|
||||||
curl -X PUT -d {\"enabled\":\"false\"} http://127.0.0.1/restconf/data/interfaces/interface=eth1
|
curl -X PUT -d '{"enabled":"false"}' http://127.0.0.1/restconf/data/interfaces/interface=eth1
|
||||||
*
|
*
|
||||||
PUT:
|
PUT:
|
||||||
if the PUT request creates a new resource,
|
if the PUT request creates a new resource,
|
||||||
|
|
|
||||||
|
|
@ -652,7 +652,7 @@ kv_get(xmldb_handle xh,
|
||||||
}
|
}
|
||||||
/* Top is special case */
|
/* Top is special case */
|
||||||
if (!xml_flag(xt, XML_FLAG_MARK))
|
if (!xml_flag(xt, XML_FLAG_MARK))
|
||||||
if (xml_tree_prune_unmarked(xt, NULL) < 0)
|
if (xml_tree_prune_flagged(xt, XML_FLAG_MARK, 1, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (xml_apply(xt, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, (void*)XML_FLAG_MARK) < 0)
|
if (xml_apply(xt, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, (void*)XML_FLAG_MARK) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -1309,7 +1309,7 @@ kv_put(xmldb_handle xh,
|
||||||
yang_spec *yspec;
|
yang_spec *yspec;
|
||||||
char *dbfilename = NULL;
|
char *dbfilename = NULL;
|
||||||
|
|
||||||
if ((xml_child_nr(xt)==0 || xml_body(xt)!= NULL) &&
|
if (xt && (xml_child_nr(xt)==0 || xml_body(xt)!= NULL) &&
|
||||||
api_path && strlen(api_path) && strcmp(api_path,"/"))
|
api_path && strlen(api_path) && strcmp(api_path,"/"))
|
||||||
return xmldb_put_xkey(kh, db, op, api_path, xml_body(xt));
|
return xmldb_put_xkey(kh, db, op, api_path, xml_body(xt));
|
||||||
if ((yspec = kh->kh_yangspec) == NULL){
|
if ((yspec = kh->kh_yangspec) == NULL){
|
||||||
|
|
|
||||||
|
|
@ -245,6 +245,32 @@ text_setopt(xmldb_handle xh,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Populate with spec
|
||||||
|
* @param[in] xt XML tree with some node marked
|
||||||
|
*/
|
||||||
|
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 */
|
||||||
|
xml_spec_set(x, y);
|
||||||
|
retval = 0;
|
||||||
|
// done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Get content of database using xpath. return a set of matching sub-trees
|
/*! Get content of database using xpath. return a set of matching sub-trees
|
||||||
* The function returns a minimal tree that includes all sub-trees that match
|
* The function returns a minimal tree that includes all sub-trees that match
|
||||||
* xpath.
|
* xpath.
|
||||||
|
|
@ -335,12 +361,12 @@ text_get(xmldb_handle xh,
|
||||||
}
|
}
|
||||||
/* Top is special case */
|
/* Top is special case */
|
||||||
if (!xml_flag(xt, XML_FLAG_MARK))
|
if (!xml_flag(xt, XML_FLAG_MARK))
|
||||||
if (xml_tree_prune_unmarked(xt, NULL) < 0)
|
if (xml_tree_prune_flagged(xt, XML_FLAG_MARK, 1, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (xml_apply(xt, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, (void*)XML_FLAG_MARK) < 0)
|
if (xml_apply(xt, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, (void*)XML_FLAG_MARK) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
if (xml_apply(xt, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
||||||
if (0){ /* No xml_spec(xt) */
|
goto done;
|
||||||
if (xml_apply(xt, CX_ELMNT, xml_default, NULL) < 0)
|
if (xml_apply(xt, CX_ELMNT, xml_default, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* XXX does not work for top-level */
|
/* XXX does not work for top-level */
|
||||||
|
|
@ -348,7 +374,7 @@ text_get(xmldb_handle xh,
|
||||||
goto done;
|
goto done;
|
||||||
if (xml_apply(xt, CX_ELMNT, xml_sanity, NULL) < 0)
|
if (xml_apply(xt, CX_ELMNT, xml_sanity, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
|
||||||
if (debug>1)
|
if (debug>1)
|
||||||
clicon_xml2file(stderr, xt, 0, 1);
|
clicon_xml2file(stderr, xt, 0, 1);
|
||||||
if (xvec0 && xlen0){
|
if (xvec0 && xlen0){
|
||||||
|
|
@ -755,11 +781,14 @@ text_modify(cxobj *x0,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Fall thru */
|
/* Fall thru */
|
||||||
|
case OP_NONE: /* XXX */
|
||||||
case OP_MERGE:
|
case OP_MERGE:
|
||||||
case OP_REPLACE:
|
case OP_REPLACE:
|
||||||
if (x0==NULL){
|
if (x0==NULL){
|
||||||
if ((x0 = xml_new_spec(name, x0p, y)) == NULL)
|
if ((x0 = xml_new_spec(name, x0p, y)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
|
if (op==OP_NONE)
|
||||||
|
xml_flag_set(x0, XML_FLAG_NONE); /* Mark for potential deletion */
|
||||||
if (x1bstr){ /* empty type does not have body */
|
if (x1bstr){ /* empty type does not have body */
|
||||||
if ((x0b = xml_new("body", x0)) == NULL)
|
if ((x0b = xml_new("body", x0)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -767,12 +796,24 @@ text_modify(cxobj *x0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (x1bstr){
|
if (x1bstr){
|
||||||
if ((x0b = xml_body_get(x0)) == NULL)
|
if ((x0b = xml_body_get(x0)) == NULL){
|
||||||
|
if ((x0b = xml_new("body", x0)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
|
xml_type_set(x0b, CX_BODY);
|
||||||
|
}
|
||||||
if (xml_value_set(x0b, x1bstr) < 0)
|
if (xml_value_set(x0b, x1bstr) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case OP_DELETE:
|
||||||
|
if (x0==NULL){
|
||||||
|
clicon_err(OE_XML, 0, "Object to delete does not exist");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
case OP_REMOVE:
|
||||||
|
if (x0)
|
||||||
|
xml_purge(x0);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
} /* switch op */
|
} /* switch op */
|
||||||
|
|
@ -799,11 +840,15 @@ text_modify(cxobj *x0,
|
||||||
xml_purge(x0);
|
xml_purge(x0);
|
||||||
x0 = NULL;
|
x0 = NULL;
|
||||||
}
|
}
|
||||||
|
case OP_NONE: /* XXX */
|
||||||
case OP_MERGE:
|
case OP_MERGE:
|
||||||
if (x0==NULL){
|
if (x0==NULL){
|
||||||
if ((x0 = xml_new_spec(name, x0p, y)) == NULL)
|
if ((x0 = xml_new_spec(name, x0p, y)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
|
if (op==OP_NONE)
|
||||||
|
xml_flag_set(x0, XML_FLAG_NONE); /* Mark for potential deletion */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loop through children of the modification tree */
|
/* Loop through children of the modification tree */
|
||||||
x1c = NULL;
|
x1c = NULL;
|
||||||
while ((x1c = xml_child_each(x1, x1c, CX_ELMNT)) != NULL) {
|
while ((x1c = xml_child_each(x1, x1c, CX_ELMNT)) != NULL) {
|
||||||
|
|
@ -823,6 +868,15 @@ text_modify(cxobj *x0,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case OP_DELETE:
|
||||||
|
if (x0==NULL){
|
||||||
|
clicon_err(OE_XML, 0, "Object to delete does not exist");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
case OP_REMOVE:
|
||||||
|
if (x0)
|
||||||
|
xml_purge(x0);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
} /* CONTAINER switch op */
|
} /* CONTAINER switch op */
|
||||||
|
|
@ -877,10 +931,12 @@ text_put(xmldb_handle xh,
|
||||||
cxobj *xnew = NULL;
|
cxobj *xnew = NULL;
|
||||||
yang_node *y = NULL;
|
yang_node *y = NULL;
|
||||||
|
|
||||||
|
#if 0 /* Just ignore */
|
||||||
if ((op==OP_DELETE || op==OP_REMOVE) && xmod){
|
if ((op==OP_DELETE || op==OP_REMOVE) && xmod){
|
||||||
clicon_err(OE_XML, 0, "xml tree should be NULL for REMOVE/DELETE");
|
clicon_err(OE_XML, 0, "xml tree should be NULL for REMOVE/DELETE");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
if (text_db2file(th, db, &dbfile) < 0)
|
if (text_db2file(th, db, &dbfile) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (dbfile==NULL){
|
if (dbfile==NULL){
|
||||||
|
|
@ -942,6 +998,12 @@ text_put(xmldb_handle xh,
|
||||||
else
|
else
|
||||||
if (text_modify(xbase, xbasep, xmod, op, (yang_node*)y, yspec) < 0)
|
if (text_modify(xbase, xbasep, xmod, op, (yang_node*)y, yspec) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
/* Remove NONE nodes if all subs recursively are also NONE */
|
||||||
|
if (xml_tree_prune_flagged(xt, XML_FLAG_NONE, 0, NULL) <0)
|
||||||
|
goto done;
|
||||||
|
if (xml_apply(xt, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset,
|
||||||
|
(void*)XML_FLAG_NONE) < 0)
|
||||||
|
goto done;
|
||||||
// output:
|
// output:
|
||||||
/* Print out top-level xml tree after modification to file */
|
/* Print out top-level xml tree after modification to file */
|
||||||
if ((cb = cbuf_new()) == NULL){
|
if ((cb = cbuf_new()) == NULL){
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,7 @@ CLICON_CLIGEN_CALLBACK_SINGLE_ARG 0
|
||||||
|
|
||||||
# Enabled uses "startup" configuration on boot
|
# Enabled uses "startup" configuration on boot
|
||||||
CLICON_USE_STARTUP_CONFIG 0
|
CLICON_USE_STARTUP_CONFIG 0
|
||||||
|
|
||||||
|
# XMLDB datastore plugin filename (see datastore/ and clixon_xml_db.[ch])
|
||||||
|
CLICON_XMLDB_PLUGIN /usr/local/lib/xmldb/text.so
|
||||||
|
#CLICON_XMLDB_PLUGIN /usr/local/lib/xmldb/keyvalue.so
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,7 @@ typedef int (xml_applyfn_t)(cxobj *yn, void *arg);
|
||||||
#define XML_FLAG_ADD 0x02 /* Node is added (commits) or parent added rec*/
|
#define XML_FLAG_ADD 0x02 /* Node is added (commits) or parent added rec*/
|
||||||
#define XML_FLAG_DEL 0x04 /* Node is deleted (commits) or parent deleted rec */
|
#define XML_FLAG_DEL 0x04 /* Node is deleted (commits) or parent deleted rec */
|
||||||
#define XML_FLAG_CHANGE 0x08 /* Node is changed (commits) or child changed rec */
|
#define XML_FLAG_CHANGE 0x08 /* Node is changed (commits) or child changed rec */
|
||||||
|
#define XML_FLAG_NONE 0x10 /* Node is added as NONE */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prototypes
|
* Prototypes
|
||||||
|
|
@ -102,6 +103,7 @@ int xml_childvec_set(cxobj *x, int len);
|
||||||
cxobj *xml_new(char *name, cxobj *xn_parent);
|
cxobj *xml_new(char *name, cxobj *xn_parent);
|
||||||
cxobj *xml_new_spec(char *name, cxobj *xn_parent, void *spec);
|
cxobj *xml_new_spec(char *name, cxobj *xn_parent, void *spec);
|
||||||
void *xml_spec(cxobj *x);
|
void *xml_spec(cxobj *x);
|
||||||
|
void *xml_spec_set(cxobj *x, void *spec);
|
||||||
cxobj *xml_find(cxobj *xn_parent, char *name);
|
cxobj *xml_find(cxobj *xn_parent, char *name);
|
||||||
|
|
||||||
int xml_addsub(cxobj *xp, cxobj *xc);
|
int xml_addsub(cxobj *xp, cxobj *xc);
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,7 @@ typedef int (xmldb_delete_t)(xmldb_handle xh, char *db);
|
||||||
/* Type of xmldb init function */
|
/* Type of xmldb init function */
|
||||||
typedef int (xmldb_init_t)(xmldb_handle xh, char *db);
|
typedef int (xmldb_init_t)(xmldb_handle xh, char *db);
|
||||||
|
|
||||||
/* grideye agent plugin init struct for the api */
|
/* plugin init struct for the api */
|
||||||
struct xmldb_api{
|
struct xmldb_api{
|
||||||
int xa_version;
|
int xa_version;
|
||||||
int xa_magic;
|
int xa_magic;
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ int xml_diff(yang_spec *yspec, cxobj *xt1, cxobj *xt2,
|
||||||
int yang2xmlkeyfmt(yang_stmt *ys, int inclkey, char **xkfmt);
|
int yang2xmlkeyfmt(yang_stmt *ys, int inclkey, char **xkfmt);
|
||||||
int xmlkeyfmt2key(char *xkfmt, cvec *cvv, char **xk);
|
int xmlkeyfmt2key(char *xkfmt, cvec *cvv, char **xk);
|
||||||
int xmlkeyfmt2xpath(char *xkfmt, cvec *cvv, char **xk);
|
int xmlkeyfmt2xpath(char *xkfmt, cvec *cvv, char **xk);
|
||||||
int xml_tree_prune_unmarked(cxobj *xt, int *upmark);
|
int xml_tree_prune_flagged(cxobj *xt, int flag, int test, int *upmark);
|
||||||
int xml_default(cxobj *x, void *arg);
|
int xml_default(cxobj *x, void *arg);
|
||||||
int xml_order(cxobj *x, void *arg);
|
int xml_order(cxobj *x, void *arg);
|
||||||
int xml_sanity(cxobj *x, void *arg);
|
int xml_sanity(cxobj *x, void *arg);
|
||||||
|
|
|
||||||
|
|
@ -521,12 +521,21 @@ xml_new_spec(char *name,
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void *
|
void *
|
||||||
xml_spec(cxobj *x)
|
xml_spec(cxobj *x)
|
||||||
{
|
{
|
||||||
return x->x_spec;
|
return x->x_spec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
xml_spec_set(cxobj *x,
|
||||||
|
void *spec)
|
||||||
|
{
|
||||||
|
x->x_spec = spec;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Find an XML node matching name among a parent's children.
|
/*! Find an XML node matching name among a parent's children.
|
||||||
*
|
*
|
||||||
* Get first XML node directly under x_up in the xml hierarchy with
|
* Get first XML node directly under x_up in the xml hierarchy with
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,9 @@
|
||||||
#include "clixon_options.h"
|
#include "clixon_options.h"
|
||||||
#include "clixon_xml_db.h"
|
#include "clixon_xml_db.h"
|
||||||
|
|
||||||
|
/* Set to log get and put requests */
|
||||||
|
#define DEBUG 0
|
||||||
|
|
||||||
/*! Load an xmldb storage plugin according to filename
|
/*! Load an xmldb storage plugin according to filename
|
||||||
* If init function fails (not found, wrong version, etc) print a log and dont
|
* If init function fails (not found, wrong version, etc) print a log and dont
|
||||||
* add it.
|
* add it.
|
||||||
|
|
@ -350,7 +353,7 @@ xmldb_get(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
retval = xa->xa_get_fn(xh, db, xpath, xtop, xvec, xlen);
|
retval = xa->xa_get_fn(xh, db, xpath, xtop, xvec, xlen);
|
||||||
#if 0 /* XXX DEBUG */
|
#if DEBUG
|
||||||
if (retval == 0) {
|
if (retval == 0) {
|
||||||
cbuf *cb = cbuf_new();
|
cbuf *cb = cbuf_new();
|
||||||
clicon_xml2cbuf(cb, *xtop, 0, 0);
|
clicon_xml2cbuf(cb, *xtop, 0, 0);
|
||||||
|
|
@ -407,7 +410,7 @@ xmldb_put(clicon_handle h,
|
||||||
clicon_err(OE_DB, 0, "Not connected to datastore plugin");
|
clicon_err(OE_DB, 0, "Not connected to datastore plugin");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
#if 0 /* XXX DEBUG */
|
#if DEBUG
|
||||||
{
|
{
|
||||||
cbuf *cb = cbuf_new();
|
cbuf *cb = cbuf_new();
|
||||||
if (xt)
|
if (xt)
|
||||||
|
|
|
||||||
|
|
@ -1076,15 +1076,22 @@ xmlkeyfmt2xpath(char *xkfmt,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Prune everything that has not been marked
|
/*! Prune everything that does not pass test
|
||||||
* @param[in] xt XML tree with some node marked
|
* @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.
|
* @param[out] upmark Set if a child (recursively) has marked set.
|
||||||
* The function removes all branches that does not contain a marked child
|
* The function removes all branches that does not a child that pass the test
|
||||||
* XXX: maybe key leafs should not be purged if list is not purged?
|
* Purge all nodes that dont have MARK flag set recursively.
|
||||||
* XXX: consider move to clicon_xml
|
* 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);
|
||||||
|
* @endcode
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xml_tree_prune_unmarked(cxobj *xt,
|
xml_tree_prune_flagged(cxobj *xt,
|
||||||
|
int flag,
|
||||||
|
int test,
|
||||||
int *upmark)
|
int *upmark)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
@ -1097,12 +1104,12 @@ xml_tree_prune_unmarked(cxobj *xt,
|
||||||
x = NULL;
|
x = NULL;
|
||||||
xprev = x = NULL;
|
xprev = x = NULL;
|
||||||
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
|
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
|
||||||
if (xml_flag(x, XML_FLAG_MARK)){
|
if (xml_flag(x, flag) == test?flag:0){
|
||||||
mark++;
|
mark++;
|
||||||
xprev = x;
|
xprev = x;
|
||||||
continue; /* mark and stop here */
|
continue; /* mark and stop here */
|
||||||
}
|
}
|
||||||
if (xml_tree_prune_unmarked(x, &submark) < 0)
|
if (xml_tree_prune_flagged(x, flag, test, &submark) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (submark)
|
if (submark)
|
||||||
mark++;
|
mark++;
|
||||||
|
|
|
||||||
|
|
@ -358,6 +358,13 @@ xpath_parse(char *xpath,
|
||||||
else if (strncmp(s,"descendant-or-self::", strlen("descendant-or-self::"))==0){
|
else if (strncmp(s,"descendant-or-self::", strlen("descendant-or-self::"))==0){
|
||||||
xpath_element_new(A_DESCENDANT_OR_SELF, s+strlen("descendant-or-self::"), &xpnext);
|
xpath_element_new(A_DESCENDANT_OR_SELF, s+strlen("descendant-or-self::"), &xpnext);
|
||||||
}
|
}
|
||||||
|
#if 1
|
||||||
|
else if (strncmp(s,"..", strlen(".."))==0) /* abbreviatedstep */
|
||||||
|
xpath_element_new(A_PARENT, s+strlen(".."), &xpnext);
|
||||||
|
#else
|
||||||
|
else if (strncmp(s,"..", strlen(s))==0) /* abbreviatedstep */
|
||||||
|
xpath_element_new(A_PARENT, NULL, &xpnext);
|
||||||
|
#endif
|
||||||
#if 1 /* Problems with .[userid=1321] */
|
#if 1 /* Problems with .[userid=1321] */
|
||||||
else if (strncmp(s,".", strlen("."))==0)
|
else if (strncmp(s,".", strlen("."))==0)
|
||||||
xpath_element_new(A_SELF, s+strlen("."), &xpnext);
|
xpath_element_new(A_SELF, s+strlen("."), &xpnext);
|
||||||
|
|
@ -368,13 +375,7 @@ xpath_parse(char *xpath,
|
||||||
|
|
||||||
else if (strncmp(s,"self::", strlen("self::"))==0)
|
else if (strncmp(s,"self::", strlen("self::"))==0)
|
||||||
xpath_element_new(A_SELF, s+strlen("self::"), &xpnext);
|
xpath_element_new(A_SELF, s+strlen("self::"), &xpnext);
|
||||||
#if 1
|
|
||||||
else if (strncmp(s,"..", strlen(".."))==0) /* abbreviatedstep */
|
|
||||||
xpath_element_new(A_PARENT, s+strlen(".."), &xpnext);
|
|
||||||
#else
|
|
||||||
else if (strncmp(s,"..", strlen(s))==0) /* abbreviatedstep */
|
|
||||||
xpath_element_new(A_PARENT, NULL, &xpnext);
|
|
||||||
#endif
|
|
||||||
else if (strncmp(s,"parent::", strlen("parent::"))==0)
|
else if (strncmp(s,"parent::", strlen("parent::"))==0)
|
||||||
xpath_element_new(A_PARENT, s+strlen("parent::"), &xpnext);
|
xpath_element_new(A_PARENT, s+strlen("parent::"), &xpnext);
|
||||||
else if (strncmp(s,"ancestor::", strlen("ancestor::"))==0)
|
else if (strncmp(s,"ancestor::", strlen("ancestor::"))==0)
|
||||||
|
|
@ -1076,7 +1077,7 @@ int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
cxobj **xv;
|
cxobj **xv
|
||||||
cxobj *x;
|
cxobj *x;
|
||||||
cxobj *xn;
|
cxobj *xn;
|
||||||
size_t xlen = 0;
|
size_t xlen = 0;
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@ sudo clixon_backend -If $clixon_cf
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
err
|
err
|
||||||
fi
|
fi
|
||||||
|
new "cli tests"
|
||||||
|
|
||||||
new "cli configure top"
|
new "cli configure top"
|
||||||
expectfn "$clixon_cli -1f $clixon_cf set interfaces" ""
|
expectfn "$clixon_cli -1f $clixon_cf set interfaces" ""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,14 +20,44 @@ sudo clixon_backend -If $clixon_cf
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
err
|
err
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
new "netconf tests"
|
||||||
|
|
||||||
new "netconf get empty config"
|
new "netconf get empty config"
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc message-id=\"101\"><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply message-id=\"101\"><data/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $clixon_cf" '<rpc message-id="101"><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply message-id="101"><data/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
|
new "Add subtree eth0 using none which should not change anything"
|
||||||
|
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><edit-config><default-operation>none</default-operation><target><candidate/></target><config><interfaces><interface><name>eth0</name></interface></interfaces></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "Check nothing added"
|
||||||
|
expecteof "$clixon_netconf -qf $clixon_cf" '<rpc message-id="101"><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply message-id="101"><data/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
|
new "Add subtree eth0 using none and create which should add eth0"
|
||||||
|
expecteof "$clixon_netconf -qf $clixon_cf" '<rpc><edit-config><target><candidate/></target><config><interfaces><interface operation="create"><name>eth0</name><type>eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "Check eth0 added using xpath"
|
||||||
|
expecteof "$clixon_netconf -qf $clixon_cf" '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name=eth0]"/></get-config></rpc>]]>]]>' "^<rpc-reply><data><config><interfaces><interface><name>eth0</name><type>eth</type><enabled>true</enabled></interface></interfaces></config></data></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "Re-create same eth0 which should generate error"
|
||||||
|
expecteof "$clixon_netconf -qf $clixon_cf" '<rpc><edit-config><target><candidate/></target><config><interfaces><interface operation="create"><name>eth0</name><type>eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>]]>]]>' "^<rpc-reply><rpc-error>"
|
||||||
|
|
||||||
|
new "Delete eth0 using none config"
|
||||||
|
expecteof "$clixon_netconf -qf $clixon_cf" '<rpc><edit-config><target><candidate/></target><config><interfaces><interface operation="delete"><name>eth0</name><type>eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "Check deleted eth0"
|
||||||
|
expecteof "$clixon_netconf -qf $clixon_cf" '<rpc message-id="101"><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply message-id="101"><data><config><interfaces/></config></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
|
new "Re-Delete eth0 using none should generate error"
|
||||||
|
expecteof "$clixon_netconf -qf $clixon_cf" '<rpc><edit-config><target><candidate/></target><config><interfaces><interface operation="delete"><name>eth0</name><type>eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>]]>]]>' "^<rpc-reply><rpc-error>"
|
||||||
|
|
||||||
new "netconf edit config"
|
new "netconf edit config"
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><edit-config><target><candidate/></target><config><interfaces><interface><name>eth0</name></interface><interface><name>eth1</name><enabled>true</enabled><ipv4><address><ip>9.2.3.4</ip><prefix-length>24</prefix-length></address></ipv4></interface></interfaces></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><edit-config><target><candidate/></target><config><interfaces><interface><name>eth0</name></interface><interface><name>eth1</name><enabled>true</enabled><ipv4><address><ip>9.2.3.4</ip><prefix-length>24</prefix-length></address></ipv4></interface></interfaces></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf get config xpath"
|
new "netconf get config xpath"
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/interfaces/interface[name=eth1]/enabled\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><config><interfaces><interface><enabled>true</enabled></interface></interfaces></config></data></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $clixon_cf" '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name=eth1]/enabled"/></get-config></rpc>]]>]]>' "^<rpc-reply><data><config><interfaces><interface><enabled>true</enabled></interface></interfaces></config></data></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "netconf get config xpath parent"
|
||||||
|
expecteof "$clixon_netconf -qf $clixon_cf" '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name=eth1]/enabled/../.."/></get-config></rpc>]]>]]>' "^<rpc-reply><data><config><interfaces><interface><name>eth0</name><enabled>true</enabled></interface><interface><name>eth1</name><enabled>true</enabled><ipv4><enabled>true</enabled><forwarding>false</forwarding><address><ip>9.2.3.4</ip><prefix-length>24</prefix-length></address></ipv4></interface></interfaces></config></data></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf validate missing type"
|
new "netconf validate missing type"
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error>"
|
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error>"
|
||||||
|
|
@ -53,18 +83,6 @@ expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><edit-config><target><candidate
|
||||||
new "netconf get replaced config"
|
new "netconf get replaced config"
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><config><interfaces><interface><name>eth1</name><type>eth</type><enabled>true</enabled></interface><interface><name>eth2</name><type>eth</type><enabled>true</enabled></interface></interfaces></config></data></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><config><interfaces><interface><name>eth1</name><type>eth</type><enabled>true</enabled></interface><interface><name>eth2</name><type>eth</type><enabled>true</enabled></interface></interfaces></config></data></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf edit config create"
|
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf" '<rpc><edit-config><target><candidate/></target><config><interfaces><interface operation="create"><name>eth3</name><type>eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
|
||||||
|
|
||||||
new "netconf edit config create 2nd"
|
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf" '<rpc><edit-config><target><candidate/></target><config><interfaces><interface operation="create"><name>eth3</name><type>eth</type></interface></interfaces></config><default-operation>merge</default-operation> </edit-config></rpc>]]>]]>' "^<rpc-reply><rpc-error>"
|
|
||||||
|
|
||||||
new "netconf edit config delete"
|
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf" '<rpc><edit-config><target><candidate/></target><config><interfaces><interface operation="delete"><name>eth3</name><type>eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
|
||||||
|
|
||||||
new "netconf get delete config"
|
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><config><interfaces><interface><name>eth1</name><type>eth</type><enabled>true</enabled></interface><interface><name>eth2</name><type>eth</type><enabled>true</enabled></interface></interfaces></config></data></rpc-reply>]]>]]>$"
|
|
||||||
|
|
||||||
new "netconf discard-changes"
|
new "netconf discard-changes"
|
||||||
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,32 +24,40 @@ sudo start-stop-daemon -S -q -o -b -x /www-data/clixon_restconf -d /www-data -c
|
||||||
|
|
||||||
sleep 1
|
sleep 1
|
||||||
|
|
||||||
|
new "restconf tests"
|
||||||
|
|
||||||
new "restconf options"
|
new "restconf options"
|
||||||
expectfn "curl -i -s -X OPTIONS http://localhost/restconf/data" "Allow: OPTIONS,HEAD,GET,POST,PUT,DELETE"
|
expectfn "curl -i -s -X OPTIONS http://localhost/restconf/data" "Allow: OPTIONS,HEAD,GET,POST,PUT,DELETE"
|
||||||
|
|
||||||
new "restconf get empty config"
|
|
||||||
expectfn "curl -sG http://localhost/restconf/data" "^null
$"
|
|
||||||
|
|
||||||
new "restconf put config"
|
|
||||||
expectfn 'curl -sX POST -d {"interfaces":{"interface":[{"name":"eth1","type":"eth","enabled":"true"},{"name":"eth0","type":"eth","enabled":"true"}]}} http://localhost/restconf/data' ""
|
|
||||||
|
|
||||||
new "restconf get config"
|
|
||||||
expectfn "curl -sG http://localhost/restconf/data" '{"interfaces": {"interface": \[{"name": "eth1","type": "eth","enabled": "true"},{ "name": "eth0","type": "eth","enabled": "true"}\]}}
|
|
||||||
$'
|
|
||||||
|
|
||||||
new "restconf head"
|
new "restconf head"
|
||||||
expectfn "curl -s -I http://localhost/restconf/data" "Content-Type: application/yang.data\+json"
|
expectfn "curl -s -I http://localhost/restconf/data" "Content-Type: application/yang.data\+json"
|
||||||
|
|
||||||
new "restconf POST config"
|
new "restconf get empty config"
|
||||||
expectfn 'curl -sX POST -d {"type":"eth"} http://localhost/restconf/data/interfaces/interface=eth4' ""
|
expectfn "curl -sG http://localhost/restconf/data" "^null
$"
|
||||||
|
|
||||||
new "restconf DELETE config"
|
#
|
||||||
|
new "Add subtree eth0,eth1 using POST"
|
||||||
|
expectfn 'curl -sX POST -d {"interfaces":{"interface":[{"name":"eth0","type":"eth","enabled":"true"},{"name":"eth1","type":"eth","enabled":"true"}]}} http://localhost/restconf/data' ""
|
||||||
|
|
||||||
|
new "Check eth0 added"
|
||||||
|
expectfn "curl -sG http://localhost/restconf/data" '{"interfaces": {"interface": \[{"name": "eth0","type": "eth","enabled": "true"},{ "name": "eth1","type": "eth","enabled": "true"}\]}}
|
||||||
|
$'
|
||||||
|
|
||||||
|
new "Re-post eth0 which should generate error"
|
||||||
|
expectfn 'curl -sX POST -d {"interfaces":{"interface":{"name":"eth0","type":"eth","enabled":"true"}}} http://localhost/restconf/data' "Not Found"
|
||||||
|
|
||||||
|
new "delete eth0"
|
||||||
expectfn 'curl -sX DELETE http://localhost/restconf/data/interfaces/interface=eth0' ""
|
expectfn 'curl -sX DELETE http://localhost/restconf/data/interfaces/interface=eth0' ""
|
||||||
|
|
||||||
new "restconf get config"
|
new "Check deleted eth0"
|
||||||
expectfn "curl -sG http://localhost/restconf/data" '{"interfaces": {"interface": \[{"name": "eth1","type": "eth","enabled": "true"},{ "name": "eth4","type": "eth","enabled": "true"}\]}}
|
expectfn 'curl -sG http://localhost/restconf/data' '{"interfaces": {"interface": {"name": "eth1","type": "eth","enabled": "true"}}}
|
||||||
$'
|
$'
|
||||||
|
|
||||||
|
new "Re-Delete eth0 using none should generate error"
|
||||||
|
expectfn 'curl -sX DELETE http://localhost/restconf/data/interfaces/interface=eth0' "Not Found"
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
new "restconf PATCH config"
|
new "restconf PATCH config"
|
||||||
expectfn 'curl -sX PATCH -d {"type":"eth"} http://localhost/restconf/data/interfaces/interface=eth4' ""
|
expectfn 'curl -sX PATCH -d {"type":"eth"} http://localhost/restconf/data/interfaces/interface=eth4' ""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,15 +47,18 @@ db='<config><x><y><a>1</a><b>2</b><c>first-entry</c></y><y><a>1</a><b>3</b><c>se
|
||||||
run(){
|
run(){
|
||||||
name=$1
|
name=$1
|
||||||
dir=/tmp/$name
|
dir=/tmp/$name
|
||||||
|
|
||||||
if [ ! -d $dir ]; then
|
if [ ! -d $dir ]; then
|
||||||
mkdir $dir
|
mkdir $dir
|
||||||
fi
|
fi
|
||||||
rm -rf $dir/*
|
rm -rf $dir/*
|
||||||
|
|
||||||
conf="-d candidate -b $dir -p ../datastore/$name/$name.so -y /tmp -m ietf-ip"
|
conf="-d candidate -b $dir -p ../datastore/$name/$name.so -y /tmp -m ietf-ip"
|
||||||
echo "conf:$conf"
|
# echo "conf:$conf"
|
||||||
new "datastore $name init"
|
new "datastore $name init"
|
||||||
expectfn "$datastore $conf init" ""
|
expectfn "$datastore $conf init" ""
|
||||||
|
|
||||||
|
# Whole tree operations
|
||||||
new "datastore $name put all replace"
|
new "datastore $name put all replace"
|
||||||
expectfn "$datastore $conf put replace / $db" ""
|
expectfn "$datastore $conf put replace / $db" ""
|
||||||
|
|
||||||
|
|
@ -89,31 +92,55 @@ run(){
|
||||||
new "datastore $name put top create"
|
new "datastore $name put top create"
|
||||||
expectfn "$datastore $conf put create / <config><x/></config>" "" # error
|
expectfn "$datastore $conf put create / <config><x/></config>" "" # error
|
||||||
|
|
||||||
return
|
# Single key operations
|
||||||
|
# leaf
|
||||||
|
new "datastore $name put all delete"
|
||||||
|
expectfn "$datastore $conf delete" ""
|
||||||
|
|
||||||
|
new "datastore $name init"
|
||||||
|
expectfn "$datastore $conf init" ""
|
||||||
|
|
||||||
|
new "datastore $name create leaf"
|
||||||
|
expectfn "$datastore $conf put create /x/y=1,3/c <c>newentry</c>"
|
||||||
|
|
||||||
new "datastore $name put top"
|
new "datastore $name create leaf"
|
||||||
expectfn "$datastore $conf put replace / $db"
|
expectfn "$datastore $conf put create /x/y=1,3/c <c>newentry</c>"
|
||||||
|
|
||||||
new "datastore $name put del"
|
new "datastore $name delete leaf"
|
||||||
|
expectfn "$datastore $conf put delete /x/y=1,3"
|
||||||
|
|
||||||
|
new "datastore $name replace leaf"
|
||||||
|
expectfn "$datastore $conf put create /x/y=1,3/c <c>newentry</c>"
|
||||||
|
|
||||||
|
new "datastore $name remove leaf"
|
||||||
|
expectfn "$datastore $conf put remove /x/g"
|
||||||
|
|
||||||
|
new "datastore $name remove leaf"
|
||||||
|
expectfn "$datastore $conf put remove /x/y=1,3/c"
|
||||||
|
|
||||||
|
new "datastore $name delete leaf"
|
||||||
expectfn "$datastore $conf put delete /x/g"
|
expectfn "$datastore $conf put delete /x/g"
|
||||||
|
|
||||||
return
|
new "datastore $name merge leaf"
|
||||||
new "datastore $name get empty"
|
expectfn "$datastore $conf put merge /x/g <g>nalle</g>"
|
||||||
expectfn "$datastore $conf get /" "^<config/>$"
|
|
||||||
|
|
||||||
new "datastore $name put top"
|
new "datastore $name replace leaf"
|
||||||
expectfn "$datastore $conf put replace / <config><x><y><a>foo</a><b>bar</b><c>fie</c></y></x></config>" ""
|
expectfn "$datastore $conf put replace /x/g <g>nalle</g>"
|
||||||
|
|
||||||
new "datastore $name get config"
|
new "datastore $name merge leaf"
|
||||||
expectfn "$datastore $conf get /" "^<config><x><y><a>foo</a><b>bar</b><c>fie</c></y></x></config>$"
|
expectfn "$datastore $conf put merge /x/y=1,3/c <c>newentry</c>"
|
||||||
|
|
||||||
new "datastore $name put delete"
|
new "datastore $name replace leaf"
|
||||||
expectfn "$datastore $conf put delete / <config/>" ""
|
expectfn "$datastore $conf put replace /x/y=1,3/c <c>newentry</c>"
|
||||||
|
|
||||||
|
new "datastore $name create leaf"
|
||||||
|
expectfn "$datastore $conf put create /x/h <h><j>aaa</j></h>"
|
||||||
|
|
||||||
|
new "datastore $name create leaf"
|
||||||
|
expectfn "$datastore $conf put create /x/y=1,3/c <c>newentry</c>"
|
||||||
|
|
||||||
|
#leaf-list
|
||||||
|
|
||||||
new "datastore $name get deleted"
|
|
||||||
expectfn "$datastore $conf get /" "^<config/>$"
|
|
||||||
|
|
||||||
rm -rf $dir
|
rm -rf $dir
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue