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 *****
|
||||
|
||||
- Refined netconf "none" semantics in tests and text datastore
|
||||
|
||||
- Moved apps/dbctrl to datastore/
|
||||
|
||||
- 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
|
||||
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
|
||||
page](http://www.clicon.org)
|
||||
|
||||
## Installation
|
||||
|
||||
A typical installation is as follows:
|
||||
|
||||
> 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
|
||||
[KTH](http://www.csc.kth.se/~olofh/10G_OSR)
|
||||
|
||||
## Dependencies
|
||||
|
||||
[CLIgen](http://www.cligen.se) is required for building CLIXON. If you need
|
||||
to build and install CLIgen:
|
||||
|
||||
git clone https://github.com/olofhagsand/cligen.git
|
||||
cd cligen; configure; make; make install
|
||||
|
||||
## Licenses
|
||||
|
||||
CLIXON is dual license. Either Apache License, Version 2.0 or GNU
|
||||
General Public License Version 2. You choose.
|
||||
|
||||
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){
|
||||
/* XXX see from_client_xmlput() */
|
||||
if (xmldb_put(h, target, operation, api_path, xc) < 0){
|
||||
cprintf(cbret, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>operation-failed</error-tag>"
|
||||
|
|
|
|||
|
|
@ -66,8 +66,8 @@ curl -sX POST -d '{"clicon":{"interfaces":{"interface":{"name":"eth1","type":"et
|
|||
|
||||
3. DEBUGGING
|
||||
++++++++++++
|
||||
Start the restconf programs with debug flag:
|
||||
sudo su -c "/www-data/clixon_restconf -D" -s /bin/sh www-data
|
||||
Start the restconf fastcgi program with debug flag:
|
||||
sudo su -c "/www-data/clixon_restconf -Df /usr/local/etc/routing.conf" -s /bin/sh www-data
|
||||
|
||||
Look at syslog:
|
||||
tail -f /var/log/syslog | grep clixon_restconf
|
||||
|
|
@ -296,7 +296,7 @@ api_data_edit(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
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",
|
||||
operation,
|
||||
api_path,
|
||||
|
|
@ -337,7 +337,8 @@ api_data_edit(clicon_handle h,
|
|||
|
||||
If the data resource already exists, then the POST request MUST fail
|
||||
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
|
||||
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] qvec Vector of query string (QUERY_STRING)
|
||||
* @param[in] data Stream input data
|
||||
* Example:
|
||||
curl -X PUT -d {\"enabled\":\"false\"} http://127.0.0.1/restconf/data/interfaces/interface=eth1
|
||||
* @example
|
||||
curl -X PUT -d '{"enabled":"false"}' http://127.0.0.1/restconf/data/interfaces/interface=eth1
|
||||
*
|
||||
PUT:
|
||||
if the PUT request creates a new resource,
|
||||
|
|
|
|||
|
|
@ -652,7 +652,7 @@ kv_get(xmldb_handle xh,
|
|||
}
|
||||
/* Top is special case */
|
||||
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;
|
||||
if (xml_apply(xt, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, (void*)XML_FLAG_MARK) < 0)
|
||||
goto done;
|
||||
|
|
@ -1309,7 +1309,7 @@ kv_put(xmldb_handle xh,
|
|||
yang_spec *yspec;
|
||||
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,"/"))
|
||||
return xmldb_put_xkey(kh, db, op, api_path, xml_body(xt));
|
||||
if ((yspec = kh->kh_yangspec) == NULL){
|
||||
|
|
|
|||
|
|
@ -245,6 +245,32 @@ text_setopt(xmldb_handle xh,
|
|||
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
|
||||
* The function returns a minimal tree that includes all sub-trees that match
|
||||
* xpath.
|
||||
|
|
@ -335,20 +361,20 @@ text_get(xmldb_handle xh,
|
|||
}
|
||||
/* Top is special case */
|
||||
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;
|
||||
if (xml_apply(xt, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, (void*)XML_FLAG_MARK) < 0)
|
||||
goto done;
|
||||
if (xml_apply(xt, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
||||
goto done;
|
||||
if (xml_apply(xt, CX_ELMNT, xml_default, NULL) < 0)
|
||||
goto done;
|
||||
/* XXX does not work for top-level */
|
||||
if (xml_apply(xt, CX_ELMNT, xml_order, NULL) < 0)
|
||||
goto done;
|
||||
if (xml_apply(xt, CX_ELMNT, xml_sanity, NULL) < 0)
|
||||
goto done;
|
||||
|
||||
if (0){ /* No xml_spec(xt) */
|
||||
if (xml_apply(xt, CX_ELMNT, xml_default, NULL) < 0)
|
||||
goto done;
|
||||
/* XXX does not work for top-level */
|
||||
if (xml_apply(xt, CX_ELMNT, xml_order, NULL) < 0)
|
||||
goto done;
|
||||
if (xml_apply(xt, CX_ELMNT, xml_sanity, NULL) < 0)
|
||||
goto done;
|
||||
}
|
||||
if (debug>1)
|
||||
clicon_xml2file(stderr, xt, 0, 1);
|
||||
if (xvec0 && xlen0){
|
||||
|
|
@ -755,11 +781,14 @@ text_modify(cxobj *x0,
|
|||
goto done;
|
||||
}
|
||||
/* Fall thru */
|
||||
case OP_NONE: /* XXX */
|
||||
case OP_MERGE:
|
||||
case OP_REPLACE:
|
||||
if (x0==NULL){
|
||||
if ((x0 = xml_new_spec(name, x0p, y)) == NULL)
|
||||
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 ((x0b = xml_new("body", x0)) == NULL)
|
||||
goto done;
|
||||
|
|
@ -767,12 +796,24 @@ text_modify(cxobj *x0,
|
|||
}
|
||||
}
|
||||
if (x1bstr){
|
||||
if ((x0b = xml_body_get(x0)) == NULL)
|
||||
goto done;
|
||||
if ((x0b = xml_body_get(x0)) == NULL){
|
||||
if ((x0b = xml_new("body", x0)) == NULL)
|
||||
goto done;
|
||||
xml_type_set(x0b, CX_BODY);
|
||||
}
|
||||
if (xml_value_set(x0b, x1bstr) < 0)
|
||||
goto done;
|
||||
}
|
||||
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:
|
||||
break;
|
||||
} /* switch op */
|
||||
|
|
@ -799,11 +840,15 @@ text_modify(cxobj *x0,
|
|||
xml_purge(x0);
|
||||
x0 = NULL;
|
||||
}
|
||||
case OP_NONE: /* XXX */
|
||||
case OP_MERGE:
|
||||
if (x0==NULL){
|
||||
if ((x0 = xml_new_spec(name, x0p, y)) == NULL)
|
||||
goto done;
|
||||
if (op==OP_NONE)
|
||||
xml_flag_set(x0, XML_FLAG_NONE); /* Mark for potential deletion */
|
||||
}
|
||||
|
||||
/* Loop through children of the modification tree */
|
||||
x1c = NULL;
|
||||
while ((x1c = xml_child_each(x1, x1c, CX_ELMNT)) != NULL) {
|
||||
|
|
@ -823,6 +868,15 @@ text_modify(cxobj *x0,
|
|||
goto done;
|
||||
}
|
||||
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:
|
||||
break;
|
||||
} /* CONTAINER switch op */
|
||||
|
|
@ -857,7 +911,7 @@ text_modify(cxobj *x0,
|
|||
* @endcode
|
||||
*/
|
||||
int
|
||||
text_put(xmldb_handle xh,
|
||||
text_put(xmldb_handle xh,
|
||||
char *db,
|
||||
enum operation_type op,
|
||||
char *api_path,
|
||||
|
|
@ -877,10 +931,12 @@ text_put(xmldb_handle xh,
|
|||
cxobj *xnew = NULL;
|
||||
yang_node *y = NULL;
|
||||
|
||||
#if 0 /* Just ignore */
|
||||
if ((op==OP_DELETE || op==OP_REMOVE) && xmod){
|
||||
clicon_err(OE_XML, 0, "xml tree should be NULL for REMOVE/DELETE");
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
if (text_db2file(th, db, &dbfile) < 0)
|
||||
goto done;
|
||||
if (dbfile==NULL){
|
||||
|
|
@ -942,6 +998,12 @@ text_put(xmldb_handle xh,
|
|||
else
|
||||
if (text_modify(xbase, xbasep, xmod, op, (yang_node*)y, yspec) < 0)
|
||||
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:
|
||||
/* Print out top-level xml tree after modification to file */
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
|
|
|
|||
|
|
@ -27,3 +27,7 @@ CLICON_CLIGEN_CALLBACK_SINGLE_ARG 0
|
|||
|
||||
# Enabled uses "startup" configuration on boot
|
||||
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_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_NONE 0x10 /* Node is added as NONE */
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
|
|
@ -102,6 +103,7 @@ int xml_childvec_set(cxobj *x, int len);
|
|||
cxobj *xml_new(char *name, cxobj *xn_parent);
|
||||
cxobj *xml_new_spec(char *name, cxobj *xn_parent, void *spec);
|
||||
void *xml_spec(cxobj *x);
|
||||
void *xml_spec_set(cxobj *x, void *spec);
|
||||
cxobj *xml_find(cxobj *xn_parent, char *name);
|
||||
|
||||
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 */
|
||||
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{
|
||||
int xa_version;
|
||||
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 xmlkeyfmt2key(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_order(cxobj *x, void *arg);
|
||||
int xml_sanity(cxobj *x, void *arg);
|
||||
|
|
|
|||
|
|
@ -521,12 +521,21 @@ xml_new_spec(char *name,
|
|||
return x;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
xml_spec(cxobj *x)
|
||||
{
|
||||
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.
|
||||
*
|
||||
* Get first XML node directly under x_up in the xml hierarchy with
|
||||
|
|
|
|||
|
|
@ -63,6 +63,9 @@
|
|||
#include "clixon_options.h"
|
||||
#include "clixon_xml_db.h"
|
||||
|
||||
/* Set to log get and put requests */
|
||||
#define DEBUG 0
|
||||
|
||||
/*! Load an xmldb storage plugin according to filename
|
||||
* If init function fails (not found, wrong version, etc) print a log and dont
|
||||
* add it.
|
||||
|
|
@ -350,7 +353,7 @@ xmldb_get(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
retval = xa->xa_get_fn(xh, db, xpath, xtop, xvec, xlen);
|
||||
#if 0 /* XXX DEBUG */
|
||||
#if DEBUG
|
||||
if (retval == 0) {
|
||||
cbuf *cb = cbuf_new();
|
||||
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");
|
||||
goto done;
|
||||
}
|
||||
#if 0 /* XXX DEBUG */
|
||||
#if DEBUG
|
||||
{
|
||||
cbuf *cb = cbuf_new();
|
||||
if (xt)
|
||||
|
|
|
|||
|
|
@ -1076,16 +1076,23 @@ xmlkeyfmt2xpath(char *xkfmt,
|
|||
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] 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 contain a marked child
|
||||
* XXX: maybe key leafs should not be purged if list is not purged?
|
||||
* XXX: consider move to clicon_xml
|
||||
* The function removes all branches that does not a child that 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);
|
||||
* @endcode
|
||||
*/
|
||||
int
|
||||
xml_tree_prune_unmarked(cxobj *xt,
|
||||
int *upmark)
|
||||
xml_tree_prune_flagged(cxobj *xt,
|
||||
int flag,
|
||||
int test,
|
||||
int *upmark)
|
||||
{
|
||||
int retval = -1;
|
||||
int submark;
|
||||
|
|
@ -1097,12 +1104,12 @@ xml_tree_prune_unmarked(cxobj *xt,
|
|||
x = NULL;
|
||||
xprev = x = 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++;
|
||||
xprev = x;
|
||||
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;
|
||||
if (submark)
|
||||
mark++;
|
||||
|
|
|
|||
|
|
@ -358,6 +358,13 @@ xpath_parse(char *xpath,
|
|||
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);
|
||||
}
|
||||
#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] */
|
||||
else if (strncmp(s,".", strlen("."))==0)
|
||||
xpath_element_new(A_SELF, s+strlen("."), &xpnext);
|
||||
|
|
@ -368,13 +375,7 @@ xpath_parse(char *xpath,
|
|||
|
||||
else if (strncmp(s,"self::", strlen("self::"))==0)
|
||||
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)
|
||||
xpath_element_new(A_PARENT, s+strlen("parent::"), &xpnext);
|
||||
else if (strncmp(s,"ancestor::", strlen("ancestor::"))==0)
|
||||
|
|
@ -1076,7 +1077,7 @@ int
|
|||
main(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
cxobj **xv;
|
||||
cxobj **xv
|
||||
cxobj *x;
|
||||
cxobj *xn;
|
||||
size_t xlen = 0;
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ sudo clixon_backend -If $clixon_cf
|
|||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
new "cli tests"
|
||||
|
||||
new "cli configure top"
|
||||
expectfn "$clixon_cli -1f $clixon_cf set interfaces" ""
|
||||
|
||||
|
|
|
|||
|
|
@ -20,14 +20,44 @@ sudo clixon_backend -If $clixon_cf
|
|||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
|
||||
new "netconf tests"
|
||||
|
||||
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"
|
||||
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"
|
||||
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"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error>"
|
||||
|
|
@ -48,23 +78,11 @@ new "netconf commit"
|
|||
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf edit config replace"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><edit-config><target><candidate/></target><config><interfaces><interface><name>eth2</name><type>eth</type></interface></interfaces></config><default-operation>merge</default-operation> </edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $clixon_cf" "<rpc><edit-config><target><candidate/></target><config><interfaces><interface><name>eth2</name><type>eth</type></interface></interfaces></config><default-operation>merge</default-operation></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
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>]]>]]>$"
|
||||
|
||||
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"
|
||||
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
|
||||
|
||||
new "restconf tests"
|
||||
|
||||
new "restconf options"
|
||||
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"
|
||||
expectfn "curl -s -I http://localhost/restconf/data" "Content-Type: application/yang.data\+json"
|
||||
|
||||
new "restconf POST config"
|
||||
expectfn 'curl -sX POST -d {"type":"eth"} http://localhost/restconf/data/interfaces/interface=eth4' ""
|
||||
new "restconf get empty config"
|
||||
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' ""
|
||||
|
||||
new "restconf get config"
|
||||
expectfn "curl -sG http://localhost/restconf/data" '{"interfaces": {"interface": \[{"name": "eth1","type": "eth","enabled": "true"},{ "name": "eth4","type": "eth","enabled": "true"}\]}}
|
||||
new "Check deleted eth0"
|
||||
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"
|
||||
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(){
|
||||
name=$1
|
||||
dir=/tmp/$name
|
||||
|
||||
if [ ! -d $dir ]; then
|
||||
mkdir $dir
|
||||
fi
|
||||
rm -rf $dir/*
|
||||
|
||||
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"
|
||||
expectfn "$datastore $conf init" ""
|
||||
|
||||
# Whole tree operations
|
||||
new "datastore $name put all replace"
|
||||
expectfn "$datastore $conf put replace / $db" ""
|
||||
|
||||
|
|
@ -89,31 +92,55 @@ run(){
|
|||
new "datastore $name put top create"
|
||||
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"
|
||||
expectfn "$datastore $conf put replace / $db"
|
||||
new "datastore $name create leaf"
|
||||
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"
|
||||
|
||||
return
|
||||
new "datastore $name get empty"
|
||||
expectfn "$datastore $conf get /" "^<config/>$"
|
||||
new "datastore $name merge leaf"
|
||||
expectfn "$datastore $conf put merge /x/g <g>nalle</g>"
|
||||
|
||||
new "datastore $name put top"
|
||||
expectfn "$datastore $conf put replace / <config><x><y><a>foo</a><b>bar</b><c>fie</c></y></x></config>" ""
|
||||
new "datastore $name replace leaf"
|
||||
expectfn "$datastore $conf put replace /x/g <g>nalle</g>"
|
||||
|
||||
new "datastore $name get config"
|
||||
expectfn "$datastore $conf get /" "^<config><x><y><a>foo</a><b>bar</b><c>fie</c></y></x></config>$"
|
||||
new "datastore $name merge leaf"
|
||||
expectfn "$datastore $conf put merge /x/y=1,3/c <c>newentry</c>"
|
||||
|
||||
new "datastore $name put delete"
|
||||
expectfn "$datastore $conf put delete / <config/>" ""
|
||||
new "datastore $name replace leaf"
|
||||
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
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue