Merge branch 'develop' of https://github.com/clicon/clixon into develop
This commit is contained in:
commit
5d7c4a8d18
14 changed files with 203 additions and 46 deletions
|
|
@ -2,9 +2,14 @@
|
|||
|
||||
## 3.7.0 (Upcoming)
|
||||
### Major changes:
|
||||
|
||||
* Full support of XPATH 1.0 according to https://www.w3.org/TR/xpath-10 using yacc/lex
|
||||
* The previous XPATH imlementation was very restricted.
|
||||
* The only function implemented is the Yang extension "current()". No other functions are implemented (eg last(), count()).
|
||||
* Conformance of restconf(RFC-8040) operations where prefix was used instead of module name.
|
||||
* Proper specification for an operation is POST /restconf/operations/<module_name>:<rpc_procedure> HTTP/1.1
|
||||
* See https://github.com/clicon/clixon/issues/31, https://github.com/clicon/clixon/pull/32 and https://github.com/clicon/clixon/issues/30
|
||||
* Thanks David Cornejo and Dmitry Vakhrushev of Netgate for pointing this out.
|
||||
* Support for YANG identity and identityref according to RFC 7950 Sec 7.18 and 9.10
|
||||
* Previous support did no validation of values.
|
||||
* Validation of types and CLI expansion
|
||||
|
|
@ -12,7 +17,9 @@
|
|||
* Applications which have not strictly enforced the identities may now have problems with validation and may need to be modified.
|
||||
|
||||
### Minor changes:
|
||||
* Dedicated xml,json,yang and xpath parser utility programs added
|
||||
* Added systemd example files under example/systemd
|
||||
* Changed `plugin_init()` backend return semantics: If returns NULL, _without_ calling clicon_err(), the module is disabled.
|
||||
* Dedicated standalone xml,json,yang and xpath parser utility test programs added under lib/src/.
|
||||
* CDATA xml support (patch by David Cornejo, Netgate)
|
||||
* Encode and decode (parsing) support
|
||||
* Validation of yang bits type space-separated list value
|
||||
|
|
|
|||
|
|
@ -2,7 +2,12 @@
|
|||
|
||||
### Installation using Nginx
|
||||
|
||||
Define nginx config file/etc/nginx/sites-available/default
|
||||
Ensure www-data is member of the CLICON_SOCK_GROUP (default clicon). If not, add it:
|
||||
```
|
||||
sudo usermod -a -G clicon www-data
|
||||
```
|
||||
|
||||
Define nginx config file: /etc/nginx/sites-available/default
|
||||
```
|
||||
server {
|
||||
...
|
||||
|
|
|
|||
|
|
@ -925,8 +925,7 @@ api_operations_get(clicon_handle h,
|
|||
yang_spec *yspec;
|
||||
yang_stmt *ym;
|
||||
yang_stmt *yc;
|
||||
yang_stmt *yprefix;
|
||||
char *prefix;
|
||||
char *modname;
|
||||
cbuf *cbx = NULL;
|
||||
cxobj *xt = NULL;
|
||||
|
||||
|
|
@ -937,15 +936,12 @@ api_operations_get(clicon_handle h,
|
|||
cprintf(cbx, "<operations>");
|
||||
ym = NULL;
|
||||
while ((ym = yn_each((yang_node*)yspec, ym)) != NULL) {
|
||||
if ((yprefix = yang_find((yang_node*)ym, Y_PREFIX, NULL)) != NULL)
|
||||
prefix = yprefix->ys_argument;
|
||||
else
|
||||
continue;
|
||||
modname = ym->ys_argument;
|
||||
yc = NULL;
|
||||
while ((yc = yn_each((yang_node*)ym, yc)) != NULL) {
|
||||
if (yc->ys_keyword != Y_RPC)
|
||||
continue;
|
||||
cprintf(cbx, "<%s:%s />", prefix, yc->ys_argument);
|
||||
cprintf(cbx, "<%s:%s />", modname, yc->ys_argument);
|
||||
}
|
||||
}
|
||||
cprintf(cbx, "</operations>");
|
||||
|
|
@ -1030,6 +1026,9 @@ api_operations_post(clicon_handle h,
|
|||
char *username;
|
||||
cbuf *cbret = NULL;
|
||||
int ret = 0;
|
||||
char *prefix = NULL;
|
||||
char *id = NULL;
|
||||
yang_stmt *ys = NULL;
|
||||
|
||||
clicon_debug(1, "%s json:\"%s\" path:\"%s\"", __FUNCTION__, data, path);
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
|
|
@ -1047,8 +1046,22 @@ api_operations_post(clicon_handle h,
|
|||
}
|
||||
clicon_debug(1, "%s oppath: %s", __FUNCTION__, oppath);
|
||||
|
||||
/* Find yang rpc statement, return yang rpc statement if found */
|
||||
if (yang_abs_schema_nodeid(yspec, oppath, Y_RPC, &yrpc) < 0){
|
||||
/* Find yang rpc statement, return yang rpc statement if found
|
||||
* POST {+restconf}/operations/<operation>
|
||||
*
|
||||
* The <operation> field identifies the module name and rpc identifier
|
||||
* string for the desired operation.
|
||||
*/
|
||||
if (yang_nodeid_split(oppath+1, &prefix, &id) < 0) /* +1 skip / */
|
||||
goto done;
|
||||
if ((ys = yang_find((yang_node*)yspec, Y_MODULE, prefix)) == NULL){
|
||||
if (netconf_operation_failed_xml(&xerr, "protocol", "yang module not found") < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
if ((yrpc = yang_find((yang_node*)ys, Y_RPC, id)) == NULL){
|
||||
if (netconf_operation_failed_xml(&xerr, "protocol", "yang node not found") < 0)
|
||||
goto done;
|
||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||
|
|
@ -1229,6 +1242,10 @@ api_operations_post(clicon_handle h,
|
|||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
if (prefix)
|
||||
free(prefix);
|
||||
if (id)
|
||||
free(id);
|
||||
if (xdata)
|
||||
xml_free(xdata);
|
||||
if (xtop)
|
||||
|
|
|
|||
26
doc/FAQ.md
26
doc/FAQ.md
|
|
@ -1,4 +1,4 @@
|
|||
i# Clixon FAQ
|
||||
# Clixon FAQ
|
||||
|
||||
## What is Clixon?
|
||||
|
||||
|
|
@ -24,7 +24,7 @@ Clixon is written in C. The plugins are written in C. The CLI
|
|||
specification uses cligen (http://cligen.se)
|
||||
|
||||
## How to best understand Clixon?
|
||||
Run the Clixon example, in the example directory.
|
||||
Run the Clixon example, in the [example](../example) directory.
|
||||
|
||||
## How do you build and install Clixon (and the example)?
|
||||
Clixon:
|
||||
|
|
@ -41,14 +41,25 @@ The example:
|
|||
sudo make install
|
||||
```
|
||||
|
||||
## Do I need to setup anything?
|
||||
## Do I need to setup anything? (IMPORTANT)
|
||||
|
||||
The config demon requires a valid group to create a server UNIX socket.
|
||||
Define a valid CLICON_SOCK_GROUP in the config file or via the -g option
|
||||
or create the group and add the user to it. The default group is 'clicon'.
|
||||
Add yourself and www-data, if you intend to use restconf.
|
||||
|
||||
On linux:
|
||||
```
|
||||
sudo groupadd clicon
|
||||
sudo usermod -a -G clicon user
|
||||
sudo usermod -a -G clicon <user>
|
||||
sudo usermod -a -G clicon www-data
|
||||
```
|
||||
|
||||
Verify:
|
||||
```
|
||||
grep clicon /etc/group
|
||||
clicon:x:1001:<user>,www-data
|
||||
```
|
||||
|
||||
## What about reference documentation?
|
||||
Clixon uses Doxygen for reference documentation.
|
||||
|
|
@ -178,6 +189,11 @@ You may also add a default method in the configuration file:
|
|||
</config>
|
||||
```
|
||||
|
||||
## Can I use systemd with Clixon?
|
||||
|
||||
Yes. Systemd example files are provide for the backend and the
|
||||
restconf daemon as part of the [example](../example/systemd).
|
||||
|
||||
## How can I add extra XML?
|
||||
|
||||
There are two ways to add extra XML to running database after start. Note that this XML is not "committed" into running.
|
||||
|
|
@ -345,7 +361,7 @@ To authenticate, the callback needs to return the value 1 and supply a username.
|
|||
See [../apps/example/example_restconf.c] example_restconf_credentials() for
|
||||
an example of HTTP basic auth.
|
||||
|
||||
## How do I write a CLI translator function
|
||||
## How do I write a CLI translator function?
|
||||
|
||||
The CLI can perform variable translation. This is useful if you want to
|
||||
prcess the input, such as hashing, encrypting or in other way
|
||||
|
|
|
|||
|
|
@ -16,14 +16,18 @@ routing example. It contains the following files:
|
|||
* example_netconf.c Netconf callback plugin
|
||||
* Makefile.in Example makefile where plugins are built and installed
|
||||
|
||||
|
||||
## Compile and run
|
||||
|
||||
Before you start, see [preparation](../doc/FAQ.md#do-i-need-to-setup-anything-important).
|
||||
|
||||
```
|
||||
cd example
|
||||
make && sudo make install
|
||||
```
|
||||
Start backend:
|
||||
```
|
||||
clixon_backend -f /usr/local/etc/example.xml -I
|
||||
sudo clixon_backend -f /usr/local/etc/example.xml -s init
|
||||
```
|
||||
Edit cli:
|
||||
```
|
||||
|
|
@ -188,6 +192,10 @@ The example contains some stubs for authorization according to [RFC8341(NACM)](h
|
|||
* A NACM backend plugin reporting the mandatory NACM state variables.
|
||||
|
||||
|
||||
## Systemd files
|
||||
|
||||
Example systemd files for backend and restconf daemons are found under the systemd directory. Install them under /etc/systemd/system for example.
|
||||
|
||||
## Run as docker container
|
||||
|
||||
(Note not updated)
|
||||
|
|
|
|||
|
|
@ -114,6 +114,13 @@ static clixon_plugin_api api = {
|
|||
clixon_plugin_api *
|
||||
clixon_plugin_init(clicon_handle h)
|
||||
{
|
||||
char *nacm_mode;
|
||||
|
||||
clicon_debug(1, "%s backend nacm", __FUNCTION__);
|
||||
nacm_mode = clicon_option_str(h, "CLICON_NACM_MODE");
|
||||
if (nacm_mode==NULL || strcmp(nacm_mode, "disabled") == 0){
|
||||
clicon_debug(1, "%s CLICON_NACM_MODE not enabled: example nacm module disabled", __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
return &api;
|
||||
}
|
||||
|
|
|
|||
13
example/systemd/example.service
Normal file
13
example/systemd/example.service
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
[Unit]
|
||||
Description=Starts and stops a clixon example service on this system
|
||||
Wants=example_restconf.service
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
User=root
|
||||
RestartSec=60
|
||||
Restart=on-failure
|
||||
ExecStart=/usr/local/sbin/clixon_backend -s running -f /usr/local/etc/example.xml
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
14
example/systemd/example_restconf.service
Normal file
14
example/systemd/example_restconf.service
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
[Unit]
|
||||
Description=Starts and stops an example clixon restconf service on this system
|
||||
Wants=example.service
|
||||
After=example.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=www-data
|
||||
WorkingDirectory=/www-data
|
||||
Restart=on-failure
|
||||
ExecStart=/www-data/clixon_restconf -f /usr/local/etc/example.xml
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
@ -41,7 +41,9 @@
|
|||
/*
|
||||
* Constants
|
||||
*/
|
||||
/* Hardcoded plugin symbol. Must exist in all plugins to kickstart */
|
||||
/* Hardcoded plugin symbol. Must exist in all plugins to kickstart
|
||||
* @see clixon_plugin_init
|
||||
*/
|
||||
#define CLIXON_PLUGIN_INIT "clixon_plugin_init"
|
||||
|
||||
/*
|
||||
|
|
@ -181,6 +183,7 @@ typedef struct clixon_plugin clixon_plugin;
|
|||
/*! Plugin initialization function. Must appear in all plugins
|
||||
* @param[in] h Clixon handle
|
||||
* @retval api Pointer to API struct
|
||||
* @retval NULL Failure (if clixon_err() called), module disabled otherwise.
|
||||
* @see CLIXON_PLUGIN_INIT default symbol
|
||||
*/
|
||||
clixon_plugin_api *clixon_plugin_init(clicon_handle h);
|
||||
|
|
|
|||
|
|
@ -246,6 +246,7 @@ yang_stmt *yn_each(yang_node *yn, yang_stmt *ys);
|
|||
char *yang_key2str(int keyword);
|
||||
char *yarg_prefix(yang_stmt *ys);
|
||||
char *yarg_id(yang_stmt *ys);
|
||||
int yang_nodeid_split(char *nodeid, char **prefix, char **id);
|
||||
yang_stmt *ys_module(yang_stmt *ys);
|
||||
yang_spec *ys_spec(yang_stmt *ys);
|
||||
yang_stmt *yang_find_module_by_prefix(yang_stmt *ys, char *prefix);
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
#include <errno.h>
|
||||
#include <dlfcn.h>
|
||||
#include <dirent.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/param.h>
|
||||
|
|
@ -204,13 +205,17 @@ plugin_load_one(clicon_handle h,
|
|||
clicon_err(OE_UNIX, 0, "dlsym: %s: %s", file, error);
|
||||
goto done;
|
||||
}
|
||||
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);
|
||||
dlclose(handle);
|
||||
}
|
||||
else{
|
||||
clicon_err(OE_PLUGIN, errno, "Failed to initiate %s", strrchr(file,'/')?strchr(file, '/'):file);
|
||||
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
|
||||
clicon_err(OE_DB, 0, "Unknown error: %s: plugin_init does not make clicon_err call on error",
|
||||
file);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
/* Note: sizeof clixon_plugin_api which is largest of clixon_plugin_api:s */
|
||||
if ((cp = (clixon_plugin *)malloc(sizeof(struct clixon_plugin))) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "malloc");
|
||||
|
|
@ -228,6 +233,7 @@ plugin_load_one(clicon_handle h,
|
|||
|
||||
snprintf(cp->cp_name, sizeof(cp->cp_name), "%*s",
|
||||
(int)strlen(name), name);
|
||||
if (api)
|
||||
cp->cp_api = *api;
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
done:
|
||||
|
|
|
|||
|
|
@ -1725,6 +1725,7 @@ xml_merge1(cxobj *x0,
|
|||
cxobj *x1c; /* mod child */
|
||||
char *x1bstr; /* mod body string */
|
||||
yang_stmt *yc; /* yang child */
|
||||
cbuf *cbr = NULL; /* Reason buffer */
|
||||
|
||||
assert(x1 && xml_type(x1) == CX_ELMNT);
|
||||
assert(y0);
|
||||
|
|
@ -1763,10 +1764,17 @@ xml_merge1(cxobj *x0,
|
|||
x1cname = xml_name(x1c);
|
||||
/* Get yang spec of the child */
|
||||
if ((yc = yang_find_datanode(y0, x1cname)) == NULL){
|
||||
if (reason && (*reason = strdup("XML node has no corresponding yang specification (Invalid XML or wrong Yang spec?")) == NULL){
|
||||
if (reason){
|
||||
if ((cbr = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
cprintf(cbr, "XML node %s/%s has no corresponding yang specification (Invalid XML or wrong Yang spec?", xml_name(x1), x1cname);
|
||||
if ((*reason = strdup(cbuf_get(cbr))) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* See if there is a corresponding node in the base tree */
|
||||
|
|
@ -1782,6 +1790,8 @@ xml_merge1(cxobj *x0,
|
|||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
if (cbr)
|
||||
cbuf_free(cbr);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -1807,6 +1817,7 @@ xml_merge(cxobj *x0,
|
|||
cxobj *x0c; /* base child */
|
||||
cxobj *x1c; /* mod child */
|
||||
yang_stmt *yc;
|
||||
cbuf *cbr = NULL; /* Reason buffer */
|
||||
|
||||
/* Loop through children of the modification tree */
|
||||
x1c = NULL;
|
||||
|
|
@ -1814,10 +1825,17 @@ xml_merge(cxobj *x0,
|
|||
x1cname = xml_name(x1c);
|
||||
/* Get yang spec of the child */
|
||||
if ((yc = yang_find_topnode(yspec, x1cname, YC_DATANODE)) == NULL){
|
||||
if (reason && (*reason = strdup("XML node has no corresponding yang specification (Invalid XML or wrong Yang spec?")) == NULL){
|
||||
if (reason){
|
||||
if ((cbr = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
cprintf(cbr, "XML node %s/%s has no corresponding yang specification (Invalid XML or wrong Yang spec?", xml_name(x1), x1cname);
|
||||
if ((*reason = strdup(cbuf_get(cbr))) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* See if there is a corresponding node in the base tree */
|
||||
|
|
@ -1830,6 +1848,8 @@ xml_merge(cxobj *x0,
|
|||
}
|
||||
retval = 0; /* OK */
|
||||
done:
|
||||
if (cbr)
|
||||
cbuf_free(cbr);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -611,8 +611,8 @@ yang_find_schemanode(yang_node *yn,
|
|||
/*! Find first matching data node in all (sub)modules in a yang spec
|
||||
*
|
||||
* @param[in] ysp Yang specification
|
||||
* @param[in] argument if NULL, match any(first) argument. XXX is that really a case?
|
||||
* @param[in] schemanode If set look for schema nodes, otherwise only data nodes
|
||||
* @param[in] argument Name of node. If NULL match first
|
||||
* @param[in] class See yang_class for class of yang nodes
|
||||
* A yang specification has modules as children which in turn can have
|
||||
* syntax-nodes as children. This function goes through all the modules to
|
||||
* look for nodes. Note that if a child to a module is a choice,
|
||||
|
|
@ -803,7 +803,7 @@ yarg_id(yang_stmt *ys)
|
|||
return id;
|
||||
}
|
||||
|
||||
/* Assume argument is id on the type: <[prefix:]id>, return 'prefix'
|
||||
/*! Assume argument is id on the type: <[prefix:]id>, return 'prefix'
|
||||
* @param[in] ys A yang statement
|
||||
* @retval NULL No prefix
|
||||
* @retval prefix Malloced string that needs to be freed by caller.
|
||||
|
|
@ -822,6 +822,46 @@ yarg_prefix(yang_stmt *ys)
|
|||
return prefix;
|
||||
}
|
||||
|
||||
|
||||
/*! Split yang node identifier into prefix and identifer.
|
||||
* @param[in] node-id
|
||||
* @param[out] prefix Malloced string. May be NULL.
|
||||
* @param[out] id Malloced identifier.
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @note caller need to free id and prefix after use
|
||||
*/
|
||||
int
|
||||
yang_nodeid_split(char *nodeid,
|
||||
char **prefix,
|
||||
char **id)
|
||||
{
|
||||
int retval = -1;
|
||||
char *str;
|
||||
|
||||
if ((str = strchr(nodeid, ':')) == NULL){
|
||||
if ((*id = strdup(nodeid)) == NULL){
|
||||
clicon_err(OE_YANG, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else{
|
||||
if ((*prefix = strdup(nodeid)) == NULL){
|
||||
clicon_err(OE_YANG, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
(*prefix)[str-nodeid] = '\0';
|
||||
str++;
|
||||
if ((*id = strdup(str)) == NULL){
|
||||
clicon_err(OE_YANG, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Given a yang statement and a prefix, return yang module to that prefix
|
||||
* Note, not the other module but the proxy import statement only
|
||||
* @param[in] ys A yang statement
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ new "kill old restconf daemon"
|
|||
sudo pkill -u www-data clixon_restconf
|
||||
|
||||
new "start restconf daemon"
|
||||
sudo start-stop-daemon -S -q -o -b -x /www-data/clixon_restconf -d /www-data -c www-data -- -f $cfg -y $fyang # -D
|
||||
sudo start-stop-daemon -S -q -o -b -x /www-data/clixon_restconf -d /www-data -c www-data -- -f $cfg -y $fyang -D
|
||||
|
||||
sleep 1
|
||||
|
||||
|
|
@ -113,12 +113,12 @@ expecteq "$(curl -s -H 'Accept: application/yang-data+xml' -G http://localhost/r
|
|||
'
|
||||
|
||||
new2 "restconf get restconf/operations. RFC8040 3.3.2 (json)"
|
||||
expecteq "$(curl -sG http://localhost/restconf/operations)" '{"operations": {"ex:empty": null,"ex:input": null,"ex:output": null,"ex:client-rpc": null,"rt:fib-route": null,"rt:route-count": null}}
|
||||
expecteq "$(curl -sG http://localhost/restconf/operations)" '{"operations": {"example:empty": null,"example:input": null,"example:output": null,"example:client-rpc": null,"ietf-routing:fib-route": null,"ietf-routing:route-count": null}}
|
||||
'
|
||||
|
||||
new "restconf get restconf/operations. RFC8040 3.3.2 (xml)"
|
||||
ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/operations)
|
||||
expect="<operations><ex:empty/><ex:input/><ex:output/><ex:client-rpc/><rt:fib-route/><rt:route-count/></operations>"
|
||||
expect="<operations><example:empty/><example:input/><example:output/><example:client-rpc/><ietf-routing:fib-route/><ietf-routing:route-count/></operations>"
|
||||
match=`echo $ret | grep -EZo "$expect"`
|
||||
if [ -z "$match" ]; then
|
||||
err "$expect" "$ret"
|
||||
|
|
@ -143,7 +143,7 @@ expectfn "curl -s -I http://localhost/restconf/data" 0 "HTTP/1.1 200 OK"
|
|||
#Content-Type: application/yang-data+json"
|
||||
|
||||
new2 "restconf empty rpc"
|
||||
expecteq "$(curl -s -X POST -d {\"input\":{\"name\":\"\"}} http://localhost/restconf/operations/ex:empty)" ""
|
||||
expecteq "$(curl -s -X POST -d {\"input\":{\"name\":\"\"}} http://localhost/restconf/operations/example:empty)" ""
|
||||
|
||||
new2 "restconf get empty config + state json"
|
||||
expecteq "$(curl -sSG http://localhost/restconf/data)" '{"data": {"interfaces-state": {"interface": [{"name": "eth0","type": "ex:eth","if-index": 42}]}}}
|
||||
|
|
@ -246,29 +246,29 @@ expecteq "$(curl -s -G http://localhost/restconf/data)" '{"data": {"interfaces":
|
|||
'
|
||||
|
||||
new2 "restconf rpc using POST json"
|
||||
expecteq "$(curl -s -X POST -d '{"input":{"routing-instance-name":"ipv4"}}' http://localhost/restconf/operations/rt:fib-route)" '{"output": {"route": {"address-family": "ipv4","next-hop": {"next-hop-list": "2.3.4.5"}}}}
|
||||
expecteq "$(curl -s -X POST -d '{"input":{"routing-instance-name":"ipv4"}}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"output": {"route": {"address-family": "ipv4","next-hop": {"next-hop-list": "2.3.4.5"}}}}
|
||||
'
|
||||
|
||||
# Cant get this to work due to quoting
|
||||
#new2 "restconf rpc using POST wrong JSON"
|
||||
#expecteq "$(curl -s -X POST -d '{"input":{"routing-instance-name":ipv4}}' http://localhost/restconf/operations/rt:fib-route)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": " on line 1: syntax error at or before: i"}}}}
'
|
||||
#expecteq "$(curl -s -X POST -d '{"input":{"routing-instance-name":ipv4}}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": " on line 1: syntax error at or before: i"}}}}
'
|
||||
|
||||
new2 "restconf rpc using POST json w/o mandatory element"
|
||||
expecteq "$(curl -s -X POST -d '{"input":{"wrongelement":"ipv4"}}' http://localhost/restconf/operations/rt:fib-route)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "Missing mandatory variable: routing-instance-name"}}}}
'
|
||||
expecteq "$(curl -s -X POST -d '{"input":{"wrongelement":"ipv4"}}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "Missing mandatory variable: routing-instance-name"}}}}
'
|
||||
new2 "restconf rpc non-existing rpc w/o namespace"
|
||||
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/kalle)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "yang node not found"}}}}
'
|
||||
|
||||
new2 "restconf rpc non-existing rpc"
|
||||
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/ex:kalle)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "yang node not found"}}}}
'
|
||||
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/example:kalle)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "yang node not found"}}}}
'
|
||||
|
||||
new2 "restconf rpc missing name"
|
||||
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "Operation name expected"}}}}
'
|
||||
|
||||
new2 "restconf rpc missing input"
|
||||
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/rt:fib-route)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "Missing mandatory variable: routing-instance-name"}}}}
'
|
||||
expecteq "$(curl -s -X POST -d '{}' http://localhost/restconf/operations/ietf-routing:fib-route)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "Missing mandatory variable: routing-instance-name"}}}}
'
|
||||
|
||||
new "restconf rpc using POST xml"
|
||||
ret=$(curl -s -X POST -H "Accept: application/yang-data+xml" -d '{"input":{"routing-instance-name":"ipv4"}}' http://localhost/restconf/operations/rt:fib-route)
|
||||
ret=$(curl -s -X POST -H "Accept: application/yang-data+xml" -d '{"input":{"routing-instance-name":"ipv4"}}' http://localhost/restconf/operations/ietf-routing:fib-route)
|
||||
expect="<output><route><address-family>ipv4</address-family><next-hop><next-hop-list>2.3.4.5</next-hop-list></next-hop></route></output>"
|
||||
match=`echo $ret | grep -EZo "$expect"`
|
||||
if [ -z "$match" ]; then
|
||||
|
|
@ -276,10 +276,10 @@ if [ -z "$match" ]; then
|
|||
fi
|
||||
|
||||
new2 "restconf rpc using wrong prefix"
|
||||
expecteq "$(curl -s -X POST -d '{"input":{"routing-instance-name":"ipv4"}}' http://localhost/restconf/operations/wrong:fib-route)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "yang node not found"}}}}
'
|
||||
expecteq "$(curl -s -X POST -d '{"input":{"routing-instance-name":"ipv4"}}' http://localhost/restconf/operations/wrong:fib-route)" '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-tag": "operation-failed","error-type": "protocol","error-severity": "error","error-message": "yang module not found"}}}}
'
|
||||
|
||||
new "restconf local client rpc using POST xml"
|
||||
ret=$(curl -s -X POST -H "Accept: application/yang-data+xml" -d '{"input":{"request":"example"}}' http://localhost/restconf/operations/ex:client-rpc)
|
||||
ret=$(curl -s -X POST -H "Accept: application/yang-data+xml" -d '{"input":{"request":"example"}}' http://localhost/restconf/operations/example:client-rpc)
|
||||
expect="<output><result>ok</result></output>"
|
||||
match=`echo $ret | grep -EZo "$expect"`
|
||||
if [ -z "$match" ]; then
|
||||
|
|
@ -287,7 +287,7 @@ if [ -z "$match" ]; then
|
|||
fi
|
||||
|
||||
# XXX cant get -H to work
|
||||
#expecteq 'curl -s -X POST -H "Accept: application/yang-data+xml" -d {"input":{"routing-instance-name":"ipv4"}} http://localhost/restconf/operations/rt:fib-route' '<output><route><address-family>ipv4</address-family><next-hop><next-hop-list>2.3.4.5</next-hop-list></next-hop></route></output>'
|
||||
#expecteq 'curl -s -X POST -H "Accept: application/yang-data+xml" -d {"input":{"routing-instance-name":"ipv4"}} http://localhost/restconf/operations/ietf-routing:fib-route' '<output><route><address-family>ipv4</address-family><next-hop><next-hop-list>2.3.4.5</next-hop-list></next-hop></route></output>'
|
||||
|
||||
# Cant get shell macros to work, inline matching from lib.sh
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue