The Clixon API has been extended with namespaces, or namespace contexts in the following cases:
* CLIspec functions have added namespace parameter:
* `cli_show_config <db> <format> <xpath>` --> `cli_show_config <db> <format> <xpath> <namespace>`
* `cli_copy_config <db> <xpath> ...` --> `cli_copy_config <db> <xpath> <namespace> ...`
* Xpath API
* `xpath_first(x, format, ...)` --> `xpath_first(x, nsc, format, ...)`
* `xpath_vec(x, format, vec, veclen, ...)` --> `xpath_vec(x, nsc, format, vec, veclen, ...)`
* `xpath_vec_flag(x, format, flags, vec, veclen, ...)` --> `xpath_vec_flag(x, format, flags, vec, veclen, ...)`
* `xpath_vec_bool(x, format, ...)` --> `xpath_vec_bool(x, nsc, format, ...)`
* `xpath_vec_ctx(x, xpath, xp)` --> `xpath_vec_ctx(x, nsc, xpath, xp)`
* xmldb_get0 has an added `nsc` parameter:
* `xmldb_get0(h, db, xpath, copy, xret, msd)` --> `xmldb_get0(h, db, nsc, xpath, copy, xret, msd)`
* The plugin statedata callback (ca_statedata) has been extended with an nsc parameter:
* `int example_statedata(clicon_handle h, cvec *nsc, char *xpath, cxobj *xstate);`
* rpc get and get-config api function has an added namespace argument:
* `clicon_rpc_get_config(clicon_handle h, char *db, char *xpath, char *namespace, cxobj **xt);`
* `int clicon_rpc_get(clicon_handle h, char *xpath, char *namespace, cxobj **xt);`
This commit is contained in:
parent
73d8e97a01
commit
67b8685bab
78 changed files with 1507 additions and 538 deletions
19
CHANGELOG.md
19
CHANGELOG.md
|
|
@ -69,6 +69,24 @@
|
||||||
|
|
||||||
### API changes on existing features (you may need to change your code)
|
### API changes on existing features (you may need to change your code)
|
||||||
|
|
||||||
|
* The Clixon API has been extended with namespaces, or namespace contexts in the following cases:
|
||||||
|
* CLIspec functions have added namespace parameter:
|
||||||
|
* `cli_show_config <db> <format> <xpath>` --> `cli_show_config <db> <format> <xpath> <namespace>`
|
||||||
|
* `cli_copy_config <db> <xpath> ...` --> `cli_copy_config <db> <xpath> <namespace> ...`
|
||||||
|
* Xpath API
|
||||||
|
* `xpath_first(x, format, ...)` --> `xpath_first(x, nsc, format, ...)`
|
||||||
|
* `xpath_vec(x, format, vec, veclen, ...)` --> `xpath_vec(x, nsc, format, vec, veclen, ...)`
|
||||||
|
* `xpath_vec_flag(x, format, flags, vec, veclen, ...)` --> `xpath_vec_flag(x, format, flags, vec, veclen, ...)`
|
||||||
|
* `xpath_vec_bool(x, format, ...)` --> `xpath_vec_bool(x, nsc, format, ...)`
|
||||||
|
* `xpath_vec_ctx(x, xpath, xp)` --> `xpath_vec_ctx(x, nsc, xpath, xp)`
|
||||||
|
* xmldb_get0 has an added `nsc` parameter:
|
||||||
|
* `xmldb_get0(h, db, xpath, copy, xret, msd)` --> `xmldb_get0(h, db, nsc, xpath, copy, xret, msd)`
|
||||||
|
* The plugin statedata callback (ca_statedata) has been extended with an nsc parameter:
|
||||||
|
* `int example_statedata(clicon_handle h, cvec *nsc, char *xpath, cxobj *xstate);`
|
||||||
|
* rpc get and get-config api function has an added namespace argument:
|
||||||
|
* `clicon_rpc_get_config(clicon_handle h, char *db, char *xpath, char *namespace, cxobj **xt);`
|
||||||
|
* `int clicon_rpc_get(clicon_handle h, char *xpath, char *namespace, cxobj **xt);`
|
||||||
|
|
||||||
* RESTCONF strict namespace validation of data in POST and PUT.
|
* RESTCONF strict namespace validation of data in POST and PUT.
|
||||||
* Accepted:
|
* Accepted:
|
||||||
```
|
```
|
||||||
|
|
@ -191,6 +209,7 @@
|
||||||
|
|
||||||
### Minor changes
|
### Minor changes
|
||||||
|
|
||||||
|
* Rewrote `api_path2xpath` to handle namespaces.
|
||||||
* `startup_extraxml` triggers unnecessary validation
|
* `startup_extraxml` triggers unnecessary validation
|
||||||
* Renamed startup_db_reset -> xmldb_db_reset (its a general function)
|
* Renamed startup_db_reset -> xmldb_db_reset (its a general function)
|
||||||
* In startup_extraxml(), check if reset callbacks or extraxml file actually makes and changes to the tmp db.
|
* In startup_extraxml(), check if reset callbacks or extraxml file actually makes and changes to the tmp db.
|
||||||
|
|
|
||||||
60
README.md
60
README.md
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
Clixon is a YANG-based configuration manager, with interactive CLI,
|
Clixon is a YANG-based configuration manager, with interactive CLI,
|
||||||
NETCONF and RESTCONF interfaces, an embedded database and transaction
|
NETCONF and RESTCONF interfaces, an embedded database and transaction
|
||||||
support.
|
mechanism.
|
||||||
|
|
||||||
* [Background](#background)
|
* [Background](#background)
|
||||||
* [Frequently asked questions (FAQ)](doc/FAQ.md)
|
* [Frequently asked questions (FAQ)](doc/FAQ.md)
|
||||||
|
|
@ -17,7 +17,7 @@ support.
|
||||||
* [Extending](#extending)
|
* [Extending](#extending)
|
||||||
* [Yang](#yang)
|
* [Yang](#yang)
|
||||||
* [CLI](doc/CLI.md)
|
* [CLI](doc/CLI.md)
|
||||||
* [XML and XPATH](#xml)
|
* [XML and XPATH](#xml-and-xpath)
|
||||||
* [Netconf](#netconf)
|
* [Netconf](#netconf)
|
||||||
* [Restconf](#restconf)
|
* [Restconf](#restconf)
|
||||||
* [Datastore](datastore/README.md)
|
* [Datastore](datastore/README.md)
|
||||||
|
|
@ -36,10 +36,10 @@ support.
|
||||||
## Background
|
## Background
|
||||||
|
|
||||||
Clixon was implemented to provide an open-source generic configuration
|
Clixon was implemented to provide an open-source generic configuration
|
||||||
tool. The existing [CLIgen](http://www.cligen.se) tool was for command-lines only, while Clixon is a system with configuration database, xml and rest interfaces all defined by Yang. Most of the projects using Clixon are for embedded network and measuring devices. But Clixon can be used for other systems as well due to its modular and pluggable architecture.
|
tool. The existing [CLIgen](http://www.cligen.se) tool was for command-lines only, while Clixon is a system with configuration database, XML and REST interfaces all defined by Yang. Most of the projects using Clixon are for embedded network and measuring devices. But Clixon can be used for other systems as well due to its modular and pluggable architecture.
|
||||||
|
|
||||||
Users of Clixon currently include:
|
Users of Clixon currently include:
|
||||||
* [Netgate](https://www.netgate.com)
|
* [Netgate](https://www.netgate.com) in particular the [Tnsr product](https://www.tnsr.com/product#architecture)
|
||||||
* [CloudMon360](http://cloudmon360.com)
|
* [CloudMon360](http://cloudmon360.com)
|
||||||
* [Grideye](http://hagsand.se/grideye)
|
* [Grideye](http://hagsand.se/grideye)
|
||||||
* [Netclean](https://www.netclean.com/solutions/whitebox) # only CLIgen
|
* [Netclean](https://www.netclean.com/solutions/whitebox) # only CLIgen
|
||||||
|
|
@ -122,7 +122,7 @@ You then need to set the following configure option:
|
||||||
<CLICON_YANG_REGEXP>libxml2</CLICON_YANG_REGEXP>
|
<CLICON_YANG_REGEXP>libxml2</CLICON_YANG_REGEXP>
|
||||||
```
|
```
|
||||||
|
|
||||||
## XML
|
## XML and XPATH
|
||||||
|
|
||||||
Clixon has its own implementation of XML and XPATH implementation.
|
Clixon has its own implementation of XML and XPATH implementation.
|
||||||
|
|
||||||
|
|
@ -151,6 +151,53 @@ Note that base netconf namespace syntax is not enforced but recommended, which m
|
||||||
```
|
```
|
||||||
All other namespaces are enforced.
|
All other namespaces are enforced.
|
||||||
|
|
||||||
|
### XPATH and Namespaces
|
||||||
|
|
||||||
|
XPATHs may contain prefixes. Example: `/if:a/if:b`. The prefixes have
|
||||||
|
associated namespaces. For example, `if` may be bound to
|
||||||
|
`urn:ietf:params:xml:ns:yang:ietf-interfaces`. The prefix to namespace binding is called a _namespace context_ (nsc).
|
||||||
|
|
||||||
|
In the Clixon API, there are two variants on namespace contexts: _implicit_ (given by the XML); or _explicit_ given by an external mapping.
|
||||||
|
#### 1. Implicit namespace mapping
|
||||||
|
|
||||||
|
Implicit mapping is typical for basic known XML, where the context is
|
||||||
|
given implicitly by the XML being evaluated. In node comparisons (eg
|
||||||
|
of `if:a`) only name and prefixes are compared.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
XML: <if:a xmlns:if="urn:example:if" xmlns:ip="urn:example:ip"><ip:b/></if>
|
||||||
|
XPATH: /if:a/ip:b
|
||||||
|
```
|
||||||
|
When you call an xpath API function, call it with nsc set to NULL. This is the default.
|
||||||
|
|
||||||
|
#### 2. Explicit namespace mapping
|
||||||
|
|
||||||
|
Explicit binding is typical if the namespace context is independent
|
||||||
|
from the XML. Examples include NETCONF GET using :xpath when the XML
|
||||||
|
is not known so that xpath and XML may use different prefixes for the
|
||||||
|
same namespace. In that case you cannot rely on the prefix but must
|
||||||
|
compare namespaces. The namespace context of the XML is given (by the
|
||||||
|
XML), but the xpath nsc must then be explicitly given in the xpath
|
||||||
|
call. Example:
|
||||||
|
```
|
||||||
|
XML: <if:a xmlns:if="urn:example:if" xmlns:ip="urn:example:ip"><ip:b/></if>
|
||||||
|
NETCONF:<get-config><filter select="/x:a/y:b" xmlns:x="urn:example:if" xmlns:y="urn:example:ip/>
|
||||||
|
```
|
||||||
|
Here, x,y are prefixes used for two namespaces that are given by if,ip
|
||||||
|
in the xml. In this case, the namespaces (eg `urn:example:if`) must be
|
||||||
|
compared instead.
|
||||||
|
|
||||||
|
Another case is Yang path expressions.
|
||||||
|
|
||||||
|
#### How to create namespace contexts
|
||||||
|
|
||||||
|
You can create namespace in three ways:
|
||||||
|
* `xml_nsctx_init()` by explicitly giving a default namespace
|
||||||
|
* `xml_nsctx_node()` by copying an XML namespace context from an existing XML node.
|
||||||
|
* `xml_nsctx_yang()` by computing an XML namespace context a yang module import statements.
|
||||||
|
|
||||||
|
|
||||||
## Netconf
|
## Netconf
|
||||||
|
|
||||||
Clixon implements the following NETCONF proposals or standards:
|
Clixon implements the following NETCONF proposals or standards:
|
||||||
|
|
@ -177,9 +224,6 @@ Clixon does not support the following netconf features:
|
||||||
- edit-config config-text
|
- edit-config config-text
|
||||||
- edit-config operation
|
- edit-config operation
|
||||||
|
|
||||||
Some other deviations from the RFC:
|
|
||||||
- edit-config xpath select statement does not support namespaces
|
|
||||||
|
|
||||||
## Restconf
|
## Restconf
|
||||||
|
|
||||||
Clixon Restconf is a daemon based on FastCGI C-API. Instructions are available to
|
Clixon Restconf is a daemon based on FastCGI C-API. Instructions are available to
|
||||||
|
|
|
||||||
|
|
@ -217,6 +217,7 @@ client_get_streams(clicon_handle h,
|
||||||
/*! Get system state-data, including streams and plugins
|
/*! Get system state-data, including streams and plugins
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] xpath Xpath selection, not used but may be to filter early
|
* @param[in] xpath Xpath selection, not used but may be to filter early
|
||||||
|
* @param[in] nsc XML Namespace context for xpath
|
||||||
* @param[in,out] xret Existing XML tree, merge x into this
|
* @param[in,out] xret Existing XML tree, merge x into this
|
||||||
* @retval -1 Error (fatal)
|
* @retval -1 Error (fatal)
|
||||||
* @retval 0 Statedata callback failed (clicon_err called)
|
* @retval 0 Statedata callback failed (clicon_err called)
|
||||||
|
|
@ -225,6 +226,7 @@ client_get_streams(clicon_handle h,
|
||||||
static int
|
static int
|
||||||
client_statedata(clicon_handle h,
|
client_statedata(clicon_handle h,
|
||||||
char *xpath,
|
char *xpath,
|
||||||
|
cvec *nsc,
|
||||||
cxobj **xret)
|
cxobj **xret)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
@ -251,12 +253,12 @@ client_statedata(clicon_handle h,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (clicon_option_bool(h, "CLICON_MODULE_LIBRARY_RFC7895")){
|
if (clicon_option_bool(h, "CLICON_MODULE_LIBRARY_RFC7895")){
|
||||||
if ((ret = yang_modules_state_get(h, yspec, xpath, 0, xret)) < 0)
|
if ((ret = yang_modules_state_get(h, yspec, xpath, nsc, 0, xret)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if ((ret = clixon_plugin_statedata(h, yspec, xpath, xret)) < 0)
|
if ((ret = clixon_plugin_statedata(h, yspec, nsc, xpath, xret)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
@ -264,7 +266,7 @@ client_statedata(clicon_handle h,
|
||||||
* Actually this is a safety catch, should realy be done in plugins
|
* Actually this is a safety catch, should realy be done in plugins
|
||||||
* and modules_state functions.
|
* and modules_state functions.
|
||||||
*/
|
*/
|
||||||
if (xpath_vec(*xret, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
if (xpath_vec(*xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* If vectors are specified then mark the nodes found and
|
/* If vectors are specified then mark the nodes found and
|
||||||
* then filter out everything else,
|
* then filter out everything else,
|
||||||
|
|
@ -320,6 +322,7 @@ from_client_get_config(clicon_handle h,
|
||||||
size_t xlen;
|
size_t xlen;
|
||||||
int ret;
|
int ret;
|
||||||
char *username;
|
char *username;
|
||||||
|
cvec *nsc = NULL; /* Create a netconf namespace context from filter */
|
||||||
|
|
||||||
username = clicon_username_get(h);
|
username = clicon_username_get(h);
|
||||||
if ((db = netconf_db_find(xe, "source")) == NULL){
|
if ((db = netconf_db_find(xe, "source")) == NULL){
|
||||||
|
|
@ -336,13 +339,22 @@ from_client_get_config(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
if ((xfilter = xml_find(xe, "filter")) != NULL)
|
if ((xfilter = xml_find(xe, "filter")) != NULL){
|
||||||
if ((xpath = xml_find_value(xfilter, "select"))==NULL)
|
if ((xpath = xml_find_value(xfilter, "select"))==NULL)
|
||||||
xpath="/";
|
xpath="/";
|
||||||
|
/* Create namespace context for xpath from <filter>
|
||||||
|
* The set of namespace declarations are those in scope on the
|
||||||
|
* <filter> element.
|
||||||
|
*/
|
||||||
|
else
|
||||||
|
if (xml_nsctx_node(xfilter, &nsc) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
/* Note xret can be pruned by nacm below (and change name),
|
/* Note xret can be pruned by nacm below (and change name),
|
||||||
* so zero-copy cant be used
|
* so zero-copy cant be used
|
||||||
|
* Also, must use external namespace context here due to <filter stmt
|
||||||
*/
|
*/
|
||||||
if (xmldb_get(h, db, xpath, &xret) < 0){
|
if (xmldb_get0(h, db, nsc, xpath, 1, &xret, NULL) < 0) {
|
||||||
if (netconf_operation_failed(cbret, "application", "read registry")< 0)
|
if (netconf_operation_failed(cbret, "application", "read registry")< 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto ok;
|
goto ok;
|
||||||
|
|
@ -351,7 +363,7 @@ from_client_get_config(clicon_handle h,
|
||||||
if ((ret = nacm_access_pre(h, username, NACM_DATA, &xnacm)) < 0)
|
if ((ret = nacm_access_pre(h, username, NACM_DATA, &xnacm)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0){ /* Do NACM validation */
|
if (ret == 0){ /* Do NACM validation */
|
||||||
if (xpath_vec(xret, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* NACM datanode/module read validation */
|
/* NACM datanode/module read validation */
|
||||||
if (nacm_datanode_read(xret, xvec, xlen, username, xnacm) < 0)
|
if (nacm_datanode_read(xret, xvec, xlen, username, xnacm) < 0)
|
||||||
|
|
@ -374,6 +386,8 @@ from_client_get_config(clicon_handle h,
|
||||||
xml_free(xnacm);
|
xml_free(xnacm);
|
||||||
if (xvec)
|
if (xvec)
|
||||||
free(xvec);
|
free(xvec);
|
||||||
|
if (nsc)
|
||||||
|
xml_nsctx_free(nsc);
|
||||||
if (cbx)
|
if (cbx)
|
||||||
cbuf_free(cbx);
|
cbuf_free(cbx);
|
||||||
if (xret)
|
if (xret)
|
||||||
|
|
@ -441,14 +455,14 @@ from_client_edit_config(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
if ((x = xpath_first(xn, "default-operation")) != NULL){
|
if ((x = xpath_first(xn, NULL, "default-operation")) != NULL){
|
||||||
if (xml_operation(xml_body(x), &operation) < 0){
|
if (xml_operation(xml_body(x), &operation) < 0){
|
||||||
if (netconf_invalid_value(cbret, "protocol", "Wrong operation")< 0)
|
if (netconf_invalid_value(cbret, "protocol", "Wrong operation")< 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((xc = xpath_first(xn, "config")) == NULL){
|
if ((xc = xpath_first(xn, NULL, "config")) == NULL){
|
||||||
if (netconf_missing_element(cbret, "protocol", "config", NULL) < 0)
|
if (netconf_missing_element(cbret, "protocol", "config", NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto ok;
|
goto ok;
|
||||||
|
|
@ -806,24 +820,34 @@ from_client_get(clicon_handle h,
|
||||||
cxobj **xvec = NULL;
|
cxobj **xvec = NULL;
|
||||||
size_t xlen;
|
size_t xlen;
|
||||||
cxobj *xnacm = NULL;
|
cxobj *xnacm = NULL;
|
||||||
char *username;
|
char *username;
|
||||||
|
cvec *nsc = NULL; /* Create a netconf namespace context from filter */
|
||||||
|
|
||||||
username = clicon_username_get(h);
|
username = clicon_username_get(h);
|
||||||
if ((xfilter = xml_find(xe, "filter")) != NULL)
|
if ((xfilter = xml_find(xe, "filter")) != NULL){
|
||||||
if ((xpath = xml_find_value(xfilter, "select"))==NULL)
|
if ((xpath = xml_find_value(xfilter, "select"))==NULL)
|
||||||
xpath="/";
|
xpath="/";
|
||||||
|
/* Create namespace context for xpath from <filter>
|
||||||
|
* The set of namespace declarations are those in scope on the
|
||||||
|
* <filter> element.
|
||||||
|
*/
|
||||||
|
else
|
||||||
|
if (xml_nsctx_node(xfilter, &nsc) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
/* Get config
|
/* Get config
|
||||||
* Note xret can be pruned by nacm below and change name and
|
* Note xret can be pruned by nacm below and change name and
|
||||||
* metrged with state data, so zero-copy cant be used
|
* metrged with state data, so zero-copy cant be used
|
||||||
|
* Also, must use external namespace context here due to <filter stmt
|
||||||
*/
|
*/
|
||||||
if (xmldb_get(h, "running", xpath, &xret) < 0){
|
if (xmldb_get0(h, "running", nsc, xpath, 1, &xret, NULL) < 0) {
|
||||||
if (netconf_operation_failed(cbret, "application", "read registry")< 0)
|
if (netconf_operation_failed(cbret, "application", "read registry")< 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
/* Get state data from plugins as defined by plugin_statedata(), if any */
|
/* Get state data from plugins as defined by plugin_statedata(), if any */
|
||||||
clicon_err_reset();
|
clicon_err_reset();
|
||||||
if ((ret = client_statedata(h, xpath, &xret)) < 0)
|
if ((ret = client_statedata(h, xpath, nsc, &xret)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0){ /* Error from callback (error in xret) */
|
if (ret == 0){ /* Error from callback (error in xret) */
|
||||||
if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
|
if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
|
||||||
|
|
@ -834,7 +858,7 @@ from_client_get(clicon_handle h,
|
||||||
if ((ret = nacm_access_pre(h, username, NACM_DATA, &xnacm)) < 0)
|
if ((ret = nacm_access_pre(h, username, NACM_DATA, &xnacm)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0){ /* Do NACM validation */
|
if (ret == 0){ /* Do NACM validation */
|
||||||
if (xpath_vec(xret, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* NACM datanode/module read validation */
|
/* NACM datanode/module read validation */
|
||||||
if (nacm_datanode_read(xret, xvec, xlen, username, xnacm) < 0)
|
if (nacm_datanode_read(xret, xvec, xlen, username, xnacm) < 0)
|
||||||
|
|
@ -858,6 +882,8 @@ from_client_get(clicon_handle h,
|
||||||
xml_free(xnacm);
|
xml_free(xnacm);
|
||||||
if (xvec)
|
if (xvec)
|
||||||
free(xvec);
|
free(xvec);
|
||||||
|
if (nsc)
|
||||||
|
xml_nsctx_free(nsc);
|
||||||
if (xret)
|
if (xret)
|
||||||
xml_free(xret);
|
xml_free(xret);
|
||||||
return retval;
|
return retval;
|
||||||
|
|
@ -986,10 +1012,13 @@ from_client_create_subscription(clicon_handle h,
|
||||||
char *selector = NULL;
|
char *selector = NULL;
|
||||||
struct timeval start;
|
struct timeval start;
|
||||||
struct timeval stop;
|
struct timeval stop;
|
||||||
|
cvec *nsc = NULL;
|
||||||
|
|
||||||
if ((x = xpath_first(xe, "//stream")) != NULL)
|
if ((nsc = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:netmod:notification")) == NULL)
|
||||||
|
goto done;
|
||||||
|
if ((x = xpath_first(xe, nsc, "//stream")) != NULL)
|
||||||
stream = xml_find_value(x, "body");
|
stream = xml_find_value(x, "body");
|
||||||
if ((x = xpath_first(xe, "//stopTime")) != NULL){
|
if ((x = xpath_first(xe, nsc, "//stopTime")) != NULL){
|
||||||
if ((stoptime = xml_find_value(x, "body")) != NULL &&
|
if ((stoptime = xml_find_value(x, "body")) != NULL &&
|
||||||
str2time(stoptime, &stop) < 0){
|
str2time(stoptime, &stop) < 0){
|
||||||
if (netconf_bad_element(cbret, "application", "stopTime", "Expected timestamp") < 0)
|
if (netconf_bad_element(cbret, "application", "stopTime", "Expected timestamp") < 0)
|
||||||
|
|
@ -997,7 +1026,7 @@ from_client_create_subscription(clicon_handle h,
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((x = xpath_first(xe, "//startTime")) != NULL){
|
if ((x = xpath_first(xe, nsc, "//startTime")) != NULL){
|
||||||
if ((starttime = xml_find_value(x, "body")) != NULL &&
|
if ((starttime = xml_find_value(x, "body")) != NULL &&
|
||||||
str2time(starttime, &start) < 0){
|
str2time(starttime, &start) < 0){
|
||||||
if (netconf_bad_element(cbret, "application", "startTime", "Expected timestamp") < 0)
|
if (netconf_bad_element(cbret, "application", "startTime", "Expected timestamp") < 0)
|
||||||
|
|
@ -1005,7 +1034,7 @@ from_client_create_subscription(clicon_handle h,
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((xfilter = xpath_first(xe, "//filter")) != NULL){
|
if ((xfilter = xpath_first(xe, nsc, "//filter")) != NULL){
|
||||||
if ((ftype = xml_find_value(xfilter, "type")) != NULL){
|
if ((ftype = xml_find_value(xfilter, "type")) != NULL){
|
||||||
/* Only accept xpath as filter type */
|
/* Only accept xpath as filter type */
|
||||||
if (strcmp(ftype, "xpath") != 0){
|
if (strcmp(ftype, "xpath") != 0){
|
||||||
|
|
@ -1041,6 +1070,8 @@ from_client_create_subscription(clicon_handle h,
|
||||||
ok:
|
ok:
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
if (nsc)
|
||||||
|
xml_nsctx_free(nsc);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1144,7 +1175,7 @@ from_client_msg(clicon_handle h,
|
||||||
goto reply;
|
goto reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((x = xpath_first(xt, "/rpc")) == NULL){
|
if ((x = xpath_first(xt, NULL, "/rpc")) == NULL){
|
||||||
if (netconf_malformed_message(cbret, "rpc keyword expected")< 0)
|
if (netconf_malformed_message(cbret, "rpc keyword expected")< 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto reply;
|
goto reply;
|
||||||
|
|
|
||||||
|
|
@ -184,7 +184,7 @@ startup_common(clicon_handle h,
|
||||||
if ((msd = modstate_diff_new()) == NULL)
|
if ((msd = modstate_diff_new()) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
clicon_debug(1, "Reading startup config from %s", db);
|
clicon_debug(1, "Reading startup config from %s", db);
|
||||||
if (xmldb_get0(h, db, "/", 0, &xt, msd) < 0)
|
if (xmldb_get0(h, db, NULL, "/", 0, &xt, msd) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Clear flags xpath for get */
|
/* Clear flags xpath for get */
|
||||||
xml_apply0(xt, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset,
|
xml_apply0(xt, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset,
|
||||||
|
|
@ -404,7 +404,7 @@ from_validate_common(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* This is the state we are going to */
|
/* This is the state we are going to */
|
||||||
if (xmldb_get0(h, candidate, "/", 0, &td->td_target, NULL) < 0)
|
if (xmldb_get0(h, candidate, NULL, "/", 0, &td->td_target, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* Clear flags xpath for get */
|
/* Clear flags xpath for get */
|
||||||
|
|
@ -422,7 +422,7 @@ from_validate_common(clicon_handle h,
|
||||||
|
|
||||||
/* 2. Parse xml trees
|
/* 2. Parse xml trees
|
||||||
* This is the state we are going from */
|
* This is the state we are going from */
|
||||||
if (xmldb_get0(h, "running", "/", 0, &td->td_src, NULL) < 0)
|
if (xmldb_get0(h, "running", NULL, "/", 0, &td->td_src, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Clear flags xpath for get */
|
/* Clear flags xpath for get */
|
||||||
xml_apply0(td->td_src, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset,
|
xml_apply0(td->td_src, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset,
|
||||||
|
|
|
||||||
|
|
@ -122,6 +122,7 @@ clixon_plugin_reset(clicon_handle h,
|
||||||
int
|
int
|
||||||
clixon_plugin_statedata(clicon_handle h,
|
clixon_plugin_statedata(clicon_handle h,
|
||||||
yang_stmt *yspec,
|
yang_stmt *yspec,
|
||||||
|
cvec *nsc,
|
||||||
char *xpath,
|
char *xpath,
|
||||||
cxobj **xret)
|
cxobj **xret)
|
||||||
{
|
{
|
||||||
|
|
@ -136,7 +137,7 @@ clixon_plugin_statedata(clicon_handle h,
|
||||||
continue;
|
continue;
|
||||||
if ((x = xml_new("config", NULL, NULL)) == NULL)
|
if ((x = xml_new("config", NULL, NULL)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (fn(h, xpath, x) < 0)
|
if (fn(h, nsc, xpath, x) < 0)
|
||||||
goto fail; /* Dont quit here on user callbacks */
|
goto fail; /* Dont quit here on user callbacks */
|
||||||
if (xml_apply(x, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
if (xml_apply(x, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,8 @@ int backend_plugin_initiate(clicon_handle h);
|
||||||
|
|
||||||
int clixon_plugin_reset(clicon_handle h, char *db);
|
int clixon_plugin_reset(clicon_handle h, char *db);
|
||||||
|
|
||||||
int clixon_plugin_statedata(clicon_handle h, yang_stmt *yspec, char *xpath, cxobj **xtop);
|
int clixon_plugin_statedata(clicon_handle h, yang_stmt *yspec, cvec *nsc,
|
||||||
|
char *xpath, cxobj **xtop);
|
||||||
transaction_data_t * transaction_new(void);
|
transaction_data_t * transaction_new(void);
|
||||||
int transaction_free(transaction_data_t *);
|
int transaction_free(transaction_data_t *);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ db_merge(clicon_handle h,
|
||||||
cxobj *xt = NULL;
|
cxobj *xt = NULL;
|
||||||
|
|
||||||
/* Get data as xml from db1 */
|
/* Get data as xml from db1 */
|
||||||
if (xmldb_get0(h, (char*)db1, NULL, 0, &xt, NULL) < 0)
|
if (xmldb_get0(h, (char*)db1, NULL, NULL, 0, &xt, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Merge xml into db2. Without commit */
|
/* Merge xml into db2. Without commit */
|
||||||
retval = xmldb_put(h, (char*)db2, OP_MERGE, xt, clicon_username_get(h), cbret);
|
retval = xmldb_put(h, (char*)db2, OP_MERGE, xt, clicon_username_get(h), cbret);
|
||||||
|
|
@ -339,7 +339,7 @@ startup_module_state(clicon_handle h,
|
||||||
goto ok;
|
goto ok;
|
||||||
/* Set up cache
|
/* Set up cache
|
||||||
* Now, access brief module cache with clicon_modst_cache_get(h, 1) */
|
* Now, access brief module cache with clicon_modst_cache_get(h, 1) */
|
||||||
if ((ret = yang_modules_state_get(h, yspec, NULL, 1, &x)) < 0)
|
if ((ret = yang_modules_state_get(h, yspec, NULL, NULL, 1, &x)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
|
||||||
|
|
@ -680,15 +680,15 @@ compare_dbs(clicon_handle h,
|
||||||
astext = cv_int32_get(cvec_i(argv, 0));
|
astext = cv_int32_get(cvec_i(argv, 0));
|
||||||
else
|
else
|
||||||
astext = 0;
|
astext = 0;
|
||||||
if (clicon_rpc_get_config(h, "running", "/", &xc1) < 0)
|
if (clicon_rpc_get_config(h, "running", "/", NULL, &xc1) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xerr = xpath_first(xc1, "/rpc-error")) != NULL){
|
if ((xerr = xpath_first(xc1, NULL, "/rpc-error")) != NULL){
|
||||||
clicon_rpc_generate_error("Get configuration", xerr);
|
clicon_rpc_generate_error("Get configuration", xerr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (clicon_rpc_get_config(h, "candidate", "/", &xc2) < 0)
|
if (clicon_rpc_get_config(h, "candidate", "/", NULL, &xc2) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xerr = xpath_first(xc2, "/rpc-error")) != NULL){
|
if ((xerr = xpath_first(xc2, NULL, "/rpc-error")) != NULL){
|
||||||
clicon_rpc_generate_error("Get configuration", xerr);
|
clicon_rpc_generate_error("Get configuration", xerr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -847,13 +847,13 @@ save_config_file(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
filename = cv_string_get(cv);
|
filename = cv_string_get(cv);
|
||||||
if (clicon_rpc_get_config(h, dbstr,"/", &xt) < 0)
|
if (clicon_rpc_get_config(h, dbstr,"/", NULL, &xt) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (xt == NULL){
|
if (xt == NULL){
|
||||||
clicon_err(OE_CFG, 0, "get config: empty tree"); /* Shouldnt happen */
|
clicon_err(OE_CFG, 0, "get config: empty tree"); /* Shouldnt happen */
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
|
if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
|
||||||
clicon_rpc_generate_error("Get configuration", xerr);
|
clicon_rpc_generate_error("Get configuration", xerr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -961,7 +961,7 @@ cli_notification_cb(int s,
|
||||||
}
|
}
|
||||||
if (clicon_msg_decode(reply, NULL, &xt) < 0) /* XXX pass yang_spec */
|
if (clicon_msg_decode(reply, NULL, &xt) < 0) /* XXX pass yang_spec */
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xt, "//event")) != NULL){
|
if ((xe = xpath_first(xt, NULL, "//event")) != NULL){
|
||||||
x = NULL;
|
x = NULL;
|
||||||
while ((x = xml_child_each(xe, x, -1)) != NULL) {
|
while ((x = xml_child_each(xe, x, -1)) != NULL) {
|
||||||
switch (format){
|
switch (format){
|
||||||
|
|
@ -1110,14 +1110,15 @@ cli_unlock(clicon_handle h,
|
||||||
* @param[in] cvv Vector of variables from CLIgen command-line
|
* @param[in] cvv Vector of variables from CLIgen command-line
|
||||||
* @param[in] argv Vector: <db>, <xpath>, <field>, <fromvar>, <tovar>
|
* @param[in] argv Vector: <db>, <xpath>, <field>, <fromvar>, <tovar>
|
||||||
* Explanation of argv fields:
|
* Explanation of argv fields:
|
||||||
* db: Database name, eg candidate|tmp|startup
|
* db: Database name, eg candidate|tmp|startup
|
||||||
* xpath: XPATH expression with exactly two %s pointing to field and from name
|
* xpath: XPATH expression with exactly two %s pointing to field and from name
|
||||||
* field: Name of list key, eg name
|
* namespace: XPATH default namespace
|
||||||
* fromvar:Name of variable containing name of object to copy from (given by xpath)
|
* field: Name of list key, eg name
|
||||||
* tovar: Name of variable containing name of object to copy to.
|
* fromvar: Name of variable containing name of object to copy from (given by xpath)
|
||||||
|
* tovar: Name of variable containing name of object to copy to.
|
||||||
* @code
|
* @code
|
||||||
* cli spec:
|
* cli spec:
|
||||||
* copy snd <n1:string> to <n2:string>, cli_copy_config("candidate", "/sender[%s='%s']", "from", "n1", "n2");
|
* copy snd <n1:string> to <n2:string>, cli_copy_config("candidate", "/sender[%s='%s']", "urn:example:clixon", "from", "n1", "n2");
|
||||||
* cli command:
|
* cli command:
|
||||||
* copy snd from to to
|
* copy snd from to to
|
||||||
* @endcode
|
* @endcode
|
||||||
|
|
@ -1133,6 +1134,7 @@ cli_copy_config(clicon_handle h,
|
||||||
cxobj *x2 = NULL;
|
cxobj *x2 = NULL;
|
||||||
cxobj *x;
|
cxobj *x;
|
||||||
char *xpath;
|
char *xpath;
|
||||||
|
char *namespace;
|
||||||
int i;
|
int i;
|
||||||
int j;
|
int j;
|
||||||
cbuf *cb = NULL;
|
cbuf *cb = NULL;
|
||||||
|
|
@ -1144,21 +1146,24 @@ cli_copy_config(clicon_handle h,
|
||||||
cg_var *tocv;
|
cg_var *tocv;
|
||||||
char *toname;
|
char *toname;
|
||||||
cxobj *xerr;
|
cxobj *xerr;
|
||||||
|
cvec *nsc = NULL;
|
||||||
|
|
||||||
if (cvec_len(argv) != 5){
|
if (cvec_len(argv) != 6){
|
||||||
clicon_err(OE_PLUGIN, 0, "Requires four elements: <db> <xpath> <keyname> <from> <to>");
|
clicon_err(OE_PLUGIN, 0, "Requires 6 elements: <db> <xpath> <namespace> <keyname> <from> <to>");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* First argv argument: Database */
|
/* First argv argument: Database */
|
||||||
db = cv_string_get(cvec_i(argv, 0));
|
db = cv_string_get(cvec_i(argv, 0));
|
||||||
/* Second argv argument: xpath */
|
/* Second argv argument: xpath */
|
||||||
xpath = cv_string_get(cvec_i(argv, 1));
|
xpath = cv_string_get(cvec_i(argv, 1));
|
||||||
|
/* Third argv argument: namespace */
|
||||||
|
namespace = cv_string_get(cvec_i(argv, 2));
|
||||||
/* Third argv argument: name of keyname */
|
/* Third argv argument: name of keyname */
|
||||||
keyname = cv_string_get(cvec_i(argv, 2));
|
keyname = cv_string_get(cvec_i(argv, 3));
|
||||||
/* Fourth argv argument: from variable */
|
/* Fourth argv argument: from variable */
|
||||||
fromvar = cv_string_get(cvec_i(argv, 3));
|
fromvar = cv_string_get(cvec_i(argv, 4));
|
||||||
/* Fifth argv argument: to variable */
|
/* Fifth argv argument: to variable */
|
||||||
tovar = cv_string_get(cvec_i(argv, 4));
|
tovar = cv_string_get(cvec_i(argv, 5));
|
||||||
|
|
||||||
/* Get from variable -> cv -> from name */
|
/* Get from variable -> cv -> from name */
|
||||||
if ((fromcv = cvec_find(cvv, fromvar)) == NULL){
|
if ((fromcv = cvec_find(cvv, fromvar)) == NULL){
|
||||||
|
|
@ -1184,9 +1189,9 @@ cli_copy_config(clicon_handle h,
|
||||||
}
|
}
|
||||||
cprintf(cb, xpath, keyname, fromname);
|
cprintf(cb, xpath, keyname, fromname);
|
||||||
/* Get from object configuration and store in x1 */
|
/* Get from object configuration and store in x1 */
|
||||||
if (clicon_rpc_get_config(h, db, cbuf_get(cb), &x1) < 0)
|
if (clicon_rpc_get_config(h, db, cbuf_get(cb), namespace, &x1) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xerr = xpath_first(x1, "/rpc-error")) != NULL){
|
if ((xerr = xpath_first(x1, NULL, "/rpc-error")) != NULL){
|
||||||
clicon_rpc_generate_error("Get configuration", xerr);
|
clicon_rpc_generate_error("Get configuration", xerr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -1204,7 +1209,9 @@ cli_copy_config(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
xml_name_set(x2, "config");
|
xml_name_set(x2, "config");
|
||||||
cprintf(cb, "/%s", keyname);
|
cprintf(cb, "/%s", keyname);
|
||||||
if ((x = xpath_first(x2, "%s", cbuf_get(cb))) == NULL){
|
if ((nsc = xml_nsctx_init(NULL, namespace)) == NULL)
|
||||||
|
goto done;
|
||||||
|
if ((x = xpath_first(x2, nsc, "%s", cbuf_get(cb))) == NULL){
|
||||||
clicon_err(OE_PLUGIN, 0, "Field %s not found in copy tree", keyname);
|
clicon_err(OE_PLUGIN, 0, "Field %s not found in copy tree", keyname);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -1218,6 +1225,8 @@ cli_copy_config(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
if (nsc)
|
||||||
|
xml_nsctx_free(nsc);
|
||||||
if (cb)
|
if (cb)
|
||||||
cbuf_free(cb);
|
cbuf_free(cb);
|
||||||
if (x1 != NULL)
|
if (x1 != NULL)
|
||||||
|
|
|
||||||
|
|
@ -178,7 +178,7 @@ yang2cli_var_identityref(yang_stmt *ys,
|
||||||
char *helptext,
|
char *helptext,
|
||||||
cbuf *cb)
|
cbuf *cb)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
yang_stmt *ybaseref;
|
yang_stmt *ybaseref;
|
||||||
yang_stmt *ybaseid;
|
yang_stmt *ybaseid;
|
||||||
cg_var *cv = NULL;
|
cg_var *cv = NULL;
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,8 @@ expand_dbvar(void *h,
|
||||||
cxobj *xcur;
|
cxobj *xcur;
|
||||||
char *xpathcur;
|
char *xpathcur;
|
||||||
char *reason = NULL;
|
char *reason = NULL;
|
||||||
|
char *namespace = NULL;
|
||||||
|
cvec *nsc = NULL;
|
||||||
|
|
||||||
if (argv == NULL || cvec_len(argv) != 2){
|
if (argv == NULL || cvec_len(argv) != 2){
|
||||||
clicon_err(OE_PLUGIN, 0, "requires arguments: <db> <xmlkeyfmt>");
|
clicon_err(OE_PLUGIN, 0, "requires arguments: <db> <xmlkeyfmt>");
|
||||||
|
|
@ -148,14 +150,14 @@ expand_dbvar(void *h,
|
||||||
--> ^/interface/eth0/address/.*$
|
--> ^/interface/eth0/address/.*$
|
||||||
--> /interface/[name="eth0"]/address
|
--> /interface/[name="eth0"]/address
|
||||||
*/
|
*/
|
||||||
if (api_path_fmt2xpath(api_path_fmt, cvv, &xpath) < 0)
|
|
||||||
goto done;
|
|
||||||
if (api_path_fmt2api_path(api_path_fmt, cvv, &api_path) < 0)
|
if (api_path_fmt2api_path(api_path_fmt, cvv, &api_path) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
if (api_path2xpath(api_path, yspec, &xpath, &namespace) < 0)
|
||||||
|
goto done;
|
||||||
/* Get configuration */
|
/* Get configuration */
|
||||||
if (clicon_rpc_get_config(h, dbstr, xpath, &xt) < 0)
|
if (clicon_rpc_get_config(h, dbstr, xpath, namespace, &xt) < 0) /* XXX */
|
||||||
goto done;
|
goto done;
|
||||||
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
|
if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
|
||||||
clicon_rpc_generate_error("Get configuration", xerr);
|
clicon_rpc_generate_error("Get configuration", xerr);
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
|
|
@ -172,6 +174,9 @@ expand_dbvar(void *h,
|
||||||
goto done;
|
goto done;
|
||||||
if (y==NULL)
|
if (y==NULL)
|
||||||
goto ok;
|
goto ok;
|
||||||
|
if ((nsc = xml_nsctx_init(NULL, namespace)) == NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
/* Special case for leafref. Detect leafref via Yang-type,
|
/* Special case for leafref. Detect leafref via Yang-type,
|
||||||
* Get Yang path element, tentatively add the new syntax to the whole
|
* Get Yang path element, tentatively add the new syntax to the whole
|
||||||
* tree and apply the path to that.
|
* tree and apply the path to that.
|
||||||
|
|
@ -193,12 +198,12 @@ expand_dbvar(void *h,
|
||||||
fprintf(stderr, "%s\n", reason);
|
fprintf(stderr, "%s\n", reason);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((xcur = xpath_first(xt, "%s", xpath)) == NULL){
|
if ((xcur = xpath_first(xt, nsc, "%s", xpath)) == NULL){
|
||||||
clicon_err(OE_DB, 0, "xpath %s should return merged content", xpath);
|
clicon_err(OE_DB, 0, "xpath %s should return merged content", xpath);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (xpath_vec(xcur, "%s", &xvec, &xlen, xpathcur) < 0)
|
if (xpath_vec(xcur, nsc, "%s", &xvec, &xlen, xpathcur) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
bodystr0 = NULL; /* Assume sorted XML where duplicates are adjacent */
|
bodystr0 = NULL; /* Assume sorted XML where duplicates are adjacent */
|
||||||
for (i = 0; i < xlen; i++) {
|
for (i = 0; i < xlen; i++) {
|
||||||
|
|
@ -217,6 +222,8 @@ expand_dbvar(void *h,
|
||||||
ok:
|
ok:
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
if (nsc)
|
||||||
|
xml_nsctx_free(nsc);
|
||||||
if (reason)
|
if (reason)
|
||||||
free(reason);
|
free(reason);
|
||||||
if (api_path)
|
if (api_path)
|
||||||
|
|
@ -231,6 +238,7 @@ expand_dbvar(void *h,
|
||||||
free(xpath);
|
free(xpath);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
expandv_dbvar(void *h,
|
expandv_dbvar(void *h,
|
||||||
char *name,
|
char *name,
|
||||||
|
|
@ -241,6 +249,7 @@ expandv_dbvar(void *h,
|
||||||
{
|
{
|
||||||
return expand_dbvar(h, name, cvv, argv, commands, helptexts);
|
return expand_dbvar(h, name, cvv, argv, commands, helptexts);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! List files in a directory
|
/*! List files in a directory
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
|
|
@ -390,10 +399,10 @@ show_yang(clicon_handle h,
|
||||||
* Format of argv:
|
* Format of argv:
|
||||||
* <dbname> "running"|"candidate"|"startup" # note only running state=1
|
* <dbname> "running"|"candidate"|"startup" # note only running state=1
|
||||||
* <format> "text"|"xml"|"json"|"cli"|"netconf" (see format_enum)
|
* <format> "text"|"xml"|"json"|"cli"|"netconf" (see format_enum)
|
||||||
* <xpath> xpath expression, that may contain one %, eg "/sender[name="%s"]"
|
* <xpath> xpath expression, that may contain one %, eg "/sender[name='foo']"
|
||||||
* <varname> optional name of variable in cvv. If set, xpath must have a '%s'
|
* <namespace> If xpath set, the namespace the symbols in xpath belong to (optional)
|
||||||
* @code
|
* @code
|
||||||
* show config id <n:string>, cli_show_config("running","xml","iface[name="%s"]","n");
|
* show config id <n:string>, cli_show_config("running","xml","iface[name='foo']","urn:example:example");
|
||||||
* @endcode
|
* @endcode
|
||||||
* @note if state parameter is set, then db must be running
|
* @note if state parameter is set, then db must be running
|
||||||
*/
|
*/
|
||||||
|
|
@ -409,16 +418,13 @@ cli_show_config1(clicon_handle h,
|
||||||
char *xpath;
|
char *xpath;
|
||||||
enum format_enum format;
|
enum format_enum format;
|
||||||
cbuf *cbxpath = NULL;
|
cbuf *cbxpath = NULL;
|
||||||
char *attr = NULL;
|
|
||||||
int i;
|
|
||||||
int j;
|
|
||||||
cg_var *cvattr;
|
|
||||||
char *val = NULL;
|
char *val = NULL;
|
||||||
cxobj *xt = NULL;
|
cxobj *xt = NULL;
|
||||||
cxobj *xc;
|
cxobj *xc;
|
||||||
cxobj *xerr;
|
cxobj *xerr;
|
||||||
enum genmodel_type gt;
|
enum genmodel_type gt;
|
||||||
yang_stmt *yspec;
|
yang_stmt *yspec;
|
||||||
|
char *namespace = NULL;
|
||||||
|
|
||||||
if (cvec_len(argv) != 3 && cvec_len(argv) != 4){
|
if (cvec_len(argv) != 3 && cvec_len(argv) != 4){
|
||||||
clicon_err(OE_PLUGIN, 0, "Got %d arguments. Expected: <dbname>,<format>,<xpath>[,<attr>]", cvec_len(argv));
|
clicon_err(OE_PLUGIN, 0, "Got %d arguments. Expected: <dbname>,<format>,<xpath>[,<attr>]", cvec_len(argv));
|
||||||
|
|
@ -441,33 +447,12 @@ cli_show_config1(clicon_handle h,
|
||||||
clicon_err(OE_PLUGIN, errno, "cbuf_new");
|
clicon_err(OE_PLUGIN, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Fourth argument is stdarg to xpath format string */
|
cprintf(cbxpath, "%s", xpath);
|
||||||
if (cvec_len(argv) == 4){
|
/* Fourth argument is namespace */
|
||||||
attr = cv_string_get(cvec_i(argv, 3));
|
if (cvec_len(argv) == 4)
|
||||||
j = 0;
|
namespace = cv_string_get(cvec_i(argv, 3));
|
||||||
for (i=0; i<strlen(xpath); i++)
|
|
||||||
if (xpath[i] == '%')
|
|
||||||
j++;
|
|
||||||
if (j != 1){
|
|
||||||
clicon_err(OE_PLUGIN, 0, "xpath '%s' does not have a single '%%'",
|
|
||||||
xpath);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if ((cvattr = cvec_find(cvv, attr)) == NULL){
|
|
||||||
clicon_err(OE_PLUGIN, 0, "attr '%s' not found in cligen var list", attr);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if ((val = cv2str_dup(cvattr)) == NULL){
|
|
||||||
clicon_err(OE_PLUGIN, errno, "cv2str_dup");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
cprintf(cbxpath, xpath, val);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
cprintf(cbxpath, "%s", xpath);
|
|
||||||
|
|
||||||
if (state == 0){ /* Get configuration-only from database */
|
if (state == 0){ /* Get configuration-only from database */
|
||||||
if (clicon_rpc_get_config(h, db, cbuf_get(cbxpath), &xt) < 0)
|
if (clicon_rpc_get_config(h, db, cbuf_get(cbxpath), namespace, &xt) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else { /* Get configuration and state from database */
|
else { /* Get configuration and state from database */
|
||||||
|
|
@ -475,10 +460,10 @@ cli_show_config1(clicon_handle h,
|
||||||
clicon_err(OE_FATAL, 0, "Show state only for running database, not %s", db);
|
clicon_err(OE_FATAL, 0, "Show state only for running database, not %s", db);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (clicon_rpc_get(h, cbuf_get(cbxpath), &xt) < 0)
|
if (clicon_rpc_get(h, cbuf_get(cbxpath), namespace, &xt) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
|
if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
|
||||||
clicon_rpc_generate_error("Get configuration", xerr);
|
clicon_rpc_generate_error("Get configuration", xerr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -540,9 +525,9 @@ done:
|
||||||
* <dbname> "running"|"candidate"|"startup"
|
* <dbname> "running"|"candidate"|"startup"
|
||||||
* <format> "text"|"xml"|"json"|"cli"|"netconf" (see format_enum)
|
* <format> "text"|"xml"|"json"|"cli"|"netconf" (see format_enum)
|
||||||
* <xpath> xpath expression, that may contain one %, eg "/sender[name="%s"]"
|
* <xpath> xpath expression, that may contain one %, eg "/sender[name="%s"]"
|
||||||
* <varname> optional name of variable in cvv. If set, xpath must have a '%s'
|
* <namespace> If xpath set, the namespace the symbols in xpath belong to (optional)
|
||||||
* @code
|
* @code
|
||||||
* show config id <n:string>, cli_show_config("running","xml","iface[name="%s"]","n");
|
* show config id <n:string>, cli_show_config("running","xml","iface[name='foo']","urn:example:example");
|
||||||
* @endcode
|
* @endcode
|
||||||
* @see cli_show_config_state For config and state data (not only config)
|
* @see cli_show_config_state For config and state data (not only config)
|
||||||
*/
|
*/
|
||||||
|
|
@ -565,7 +550,7 @@ cli_show_config(clicon_handle h,
|
||||||
* <xpath> xpath expression, that may contain one %, eg "/sender[name="%s"]"
|
* <xpath> xpath expression, that may contain one %, eg "/sender[name="%s"]"
|
||||||
* <varname> optional name of variable in cvv. If set, xpath must have a '%s'
|
* <varname> optional name of variable in cvv. If set, xpath must have a '%s'
|
||||||
* @code
|
* @code
|
||||||
* show config id <n:string>, cli_show_config_state("running","xml","iface[name="%s"]","n");
|
* show state id <n:string>, cli_show_config_state("running","xml","iface[name='foo']","urn:example:example");
|
||||||
* @endcode
|
* @endcode
|
||||||
* @see cli_show_config For config-only, no state
|
* @see cli_show_config For config-only, no state
|
||||||
*/
|
*/
|
||||||
|
|
@ -580,9 +565,9 @@ cli_show_config_state(clicon_handle h,
|
||||||
/*! Show configuration as text given an xpath
|
/*! Show configuration as text given an xpath
|
||||||
* Utility function used by cligen spec file
|
* Utility function used by cligen spec file
|
||||||
* @param[in] h CLICON handle
|
* @param[in] h CLICON handle
|
||||||
* @param[in] cvv Vector of variables from CLIgen command-line
|
* @param[in] cvv Vector of variables from CLIgen command-line must contain xpath and ns variables
|
||||||
* @param[in] arg A string: <dbname> <xpath>
|
* @param[in] argv A string: <dbname>
|
||||||
* @note Hardcoded that a variable in cvv is named "xpath"
|
* @note Hardcoded that variable xpath and ns cvv must exist. (kludge)
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
show_conf_xpath(clicon_handle h,
|
show_conf_xpath(clicon_handle h,
|
||||||
|
|
@ -598,6 +583,8 @@ show_conf_xpath(clicon_handle h,
|
||||||
cxobj **xv = NULL;
|
cxobj **xv = NULL;
|
||||||
size_t xlen;
|
size_t xlen;
|
||||||
int i;
|
int i;
|
||||||
|
char *namespace = NULL;
|
||||||
|
cvec *nsc = NULL;
|
||||||
|
|
||||||
if (cvec_len(argv) != 1){
|
if (cvec_len(argv) != 1){
|
||||||
clicon_err(OE_PLUGIN, 0, "Requires one element to be <dbname>");
|
clicon_err(OE_PLUGIN, 0, "Requires one element to be <dbname>");
|
||||||
|
|
@ -611,21 +598,31 @@ show_conf_xpath(clicon_handle h,
|
||||||
clicon_err(OE_PLUGIN, 0, "No such db name: %s", str);
|
clicon_err(OE_PLUGIN, 0, "No such db name: %s", str);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
/* Look for xpath in command (kludge: cv must be called "xpath") */
|
||||||
cv = cvec_find(cvv, "xpath");
|
cv = cvec_find(cvv, "xpath");
|
||||||
xpath = cv_string_get(cv);
|
xpath = cv_string_get(cv);
|
||||||
if (clicon_rpc_get_config(h, str, xpath, &xt) < 0)
|
|
||||||
|
/* Look for namespace in command (kludge: cv must be called "ns") */
|
||||||
|
cv = cvec_find(cvv, "ns");
|
||||||
|
namespace = cv_string_get(cv);
|
||||||
|
|
||||||
|
if (clicon_rpc_get_config(h, str, xpath, namespace, &xt) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
|
if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
|
||||||
clicon_rpc_generate_error("Get configuration", xerr);
|
clicon_rpc_generate_error("Get configuration", xerr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (xpath_vec(xt, "%s", &xv, &xlen, xpath) < 0)
|
if ((nsc = xml_nsctx_init(NULL, namespace)) == NULL)
|
||||||
|
goto done;
|
||||||
|
if (xpath_vec(xt, nsc, "%s", &xv, &xlen, xpath) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
for (i=0; i<xlen; i++)
|
for (i=0; i<xlen; i++)
|
||||||
xml_print(stdout, xv[i]);
|
xml_print(stdout, xv[i]);
|
||||||
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
if (nsc)
|
||||||
|
xml_nsctx_free(nsc);
|
||||||
if (xv)
|
if (xv)
|
||||||
free(xv);
|
free(xv);
|
||||||
if (xt)
|
if (xt)
|
||||||
|
|
@ -641,7 +638,7 @@ int cli_show_version(clicon_handle h,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Generic show configuration CLIGEN callback using generated CLI syntax
|
/*! Generic show configuration CLIgen callback using generated CLI syntax
|
||||||
* @param[in] h CLICON handle
|
* @param[in] h CLICON handle
|
||||||
* @param[in] state If set, show both config and state, otherwise only config
|
* @param[in] state If set, show both config and state, otherwise only config
|
||||||
* @param[in] cvv Vector of variables from CLIgen command-line
|
* @param[in] cvv Vector of variables from CLIgen command-line
|
||||||
|
|
@ -651,6 +648,7 @@ int cli_show_version(clicon_handle h,
|
||||||
* <dbname> "running"|"candidate"|"startup"
|
* <dbname> "running"|"candidate"|"startup"
|
||||||
* <format> "text"|"xml"|"json"|"cli"|"netconf" (see format_enum)
|
* <format> "text"|"xml"|"json"|"cli"|"netconf" (see format_enum)
|
||||||
* @note if state parameter is set, then db must be running
|
* @note if state parameter is set, then db must be running
|
||||||
|
* @note that first argument is generated by code.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
cli_show_auto1(clicon_handle h,
|
cli_show_auto1(clicon_handle h,
|
||||||
|
|
@ -664,12 +662,15 @@ cli_show_auto1(clicon_handle h,
|
||||||
// char *api_path = NULL; /* xml key */
|
// char *api_path = NULL; /* xml key */
|
||||||
char *db;
|
char *db;
|
||||||
char *xpath = NULL;
|
char *xpath = NULL;
|
||||||
|
cvec *nsc = NULL;
|
||||||
char *formatstr;
|
char *formatstr;
|
||||||
enum format_enum format = FORMAT_XML;
|
enum format_enum format = FORMAT_XML;
|
||||||
cxobj *xt = NULL;
|
cxobj *xt = NULL;
|
||||||
cxobj *xp;
|
cxobj *xp;
|
||||||
cxobj *xerr;
|
cxobj *xerr;
|
||||||
enum genmodel_type gt;
|
enum genmodel_type gt;
|
||||||
|
char *namespace = NULL;
|
||||||
|
char *api_path = NULL;
|
||||||
|
|
||||||
if (cvec_len(argv) != 3){
|
if (cvec_len(argv) != 3){
|
||||||
clicon_err(OE_PLUGIN, 0, "Usage: <api-path-fmt>* <database> <format>. (*) generated.");
|
clicon_err(OE_PLUGIN, 0, "Usage: <api-path-fmt>* <database> <format>. (*) generated.");
|
||||||
|
|
@ -689,19 +690,20 @@ cli_show_auto1(clicon_handle h,
|
||||||
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
if (api_path_fmt2api_path(api_path_fmt, cvv, &api_path) < 0)
|
||||||
// if (api_path_fmt2api_path(api_path_fmt, cvv, &api_path) < 0)
|
goto done;
|
||||||
// goto done;
|
if (api_path2xpath(api_path, yspec, &xpath, &namespace) < 0)
|
||||||
if (api_path_fmt2xpath(api_path_fmt, cvv, &xpath) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
/* XXX Kludge to overcome a trailing / in show, that I cannot add to
|
/* XXX Kludge to overcome a trailing / in show, that I cannot add to
|
||||||
* yang2api_path_fmt_1 where it should belong.
|
* yang2api_path_fmt_1 where it should belong.
|
||||||
*/
|
*/
|
||||||
if (xpath[strlen(xpath)-1] == '/')
|
if (xpath[strlen(xpath)-1] == '/')
|
||||||
xpath[strlen(xpath)-1] = '\0';
|
xpath[strlen(xpath)-1] = '\0';
|
||||||
|
if ((nsc = xml_nsctx_init(NULL, namespace)) == NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
if (state == 0){ /* Get configuration-only from database */
|
if (state == 0){ /* Get configuration-only from database */
|
||||||
if (clicon_rpc_get_config(h, db, xpath, &xt) < 0)
|
if (clicon_rpc_get_config(h, db, xpath, namespace, &xt) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else{ /* Get configuration and state from database */
|
else{ /* Get configuration and state from database */
|
||||||
|
|
@ -709,15 +711,15 @@ cli_show_auto1(clicon_handle h,
|
||||||
clicon_err(OE_FATAL, 0, "Show state only for running database, not %s", db);
|
clicon_err(OE_FATAL, 0, "Show state only for running database, not %s", db);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (clicon_rpc_get(h, xpath, &xt) < 0)
|
if (clicon_rpc_get(h, xpath, namespace, &xt) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
|
if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
|
||||||
clicon_rpc_generate_error("Get configuration", xerr);
|
clicon_rpc_generate_error("Get configuration", xerr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((xp = xpath_first(xt, "%s", xpath)) != NULL)
|
if ((xp = xpath_first(xt, nsc, "%s", xpath)) != NULL)
|
||||||
/* Print configuration according to format */
|
/* Print configuration according to format */
|
||||||
switch (format){
|
switch (format){
|
||||||
case FORMAT_XML:
|
case FORMAT_XML:
|
||||||
|
|
@ -744,6 +746,10 @@ cli_show_auto1(clicon_handle h,
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
if (nsc)
|
||||||
|
xml_nsctx_free(nsc);
|
||||||
|
if (api_path)
|
||||||
|
free(api_path);
|
||||||
if (xpath)
|
if (xpath)
|
||||||
free(xpath);
|
free(xpath);
|
||||||
if (xt)
|
if (xt)
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ netconf_hello_dispatch(cxobj *xn)
|
||||||
cxobj *xp;
|
cxobj *xp;
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
||||||
if ((xp = xpath_first(xn, "//hello")) != NULL)
|
if ((xp = xpath_first(xn, NULL, "//hello")) != NULL)
|
||||||
retval = netconf_hello(xp);
|
retval = netconf_hello(xp);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -164,14 +164,14 @@ netconf_get_target(cxobj *xn,
|
||||||
cxobj *x;
|
cxobj *x;
|
||||||
char *target = NULL;
|
char *target = NULL;
|
||||||
|
|
||||||
if ((x = xpath_first(xn, "%s", path)) != NULL){
|
if ((x = xpath_first(xn, NULL, "%s", path)) != NULL){
|
||||||
if (xpath_first(x, "candidate") != NULL)
|
if (xpath_first(x, NULL, "candidate") != NULL)
|
||||||
target = "candidate";
|
target = "candidate";
|
||||||
else
|
else
|
||||||
if (xpath_first(x, "running") != NULL)
|
if (xpath_first(x, NULL, "running") != NULL)
|
||||||
target = "running";
|
target = "running";
|
||||||
else
|
else
|
||||||
if (xpath_first(x, "startup") != NULL)
|
if (xpath_first(x, NULL, "startup") != NULL)
|
||||||
target = "startup";
|
target = "startup";
|
||||||
}
|
}
|
||||||
return target;
|
return target;
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ netconf_input_packet(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
free(str0);
|
free(str0);
|
||||||
if ((xrpc=xpath_first(xreq, "//rpc")) != NULL){
|
if ((xrpc=xpath_first(xreq, NULL, "//rpc")) != NULL){
|
||||||
isrpc++;
|
isrpc++;
|
||||||
if (xml_spec_populate_rpc(h, xrpc, yspec) < 0)
|
if (xml_spec_populate_rpc(h, xrpc, yspec) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -134,7 +134,7 @@ netconf_input_packet(clicon_handle h,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (xpath_first(xreq, "//hello") != NULL)
|
if (xpath_first(xreq, NULL, "//hello") != NULL)
|
||||||
;
|
;
|
||||||
else{
|
else{
|
||||||
clicon_log(LOG_WARNING, "Invalid netconf msg: neither rpc or hello: dropped");
|
clicon_log(LOG_WARNING, "Invalid netconf msg: neither rpc or hello: dropped");
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,7 @@ netconf_get_config(clicon_handle h,
|
||||||
cxobj *xconf;
|
cxobj *xconf;
|
||||||
|
|
||||||
/* ie <filter>...</filter> */
|
/* ie <filter>...</filter> */
|
||||||
if ((xfilter = xpath_first(xn, "filter")) != NULL)
|
if ((xfilter = xpath_first(xn, NULL, "filter")) != NULL)
|
||||||
ftype = xml_find_value(xfilter, "type");
|
ftype = xml_find_value(xfilter, "type");
|
||||||
if (ftype == NULL || strcmp(ftype, "xpath")==0){
|
if (ftype == NULL || strcmp(ftype, "xpath")==0){
|
||||||
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
|
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
|
||||||
|
|
@ -154,8 +154,8 @@ netconf_get_config(clicon_handle h,
|
||||||
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
|
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (xfilter &&
|
if (xfilter &&
|
||||||
(xfilterconf = xpath_first(xfilter, "//configuration"))!= NULL &&
|
(xfilterconf = xpath_first(xfilter, NULL, "//configuration"))!= NULL &&
|
||||||
(xconf = xpath_first(*xret, "/rpc-reply/data")) != NULL){
|
(xconf = xpath_first(*xret, NULL, "/rpc-reply/data")) != NULL){
|
||||||
/* xml_filter removes parts of xml tree not matching */
|
/* xml_filter removes parts of xml tree not matching */
|
||||||
if ((strcmp(xml_name(xfilterconf), xml_name(xconf))!=0) ||
|
if ((strcmp(xml_name(xfilterconf), xml_name(xconf))!=0) ||
|
||||||
xml_filter(xfilterconf, xconf) < 0){
|
xml_filter(xfilterconf, xconf) < 0){
|
||||||
|
|
@ -208,7 +208,7 @@ get_edit_opts(cxobj *xn,
|
||||||
cxobj *x;
|
cxobj *x;
|
||||||
char *optstr;
|
char *optstr;
|
||||||
|
|
||||||
if ((x = xpath_first(xn, "test-option")) != NULL){
|
if ((x = xpath_first(xn, NULL, "test-option")) != NULL){
|
||||||
if ((optstr = xml_body(x)) != NULL){
|
if ((optstr = xml_body(x)) != NULL){
|
||||||
if (strcmp(optstr, "test-then-set") == 0)
|
if (strcmp(optstr, "test-then-set") == 0)
|
||||||
*testopt = TEST_THEN_SET;
|
*testopt = TEST_THEN_SET;
|
||||||
|
|
@ -220,7 +220,7 @@ get_edit_opts(cxobj *xn,
|
||||||
goto parerr;
|
goto parerr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((x = xpath_first(xn, "error-option")) != NULL){
|
if ((x = xpath_first(xn, NULL, "error-option")) != NULL){
|
||||||
if ((optstr = xml_body(x)) != NULL){
|
if ((optstr = xml_body(x)) != NULL){
|
||||||
if (strcmp(optstr, "stop-on-error") == 0)
|
if (strcmp(optstr, "stop-on-error") == 0)
|
||||||
*erropt = STOP_ON_ERROR;
|
*erropt = STOP_ON_ERROR;
|
||||||
|
|
@ -352,7 +352,7 @@ netconf_get(clicon_handle h,
|
||||||
cxobj *xconf;
|
cxobj *xconf;
|
||||||
|
|
||||||
/* ie <filter>...</filter> */
|
/* ie <filter>...</filter> */
|
||||||
if ((xfilter = xpath_first(xn, "filter")) != NULL)
|
if ((xfilter = xpath_first(xn, NULL, "filter")) != NULL)
|
||||||
ftype = xml_find_value(xfilter, "type");
|
ftype = xml_find_value(xfilter, "type");
|
||||||
if (ftype == NULL || strcmp(ftype, "xpath")==0){
|
if (ftype == NULL || strcmp(ftype, "xpath")==0){
|
||||||
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
|
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
|
||||||
|
|
@ -366,8 +366,8 @@ netconf_get(clicon_handle h,
|
||||||
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
|
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (xfilter &&
|
if (xfilter &&
|
||||||
(xfilterconf = xpath_first(xfilter, "//configuration"))!= NULL &&
|
(xfilterconf = xpath_first(xfilter, NULL, "//configuration"))!= NULL &&
|
||||||
(xconf = xpath_first(*xret, "/rpc-reply/data")) != NULL){
|
(xconf = xpath_first(*xret, NULL, "/rpc-reply/data")) != NULL){
|
||||||
/* xml_filter removes parts of xml tree not matching */
|
/* xml_filter removes parts of xml tree not matching */
|
||||||
if ((strcmp(xml_name(xfilterconf), xml_name(xconf))!=0) ||
|
if ((strcmp(xml_name(xfilterconf), xml_name(xconf))!=0) ||
|
||||||
xml_filter(xfilterconf, xconf) < 0){
|
xml_filter(xfilterconf, xconf) < 0){
|
||||||
|
|
@ -428,6 +428,7 @@ netconf_notification_cb(int s,
|
||||||
cxobj *xt = NULL; /* top xml */
|
cxobj *xt = NULL; /* top xml */
|
||||||
clicon_handle h = (clicon_handle)arg;
|
clicon_handle h = (clicon_handle)arg;
|
||||||
yang_stmt *yspec = NULL;
|
yang_stmt *yspec = NULL;
|
||||||
|
cvec *nsc = NULL;
|
||||||
|
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
/* get msg (this is the reason this function is called) */
|
/* get msg (this is the reason this function is called) */
|
||||||
|
|
@ -444,7 +445,10 @@ netconf_notification_cb(int s,
|
||||||
yspec = clicon_dbspec_yang(h);
|
yspec = clicon_dbspec_yang(h);
|
||||||
if (clicon_msg_decode(reply, yspec, &xt) < 0)
|
if (clicon_msg_decode(reply, yspec, &xt) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xn = xpath_first(xt, "notification")) == NULL)
|
|
||||||
|
if ((nsc = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:netconf:notification:1.0")) == NULL)
|
||||||
|
goto done;
|
||||||
|
if ((xn = xpath_first(xt, nsc, "notification")) == NULL)
|
||||||
goto ok;
|
goto ok;
|
||||||
/* create netconf message */
|
/* create netconf message */
|
||||||
if ((cb = cbuf_new()) == NULL){
|
if ((cb = cbuf_new()) == NULL){
|
||||||
|
|
@ -460,9 +464,11 @@ netconf_notification_cb(int s,
|
||||||
}
|
}
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
cbuf_free(cb);
|
cbuf_free(cb);
|
||||||
ok:
|
ok:
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
if (nsc)
|
||||||
|
xml_nsctx_free(nsc);
|
||||||
if (xt != NULL)
|
if (xt != NULL)
|
||||||
xml_free(xt);
|
xml_free(xt);
|
||||||
if (reply)
|
if (reply)
|
||||||
|
|
@ -494,7 +500,7 @@ netconf_create_subscription(clicon_handle h,
|
||||||
int s;
|
int s;
|
||||||
char *ftype;
|
char *ftype;
|
||||||
|
|
||||||
if ((xfilter = xpath_first(xn, "//filter")) != NULL){
|
if ((xfilter = xpath_first(xn, NULL, "//filter")) != NULL){
|
||||||
if ((ftype = xml_find_value(xfilter, "type")) != NULL){
|
if ((ftype = xml_find_value(xfilter, "type")) != NULL){
|
||||||
if (strcmp(ftype, "xpath") != 0){
|
if (strcmp(ftype, "xpath") != 0){
|
||||||
xml_parse_va(xret, NULL, "<rpc-reply><rpc-error>"
|
xml_parse_va(xret, NULL, "<rpc-reply><rpc-error>"
|
||||||
|
|
@ -510,7 +516,7 @@ netconf_create_subscription(clicon_handle h,
|
||||||
}
|
}
|
||||||
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, &s) < 0)
|
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, &s) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (xpath_first(*xret, "rpc-reply/rpc-error") != NULL)
|
if (xpath_first(*xret, NULL, "rpc-reply/rpc-error") != NULL)
|
||||||
goto ok;
|
goto ok;
|
||||||
if (event_reg_fd(s,
|
if (event_reg_fd(s,
|
||||||
netconf_notification_cb,
|
netconf_notification_cb,
|
||||||
|
|
@ -616,7 +622,7 @@ netconf_application_rpc(clicon_handle h,
|
||||||
*/
|
*/
|
||||||
if (0)
|
if (0)
|
||||||
if ((youtput = yang_find(yrpc, Y_OUTPUT, NULL)) != NULL){
|
if ((youtput = yang_find(yrpc, Y_OUTPUT, NULL)) != NULL){
|
||||||
xoutput=xpath_first(*xret, "/");
|
xoutput=xpath_first(*xret, NULL, "/");
|
||||||
xml_spec_set(xoutput, youtput); /* needed for xml_spec_populate */
|
xml_spec_set(xoutput, youtput); /* needed for xml_spec_populate */
|
||||||
if (xml_apply(xoutput, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
if (xml_apply(xoutput, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -412,7 +412,7 @@ api_return_err(clicon_handle h,
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
if ((cb = cbuf_new()) == NULL)
|
if ((cb = cbuf_new()) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xtag = xpath_first(xerr, "//error-tag")) == NULL){
|
if ((xtag = xpath_first(xerr, NULL, "//error-tag")) == NULL){
|
||||||
notfound(r);
|
notfound(r);
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -396,7 +396,7 @@ api_restconf(clicon_handle h,
|
||||||
else{
|
else{
|
||||||
if (netconf_access_denied_xml(&xret, "protocol", "The requested URL was unauthorized") < 0)
|
if (netconf_access_denied_xml(&xret, "protocol", "The requested URL was unauthorized") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto ok;
|
goto ok;
|
||||||
|
|
|
||||||
|
|
@ -186,7 +186,7 @@ api_data_get2(clicon_handle h,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cbuf *cbpath = NULL;
|
cbuf *cbpath = NULL;
|
||||||
char *path;
|
char *xpath = NULL;
|
||||||
cbuf *cbx = NULL;
|
cbuf *cbx = NULL;
|
||||||
yang_stmt *yspec;
|
yang_stmt *yspec;
|
||||||
cxobj *xret = NULL;
|
cxobj *xret = NULL;
|
||||||
|
|
@ -197,6 +197,8 @@ api_data_get2(clicon_handle h,
|
||||||
int i;
|
int i;
|
||||||
cxobj *x;
|
cxobj *x;
|
||||||
int ret;
|
int ret;
|
||||||
|
char *namespace = NULL;
|
||||||
|
cvec *nsc = NULL;
|
||||||
|
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
yspec = clicon_dbspec_yang(h);
|
yspec = clicon_dbspec_yang(h);
|
||||||
|
|
@ -204,13 +206,13 @@ api_data_get2(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
cprintf(cbpath, "/");
|
cprintf(cbpath, "/");
|
||||||
/* We know "data" is element pi-1 */
|
/* We know "data" is element pi-1 */
|
||||||
if ((ret = api_path2xpath(yspec, pcvec, pi, cbpath)) < 0)
|
if ((ret = api_path2xpath_cvv(pcvec, pi, yspec, cbpath, &namespace)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0){
|
if (ret == 0){
|
||||||
if (netconf_operation_failed_xml(&xerr, "protocol", clicon_err_reason) < 0)
|
if (netconf_operation_failed_xml(&xerr, "protocol", clicon_err_reason) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
clicon_err_reset();
|
clicon_err_reset();
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -218,12 +220,16 @@ api_data_get2(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
path = cbuf_get(cbpath);
|
xpath = cbuf_get(cbpath);
|
||||||
clicon_debug(1, "%s path:%s", __FUNCTION__, path);
|
clicon_debug(1, "%s path:%s", __FUNCTION__, xpath);
|
||||||
if (clicon_rpc_get(h, path, &xret) < 0){
|
/* Create a namespace context for ymod as the default namespace to use with
|
||||||
|
* xpath expressions */
|
||||||
|
if ((nsc = xml_nsctx_init(NULL, namespace)) == NULL)
|
||||||
|
goto done;
|
||||||
|
if (clicon_rpc_get(h, xpath, namespace, &xret) < 0){
|
||||||
if (netconf_operation_failed_xml(&xerr, "protocol", clicon_err_reason) < 0)
|
if (netconf_operation_failed_xml(&xerr, "protocol", clicon_err_reason) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -245,7 +251,7 @@ api_data_get2(clicon_handle h,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/* Check if error return */
|
/* Check if error return */
|
||||||
if ((xe = xpath_first(xret, "//rpc-error")) != NULL){
|
if ((xe = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto ok;
|
goto ok;
|
||||||
|
|
@ -259,7 +265,7 @@ api_data_get2(clicon_handle h,
|
||||||
FCGX_FPrintF(r->out, "\r\n");
|
FCGX_FPrintF(r->out, "\r\n");
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
if (path==NULL || strcmp(path,"/")==0){ /* Special case: data root */
|
if (xpath==NULL || strcmp(xpath,"/")==0){ /* Special case: data root */
|
||||||
if (use_xml){
|
if (use_xml){
|
||||||
if (clicon_xml2cbuf(cbx, xret, 0, pretty) < 0) /* Dont print top object? */
|
if (clicon_xml2cbuf(cbx, xret, 0, pretty) < 0) /* Dont print top object? */
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -270,10 +276,10 @@ api_data_get2(clicon_handle h,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
if (xpath_vec(xret, "%s", &xvec, &xlen, path) < 0){
|
if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, xpath) < 0){
|
||||||
if (netconf_operation_failed_xml(&xerr, "application", clicon_err_reason) < 0)
|
if (netconf_operation_failed_xml(&xerr, "application", clicon_err_reason) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -283,14 +289,14 @@ api_data_get2(clicon_handle h,
|
||||||
}
|
}
|
||||||
if (use_xml){
|
if (use_xml){
|
||||||
for (i=0; i<xlen; i++){
|
for (i=0; i<xlen; i++){
|
||||||
char *prefix, *namespace;
|
char *prefix, *namespace2; /* Same as namespace? */
|
||||||
x = xvec[i];
|
x = xvec[i];
|
||||||
/* Some complexities in grafting namespace in existing trees to new */
|
/* Some complexities in grafting namespace in existing trees to new */
|
||||||
prefix = xml_prefix(x);
|
prefix = xml_prefix(x);
|
||||||
if (xml_find_type_value(x, prefix, "xmlns", CX_ATTR) == NULL){
|
if (xml_find_type_value(x, prefix, "xmlns", CX_ATTR) == NULL){
|
||||||
if (xml2ns(x, prefix, &namespace) < 0)
|
if (xml2ns(x, prefix, &namespace2) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (namespace && xmlns_set(x, prefix, namespace) < 0)
|
if (namespace2 && xmlns_set(x, prefix, namespace2) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (clicon_xml2cbuf(cbx, x, 0, pretty) < 0) /* Dont print top object? */
|
if (clicon_xml2cbuf(cbx, x, 0, pretty) < 0) /* Dont print top object? */
|
||||||
|
|
@ -315,6 +321,8 @@ api_data_get2(clicon_handle h,
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||||
|
if (nsc)
|
||||||
|
xml_nsctx_free(nsc);
|
||||||
if (cbx)
|
if (cbx)
|
||||||
cbuf_free(cbx);
|
cbuf_free(cbx);
|
||||||
if (cbpath)
|
if (cbpath)
|
||||||
|
|
@ -483,7 +491,7 @@ api_data_post(clicon_handle h,
|
||||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
clicon_err_reset();
|
clicon_err_reset();
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -497,7 +505,7 @@ api_data_post(clicon_handle h,
|
||||||
if (xml_parse_string(data, NULL, &xdata0) < 0){
|
if (xml_parse_string(data, NULL, &xdata0) < 0){
|
||||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -510,7 +518,7 @@ api_data_post(clicon_handle h,
|
||||||
if ((ret = json_parse_str(data, yspec, &xdata0, &xerr)) < 0){
|
if ((ret = json_parse_str(data, yspec, &xdata0, &xerr)) < 0){
|
||||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -519,7 +527,7 @@ api_data_post(clicon_handle h,
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
if (ret == 0){
|
if (ret == 0){
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -534,7 +542,7 @@ api_data_post(clicon_handle h,
|
||||||
if (xml_child_nr(xdata0) != 1){
|
if (xml_child_nr(xdata0) != 1){
|
||||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -556,7 +564,7 @@ api_data_post(clicon_handle h,
|
||||||
if (ymoddata != ymodapi){
|
if (ymoddata != ymodapi){
|
||||||
if (netconf_malformed_message_xml(&xerr, "Data is not prefixed with matching namespace") < 0)
|
if (netconf_malformed_message_xml(&xerr, "Data is not prefixed with matching namespace") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -598,7 +606,7 @@ api_data_post(clicon_handle h,
|
||||||
clicon_debug(1, "%s xml: %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_netconf(h, cbuf_get(cbx), &xret, NULL) < 0)
|
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xret, "//rpc-error")) != NULL){
|
if ((xe = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto ok;
|
goto ok;
|
||||||
|
|
@ -612,14 +620,14 @@ api_data_post(clicon_handle h,
|
||||||
cprintf(cbx, "<commit/></rpc>");
|
cprintf(cbx, "<commit/></rpc>");
|
||||||
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
|
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){
|
if ((xe = xpath_first(xretcom, NULL, "//rpc-error")) != NULL){
|
||||||
cbuf_reset(cbx);
|
cbuf_reset(cbx);
|
||||||
cprintf(cbx, "<rpc username=\"%s\">", username?username:"");
|
cprintf(cbx, "<rpc username=\"%s\">", username?username:"");
|
||||||
cprintf(cbx, "<discard-changes/></rpc>");
|
cprintf(cbx, "<discard-changes/></rpc>");
|
||||||
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretdis, NULL) < 0)
|
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretdis, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* log errors from discard, but ignore */
|
/* log errors from discard, but ignore */
|
||||||
if ((xpath_first(xretdis, "//rpc-error")) != NULL)
|
if ((xpath_first(xretdis, NULL, "//rpc-error")) != NULL)
|
||||||
clicon_log(LOG_WARNING, "%s: discard-changes failed which may lead candidate in an inconsistent state", __FUNCTION__);
|
clicon_log(LOG_WARNING, "%s: discard-changes failed which may lead candidate in an inconsistent state", __FUNCTION__);
|
||||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0) /* Use original xe */
|
if (api_return_err(h, r, xe, pretty, use_xml) < 0) /* Use original xe */
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -642,7 +650,7 @@ api_data_post(clicon_handle h,
|
||||||
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
|
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* If copy-config failed, log and ignore (already committed) */
|
/* If copy-config failed, log and ignore (already committed) */
|
||||||
if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){
|
if ((xe = xpath_first(xretcom, NULL, "//rpc-error")) != NULL){
|
||||||
|
|
||||||
clicon_log(LOG_WARNING, "%s: copy-config running->startup failed", __FUNCTION__);
|
clicon_log(LOG_WARNING, "%s: copy-config running->startup failed", __FUNCTION__);
|
||||||
}
|
}
|
||||||
|
|
@ -831,7 +839,7 @@ api_data_put(clicon_handle h,
|
||||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
clicon_err_reset();
|
clicon_err_reset();
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -846,7 +854,7 @@ api_data_put(clicon_handle h,
|
||||||
if (xml_parse_string(data, yspec, &xdata0) < 0){
|
if (xml_parse_string(data, yspec, &xdata0) < 0){
|
||||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -859,7 +867,7 @@ api_data_put(clicon_handle h,
|
||||||
if ((ret = json_parse_str(data, yspec, &xdata0, &xerr)) < 0){
|
if ((ret = json_parse_str(data, yspec, &xdata0, &xerr)) < 0){
|
||||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -868,7 +876,7 @@ api_data_put(clicon_handle h,
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
if (ret == 0){
|
if (ret == 0){
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -883,7 +891,7 @@ api_data_put(clicon_handle h,
|
||||||
if (xml_child_nr(xdata0) != 1){
|
if (xml_child_nr(xdata0) != 1){
|
||||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -903,7 +911,7 @@ api_data_put(clicon_handle h,
|
||||||
if (ymoddata != ymodapi){
|
if (ymoddata != ymodapi){
|
||||||
if (netconf_malformed_message_xml(&xerr, "Data is not prefixed with matching namespace") < 0)
|
if (netconf_malformed_message_xml(&xerr, "Data is not prefixed with matching namespace") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -943,7 +951,7 @@ api_data_put(clicon_handle h,
|
||||||
if (strcmp(dname, xml_name(xbot))){
|
if (strcmp(dname, xml_name(xbot))){
|
||||||
if (netconf_operation_failed_xml(&xerr, "protocol", "Not same symbol in api-path as data") < 0)
|
if (netconf_operation_failed_xml(&xerr, "protocol", "Not same symbol in api-path as data") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -968,7 +976,7 @@ api_data_put(clicon_handle h,
|
||||||
if (match_list_keys(ybot, xdata, xbot) < 0){
|
if (match_list_keys(ybot, xdata, xbot) < 0){
|
||||||
if (netconf_operation_failed_xml(&xerr, "protocol", "api-path keys do not match data keys") < 0)
|
if (netconf_operation_failed_xml(&xerr, "protocol", "api-path keys do not match data keys") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -992,7 +1000,7 @@ api_data_put(clicon_handle h,
|
||||||
if (parbod == NULL || strcmp(parbod, xml_body(xdata))){
|
if (parbod == NULL || strcmp(parbod, xml_body(xdata))){
|
||||||
if (netconf_operation_failed_xml(&xerr, "protocol", "api-path keys do not match data keys") < 0)
|
if (netconf_operation_failed_xml(&xerr, "protocol", "api-path keys do not match data keys") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -1032,7 +1040,7 @@ api_data_put(clicon_handle h,
|
||||||
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0)
|
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if ((xe = xpath_first(xret, "//rpc-error")) != NULL){
|
if ((xe = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto ok;
|
goto ok;
|
||||||
|
|
@ -1045,14 +1053,14 @@ api_data_put(clicon_handle h,
|
||||||
cprintf(cbx, "<commit/></rpc>");
|
cprintf(cbx, "<commit/></rpc>");
|
||||||
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
|
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){
|
if ((xe = xpath_first(xretcom, NULL, "//rpc-error")) != NULL){
|
||||||
cbuf_reset(cbx);
|
cbuf_reset(cbx);
|
||||||
cprintf(cbx, "<rpc username=\"%s\">", username?username:"");
|
cprintf(cbx, "<rpc username=\"%s\">", username?username:"");
|
||||||
cprintf(cbx, "<discard-changes/></rpc>");
|
cprintf(cbx, "<discard-changes/></rpc>");
|
||||||
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretdis, NULL) < 0)
|
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretdis, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* log errors from discard, but ignore */
|
/* log errors from discard, but ignore */
|
||||||
if ((xpath_first(xretdis, "//rpc-error")) != NULL)
|
if ((xpath_first(xretdis, NULL, "//rpc-error")) != NULL)
|
||||||
clicon_log(LOG_WARNING, "%s: discard-changes failed which may lead candidate in an inconsistent state", __FUNCTION__);
|
clicon_log(LOG_WARNING, "%s: discard-changes failed which may lead candidate in an inconsistent state", __FUNCTION__);
|
||||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -1075,7 +1083,7 @@ api_data_put(clicon_handle h,
|
||||||
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
|
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* If copy-config failed, log and ignore (already committed) */
|
/* If copy-config failed, log and ignore (already committed) */
|
||||||
if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){
|
if ((xe = xpath_first(xretcom, NULL, "//rpc-error")) != NULL){
|
||||||
|
|
||||||
clicon_log(LOG_WARNING, "%s: copy-config running->startup failed", __FUNCTION__);
|
clicon_log(LOG_WARNING, "%s: copy-config running->startup failed", __FUNCTION__);
|
||||||
}
|
}
|
||||||
|
|
@ -1183,7 +1191,7 @@ api_data_delete(clicon_handle h,
|
||||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
clicon_err_reset();
|
clicon_err_reset();
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -1210,7 +1218,7 @@ api_data_delete(clicon_handle h,
|
||||||
cprintf(cbx, "</edit-config></rpc>");
|
cprintf(cbx, "</edit-config></rpc>");
|
||||||
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0)
|
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xret, "//rpc-error")) != NULL){
|
if ((xe = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto ok;
|
goto ok;
|
||||||
|
|
@ -1224,14 +1232,14 @@ api_data_delete(clicon_handle h,
|
||||||
cprintf(cbx, "<commit/></rpc>");
|
cprintf(cbx, "<commit/></rpc>");
|
||||||
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
|
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){
|
if ((xe = xpath_first(xretcom, NULL, "//rpc-error")) != NULL){
|
||||||
cbuf_reset(cbx);
|
cbuf_reset(cbx);
|
||||||
cprintf(cbx, "<rpc username=\"%s\">", NACM_RECOVERY_USER);
|
cprintf(cbx, "<rpc username=\"%s\">", NACM_RECOVERY_USER);
|
||||||
cprintf(cbx, "<discard-changes/></rpc>");
|
cprintf(cbx, "<discard-changes/></rpc>");
|
||||||
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretdis, NULL) < 0)
|
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretdis, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* log errors from discard, but ignore */
|
/* log errors from discard, but ignore */
|
||||||
if ((xpath_first(xretdis, "//rpc-error")) != NULL)
|
if ((xpath_first(xretdis, NULL, "//rpc-error")) != NULL)
|
||||||
clicon_log(LOG_WARNING, "%s: discard-changes failed which may lead candidate in an inconsistent state", __FUNCTION__);
|
clicon_log(LOG_WARNING, "%s: discard-changes failed which may lead candidate in an inconsistent state", __FUNCTION__);
|
||||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -1254,7 +1262,7 @@ api_data_delete(clicon_handle h,
|
||||||
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
|
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* If copy-config failed, log and ignore (already committed) */
|
/* If copy-config failed, log and ignore (already committed) */
|
||||||
if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){
|
if ((xe = xpath_first(xretcom, NULL, "//rpc-error")) != NULL){
|
||||||
|
|
||||||
clicon_log(LOG_WARNING, "%s: copy-config running->startup failed", __FUNCTION__);
|
clicon_log(LOG_WARNING, "%s: copy-config running->startup failed", __FUNCTION__);
|
||||||
}
|
}
|
||||||
|
|
@ -1421,7 +1429,7 @@ api_operations_post_input(clicon_handle h,
|
||||||
if (xml_parse_string(data, yspec, &xdata) < 0){
|
if (xml_parse_string(data, yspec, &xdata) < 0){
|
||||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -1434,7 +1442,7 @@ api_operations_post_input(clicon_handle h,
|
||||||
if ((ret = json_parse_str(data, yspec, &xdata, &xerr)) < 0){
|
if ((ret = json_parse_str(data, yspec, &xdata, &xerr)) < 0){
|
||||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -1443,7 +1451,7 @@ api_operations_post_input(clicon_handle h,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (ret == 0){
|
if (ret == 0){
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -1476,7 +1484,7 @@ api_operations_post_input(clicon_handle h,
|
||||||
else
|
else
|
||||||
if (netconf_malformed_message_xml(&xerr, "restconf RPC has malformed input statement (multiple or not called input)") < 0)
|
if (netconf_malformed_message_xml(&xerr, "restconf RPC has malformed input statement (multiple or not called input)") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -1550,7 +1558,7 @@ api_operations_post_output(clicon_handle h,
|
||||||
xml_child_nr_type(xret, CX_ELMNT) != 1){
|
xml_child_nr_type(xret, CX_ELMNT) != 1){
|
||||||
if (netconf_malformed_message_xml(&xerr, "restconf RPC does not have single input") < 0)
|
if (netconf_malformed_message_xml(&xerr, "restconf RPC does not have single input") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -1587,7 +1595,7 @@ api_operations_post_output(clicon_handle h,
|
||||||
(ret = xml_yang_validate_add(h, xoutput, &xerr)) < 0)
|
(ret = xml_yang_validate_add(h, xoutput, &xerr)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0){ /* validation failed */
|
if (ret == 0){ /* validation failed */
|
||||||
if ((xe = xpath_first(xerr, "rpc-reply/rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, NULL, "rpc-reply/rpc-error")) == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -1720,7 +1728,7 @@ api_operations_post(clicon_handle h,
|
||||||
if (oppath == NULL || strcmp(oppath,"/")==0){
|
if (oppath == NULL || strcmp(oppath,"/")==0){
|
||||||
if (netconf_operation_failed_xml(&xerr, "protocol", "Operation name expected") < 0)
|
if (netconf_operation_failed_xml(&xerr, "protocol", "Operation name expected") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -1739,7 +1747,7 @@ api_operations_post(clicon_handle h,
|
||||||
if ((ys = yang_find(yspec, Y_MODULE, prefix)) == NULL){
|
if ((ys = yang_find(yspec, Y_MODULE, prefix)) == NULL){
|
||||||
if (netconf_operation_failed_xml(&xerr, "protocol", "yang module not found") < 0)
|
if (netconf_operation_failed_xml(&xerr, "protocol", "yang module not found") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -1750,7 +1758,7 @@ api_operations_post(clicon_handle h,
|
||||||
if ((yrpc = yang_find(ys, Y_RPC, id)) == NULL){
|
if ((yrpc = yang_find(ys, Y_RPC, id)) == NULL){
|
||||||
if (netconf_missing_element_xml(&xerr, "application", id, "RPC not defined") < 0)
|
if (netconf_missing_element_xml(&xerr, "application", id, "RPC not defined") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -1779,7 +1787,7 @@ api_operations_post(clicon_handle h,
|
||||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
clicon_err_reset();
|
clicon_err_reset();
|
||||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -1819,7 +1827,7 @@ api_operations_post(clicon_handle h,
|
||||||
if ((ret = xml_yang_validate_rpc(h, xtop, &xret)) < 0)
|
if ((ret = xml_yang_validate_rpc(h, xtop, &xret)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0){
|
if (ret == 0){
|
||||||
if ((xe = xpath_first(xret, "rpc-error")) == NULL){
|
if ((xe = xpath_first(xret, NULL, "rpc-error")) == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
|
|
@ -1851,7 +1859,7 @@ api_operations_post(clicon_handle h,
|
||||||
if (xml_parse_string(cbuf_get(cbret), NULL, &xret) < 0)
|
if (xml_parse_string(cbuf_get(cbret), NULL, &xret) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Local error: return it and quit */
|
/* Local error: return it and quit */
|
||||||
if ((xe = xpath_first(xret, "rpc-reply/rpc-error")) != NULL){
|
if ((xe = xpath_first(xret, NULL, "rpc-reply/rpc-error")) != NULL){
|
||||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto ok;
|
goto ok;
|
||||||
|
|
@ -1860,7 +1868,7 @@ api_operations_post(clicon_handle h,
|
||||||
else { /* Send to backend */
|
else { /* Send to backend */
|
||||||
if (clicon_rpc_netconf_xml(h, xtop, &xret, NULL) < 0)
|
if (clicon_rpc_netconf_xml(h, xtop, &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xret, "rpc-reply/rpc-error")) != NULL){
|
if ((xe = xpath_first(xret, NULL, "rpc-reply/rpc-error")) != NULL){
|
||||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto ok;
|
goto ok;
|
||||||
|
|
|
||||||
|
|
@ -187,11 +187,11 @@ restconf_stream_cb(int s,
|
||||||
clicon_err(OE_PLUGIN, errno, "cbuf_new");
|
clicon_err(OE_PLUGIN, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((xn = xpath_first(xtop, "notification")) == NULL)
|
if ((xn = xpath_first(xtop, NULL, "notification")) == NULL)
|
||||||
goto ok;
|
goto ok;
|
||||||
#ifdef notused
|
#ifdef notused
|
||||||
xt = xpath_first(xn, "eventTime");
|
xt = xpath_first(xn, NULL, "eventTime");
|
||||||
if ((xe = xpath_first(xn, "event")) == NULL) /* event can depend on yang? */
|
if ((xe = xpath_first(xn, NULL, "event")) == NULL) /* event can depend on yang? */
|
||||||
goto ok;
|
goto ok;
|
||||||
|
|
||||||
if (xt)
|
if (xt)
|
||||||
|
|
@ -268,7 +268,7 @@ restconf_stream(clicon_handle h,
|
||||||
cprintf(cb, "</create-subscription></rpc>]]>]]>");
|
cprintf(cb, "</create-subscription></rpc>]]>]]>");
|
||||||
if (clicon_rpc_netconf(h, cbuf_get(cb), &xret, &s) < 0)
|
if (clicon_rpc_netconf(h, cbuf_get(cb), &xret, &s) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xe = xpath_first(xret, "rpc-reply/rpc-error")) != NULL){
|
if ((xe = xpath_first(xret, NULL, "rpc-reply/rpc-error")) != NULL){
|
||||||
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto ok;
|
goto ok;
|
||||||
|
|
@ -416,7 +416,7 @@ api_stream(clicon_handle h,
|
||||||
else{
|
else{
|
||||||
if (netconf_access_denied_xml(&xret, "protocol", "The requested URL was unauthorized") < 0)
|
if (netconf_access_denied_xml(&xret, "protocol", "The requested URL was unauthorized") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||||
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto ok;
|
goto ok;
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ discard("Discard edits (rollback 0)"), discard_changes();
|
||||||
compare("Compare running and candidate"), compare_dbs((int32)1);
|
compare("Compare running and candidate"), compare_dbs((int32)1);
|
||||||
|
|
||||||
show("Show a particular state of the system"){
|
show("Show a particular state of the system"){
|
||||||
xpath("Show configuration") <xpath:string>("XPATH expression"), show_conf_xpath("candidate");
|
xpath("Show configuration") <xpath:string>("XPATH expression") <ns:string>("Namespace"), show_conf_xpath("candidate");
|
||||||
version("Show version"), cli_show_version("candidate", "text", "/");
|
version("Show version"), cli_show_version("candidate", "text", "/");
|
||||||
compare("Compare candidate and running databases"), compare_dbs((int32)0);{
|
compare("Compare candidate and running databases"), compare_dbs((int32)0);{
|
||||||
xml("Show comparison in xml"), compare_dbs((int32)0);
|
xml("Show comparison in xml"), compare_dbs((int32)0);
|
||||||
|
|
|
||||||
|
|
@ -118,17 +118,24 @@ main_commit(clicon_handle h,
|
||||||
cxobj **vec = NULL;
|
cxobj **vec = NULL;
|
||||||
int i;
|
int i;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
cvec *nsc = NULL;
|
||||||
|
|
||||||
if (_transaction_log)
|
if (_transaction_log)
|
||||||
transaction_log(h, td, LOG_NOTICE, __FUNCTION__);
|
transaction_log(h, td, LOG_NOTICE, __FUNCTION__);
|
||||||
|
|
||||||
|
/* Create namespace context for xpath */
|
||||||
|
if ((nsc = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:yang:ietf-interfaces")) == NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
/* Get all added i/fs */
|
/* Get all added i/fs */
|
||||||
if (xpath_vec_flag(target, "//interface", XML_FLAG_ADD, &vec, &len) < 0)
|
if (xpath_vec_flag(target, NULL, "//interface", XML_FLAG_ADD, &vec, &len) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
if (debug)
|
if (debug)
|
||||||
for (i=0; i<len; i++) /* Loop over added i/fs */
|
for (i=0; i<len; i++) /* Loop over added i/fs */
|
||||||
xml_print(stdout, vec[i]); /* Print the added interface */
|
xml_print(stdout, vec[i]); /* Print the added interface */
|
||||||
// done:
|
done:
|
||||||
|
if (nsc)
|
||||||
|
xml_nsctx_free(nsc);
|
||||||
if (vec)
|
if (vec)
|
||||||
free(vec);
|
free(vec);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -263,6 +270,7 @@ example_copy_extra(clicon_handle h, /* Clicon handle */
|
||||||
|
|
||||||
/*! Called to get state data from plugin
|
/*! Called to get state data from plugin
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] nsc External XML namespace context, or NULL
|
||||||
* @param[in] xpath String with XPATH syntax. or NULL for all
|
* @param[in] xpath String with XPATH syntax. or NULL for all
|
||||||
* @param[in] xstate XML tree, <config/> on entry.
|
* @param[in] xstate XML tree, <config/> on entry.
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
|
|
@ -280,16 +288,18 @@ example_copy_extra(clicon_handle h, /* Clicon handle */
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
example_statedata(clicon_handle h,
|
example_statedata(clicon_handle h,
|
||||||
char *xpath,
|
cvec *nsc,
|
||||||
cxobj *xstate)
|
char *xpath,
|
||||||
|
cxobj *xstate)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj **xvec = NULL;
|
cxobj **xvec = NULL;
|
||||||
size_t xlen;
|
size_t xlen = 0;
|
||||||
cbuf *cb = cbuf_new();
|
cbuf *cb = cbuf_new();
|
||||||
int i;
|
int i;
|
||||||
cxobj *xt = NULL;
|
cxobj *xt = NULL;
|
||||||
char *name;
|
char *name;
|
||||||
|
cvec *nsc1 = NULL;
|
||||||
|
|
||||||
if (!_state)
|
if (!_state)
|
||||||
goto ok;
|
goto ok;
|
||||||
|
|
@ -298,10 +308,18 @@ example_statedata(clicon_handle h,
|
||||||
* state information. In this case adding dummy interface operation state
|
* state information. In this case adding dummy interface operation state
|
||||||
* to configured interfaces.
|
* to configured interfaces.
|
||||||
* Get config according to xpath */
|
* Get config according to xpath */
|
||||||
if (xmldb_get(h, "running", xpath, &xt) < 0)
|
if (xmldb_get0(h, "running", nsc, xpath, 1, &xt, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* From that subset, only get the names */
|
|
||||||
if (xpath_vec(xt, "/interfaces/interface/name", &xvec, &xlen) < 0)
|
/* Here a separate namespace context nsc1 is created. The original nsc
|
||||||
|
* created by the system cannot be used trivially, since we dont know
|
||||||
|
* the prefixes, although we could by a complex mechanism find the prefix
|
||||||
|
* (if it exists) and use that when creating our xpath.
|
||||||
|
* But it is easier creating a new namespace context nsc1.
|
||||||
|
*/
|
||||||
|
if ((nsc1 = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:yang:ietf-interfaces")) == NULL)
|
||||||
|
goto done;
|
||||||
|
if (xpath_vec(xt, nsc1, "/interfaces/interface/name", &xvec, &xlen) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (xlen){
|
if (xlen){
|
||||||
cprintf(cb, "<interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">");
|
cprintf(cb, "<interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">");
|
||||||
|
|
@ -322,6 +340,8 @@ example_statedata(clicon_handle h,
|
||||||
ok:
|
ok:
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
if (nsc1)
|
||||||
|
xml_nsctx_free(nsc1);
|
||||||
if (xt)
|
if (xt)
|
||||||
xml_free(xt);
|
xml_free(xt);
|
||||||
if (cb)
|
if (cb)
|
||||||
|
|
@ -395,7 +415,7 @@ upgrade_2016(clicon_handle h,
|
||||||
if ((name = xml_find_body(xi, "name")) == NULL)
|
if ((name = xml_find_body(xi, "name")) == NULL)
|
||||||
continue; /* shouldnt happen */
|
continue; /* shouldnt happen */
|
||||||
/* Get corresponding /interfaces/interface entry */
|
/* Get corresponding /interfaces/interface entry */
|
||||||
xif = xpath_first(xt, "/interfaces/interface[name=\"%s\"]", name);
|
xif = xpath_first(xt, NULL, "/interfaces/interface[name=\"%s\"]", name);
|
||||||
/* - Move /if:interfaces-state/if:interface/if:admin-status to
|
/* - Move /if:interfaces-state/if:interface/if:admin-status to
|
||||||
* /if:interfaces/if:interface/ */
|
* /if:interfaces/if:interface/ */
|
||||||
if ((x = xml_find(xi, "admin-status")) != NULL && xif){
|
if ((x = xml_find(xi, "admin-status")) != NULL && xif){
|
||||||
|
|
@ -498,7 +518,7 @@ upgrade_2018(clicon_handle h,
|
||||||
/* Change type /interfaces/interface/statistics/in-octets to
|
/* Change type /interfaces/interface/statistics/in-octets to
|
||||||
* decimal64 with fraction-digits 3 and divide values with 1000
|
* decimal64 with fraction-digits 3 and divide values with 1000
|
||||||
*/
|
*/
|
||||||
if ((x = xpath_first(xi, "statistics/in-octets")) != NULL){
|
if ((x = xpath_first(xi, NULL, "statistics/in-octets")) != NULL){
|
||||||
if ((xb = xml_body_get(x)) != NULL){
|
if ((xb = xml_body_get(x)) != NULL){
|
||||||
uint64_t u64;
|
uint64_t u64;
|
||||||
cbuf *cb = cbuf_new();
|
cbuf *cb = cbuf_new();
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ nacm_validate(clicon_handle h,
|
||||||
if (_transaction_log){
|
if (_transaction_log){
|
||||||
transaction_log(h, td, LOG_NOTICE, __FUNCTION__);
|
transaction_log(h, td, LOG_NOTICE, __FUNCTION__);
|
||||||
if (_transaction_error_toggle==0 &&
|
if (_transaction_error_toggle==0 &&
|
||||||
xpath_first(transaction_target(td), "%s", _transaction_xpath)){
|
xpath_first(transaction_target(td), NULL, "%s", _transaction_xpath)){
|
||||||
_transaction_error_toggle=1; /* toggle if triggered */
|
_transaction_error_toggle=1; /* toggle if triggered */
|
||||||
clicon_err(OE_XML, 0, "User error");
|
clicon_err(OE_XML, 0, "User error");
|
||||||
return -1; /* induce fail */
|
return -1; /* induce fail */
|
||||||
|
|
@ -116,7 +116,7 @@ nacm_commit(clicon_handle h,
|
||||||
if (_transaction_log){
|
if (_transaction_log){
|
||||||
transaction_log(h, td, LOG_NOTICE, __FUNCTION__);
|
transaction_log(h, td, LOG_NOTICE, __FUNCTION__);
|
||||||
if (_transaction_error_toggle==1 &&
|
if (_transaction_error_toggle==1 &&
|
||||||
xpath_first(target, "%s", _transaction_xpath)){
|
xpath_first(target, NULL, "%s", _transaction_xpath)){
|
||||||
_transaction_error_toggle=0; /* toggle if triggered */
|
_transaction_error_toggle=0; /* toggle if triggered */
|
||||||
clicon_err(OE_XML, 0, "User error");
|
clicon_err(OE_XML, 0, "User error");
|
||||||
return -1; /* induce fail */
|
return -1; /* induce fail */
|
||||||
|
|
@ -154,6 +154,7 @@ nacm_abort(clicon_handle h,
|
||||||
|
|
||||||
/*! Called to get NACM state data
|
/*! Called to get NACM state data
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] nsc External XML namespace context, or NULL
|
||||||
* @param[in] xpath String with XPATH syntax. or NULL for all
|
* @param[in] xpath String with XPATH syntax. or NULL for all
|
||||||
* @param[in] xtop XML tree, <config/> on entry.
|
* @param[in] xtop XML tree, <config/> on entry.
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
|
|
@ -164,6 +165,7 @@ nacm_abort(clicon_handle h,
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
nacm_statedata(clicon_handle h,
|
nacm_statedata(clicon_handle h,
|
||||||
|
cvec *nsc,
|
||||||
char *xpath,
|
char *xpath,
|
||||||
cxobj *xstate)
|
cxobj *xstate)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,7 @@ mycallback(clicon_handle h, cvec *cvv, cvec *argv)
|
||||||
/* Show eth0 interfaces config using XPATH */
|
/* Show eth0 interfaces config using XPATH */
|
||||||
if (clicon_rpc_get_config(h, "running",
|
if (clicon_rpc_get_config(h, "running",
|
||||||
"/interfaces/interface[name='eth0']",
|
"/interfaces/interface[name='eth0']",
|
||||||
|
"urn:example:clixon",
|
||||||
&xret) < 0)
|
&xret) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
xml_print(stdout, xret);
|
xml_print(stdout, xret);
|
||||||
|
|
@ -104,7 +105,7 @@ example_client_rpc(clicon_handle h,
|
||||||
/* Send to backend */
|
/* Send to backend */
|
||||||
if (clicon_rpc_netconf_xml(h, xrpc, &xret, NULL) < 0)
|
if (clicon_rpc_netconf_xml(h, xrpc, &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||||
clicon_rpc_generate_error("Get configuration", xerr);
|
clicon_rpc_generate_error("Get configuration", xerr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,14 +24,14 @@ debug("Debugging parts of the system"), cli_debug_cli((int32)1);{
|
||||||
}
|
}
|
||||||
copy("Copy and create a new object") {
|
copy("Copy and create a new object") {
|
||||||
interface("Copy interface"){
|
interface("Copy interface"){
|
||||||
(<name:string>|<name:string expand_dbvar("candidate","/ietf-interfaces:interfaces/interface=%s/name")>("name of interface to copy from")) to("Copy to interface") <toname:string>("Name of interface to copy to"), cli_copy_config("candidate","//interface[%s='%s']","name","name","toname");
|
(<name:string>|<name:string expand_dbvar("candidate","/ietf-interfaces:interfaces/interface=%s/name")>("name of interface to copy from")) to("Copy to interface") <toname:string>("Name of interface to copy to"), cli_copy_config("candidate","//interface[%s='%s']","urn:ietf:params:xml:ns:yang:ietf-interfaces","name","name","toname");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
discard("Discard edits (rollback 0)"), discard_changes();
|
discard("Discard edits (rollback 0)"), discard_changes();
|
||||||
compare("Compare running and candidate"), compare_dbs((int32)1);
|
compare("Compare running and candidate"), compare_dbs((int32)1);
|
||||||
|
|
||||||
show("Show a particular state of the system"){
|
show("Show a particular state of the system"){
|
||||||
xpath("Show configuration") <xpath:string>("XPATH expression"), show_conf_xpath("candidate");
|
xpath("Show configuration") <xpath:string>("XPATH expression") <ns:string>("Namespace"), show_conf_xpath("candidate");
|
||||||
version("Show version"), cli_show_version("candidate", "text", "/");
|
version("Show version"), cli_show_version("candidate", "text", "/");
|
||||||
compare("Compare candidate and running databases"), compare_dbs((int32)0);{
|
compare("Compare candidate and running databases"), compare_dbs((int32)0);{
|
||||||
xml("Show comparison in xml"), compare_dbs((int32)0);
|
xml("Show comparison in xml"), compare_dbs((int32)0);
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,16 @@
|
||||||
*/
|
*/
|
||||||
#undef RPC_USERNAME_ASSERT
|
#undef RPC_USERNAME_ASSERT
|
||||||
|
|
||||||
|
/* If rpc call does not have a namespace (eg using xmlns) then use the default
|
||||||
|
* NETCONF namespace (see rfc6241 3.1)
|
||||||
|
* Undefine it if you want to ensure strict namespace assignment on all netconf and
|
||||||
|
* XML statements.
|
||||||
|
*/
|
||||||
|
#define USE_NETCONF_NS_AS_DEFAULT
|
||||||
|
|
||||||
/* Make namespace check on RESTCONF PUT and POST -d data
|
/* Make namespace check on RESTCONF PUT and POST -d data
|
||||||
|
* Should be defined according to standard
|
||||||
|
* Undefine it if you want allow no namespace (pick first name it finds in list
|
||||||
|
* of loaded modules).
|
||||||
*/
|
*/
|
||||||
#define RESTCONF_NS_DATA_CHECK
|
#define RESTCONF_NS_DATA_CHECK
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,7 @@
|
||||||
#include <clixon/clixon_netconf_lib.h>
|
#include <clixon/clixon_netconf_lib.h>
|
||||||
#include <clixon/clixon_nacm.h>
|
#include <clixon/clixon_nacm.h>
|
||||||
#include <clixon/clixon_xml_changelog.h>
|
#include <clixon/clixon_xml_changelog.h>
|
||||||
|
#include <clixon/clixon_xml_nsctx.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Global variables generated by Makefile
|
* Global variables generated by Makefile
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,9 @@ int xmldb_connect(clicon_handle h);
|
||||||
int xmldb_disconnect(clicon_handle h);
|
int xmldb_disconnect(clicon_handle h);
|
||||||
/* in clixon_datastore_read.[ch] */
|
/* in clixon_datastore_read.[ch] */
|
||||||
int xmldb_get(clicon_handle h, const char *db, char *xpath, cxobj **xtop);
|
int xmldb_get(clicon_handle h, const char *db, char *xpath, cxobj **xtop);
|
||||||
int xmldb_get0(clicon_handle h, const char *db, char *xpath, int copy, cxobj **xtop, modstate_diff_t *msd);
|
int xmldb_get0(clicon_handle h, const char *db,
|
||||||
|
cvec *nc, char *xpath,
|
||||||
|
int copy, cxobj **xtop, modstate_diff_t *msd);
|
||||||
int xmldb_get0_clear(clicon_handle h, cxobj *x);
|
int xmldb_get0_clear(clicon_handle h, cxobj *x);
|
||||||
int xmldb_get0_free(clicon_handle h, cxobj **xp);
|
int xmldb_get0_free(clicon_handle h, cxobj **xp);
|
||||||
int xmldb_put(clicon_handle h, const char *db, enum operation_type op, cxobj *xt, char *username, cbuf *cbret); /* in clixon_datastore_write.[ch] */
|
int xmldb_put(clicon_handle h, const char *db, enum operation_type op, cxobj *xt, char *username, cbuf *cbret); /* in clixon_datastore_write.[ch] */
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,16 @@ typedef int (plgexit_t)(clicon_handle); /* Plugin exit */
|
||||||
typedef int (plgauth_t)(clicon_handle, void *);
|
typedef int (plgauth_t)(clicon_handle, void *);
|
||||||
|
|
||||||
typedef int (plgreset_t)(clicon_handle h, const char *db); /* Reset system status */
|
typedef int (plgreset_t)(clicon_handle h, const char *db); /* Reset system status */
|
||||||
typedef int (plgstatedata_t)(clicon_handle h, char *xpath, cxobj *xtop);
|
|
||||||
|
/* Plugin statedata
|
||||||
|
* @param[in] Clicon handle
|
||||||
|
* @param[in] xpath Part of state requested
|
||||||
|
* @param[in] nsc XPATH namespace context.
|
||||||
|
* @param[in] xtop XML tree where statedata is added
|
||||||
|
* @retval -1 Fatal error
|
||||||
|
* @retval 0 OK
|
||||||
|
*/
|
||||||
|
typedef int (plgstatedata_t)(clicon_handle h, cvec *nsc, char *xpath, cxobj *xtop);
|
||||||
|
|
||||||
typedef void *transaction_data;
|
typedef void *transaction_data;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,14 +45,14 @@ int clicon_rpc_msg(clicon_handle h, struct clicon_msg *msg, cxobj **xret0,
|
||||||
int clicon_rpc_netconf(clicon_handle h, char *xmlst, cxobj **xret, int *sp);
|
int clicon_rpc_netconf(clicon_handle h, char *xmlst, cxobj **xret, int *sp);
|
||||||
int clicon_rpc_netconf_xml(clicon_handle h, cxobj *xml, cxobj **xret, int *sp);
|
int clicon_rpc_netconf_xml(clicon_handle h, cxobj *xml, cxobj **xret, int *sp);
|
||||||
int clicon_rpc_generate_error(char *format, cxobj *xerr);
|
int clicon_rpc_generate_error(char *format, cxobj *xerr);
|
||||||
int clicon_rpc_get_config(clicon_handle h, char *db, char *xpath, cxobj **xret);
|
int clicon_rpc_get_config(clicon_handle h, char *db, char *xpath, char *namespace, cxobj **xret);
|
||||||
int clicon_rpc_edit_config(clicon_handle h, char *db, enum operation_type op,
|
int clicon_rpc_edit_config(clicon_handle h, char *db, enum operation_type op,
|
||||||
char *xml);
|
char *xml);
|
||||||
int clicon_rpc_copy_config(clicon_handle h, char *db1, char *db2);
|
int clicon_rpc_copy_config(clicon_handle h, char *db1, char *db2);
|
||||||
int clicon_rpc_delete_config(clicon_handle h, char *db);
|
int clicon_rpc_delete_config(clicon_handle h, char *db);
|
||||||
int clicon_rpc_lock(clicon_handle h, char *db);
|
int clicon_rpc_lock(clicon_handle h, char *db);
|
||||||
int clicon_rpc_unlock(clicon_handle h, char *db);
|
int clicon_rpc_unlock(clicon_handle h, char *db);
|
||||||
int clicon_rpc_get(clicon_handle h, char *xpath, cxobj **xret);
|
int clicon_rpc_get(clicon_handle h, char *xpath, char *namespace, cxobj **xret);
|
||||||
int clicon_rpc_close_session(clicon_handle h);
|
int clicon_rpc_close_session(clicon_handle h);
|
||||||
int clicon_rpc_kill_session(clicon_handle h, int session_id);
|
int clicon_rpc_kill_session(clicon_handle h, int session_id);
|
||||||
int clicon_rpc_validate(clicon_handle h, char *db);
|
int clicon_rpc_validate(clicon_handle h, char *db);
|
||||||
|
|
|
||||||
|
|
@ -41,12 +41,11 @@
|
||||||
/*
|
/*
|
||||||
* Constants
|
* Constants
|
||||||
*/
|
*/
|
||||||
/* If rpc call does not have a namespace (eg w xmlns) then use the default NETCONF
|
|
||||||
* namespace (rfc6241 3.1)
|
/* Default NETCONF namespace (see rfc6241 3.1)
|
||||||
|
* See USE_NETCONF_NS_AS_DEFAULT for use of this namespace as default
|
||||||
*/
|
*/
|
||||||
#define DEFAULT_XML_RPC_NAMESPACE "urn:ietf:params:xml:ns:netconf:base:1.0"
|
#define NETCONF_BASE_NAMESPACE "urn:ietf:params:xml:ns:netconf:base:1.0"
|
||||||
/* default namespace statement, such as in <rpc xmlns="..."> */
|
|
||||||
#define DEFAULT_XMLNS "xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\""
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Types
|
* Types
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,8 @@ int xml_sanity(cxobj *x, void *arg);
|
||||||
int xml_non_config_data(cxobj *xt, void *arg);
|
int xml_non_config_data(cxobj *xt, void *arg);
|
||||||
int xml_spec_populate_rpc(clicon_handle h, cxobj *x, yang_stmt *yspec);
|
int xml_spec_populate_rpc(clicon_handle h, cxobj *x, yang_stmt *yspec);
|
||||||
int xml_spec_populate(cxobj *x, void *arg);
|
int xml_spec_populate(cxobj *x, void *arg);
|
||||||
int api_path2xpath(yang_stmt *yspec, cvec *cvv, int offset, cbuf *xpath);
|
int api_path2xpath_cvv(cvec *api_path, int offset, yang_stmt *yspec, cbuf *xpath, char **namespace);
|
||||||
|
int api_path2xpath(char *api_path, yang_stmt *yspec, char **xpath, char **namespace);
|
||||||
int api_path2xml(char *api_path, yang_stmt *yspec, cxobj *xtop,
|
int api_path2xml(char *api_path, yang_stmt *yspec, cxobj *xtop,
|
||||||
yang_class nodeclass, int strict, cxobj **xpathp, yang_stmt **ypathp);
|
yang_class nodeclass, int strict, cxobj **xpathp, yang_stmt **ypathp);
|
||||||
|
|
||||||
|
|
|
||||||
59
lib/clixon/clixon_xml_nsctx.h
Normal file
59
lib/clixon/clixon_xml_nsctx.h
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
|
Copyright (C) 2009-2019 Olof Hagsand
|
||||||
|
|
||||||
|
This file is part of CLIXON.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
Alternatively, the contents of this file may be used under the terms of
|
||||||
|
the GNU General Public License Version 3 or later (the "GPL"),
|
||||||
|
in which case the provisions of the GPL are applicable instead
|
||||||
|
of those above. If you wish to allow use of your version of this file only
|
||||||
|
under the terms of the GPL, and not to allow others to
|
||||||
|
use your version of this file under the terms of Apache License version 2,
|
||||||
|
indicate your decision by deleting the provisions above and replace them with
|
||||||
|
the notice and other provisions required by the GPL. If you do not delete
|
||||||
|
the provisions above, a recipient may use your version of this file under
|
||||||
|
the terms of any one of the Apache License version 2 or the GPL.
|
||||||
|
|
||||||
|
***** END LICENSE BLOCK *****
|
||||||
|
|
||||||
|
* XML support functions.
|
||||||
|
* @see https://www.w3.org/TR/2009/REC-xml-names-20091208/
|
||||||
|
*/
|
||||||
|
#ifndef _CLIXON_XML_NSCTX_H
|
||||||
|
#define _CLIXON_XML_NSCTX_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* An xml namespace context is a cligen variable vector containing a list of
|
||||||
|
* <prefix,namespace> pairs.
|
||||||
|
* It is encoded in a cvv as a list of string values, where the c name is the
|
||||||
|
* prefix and the string values are the namespace URI.
|
||||||
|
* The default namespace is decoded as having the name NULL
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prototypes
|
||||||
|
*/
|
||||||
|
char *xml_nsctx_get(cvec *nsc, char *prefix);
|
||||||
|
int xml_nsctx_get_prefix(cvec *cvv, char *namespace, char **prefix);
|
||||||
|
int xml_nsctx_set(cvec *nsc, char *prefix, char *namespace);
|
||||||
|
cvec *xml_nsctx_init(char *prefix, char *namespace);
|
||||||
|
int xml_nsctx_node(cxobj *x, cvec **ncp);
|
||||||
|
int xml_nsctx_yang(yang_stmt *yn, cvec **ncp);
|
||||||
|
int xml_nsctx_free(cvec *ncs);
|
||||||
|
|
||||||
|
#endif /* _CLIXON_XML_NSCTX_H */
|
||||||
|
|
@ -80,24 +80,26 @@ enum axis_type{
|
||||||
*/
|
*/
|
||||||
extern const map_str2int xpopmap[];
|
extern const map_str2int xpopmap[];
|
||||||
|
|
||||||
|
extern int xpatherrordiff;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prototypes
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
#if defined(__GNUC__) && __GNUC__ >= 3
|
#if defined(__GNUC__) && __GNUC__ >= 3
|
||||||
int xpath_vec(cxobj *xcur, char *format, cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 2, 5)));
|
int xpath_vec(cxobj *xcur, cvec *nsc, char *format, cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 3, 6)));
|
||||||
int xpath_vec_flag(cxobj *xcur, char *format, uint16_t flags,
|
int xpath_vec_flag(cxobj *xcur, cvec *nsc, char *format, uint16_t flags,
|
||||||
cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 2, 6)));
|
cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 3, 7)));
|
||||||
cxobj *xpath_first(cxobj *xcur, char *format, ...) __attribute__ ((format (printf, 2, 3)));
|
cxobj *xpath_first(cxobj *xcur, cvec *nsc, char *format, ...) __attribute__ ((format (printf, 3, 4)));
|
||||||
int xpath_vec_bool(cxobj *xcur, char *format, ...) __attribute__ ((format (printf, 2, 3)));
|
int xpath_vec_bool(cxobj *xcur, cvec *nsc, char *format, ...) __attribute__ ((format (printf, 3, 4)));
|
||||||
|
|
||||||
#else
|
#else
|
||||||
int xpath_vec(cxobj *xcur, char *format, cxobj ***vec, size_t *veclen, ...);
|
int xpath_vec(cxobj *xcur, cvec *nsc, char *format, cxobj ***vec, size_t *veclen, ...);
|
||||||
int xpath_vec_flag(cxobj *xcur, char *format, uint16_t flags,
|
int xpath_vec_flag(cxobj *xcur, cvec *nsc, char *format, uint16_t flags,
|
||||||
cxobj ***vec, size_t *veclen, ...);
|
cxobj ***vec, size_t *veclen, ...);
|
||||||
cxobj *xpath_first(cxobj *xcur, char *format, ...);
|
cxobj *xpath_first(cxobj *xcur, cvec *nsc, char *format, ...);
|
||||||
int xpath_vec_bool(cxobj *xcur, char *format, ...);
|
int xpath_vec_bool(cxobj *xcur, cvec *nsc, char *format, ...);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
int xpath_vec_ctx(cxobj *xcur, char *xpath, xp_ctx **xrp);
|
|
||||||
|
int xpath_vec_ctx(cxobj *xcur, cvec *nsc, char *xpath, xp_ctx **xrp);
|
||||||
|
|
||||||
#endif /* _CLIXON_XPATH_H */
|
#endif /* _CLIXON_XPATH_H */
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
*
|
*
|
||||||
***** BEGIN LICENSE BLOCK *****
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
|
Copyright (C) 2009-2019 Olof Hagsand
|
||||||
|
|
||||||
This file is part of CLIXON.
|
This file is part of CLIXON.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
*
|
*
|
||||||
***** BEGIN LICENSE BLOCK *****
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
|
Copyright (C) 2009-2019 Olof Hagsand
|
||||||
|
|
||||||
This file is part of CLIXON.
|
This file is part of CLIXON.
|
||||||
|
|
||||||
|
|
@ -65,7 +65,7 @@ int yang_modules_init(clicon_handle h);
|
||||||
char *yang_modules_revision(clicon_handle h);
|
char *yang_modules_revision(clicon_handle h);
|
||||||
|
|
||||||
int yang_modules_state_get(clicon_handle h, yang_stmt *yspec, char *xpath,
|
int yang_modules_state_get(clicon_handle h, yang_stmt *yspec, char *xpath,
|
||||||
int brief, cxobj **xret);
|
cvec *nsc, int brief, cxobj **xret);
|
||||||
|
|
||||||
int clixon_module_upgrade(clicon_handle h, cxobj *xt, modstate_diff_t *msd, cbuf *cb);
|
int clixon_module_upgrade(clicon_handle h, cxobj *xt, modstate_diff_t *msd, cbuf *cb);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
*
|
*
|
||||||
***** BEGIN LICENSE BLOCK *****
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
|
Copyright (C) 2009-2019 Olof Hagsand
|
||||||
|
|
||||||
This file is part of CLIXON.
|
This file is part of CLIXON.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ SRC = clixon_sig.c clixon_log.c clixon_err.c clixon_event.c \
|
||||||
clixon_string.c clixon_regex.c clixon_handle.c \
|
clixon_string.c clixon_regex.c clixon_handle.c \
|
||||||
clixon_xml.c clixon_xml_sort.c clixon_xml_map.c clixon_file.c \
|
clixon_xml.c clixon_xml_sort.c clixon_xml_map.c clixon_file.c \
|
||||||
clixon_json.c clixon_yang.c clixon_yang_type.c clixon_yang_module.c \
|
clixon_json.c clixon_yang.c clixon_yang_type.c clixon_yang_module.c \
|
||||||
clixon_yang_cardinality.c clixon_xml_changelog.c \
|
clixon_yang_cardinality.c clixon_xml_changelog.c clixon_xml_nsctx.c \
|
||||||
clixon_hash.c clixon_options.c clixon_data.c clixon_plugin.c \
|
clixon_hash.c clixon_options.c clixon_data.c clixon_plugin.c \
|
||||||
clixon_proto.c clixon_proto_client.c \
|
clixon_proto.c clixon_proto_client.c \
|
||||||
clixon_xpath.c clixon_xpath_ctx.c clixon_sha1.c \
|
clixon_xpath.c clixon_xpath_ctx.c clixon_sha1.c \
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,7 @@
|
||||||
#include "clixon_netconf_lib.h"
|
#include "clixon_netconf_lib.h"
|
||||||
#include "clixon_yang_module.h"
|
#include "clixon_yang_module.h"
|
||||||
#include "clixon_xml_map.h"
|
#include "clixon_xml_map.h"
|
||||||
|
#include "clixon_xml_nsctx.h"
|
||||||
|
|
||||||
#include "clixon_datastore.h"
|
#include "clixon_datastore.h"
|
||||||
#include "clixon_datastore_read.h"
|
#include "clixon_datastore_read.h"
|
||||||
|
|
@ -257,7 +258,7 @@ text_read_modstate(clicon_handle h,
|
||||||
if ((name = xml_find_body(xm, "name")) == NULL)
|
if ((name = xml_find_body(xm, "name")) == NULL)
|
||||||
continue;
|
continue;
|
||||||
/* 3a) There is no such module in the system */
|
/* 3a) There is no such module in the system */
|
||||||
if ((xs = xpath_first(xmcache, "module[name=\"%s\"]", name)) == NULL){
|
if ((xs = xpath_first(xmcache, NULL, "module[name=\"%s\"]", name)) == NULL){
|
||||||
// fprintf(stderr, "%s: Module %s: not in system\n", __FUNCTION__, name);
|
// fprintf(stderr, "%s: Module %s: not in system\n", __FUNCTION__, name);
|
||||||
if ((xm2 = xml_dup(xm)) == NULL)
|
if ((xm2 = xml_dup(xm)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -385,6 +386,7 @@ xmldb_readfile(clicon_handle h,
|
||||||
* This is a clixon datastore plugin of the the xmldb api
|
* This is a clixon datastore plugin of the the xmldb api
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] db Name of database to search in (filename including dir path
|
* @param[in] db Name of database to search in (filename including dir path
|
||||||
|
* @param[in] nsc External XML namespace context, or NULL
|
||||||
* @param[in] xpath String with XPATH syntax. or NULL for all
|
* @param[in] xpath String with XPATH syntax. or NULL for all
|
||||||
* @param[out] xret Single return XML tree. Free with xml_free()
|
* @param[out] xret Single return XML tree. Free with xml_free()
|
||||||
* @param[out] msd If set, return modules-state differences
|
* @param[out] msd If set, return modules-state differences
|
||||||
|
|
@ -395,6 +397,7 @@ xmldb_readfile(clicon_handle h,
|
||||||
static int
|
static int
|
||||||
xmldb_get_nocache(clicon_handle h,
|
xmldb_get_nocache(clicon_handle h,
|
||||||
const char *db,
|
const char *db,
|
||||||
|
cvec *nsc,
|
||||||
char *xpath,
|
char *xpath,
|
||||||
cxobj **xtop,
|
cxobj **xtop,
|
||||||
modstate_diff_t *msd)
|
modstate_diff_t *msd)
|
||||||
|
|
@ -417,7 +420,7 @@ xmldb_get_nocache(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
/* Here xt looks like: <config>...</config> */
|
/* Here xt looks like: <config>...</config> */
|
||||||
/* Given the xpath, return a vector of matches in xvec */
|
/* Given the xpath, return a vector of matches in xvec */
|
||||||
if (xpath_vec(xt, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
if (xpath_vec(xt, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* If vectors are specified then mark the nodes found with all ancestors
|
/* If vectors are specified then mark the nodes found with all ancestors
|
||||||
|
|
@ -467,6 +470,7 @@ xmldb_get_nocache(clicon_handle h,
|
||||||
* This is a clixon datastore plugin of the the xmldb api
|
* This is a clixon datastore plugin of the the xmldb api
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] db Name of database to search in (filename including dir path
|
* @param[in] db Name of database to search in (filename including dir path
|
||||||
|
* @param[in] nsc External XML namespace context, or NULL
|
||||||
* @param[in] xpath String with XPATH syntax. or NULL for all
|
* @param[in] xpath String with XPATH syntax. or NULL for all
|
||||||
* @param[out] xret Single return XML tree. Free with xml_free()
|
* @param[out] xret Single return XML tree. Free with xml_free()
|
||||||
* @param[out] msd If set, return modules-state differences
|
* @param[out] msd If set, return modules-state differences
|
||||||
|
|
@ -475,11 +479,12 @@ xmldb_get_nocache(clicon_handle h,
|
||||||
* @see xmldb_get the generic API function
|
* @see xmldb_get the generic API function
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
xmldb_get_cache(clicon_handle h,
|
xmldb_get_cache(clicon_handle h,
|
||||||
const char *db,
|
const char *db,
|
||||||
char *xpath,
|
cvec *nsc,
|
||||||
cxobj **xtop,
|
char *xpath,
|
||||||
modstate_diff_t *msd)
|
cxobj **xtop,
|
||||||
|
modstate_diff_t *msd)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
yang_stmt *yspec;
|
yang_stmt *yspec;
|
||||||
|
|
@ -521,7 +526,7 @@ xmldb_get_cache(clicon_handle h,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Here xt looks like: <config>...</config> */
|
/* Here xt looks like: <config>...</config> */
|
||||||
if (xpath_vec(x0t, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
if (xpath_vec(x0t, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* Make new tree by copying top-of-tree from x0t to x1t */
|
/* Make new tree by copying top-of-tree from x0t to x1t */
|
||||||
|
|
@ -565,6 +570,7 @@ xmldb_get_cache(clicon_handle h,
|
||||||
* This is a clixon datastore plugin of the the xmldb api
|
* This is a clixon datastore plugin of the the xmldb api
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] db Name of database to search in (filename including dir path
|
* @param[in] db Name of database to search in (filename including dir path
|
||||||
|
* @param[in] nsc External XML namespace context, or NULL
|
||||||
* @param[in] xpath String with XPATH syntax. or NULL for all
|
* @param[in] xpath String with XPATH syntax. or NULL for all
|
||||||
* @param[in] config If set only configuration data, else also state
|
* @param[in] config If set only configuration data, else also state
|
||||||
* @param[out] xret Single return XML tree. Free with xml_free()
|
* @param[out] xret Single return XML tree. Free with xml_free()
|
||||||
|
|
@ -573,11 +579,12 @@ xmldb_get_cache(clicon_handle h,
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
xmldb_get_zerocopy(clicon_handle h,
|
xmldb_get_zerocopy(clicon_handle h,
|
||||||
const char *db,
|
const char *db,
|
||||||
char *xpath,
|
cvec *nsc,
|
||||||
cxobj **xtop,
|
char *xpath,
|
||||||
modstate_diff_t *msd)
|
cxobj **xtop,
|
||||||
|
modstate_diff_t *msd)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
yang_stmt *yspec;
|
yang_stmt *yspec;
|
||||||
|
|
@ -612,7 +619,7 @@ xmldb_get_zerocopy(clicon_handle h,
|
||||||
else
|
else
|
||||||
x0t = de->de_xml;
|
x0t = de->de_xml;
|
||||||
/* Here xt looks like: <config>...</config> */
|
/* Here xt looks like: <config>...</config> */
|
||||||
if (xpath_vec(x0t, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
if (xpath_vec(x0t, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Iterate through the match vector
|
/* Iterate through the match vector
|
||||||
* For every node found in x0, mark the tree up to t1
|
* For every node found in x0, mark the tree up to t1
|
||||||
|
|
@ -656,7 +663,7 @@ xmldb_get(clicon_handle h,
|
||||||
char *xpath,
|
char *xpath,
|
||||||
cxobj **xret)
|
cxobj **xret)
|
||||||
{
|
{
|
||||||
return xmldb_get0(h, db, xpath, 1, xret, NULL);
|
return xmldb_get0(h, db, NULL, xpath, 1, xret, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Zero-copy variant of get content of database
|
/*! Zero-copy variant of get content of database
|
||||||
|
|
@ -669,6 +676,7 @@ xmldb_get(clicon_handle h,
|
||||||
* freeing tree must be made after use.
|
* freeing tree must be made after use.
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] db Name of database to search in (filename including dir path
|
* @param[in] db Name of database to search in (filename including dir path
|
||||||
|
* @param[in] nsc External XML namespace context, or NULL
|
||||||
* @param[in] xpath String with XPATH syntax. or NULL for all
|
* @param[in] xpath String with XPATH syntax. or NULL for all
|
||||||
* @param[in] copy Force copy. Overrides cache_zerocopy -> cache
|
* @param[in] copy Force copy. Overrides cache_zerocopy -> cache
|
||||||
* @param[out] xret Single return XML tree. Free with xml_free()
|
* @param[out] xret Single return XML tree. Free with xml_free()
|
||||||
|
|
@ -677,17 +685,19 @@ xmldb_get(clicon_handle h,
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
* @code
|
* @code
|
||||||
* cxobj *xt;
|
* cxobj *xt;
|
||||||
* if (xmldb_get0(xh, "running", "/interface[name="eth"]", 0, &xt, NULL) < 0)
|
* if (xmldb_get0(xh, "running", nsc, "/interface[name="eth"]", 0, &xt, NULL) < 0)
|
||||||
* err;
|
* err;
|
||||||
* ...
|
* ...
|
||||||
* xmldb_get0_clear(h, xt); # Clear tree from default values and flags
|
* xmldb_get0_clear(h, xt); # Clear tree from default values and flags
|
||||||
* xmldb_get0_free(h, &xt); # Free tree
|
* xmldb_get0_free(h, &xt); # Free tree
|
||||||
* @endcode
|
* @endcode
|
||||||
|
* @see xml_nsctx_node to get a XML namespace context from XML tree
|
||||||
* @see xmldb_get for a copy version (old-style)
|
* @see xmldb_get for a copy version (old-style)
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xmldb_get0(clicon_handle h,
|
xmldb_get0(clicon_handle h,
|
||||||
const char *db,
|
const char *db,
|
||||||
|
cvec *nsc,
|
||||||
char *xpath,
|
char *xpath,
|
||||||
int copy,
|
int copy,
|
||||||
cxobj **xret,
|
cxobj **xret,
|
||||||
|
|
@ -701,7 +711,7 @@ xmldb_get0(clicon_handle h,
|
||||||
* Add default values in copy
|
* Add default values in copy
|
||||||
* Copy deleted by xmldb_free
|
* Copy deleted by xmldb_free
|
||||||
*/
|
*/
|
||||||
retval = xmldb_get_nocache(h, db, xpath, xret, msd);
|
retval = xmldb_get_nocache(h, db, nsc, xpath, xret, msd);
|
||||||
break;
|
break;
|
||||||
case DATASTORE_CACHE_ZEROCOPY:
|
case DATASTORE_CACHE_ZEROCOPY:
|
||||||
/* Get cache (file if empty) mark xpath match in original tree
|
/* Get cache (file if empty) mark xpath match in original tree
|
||||||
|
|
@ -709,7 +719,7 @@ xmldb_get0(clicon_handle h,
|
||||||
* Default values and markings removed in xmldb_clear
|
* Default values and markings removed in xmldb_clear
|
||||||
*/
|
*/
|
||||||
if (!copy){
|
if (!copy){
|
||||||
retval = xmldb_get_zerocopy(h, db, xpath, xret, msd);
|
retval = xmldb_get_zerocopy(h, db, nsc, xpath, xret, msd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* fall through */
|
/* fall through */
|
||||||
|
|
@ -718,7 +728,7 @@ xmldb_get0(clicon_handle h,
|
||||||
* Add default values in copy, return copy
|
* Add default values in copy, return copy
|
||||||
* Copy deleted by xmldb_free
|
* Copy deleted by xmldb_free
|
||||||
*/
|
*/
|
||||||
retval = xmldb_get_cache(h, db, xpath, xret, msd);
|
retval = xmldb_get_cache(h, db, nsc, xpath, xret, msd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,7 @@
|
||||||
#include "clixon_nacm.h"
|
#include "clixon_nacm.h"
|
||||||
#include "clixon_netconf_lib.h"
|
#include "clixon_netconf_lib.h"
|
||||||
#include "clixon_yang_module.h"
|
#include "clixon_yang_module.h"
|
||||||
|
#include "clixon_xml_nsctx.h"
|
||||||
#include "clixon_xml_map.h"
|
#include "clixon_xml_map.h"
|
||||||
|
|
||||||
#include "clixon_datastore.h"
|
#include "clixon_datastore.h"
|
||||||
|
|
@ -614,6 +615,7 @@ xmldb_put(clicon_handle h,
|
||||||
cxobj *x;
|
cxobj *x;
|
||||||
int permit = 0; /* nacm permit all */
|
int permit = 0; /* nacm permit all */
|
||||||
char *format;
|
char *format;
|
||||||
|
cvec *nsc = NULL; /* nacm namespace context */
|
||||||
|
|
||||||
if (cbret == NULL){
|
if (cbret == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "cbret is NULL");
|
clicon_err(OE_XML, EINVAL, "cbret is NULL");
|
||||||
|
|
@ -656,8 +658,11 @@ xmldb_put(clicon_handle h,
|
||||||
else if (strcmp(mode, "internal")==0)
|
else if (strcmp(mode, "internal")==0)
|
||||||
xnacm0 = x0;
|
xnacm0 = x0;
|
||||||
}
|
}
|
||||||
|
/* Create namespace context for with nacm namespace as default */
|
||||||
|
if ((nsc = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:yang:ietf-netconf-acm")) == NULL)
|
||||||
|
goto done;
|
||||||
if (xnacm0 != NULL &&
|
if (xnacm0 != NULL &&
|
||||||
(xnacm = xpath_first(xnacm0, "nacm")) != NULL){
|
(xnacm = xpath_first(xnacm0, nsc, "nacm")) != NULL){
|
||||||
/* Pre-NACM access step, if permit, then dont do any nacm checks in
|
/* Pre-NACM access step, if permit, then dont do any nacm checks in
|
||||||
* text_modify_* below */
|
* text_modify_* below */
|
||||||
if ((permit = nacm_access(mode, xnacm, username)) < 0)
|
if ((permit = nacm_access(mode, xnacm, username)) < 0)
|
||||||
|
|
@ -744,6 +749,8 @@ xmldb_put(clicon_handle h,
|
||||||
done:
|
done:
|
||||||
if (f != NULL)
|
if (f != NULL)
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
if (nsc)
|
||||||
|
xml_nsctx_free(nsc);
|
||||||
if (dbfile)
|
if (dbfile)
|
||||||
free(dbfile);
|
free(dbfile);
|
||||||
if (cb)
|
if (cb)
|
||||||
|
|
|
||||||
|
|
@ -68,8 +68,12 @@
|
||||||
#include "clixon_xpath.h"
|
#include "clixon_xpath.h"
|
||||||
#include "clixon_yang_module.h"
|
#include "clixon_yang_module.h"
|
||||||
#include "clixon_datastore.h"
|
#include "clixon_datastore.h"
|
||||||
|
#include "clixon_xml_nsctx.h"
|
||||||
#include "clixon_nacm.h"
|
#include "clixon_nacm.h"
|
||||||
|
|
||||||
|
/* NACM namespace for use with xml namespace contexts and xpath */
|
||||||
|
#define NACM_NS "urn:ietf:params:xml:ns:yang:ietf-netconf-acm"
|
||||||
|
|
||||||
/*! Match nacm access operations according to RFC8341 3.4.4.
|
/*! Match nacm access operations according to RFC8341 3.4.4.
|
||||||
* Incoming RPC Message Validation Step 7 (c)
|
* Incoming RPC Message Validation Step 7 (c)
|
||||||
* The rule's "access-operations" leaf has the "exec" bit set or
|
* The rule's "access-operations" leaf has the "exec" bit set or
|
||||||
|
|
@ -191,7 +195,11 @@ nacm_rpc(char *rpc,
|
||||||
char *gname;
|
char *gname;
|
||||||
char *action;
|
char *action;
|
||||||
int match= 0;
|
int match= 0;
|
||||||
|
cvec *nsc = NULL;
|
||||||
|
|
||||||
|
/* Create namespace context for with nacm namespace as default */
|
||||||
|
if ((nsc = xml_nsctx_init(NULL, NACM_NS)) == NULL)
|
||||||
|
goto done;
|
||||||
/* 3. If the requested operation is the NETCONF <close-session>
|
/* 3. If the requested operation is the NETCONF <close-session>
|
||||||
protocol operation, then the protocol operation is permitted.
|
protocol operation, then the protocol operation is permitted.
|
||||||
*/
|
*/
|
||||||
|
|
@ -204,8 +212,9 @@ nacm_rpc(char *rpc,
|
||||||
transport layer.) */
|
transport layer.) */
|
||||||
if (username == NULL)
|
if (username == NULL)
|
||||||
goto step10;
|
goto step10;
|
||||||
|
|
||||||
/* User's group */
|
/* User's group */
|
||||||
if (xpath_vec(xnacm, "groups/group[user-name='%s']", &gvec, &glen, username) < 0)
|
if (xpath_vec(xnacm, nsc, "groups/group[user-name='%s']", &gvec, &glen, username) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* 5. If no groups are found, continue with step 10. */
|
/* 5. If no groups are found, continue with step 10. */
|
||||||
if (glen == 0)
|
if (glen == 0)
|
||||||
|
|
@ -214,14 +223,14 @@ nacm_rpc(char *rpc,
|
||||||
configuration. If a rule-list's "group" leaf-list does not
|
configuration. If a rule-list's "group" leaf-list does not
|
||||||
match any of the user's groups, proceed to the next rule-list
|
match any of the user's groups, proceed to the next rule-list
|
||||||
entry. */
|
entry. */
|
||||||
if (xpath_vec(xnacm, "rule-list", &rlistvec, &rlistlen) < 0)
|
if (xpath_vec(xnacm, nsc, "rule-list", &rlistvec, &rlistlen) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
for (i=0; i<rlistlen; i++){
|
for (i=0; i<rlistlen; i++){
|
||||||
rlist = rlistvec[i];
|
rlist = rlistvec[i];
|
||||||
/* Loop through user's group to find match in this rule-list */
|
/* Loop through user's group to find match in this rule-list */
|
||||||
for (j=0; j<glen; j++){
|
for (j=0; j<glen; j++){
|
||||||
gname = xml_find_body(gvec[j], "name");
|
gname = xml_find_body(gvec[j], "name");
|
||||||
if (xpath_first(rlist, ".[group='%s']", gname)!=NULL)
|
if (xpath_first(rlist, nsc, ".[group='%s']", gname)!=NULL)
|
||||||
break; /* found */
|
break; /* found */
|
||||||
}
|
}
|
||||||
if (j==glen) /* not found */
|
if (j==glen) /* not found */
|
||||||
|
|
@ -230,7 +239,7 @@ nacm_rpc(char *rpc,
|
||||||
until a rule that matches the requested access operation is
|
until a rule that matches the requested access operation is
|
||||||
found.
|
found.
|
||||||
*/
|
*/
|
||||||
if (xpath_vec(rlist, "rule", &rvec, &rlen) < 0)
|
if (xpath_vec(rlist, nsc, "rule", &rvec, &rlen) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
for (j=0; j<rlen; j++){
|
for (j=0; j<rlen; j++){
|
||||||
xrule = rvec[j];
|
xrule = rvec[j];
|
||||||
|
|
@ -283,6 +292,8 @@ nacm_rpc(char *rpc,
|
||||||
retval = 1;
|
retval = 1;
|
||||||
done:
|
done:
|
||||||
clicon_debug(1, "%s retval:%d (0:deny 1:permit)", __FUNCTION__, retval);
|
clicon_debug(1, "%s retval:%d (0:deny 1:permit)", __FUNCTION__, retval);
|
||||||
|
if (nsc)
|
||||||
|
xml_nsctx_free(nsc);
|
||||||
if (gvec)
|
if (gvec)
|
||||||
free(gvec);
|
free(gvec);
|
||||||
if (rlistvec)
|
if (rlistvec)
|
||||||
|
|
@ -321,7 +332,11 @@ nacm_rule_datanode(cxobj *xt,
|
||||||
char *module;
|
char *module;
|
||||||
cxobj *xpath; /* xpath match */
|
cxobj *xpath; /* xpath match */
|
||||||
cxobj *xp; /* parent */
|
cxobj *xp; /* parent */
|
||||||
|
cvec *nsc = NULL;
|
||||||
|
|
||||||
|
/* Create namespace context for with nacm namespace as default */
|
||||||
|
if ((nsc = xml_nsctx_init(NULL, NACM_NS)) == NULL)
|
||||||
|
goto done;
|
||||||
/* 6a) The rule's "module-name" leaf is "*" or equals the name of
|
/* 6a) The rule's "module-name" leaf is "*" or equals the name of
|
||||||
* the YANG module where the requested data node is defined. */
|
* the YANG module where the requested data node is defined. */
|
||||||
if ((module_rule = xml_find_body(xrule, "module-name")) == NULL)
|
if ((module_rule = xml_find_body(xrule, "module-name")) == NULL)
|
||||||
|
|
@ -375,7 +390,7 @@ nacm_rule_datanode(cxobj *xt,
|
||||||
}
|
}
|
||||||
/* Here module is matched, now check for path if any NYI */
|
/* Here module is matched, now check for path if any NYI */
|
||||||
if (path){
|
if (path){
|
||||||
if ((xpath = xpath_first(xt, "%s", path)) == NULL)
|
if ((xpath = xpath_first(xt, nsc, "%s", path)) == NULL)
|
||||||
goto nomatch;
|
goto nomatch;
|
||||||
/* The requested node xr is the node specified by the path or is a
|
/* The requested node xr is the node specified by the path or is a
|
||||||
* descendant node of the path:
|
* descendant node of the path:
|
||||||
|
|
@ -390,6 +405,8 @@ nacm_rule_datanode(cxobj *xt,
|
||||||
match:
|
match:
|
||||||
retval = 1;
|
retval = 1;
|
||||||
done:
|
done:
|
||||||
|
if (nsc)
|
||||||
|
xml_nsctx_free(nsc);
|
||||||
return retval;
|
return retval;
|
||||||
nomatch:
|
nomatch:
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
@ -403,7 +420,8 @@ nacm_rule_datanode(cxobj *xt,
|
||||||
* @param[in] glen Length of gvec
|
* @param[in] glen Length of gvec
|
||||||
* @param[in] rlistvec NACM rule-list entries
|
* @param[in] rlistvec NACM rule-list entries
|
||||||
* @param[in] rlistlen Length of rlistvec
|
* @param[in] rlistlen Length of rlistvec
|
||||||
* @param[out] xrulep If set, then points to matching rule
|
* @param[in] nsc NACM namespace context for xpaths
|
||||||
|
* @param[out] xrulep If set, then points to matching rule
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
nacm_data_read_xr(cxobj *xt,
|
nacm_data_read_xr(cxobj *xt,
|
||||||
|
|
@ -412,6 +430,7 @@ nacm_data_read_xr(cxobj *xt,
|
||||||
size_t glen,
|
size_t glen,
|
||||||
cxobj **rlistvec,
|
cxobj **rlistvec,
|
||||||
size_t rlistlen,
|
size_t rlistlen,
|
||||||
|
cvec *nsc,
|
||||||
cxobj **xrulep)
|
cxobj **xrulep)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
@ -428,7 +447,7 @@ nacm_data_read_xr(cxobj *xt,
|
||||||
/* Loop through user's group to find match in this rule-list */
|
/* Loop through user's group to find match in this rule-list */
|
||||||
for (j=0; j<glen; j++){
|
for (j=0; j<glen; j++){
|
||||||
gname = xml_find_body(gvec[j], "name");
|
gname = xml_find_body(gvec[j], "name");
|
||||||
if (xpath_first(rlist, ".[group='%s']", gname)!=NULL)
|
if (xpath_first(rlist, nsc, ".[group='%s']", gname)!=NULL)
|
||||||
break; /* found */
|
break; /* found */
|
||||||
}
|
}
|
||||||
if (j==glen) /* not found */
|
if (j==glen) /* not found */
|
||||||
|
|
@ -437,7 +456,7 @@ nacm_data_read_xr(cxobj *xt,
|
||||||
until a rule that matches the requested access operation is
|
until a rule that matches the requested access operation is
|
||||||
found. (see 6 sub rules in nacm_rule_datanode
|
found. (see 6 sub rules in nacm_rule_datanode
|
||||||
*/
|
*/
|
||||||
if (xpath_vec(rlist, "rule", &rvec, &rlen) < 0)
|
if (xpath_vec(rlist, nsc, "rule", &rvec, &rlen) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
for (j=0; j<rlen; j++){ /* Loop through rules */
|
for (j=0; j<rlen; j++){ /* Loop through rules */
|
||||||
xrule = rvec[j];
|
xrule = rvec[j];
|
||||||
|
|
@ -556,7 +575,11 @@ nacm_datanode_read(cxobj *xt,
|
||||||
char *read_default = NULL;
|
char *read_default = NULL;
|
||||||
cxobj *xrule;
|
cxobj *xrule;
|
||||||
char *action;
|
char *action;
|
||||||
|
cvec *nsc = NULL;
|
||||||
|
|
||||||
|
/* Create namespace context for with nacm namespace as default */
|
||||||
|
if ((nsc = xml_nsctx_init(NULL, NACM_NS)) == NULL)
|
||||||
|
goto done;
|
||||||
/* 3. Check all the "group" entries to see if any of them contain a
|
/* 3. Check all the "group" entries to see if any of them contain a
|
||||||
"user-name" entry that equals the username for the session
|
"user-name" entry that equals the username for the session
|
||||||
making the request. (If the "enable-external-groups" leaf is
|
making the request. (If the "enable-external-groups" leaf is
|
||||||
|
|
@ -565,7 +588,7 @@ nacm_datanode_read(cxobj *xt,
|
||||||
if (username == NULL)
|
if (username == NULL)
|
||||||
goto step9;
|
goto step9;
|
||||||
/* User's group */
|
/* User's group */
|
||||||
if (xpath_vec(xnacm, "groups/group[user-name='%s']", &gvec, &glen, username) < 0)
|
if (xpath_vec(xnacm, nsc, "groups/group[user-name='%s']", &gvec, &glen, username) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* 4. If no groups are found (glen=0), continue and check read-default
|
/* 4. If no groups are found (glen=0), continue and check read-default
|
||||||
in step 11. */
|
in step 11. */
|
||||||
|
|
@ -573,7 +596,7 @@ nacm_datanode_read(cxobj *xt,
|
||||||
configuration. If a rule-list's "group" leaf-list does not
|
configuration. If a rule-list's "group" leaf-list does not
|
||||||
match any of the user's groups, proceed to the next rule-list
|
match any of the user's groups, proceed to the next rule-list
|
||||||
entry. */
|
entry. */
|
||||||
if (xpath_vec(xnacm, "rule-list", &rlistvec, &rlistlen) < 0)
|
if (xpath_vec(xnacm, nsc, "rule-list", &rlistvec, &rlistlen) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* read-default has default permit so should never be NULL */
|
/* read-default has default permit so should never be NULL */
|
||||||
if ((read_default = xml_find_body(xnacm, "read-default")) == NULL){
|
if ((read_default = xml_find_body(xnacm, "read-default")) == NULL){
|
||||||
|
|
@ -587,7 +610,7 @@ nacm_datanode_read(cxobj *xt,
|
||||||
xrule = NULL;
|
xrule = NULL;
|
||||||
/* Skip if no groups */
|
/* Skip if no groups */
|
||||||
if (glen && nacm_data_read_xr(xt, xr, gvec, glen, rlistvec, rlistlen,
|
if (glen && nacm_data_read_xr(xt, xr, gvec, glen, rlistvec, rlistlen,
|
||||||
&xrule) < 0)
|
nsc, &xrule) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (xrule){ /* xrule match requested node xr */
|
if (xrule){ /* xrule match requested node xr */
|
||||||
if ((action = xml_find_body(xrule, "action")) == NULL)
|
if ((action = xml_find_body(xrule, "action")) == NULL)
|
||||||
|
|
@ -628,6 +651,8 @@ nacm_datanode_read(cxobj *xt,
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||||
|
if (nsc)
|
||||||
|
xml_nsctx_free(nsc);
|
||||||
if (gvec)
|
if (gvec)
|
||||||
free(gvec);
|
free(gvec);
|
||||||
if (rlistvec)
|
if (rlistvec)
|
||||||
|
|
@ -673,7 +698,11 @@ nacm_datanode_write(cxobj *xt,
|
||||||
int match = 0;
|
int match = 0;
|
||||||
char *action;
|
char *action;
|
||||||
char *write_default = NULL;
|
char *write_default = NULL;
|
||||||
|
cvec *nsc = NULL;
|
||||||
|
|
||||||
|
/* Create namespace context for with nacm namespace as default */
|
||||||
|
if ((nsc = xml_nsctx_init(NULL, NACM_NS)) == NULL)
|
||||||
|
goto done;
|
||||||
if (xnacm == NULL)
|
if (xnacm == NULL)
|
||||||
goto permit;
|
goto permit;
|
||||||
/* 3. Check all the "group" entries to see if any of them contain a
|
/* 3. Check all the "group" entries to see if any of them contain a
|
||||||
|
|
@ -684,7 +713,7 @@ nacm_datanode_write(cxobj *xt,
|
||||||
if (username == NULL)
|
if (username == NULL)
|
||||||
goto step9;
|
goto step9;
|
||||||
/* User's group */
|
/* User's group */
|
||||||
if (xpath_vec(xnacm, "groups/group[user-name='%s']", &gvec, &glen, username) < 0)
|
if (xpath_vec(xnacm, nsc, "groups/group[user-name='%s']", &gvec, &glen, username) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* 4. If no groups are found, continue with step 9. */
|
/* 4. If no groups are found, continue with step 9. */
|
||||||
if (glen == 0)
|
if (glen == 0)
|
||||||
|
|
@ -693,19 +722,19 @@ nacm_datanode_write(cxobj *xt,
|
||||||
configuration. If a rule-list's "group" leaf-list does not
|
configuration. If a rule-list's "group" leaf-list does not
|
||||||
match any of the user's groups, proceed to the next rule-list
|
match any of the user's groups, proceed to the next rule-list
|
||||||
entry. */
|
entry. */
|
||||||
if (xpath_vec(xnacm, "rule-list", &rlistvec, &rlistlen) < 0)
|
if (xpath_vec(xnacm, nsc, "rule-list", &rlistvec, &rlistlen) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
for (i=0; i<rlistlen; i++){
|
for (i=0; i<rlistlen; i++){
|
||||||
rlist = rlistvec[i];
|
rlist = rlistvec[i];
|
||||||
/* Loop through user's group to find match in this rule-list */
|
/* Loop through user's group to find match in this rule-list */
|
||||||
for (j=0; j<glen; j++){
|
for (j=0; j<glen; j++){
|
||||||
gname = xml_find_body(gvec[j], "name");
|
gname = xml_find_body(gvec[j], "name");
|
||||||
if (xpath_first(rlist, ".[group='%s']", gname)!=NULL)
|
if (xpath_first(rlist, nsc, ".[group='%s']", gname)!=NULL)
|
||||||
break; /* found */
|
break; /* found */
|
||||||
}
|
}
|
||||||
if (j==glen) /* not found */
|
if (j==glen) /* not found */
|
||||||
continue;
|
continue;
|
||||||
if (xpath_vec(rlist, "rule", &rvec, &rlen) < 0)
|
if (xpath_vec(rlist, nsc, "rule", &rvec, &rlen) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* 6. For each rule-list entry found, process all rules, in order,
|
/* 6. For each rule-list entry found, process all rules, in order,
|
||||||
until a rule that matches the requested access operation is
|
until a rule that matches the requested access operation is
|
||||||
|
|
@ -765,6 +794,8 @@ nacm_datanode_write(cxobj *xt,
|
||||||
retval = 1;
|
retval = 1;
|
||||||
done:
|
done:
|
||||||
clicon_debug(1, "%s retval:%d (0:deny 1:permit)", __FUNCTION__, retval);
|
clicon_debug(1, "%s retval:%d (0:deny 1:permit)", __FUNCTION__, retval);
|
||||||
|
if (nsc)
|
||||||
|
xml_nsctx_free(nsc);
|
||||||
if (gvec)
|
if (gvec)
|
||||||
free(gvec);
|
free(gvec);
|
||||||
if (rlistvec)
|
if (rlistvec)
|
||||||
|
|
@ -811,8 +842,11 @@ nacm_access(char *mode,
|
||||||
cxobj *xnacm0 = NULL;
|
cxobj *xnacm0 = NULL;
|
||||||
char *enabled;
|
char *enabled;
|
||||||
cxobj *x;
|
cxobj *x;
|
||||||
|
cvec *nsc = NULL;
|
||||||
|
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
|
if ((nsc = xml_nsctx_init(NULL, NACM_NS)) == NULL)
|
||||||
|
goto done;
|
||||||
if (mode == NULL || strcmp(mode, "disabled") == 0)
|
if (mode == NULL || strcmp(mode, "disabled") == 0)
|
||||||
goto permit;
|
goto permit;
|
||||||
/* 0. If nacm-mode is external, get NACM defintion from separet tree,
|
/* 0. If nacm-mode is external, get NACM defintion from separet tree,
|
||||||
|
|
@ -828,7 +862,7 @@ nacm_access(char *mode,
|
||||||
* RFC8341 3.4 */
|
* RFC8341 3.4 */
|
||||||
/* 1. If the "enable-nacm" leaf is set to "false", then the protocol
|
/* 1. If the "enable-nacm" leaf is set to "false", then the protocol
|
||||||
operation is permitted. */
|
operation is permitted. */
|
||||||
if ((x = xpath_first(xnacm, "enable-nacm")) == NULL)
|
if ((x = xpath_first(xnacm, nsc, "enable-nacm")) == NULL)
|
||||||
goto permit;
|
goto permit;
|
||||||
enabled = xml_body(x);
|
enabled = xml_body(x);
|
||||||
if (strcmp(enabled, "true") != 0)
|
if (strcmp(enabled, "true") != 0)
|
||||||
|
|
@ -840,6 +874,8 @@ nacm_access(char *mode,
|
||||||
|
|
||||||
retval = 0; /* not permitted yet. continue with next NACM step */
|
retval = 0; /* not permitted yet. continue with next NACM step */
|
||||||
done:
|
done:
|
||||||
|
if (nsc)
|
||||||
|
xml_nsctx_free(nsc);
|
||||||
if (retval != 0 && xnacm0)
|
if (retval != 0 && xnacm0)
|
||||||
xml_free(xnacm0);
|
xml_free(xnacm0);
|
||||||
clicon_debug(1, "%s retval:%d (0:deny 1:permit)", __FUNCTION__, retval);
|
clicon_debug(1, "%s retval:%d (0:deny 1:permit)", __FUNCTION__, retval);
|
||||||
|
|
@ -882,7 +918,10 @@ nacm_access_pre(clicon_handle h,
|
||||||
cxobj *x;
|
cxobj *x;
|
||||||
cxobj *xnacm0 = NULL;
|
cxobj *xnacm0 = NULL;
|
||||||
cxobj *xnacm = NULL;
|
cxobj *xnacm = NULL;
|
||||||
|
cvec *nsc = NULL;
|
||||||
|
|
||||||
|
if ((nsc = xml_nsctx_init(NULL, NACM_NS)) == NULL)
|
||||||
|
goto done;
|
||||||
if ((mode = clicon_option_str(h, "CLICON_NACM_MODE")) != NULL){
|
if ((mode = clicon_option_str(h, "CLICON_NACM_MODE")) != NULL){
|
||||||
if (strcmp(mode, "external")==0){
|
if (strcmp(mode, "external")==0){
|
||||||
if ((x = clicon_nacm_ext(h)))
|
if ((x = clicon_nacm_ext(h)))
|
||||||
|
|
@ -890,7 +929,7 @@ nacm_access_pre(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else if (strcmp(mode, "internal")==0){
|
else if (strcmp(mode, "internal")==0){
|
||||||
if (xmldb_get(h, "running", "nacm", &xnacm0) < 0)
|
if (xmldb_get0(h, "running", nsc, "nacm", 1, &xnacm0, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -898,7 +937,7 @@ nacm_access_pre(clicon_handle h,
|
||||||
if (xnacm0 == NULL)
|
if (xnacm0 == NULL)
|
||||||
goto permit;
|
goto permit;
|
||||||
/* If config does not exist then the operation is permitted(?) */
|
/* If config does not exist then the operation is permitted(?) */
|
||||||
if ((xnacm = xpath_first(xnacm0, "nacm")) == NULL)
|
if ((xnacm = xpath_first(xnacm0, nsc, "nacm")) == NULL)
|
||||||
goto permit;
|
goto permit;
|
||||||
if (xml_rootchild_node(xnacm0, xnacm) < 0)
|
if (xml_rootchild_node(xnacm0, xnacm) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -910,6 +949,8 @@ nacm_access_pre(clicon_handle h,
|
||||||
xnacm = NULL;
|
xnacm = NULL;
|
||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
|
if (nsc)
|
||||||
|
xml_nsctx_free(nsc);
|
||||||
if (xnacm0)
|
if (xnacm0)
|
||||||
xml_free(xnacm0);
|
xml_free(xnacm0);
|
||||||
else if (xnacm)
|
else if (xnacm)
|
||||||
|
|
|
||||||
|
|
@ -1274,13 +1274,13 @@ netconf_err2cb(cxobj *xerr,
|
||||||
clicon_err(OE_XML, errno, "cbuf_new");
|
clicon_err(OE_XML, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((x=xpath_first(xerr, "error-type"))!=NULL)
|
if ((x=xpath_first(xerr, NULL, "error-type"))!=NULL)
|
||||||
cprintf(cb, "%s ", xml_body(x));
|
cprintf(cb, "%s ", xml_body(x));
|
||||||
if ((x=xpath_first(xerr, "error-tag"))!=NULL)
|
if ((x=xpath_first(xerr, NULL, "error-tag"))!=NULL)
|
||||||
cprintf(cb, "%s ", xml_body(x));
|
cprintf(cb, "%s ", xml_body(x));
|
||||||
if ((x=xpath_first(xerr, "error-message"))!=NULL)
|
if ((x=xpath_first(xerr, NULL, "error-message"))!=NULL)
|
||||||
cprintf(cb, "%s ", xml_body(x));
|
cprintf(cb, "%s ", xml_body(x));
|
||||||
if ((x=xpath_first(xerr, "error-info"))!=NULL)
|
if ((x=xpath_first(xerr, NULL, "error-info"))!=NULL)
|
||||||
clicon_xml2cbuf(cb, xml_child_i(x,0), 0, 0);
|
clicon_xml2cbuf(cb, xml_child_i(x,0), 0, 0);
|
||||||
*cberr = cb;
|
*cberr = cb;
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
|
||||||
|
|
@ -73,8 +73,15 @@
|
||||||
#include "clixon_xpath_ctx.h"
|
#include "clixon_xpath_ctx.h"
|
||||||
#include "clixon_xpath.h"
|
#include "clixon_xpath.h"
|
||||||
#include "clixon_netconf_lib.h"
|
#include "clixon_netconf_lib.h"
|
||||||
|
#include "clixon_xml_nsctx.h"
|
||||||
#include "clixon_xml_map.h"
|
#include "clixon_xml_map.h"
|
||||||
|
|
||||||
|
/*! Clixon configuration namespace
|
||||||
|
* Probably should be defined somewhere else or extracted from yang
|
||||||
|
* @see clixon-config.yang
|
||||||
|
*/
|
||||||
|
#define CLIXON_CONF_NS "http://clicon.org/config"
|
||||||
|
|
||||||
/* Mapping between Clicon startup modes string <--> constants,
|
/* Mapping between Clicon startup modes string <--> constants,
|
||||||
see clixon-config.yang type startup_mode */
|
see clixon-config.yang type startup_mode */
|
||||||
static const map_str2int startup_mode_map[] = {
|
static const map_str2int startup_mode_map[] = {
|
||||||
|
|
@ -165,6 +172,7 @@ parse_configfile(clicon_handle h,
|
||||||
cbuf *cbret = NULL;
|
cbuf *cbret = NULL;
|
||||||
cxobj *xret = NULL;
|
cxobj *xret = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
cvec *nsc = NULL;
|
||||||
|
|
||||||
if (filename == NULL || !strlen(filename)){
|
if (filename == NULL || !strlen(filename)){
|
||||||
clicon_err(OE_UNIX, 0, "Not specified");
|
clicon_err(OE_UNIX, 0, "Not specified");
|
||||||
|
|
@ -191,25 +199,12 @@ parse_configfile(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Hard-coded config for < 3.10 and clixon-config for >= 3.10 */
|
/* Hard-coded config for < 3.10 and clixon-config for >= 3.10 */
|
||||||
if ((xc = xpath_first(xt, "clixon-config")) == NULL){
|
if ((nsc = xml_nsctx_init(NULL, CLIXON_CONF_NS)) == NULL)
|
||||||
/* Backward compatible code to accept "config" as top-level symbol.
|
goto done;
|
||||||
This cannot be controlled by config option due to bootstrap */
|
if ((xc = xpath_first(xt, nsc, "clixon-config")) == NULL){
|
||||||
#if 0
|
clicon_err(OE_CFG, 0, "Config file %s: Lacks top-level \"clixon-config\" element\nClixon config files should begin with: <clixon-config xmlns=\"%s\" (See Changelog in Clixon 3.10)>", filename, CLIXON_CONF_NS);
|
||||||
if ((xc = xpath_first(xt, "config")) != NULL){
|
|
||||||
if (xml_name_set(xc, "clixon-config") < 0)
|
|
||||||
goto done;
|
|
||||||
if (xml_apply0(xc, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
|
||||||
goto done;
|
|
||||||
if (xml_apply0(xc, CX_ELMNT, xml_sort, h) < 0)
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
clicon_err(OE_CFG, 0, "Config file %s: Lacks top-level \"clixon-config\" element\nClixon config files should begin with: <clixon-config xmlns=\"http://clicon.org/config\" (See Changelog in Clixon 3.10)>", filename);
|
|
||||||
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (xml_apply0(xc, CX_ELMNT, xml_default, h) < 0)
|
if (xml_apply0(xc, CX_ELMNT, xml_default, h) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -249,6 +244,8 @@ parse_configfile(clicon_handle h,
|
||||||
*xconfig = xt;
|
*xconfig = xt;
|
||||||
xt = NULL;
|
xt = NULL;
|
||||||
done:
|
done:
|
||||||
|
if (nsc)
|
||||||
|
xml_nsctx_free(nsc);
|
||||||
if (cbret)
|
if (cbret)
|
||||||
cbuf_free(cbret);
|
cbuf_free(cbret);
|
||||||
if (xret)
|
if (xret)
|
||||||
|
|
@ -364,7 +361,7 @@ clicon_options_main(clicon_handle h,
|
||||||
if (xml_rootchild(xconfig, 0, &xconfig) < 0)
|
if (xml_rootchild(xconfig, 0, &xconfig) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (xml_spec(xconfig) == NULL){
|
if (xml_spec(xconfig) == NULL){
|
||||||
clicon_err(OE_CFG, 0, "Config file %s: did not find corresponding Yang specification\nHint: File does not begin with: <clixon-config xmlns=\"http://clicon.org/config\"> or clixon-config.yang not found?", configfile);
|
clicon_err(OE_CFG, 0, "Config file %s: did not find corresponding Yang specification\nHint: File does not begin with: <clixon-config xmlns=\"%s\"> or clixon-config.yang not found?", configfile, CLIXON_CONF_NS);
|
||||||
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -253,15 +253,16 @@ clicon_rpc_generate_error(char *prefix,
|
||||||
* @param[in] h CLICON handle
|
* @param[in] h CLICON handle
|
||||||
* @param[in] db Name of database
|
* @param[in] db Name of database
|
||||||
* @param[in] xpath XPath (or "")
|
* @param[in] xpath XPath (or "")
|
||||||
|
* @param[in] namespace Namespace associated w xpath
|
||||||
* @param[out] xt XML tree. Free with xml_free.
|
* @param[out] xt XML tree. Free with xml_free.
|
||||||
* Either <config> or <rpc-error>.
|
* Either <config> or <rpc-error>.
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
* @retval -1 Error, fatal or xml
|
* @retval -1 Error, fatal or xml
|
||||||
* @code
|
* @code
|
||||||
* cxobj *xt = NULL;
|
* cxobj *xt = NULL;
|
||||||
* if (clicon_rpc_get_config(h, "running", "/", &xt) < 0)
|
* if (clicon_rpc_get_config(h, "running", "/hello/world", "urn:example:hello", &xt) < 0)
|
||||||
* err;
|
* err;
|
||||||
* if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
|
* if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
|
||||||
* clicon_rpc_generate_error("", xerr);
|
* clicon_rpc_generate_error("", xerr);
|
||||||
* err;
|
* err;
|
||||||
* }
|
* }
|
||||||
|
|
@ -274,6 +275,7 @@ int
|
||||||
clicon_rpc_get_config(clicon_handle h,
|
clicon_rpc_get_config(clicon_handle h,
|
||||||
char *db,
|
char *db,
|
||||||
char *xpath,
|
char *xpath,
|
||||||
|
char *namespace,
|
||||||
cxobj **xt)
|
cxobj **xt)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
@ -288,18 +290,25 @@ clicon_rpc_get_config(clicon_handle h,
|
||||||
cprintf(cb, "<rpc");
|
cprintf(cb, "<rpc");
|
||||||
if ((username = clicon_username_get(h)) != NULL)
|
if ((username = clicon_username_get(h)) != NULL)
|
||||||
cprintf(cb, " username=\"%s\"", username);
|
cprintf(cb, " username=\"%s\"", username);
|
||||||
|
if (namespace)
|
||||||
|
cprintf(cb, " xmlns:nc=\"%s\"", NETCONF_BASE_NAMESPACE);
|
||||||
cprintf(cb, "><get-config><source><%s/></source>", db);
|
cprintf(cb, "><get-config><source><%s/></source>", db);
|
||||||
if (xpath && strlen(xpath))
|
if (xpath && strlen(xpath)){
|
||||||
cprintf(cb, "<filter type=\"xpath\" select=\"%s\"/>", xpath);
|
if (namespace)
|
||||||
|
cprintf(cb, "<nc:filter nc:type=\"xpath\" nc:select=\"%s\" xmlns=\"%s\"/>",
|
||||||
|
xpath, namespace);
|
||||||
|
else /* XXX shouldnt happen */
|
||||||
|
cprintf(cb, "<filter type=\"xpath\" select=\"%s\"/>", xpath);
|
||||||
|
}
|
||||||
cprintf(cb, "</get-config></rpc>");
|
cprintf(cb, "</get-config></rpc>");
|
||||||
if ((msg = clicon_msg_encode("%s", cbuf_get(cb))) == NULL)
|
if ((msg = clicon_msg_encode("%s", cbuf_get(cb))) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Send xml error back: first check error, then ok */
|
/* Send xml error back: first check error, then ok */
|
||||||
if ((xd = xpath_first(xret, "/rpc-reply/rpc-error")) != NULL)
|
if ((xd = xpath_first(xret, NULL, "/rpc-reply/rpc-error")) != NULL)
|
||||||
xd = xml_parent(xd); /* point to rpc-reply */
|
xd = xml_parent(xd); /* point to rpc-reply */
|
||||||
else if ((xd = xpath_first(xret, "/rpc-reply/data")) == NULL)
|
else if ((xd = xpath_first(xret, NULL, "/rpc-reply/data")) == NULL)
|
||||||
if ((xd = xml_new("data", NULL, NULL)) == NULL)
|
if ((xd = xml_new("data", NULL, NULL)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (xt){
|
if (xt){
|
||||||
|
|
@ -347,7 +356,7 @@ clicon_rpc_edit_config(clicon_handle h,
|
||||||
|
|
||||||
if ((cb = cbuf_new()) == NULL)
|
if ((cb = cbuf_new()) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
cprintf(cb, "<rpc %s", DEFAULT_XMLNS);
|
cprintf(cb, "<rpc xmlns=\"%s\"", NETCONF_BASE_NAMESPACE);
|
||||||
if ((username = clicon_username_get(h)) != NULL)
|
if ((username = clicon_username_get(h)) != NULL)
|
||||||
cprintf(cb, " username=\"%s\"", username);
|
cprintf(cb, " username=\"%s\"", username);
|
||||||
cprintf(cb, "><edit-config><target><%s/></target>", db);
|
cprintf(cb, "><edit-config><target><%s/></target>", db);
|
||||||
|
|
@ -360,7 +369,7 @@ clicon_rpc_edit_config(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||||
clicon_rpc_generate_error("Editing configuration", xerr);
|
clicon_rpc_generate_error("Editing configuration", xerr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -406,7 +415,7 @@ clicon_rpc_copy_config(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||||
clicon_rpc_generate_error("Copying configuration", xerr);
|
clicon_rpc_generate_error("Copying configuration", xerr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -445,7 +454,7 @@ clicon_rpc_delete_config(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||||
clicon_rpc_generate_error("Deleting configuration", xerr);
|
clicon_rpc_generate_error("Deleting configuration", xerr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -480,7 +489,7 @@ clicon_rpc_lock(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||||
clicon_rpc_generate_error("Locking configuration", xerr);
|
clicon_rpc_generate_error("Locking configuration", xerr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -514,7 +523,7 @@ clicon_rpc_unlock(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||||
clicon_rpc_generate_error("Configuration unlock", xerr);
|
clicon_rpc_generate_error("Configuration unlock", xerr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -528,17 +537,20 @@ clicon_rpc_unlock(clicon_handle h,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Get database configuration and state data
|
/*! Get database configuration and state data
|
||||||
* @param[in] h CLICON handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] xpath XPath (or "")
|
* @param[in] xpath XPath in a filter stmt (or NULL/"" for no filter)
|
||||||
* @param[out] xt XML tree. Free with xml_free.
|
* @param[in] namespace Namespace associated w xpath
|
||||||
* Either <config> or <rpc-error>.
|
* @param[out] xt XML tree. Free with xml_free.
|
||||||
* @retval 0 OK
|
* Either <config> or <rpc-error>.
|
||||||
* @retval -1 Error, fatal or xml
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error, fatal or xml
|
||||||
|
* @note if xpath is set but namespace is NULL, the default, netconf base
|
||||||
|
* namespace will be used which is most probably wrong.
|
||||||
* @code
|
* @code
|
||||||
* cxobj *xt = NULL;
|
* cxobj *xt = NULL;
|
||||||
* if (clicon_rpc_get(h, "/", &xt) < 0)
|
* if (clicon_rpc_get(h, "/hello/world", "urn:example:hello", &xt) < 0)
|
||||||
* err;
|
* err;
|
||||||
* if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
|
* if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
|
||||||
* clicon_rpc_generate_error(xerr);
|
* clicon_rpc_generate_error(xerr);
|
||||||
* err;
|
* err;
|
||||||
* }
|
* }
|
||||||
|
|
@ -550,6 +562,7 @@ clicon_rpc_unlock(clicon_handle h,
|
||||||
int
|
int
|
||||||
clicon_rpc_get(clicon_handle h,
|
clicon_rpc_get(clicon_handle h,
|
||||||
char *xpath,
|
char *xpath,
|
||||||
|
char *namespace,
|
||||||
cxobj **xt)
|
cxobj **xt)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
@ -564,18 +577,25 @@ clicon_rpc_get(clicon_handle h,
|
||||||
cprintf(cb, "<rpc");
|
cprintf(cb, "<rpc");
|
||||||
if ((username = clicon_username_get(h)) != NULL)
|
if ((username = clicon_username_get(h)) != NULL)
|
||||||
cprintf(cb, " username=\"%s\"", username);
|
cprintf(cb, " username=\"%s\"", username);
|
||||||
|
if (namespace)
|
||||||
|
cprintf(cb, " xmlns:nc=\"%s\"", NETCONF_BASE_NAMESPACE);
|
||||||
cprintf(cb, "><get>");
|
cprintf(cb, "><get>");
|
||||||
if (xpath && strlen(xpath))
|
if (xpath && strlen(xpath)) {
|
||||||
cprintf(cb, "<filter type=\"xpath\" select=\"%s\"/>", xpath);
|
if (namespace)
|
||||||
|
cprintf(cb, "<nc:filter nc:type=\"xpath\" nc:select=\"%s\" xmlns=\"%s\"/>",
|
||||||
|
xpath, namespace);
|
||||||
|
else /* XXX shouldnt happen */
|
||||||
|
cprintf(cb, "<filter type=\"xpath\" select=\"%s\"/>", xpath);
|
||||||
|
}
|
||||||
cprintf(cb, "</get></rpc>");
|
cprintf(cb, "</get></rpc>");
|
||||||
if ((msg = clicon_msg_encode("%s", cbuf_get(cb))) == NULL)
|
if ((msg = clicon_msg_encode("%s", cbuf_get(cb))) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Send xml error back: first check error, then ok */
|
/* Send xml error back: first check error, then ok */
|
||||||
if ((xd = xpath_first(xret, "/rpc-reply/rpc-error")) != NULL)
|
if ((xd = xpath_first(xret, NULL, "/rpc-reply/rpc-error")) != NULL)
|
||||||
xd = xml_parent(xd); /* point to rpc-reply */
|
xd = xml_parent(xd); /* point to rpc-reply */
|
||||||
else if ((xd = xpath_first(xret, "/rpc-reply/data")) == NULL)
|
else if ((xd = xpath_first(xret, NULL, "/rpc-reply/data")) == NULL)
|
||||||
if ((xd = xml_new("data", NULL, NULL)) == NULL)
|
if ((xd = xml_new("data", NULL, NULL)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (xt){
|
if (xt){
|
||||||
|
|
@ -614,7 +634,7 @@ clicon_rpc_close_session(clicon_handle h)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||||
clicon_rpc_generate_error("Close session", xerr);
|
clicon_rpc_generate_error("Close session", xerr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -649,7 +669,7 @@ clicon_rpc_kill_session(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||||
clicon_rpc_generate_error("Kill session", xerr);
|
clicon_rpc_generate_error("Kill session", xerr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -683,7 +703,7 @@ clicon_rpc_validate(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||||
clicon_rpc_generate_error(CLIXON_ERRSTR_VALIDATE_FAILED, xerr);
|
clicon_rpc_generate_error(CLIXON_ERRSTR_VALIDATE_FAILED, xerr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -715,7 +735,7 @@ clicon_rpc_commit(clicon_handle h)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||||
clicon_rpc_generate_error(CLIXON_ERRSTR_COMMIT_FAILED, xerr);
|
clicon_rpc_generate_error(CLIXON_ERRSTR_COMMIT_FAILED, xerr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -747,7 +767,7 @@ clicon_rpc_discard_changes(clicon_handle h)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||||
clicon_rpc_generate_error("Discard changes", xerr);
|
clicon_rpc_generate_error("Discard changes", xerr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -792,7 +812,7 @@ clicon_rpc_create_subscription(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret, s0) < 0)
|
if (clicon_rpc_msg(h, msg, &xret, s0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||||
clicon_rpc_generate_error("Create subscription", xerr);
|
clicon_rpc_generate_error("Create subscription", xerr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -827,11 +847,11 @@ clicon_rpc_debug(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||||
clicon_rpc_generate_error("Debug",xerr);
|
clicon_rpc_generate_error("Debug",xerr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (xpath_first(xret, "//rpc-reply/ok") == NULL){
|
if (xpath_first(xret, NULL, "//rpc-reply/ok") == NULL){
|
||||||
clicon_err(OE_XML, 0, "rpc error"); /* XXX extract info from rpc-error */
|
clicon_err(OE_XML, 0, "rpc error"); /* XXX extract info from rpc-error */
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -514,7 +514,7 @@ stream_notify1(clicon_handle h,
|
||||||
else{ /* xpath match */
|
else{ /* xpath match */
|
||||||
if (ss->ss_xpath == NULL ||
|
if (ss->ss_xpath == NULL ||
|
||||||
strlen(ss->ss_xpath)==0 ||
|
strlen(ss->ss_xpath)==0 ||
|
||||||
xpath_first(xevent, "%s", ss->ss_xpath) != NULL)
|
xpath_first(xevent, NULL, "%s", ss->ss_xpath) != NULL)
|
||||||
if ((*ss->ss_fn)(h, 0, xevent, ss->ss_arg) < 0)
|
if ((*ss->ss_fn)(h, 0, xevent, ss->ss_arg) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
ss = NEXTQ(struct stream_subscription *, ss);
|
ss = NEXTQ(struct stream_subscription *, ss);
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@
|
||||||
#include "clixon_xml_map.h" /* xml_spec_populate */
|
#include "clixon_xml_map.h" /* xml_spec_populate */
|
||||||
#include "clixon_xml_sort.h"
|
#include "clixon_xml_sort.h"
|
||||||
#include "clixon_xml_parse.h"
|
#include "clixon_xml_parse.h"
|
||||||
|
#include "clixon_xml_nsctx.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Constants
|
* Constants
|
||||||
|
|
@ -130,7 +131,7 @@ struct xml{
|
||||||
reference, dont free */
|
reference, dont free */
|
||||||
cg_var *x_cv; /* Cached value as cligen variable
|
cg_var *x_cv; /* Cached value as cligen variable
|
||||||
(eg xml_cmp) */
|
(eg xml_cmp) */
|
||||||
char *x_ns_cache; /* Cached namespace */
|
cvec *x_ns_cache; /* Cached vector of namespaces */
|
||||||
int _x_vector_i; /* internal use: xml_child_each */
|
int _x_vector_i; /* internal use: xml_child_each */
|
||||||
int _x_i; /* internal use for sorting:
|
int _x_i; /* internal use for sorting:
|
||||||
see xml_enumerate and xml_cmp */
|
see xml_enumerate and xml_cmp */
|
||||||
|
|
@ -229,6 +230,47 @@ xml_prefix_set(cxobj *xn,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Get cached namespace
|
||||||
|
* @param[in] x XML node
|
||||||
|
* @param[in] prefix Namespace prefix, or NULL for default
|
||||||
|
* @retval ns Cached namespace
|
||||||
|
* @retval NULL No namespace found (not cached or not found)
|
||||||
|
* @note may want to distinguish between not set cache and no namespace?
|
||||||
|
*/
|
||||||
|
static char*
|
||||||
|
nscache_get(cxobj *x,
|
||||||
|
char *prefix)
|
||||||
|
{
|
||||||
|
if (x->x_ns_cache != NULL)
|
||||||
|
return xml_nsctx_get(x->x_ns_cache, prefix);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Set cached namespace. Replace if necessary
|
||||||
|
* @param[in] x XML node
|
||||||
|
* @param[in] prefix Namespace prefix, or NULL for default
|
||||||
|
* @param[in] namespace Cached namespace to set (assume non-null?)
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
nscache_set(cxobj *x,
|
||||||
|
char *prefix,
|
||||||
|
char *namespace)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
|
||||||
|
if (x->x_ns_cache == NULL){
|
||||||
|
if ((x->x_ns_cache = xml_nsctx_init(prefix, namespace)) == NULL)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return xml_nsctx_set(x->x_ns_cache, prefix, namespace);
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Given an xml tree return URI namespace recursively : default or localname given
|
/*! Given an xml tree return URI namespace recursively : default or localname given
|
||||||
*
|
*
|
||||||
* Given an XML tree and a prefix (or NULL) return URI namespace.
|
* Given an XML tree and a prefix (or NULL) return URI namespace.
|
||||||
|
|
@ -238,7 +280,7 @@ xml_prefix_set(cxobj *xn,
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
* @see xmlns_check XXX can these be merged?
|
* @see xmlns_check XXX can these be merged?
|
||||||
* @see xml2ns_set cache is set
|
* @see xmlns_set cache is set
|
||||||
* @note, this function uses a cache.
|
* @note, this function uses a cache.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
|
|
@ -250,13 +292,13 @@ xml2ns(cxobj *x,
|
||||||
char *ns = NULL;
|
char *ns = NULL;
|
||||||
cxobj *xp;
|
cxobj *xp;
|
||||||
|
|
||||||
if ((ns = x->x_ns_cache) != NULL)
|
if ((ns = nscache_get(x, prefix)) != NULL)
|
||||||
goto ok;
|
goto ok;
|
||||||
if (prefix != NULL) /* xmlns:<prefix>="<uri>" */
|
if (prefix != NULL) /* xmlns:<prefix>="<uri>" */
|
||||||
ns = xml_find_type_value(x, "xmlns", prefix, CX_ATTR);
|
ns = xml_find_type_value(x, "xmlns", prefix, CX_ATTR);
|
||||||
else /* xmlns="<uri>" */
|
else{ /* xmlns="<uri>" */
|
||||||
ns = xml_find_type_value(x, NULL, "xmlns", CX_ATTR);
|
ns = xml_find_type_value(x, NULL, "xmlns", CX_ATTR);
|
||||||
|
}
|
||||||
/* namespace not found, try parent */
|
/* namespace not found, try parent */
|
||||||
if (ns == NULL){
|
if (ns == NULL){
|
||||||
if ((xp = xml_parent(x)) != NULL){
|
if ((xp = xml_parent(x)) != NULL){
|
||||||
|
|
@ -264,15 +306,15 @@ xml2ns(cxobj *x,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* If no parent, return default namespace if defined */
|
/* If no parent, return default namespace if defined */
|
||||||
#if defined(DEFAULT_XML_RPC_NAMESPACE)
|
#ifdef USE_NETCONF_NS_AS_DEFAULT
|
||||||
else
|
else
|
||||||
ns = DEFAULT_XML_RPC_NAMESPACE;
|
ns = NETCONF_BASE_NAMESPACE;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (ns && (x->x_ns_cache = strdup(ns)) == NULL){
|
/* Set default namespace cache (since code is at this point,
|
||||||
clicon_err(OE_XML, errno, "strdup");
|
* no cache was found */
|
||||||
|
if (ns && nscache_set(x, prefix, ns) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
|
||||||
ok:
|
ok:
|
||||||
if (namespace)
|
if (namespace)
|
||||||
*namespace = ns;
|
*namespace = ns;
|
||||||
|
|
@ -311,12 +353,8 @@ xmlns_set(cxobj *x,
|
||||||
if (xml_value_set(xa, ns) < 0)
|
if (xml_value_set(xa, ns) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* (re)set namespace cache (as used in xml2ns) */
|
/* (re)set namespace cache (as used in xml2ns) */
|
||||||
if (x->x_ns_cache)
|
if (ns && nscache_set(x, prefix, ns) < 0)
|
||||||
free(x->x_ns_cache);
|
|
||||||
if ((x->x_ns_cache = strdup(ns)) == NULL){
|
|
||||||
clicon_err(OE_XML, errno, "strdup");
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
|
|
@ -1406,7 +1444,7 @@ xml_free(cxobj *x)
|
||||||
if (x->x_cv)
|
if (x->x_cv)
|
||||||
cv_free(x->x_cv);
|
cv_free(x->x_cv);
|
||||||
if (x->x_ns_cache)
|
if (x->x_ns_cache)
|
||||||
free(x->x_ns_cache);
|
xml_nsctx_free(x->x_ns_cache);
|
||||||
free(x);
|
free(x);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,7 @@
|
||||||
#include "clixon_data.h"
|
#include "clixon_data.h"
|
||||||
#include "clixon_yang_module.h"
|
#include "clixon_yang_module.h"
|
||||||
#include "clixon_netconf_lib.h"
|
#include "clixon_netconf_lib.h"
|
||||||
|
#include "clixon_xml_nsctx.h"
|
||||||
#include "clixon_xml_map.h"
|
#include "clixon_xml_map.h"
|
||||||
#include "clixon_xml_changelog.h"
|
#include "clixon_xml_changelog.h"
|
||||||
#include "clixon_xpath_ctx.h"
|
#include "clixon_xpath_ctx.h"
|
||||||
|
|
@ -77,6 +78,7 @@ static int
|
||||||
changelog_rename(clicon_handle h,
|
changelog_rename(clicon_handle h,
|
||||||
cxobj *xt,
|
cxobj *xt,
|
||||||
cxobj *xw,
|
cxobj *xw,
|
||||||
|
cvec *nsc,
|
||||||
char *tag)
|
char *tag)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
@ -87,7 +89,7 @@ changelog_rename(clicon_handle h,
|
||||||
clicon_err(OE_XML, 0, "tag required");
|
clicon_err(OE_XML, 0, "tag required");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (xpath_vec_ctx(xw, tag, &xctx) < 0)
|
if (xpath_vec_ctx(xw, nsc, tag, &xctx) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ctx2string(xctx, &str) < 0)
|
if (ctx2string(xctx, &str) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -192,12 +194,13 @@ static int
|
||||||
changelog_move(clicon_handle h,
|
changelog_move(clicon_handle h,
|
||||||
cxobj *xt,
|
cxobj *xt,
|
||||||
cxobj *xw,
|
cxobj *xw,
|
||||||
|
cvec *nsc,
|
||||||
char *dst)
|
char *dst)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *xp; /* destination parent node */
|
cxobj *xp; /* destination parent node */
|
||||||
|
|
||||||
if ((xp = xpath_first(xt, "%s", dst)) == NULL){
|
if ((xp = xpath_first(xt, nsc, "%s", dst)) == NULL){
|
||||||
clicon_err(OE_XML, 0, "path required");
|
clicon_err(OE_XML, 0, "path required");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -235,7 +238,11 @@ changelog_op(clicon_handle h,
|
||||||
int ret;
|
int ret;
|
||||||
xp_ctx *xctx = NULL;
|
xp_ctx *xctx = NULL;
|
||||||
int i;
|
int i;
|
||||||
|
cvec *nsc = NULL;
|
||||||
|
|
||||||
|
/* Get namespace context from changelog item */
|
||||||
|
if (xml_nsctx_node(xi, &nsc) < 0)
|
||||||
|
goto done;
|
||||||
if ((op = xml_find_body(xi, "op")) == NULL)
|
if ((op = xml_find_body(xi, "op")) == NULL)
|
||||||
goto ok;
|
goto ok;
|
||||||
/* get common variables that may be used in the operations below */
|
/* get common variables that may be used in the operations below */
|
||||||
|
|
@ -246,13 +253,13 @@ changelog_op(clicon_handle h,
|
||||||
if ((wxpath = xml_find_body(xi, "where")) == NULL)
|
if ((wxpath = xml_find_body(xi, "where")) == NULL)
|
||||||
goto ok;
|
goto ok;
|
||||||
/* Get vector of target nodes meeting the where requirement */
|
/* Get vector of target nodes meeting the where requirement */
|
||||||
if (xpath_vec(xt, "%s", &wvec, &wlen, wxpath) < 0)
|
if (xpath_vec(xt, nsc, "%s", &wvec, &wlen, wxpath) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
for (i=0; i<wlen; i++){
|
for (i=0; i<wlen; i++){
|
||||||
xw = wvec[i];
|
xw = wvec[i];
|
||||||
/* If 'when' exists and is false, skip this target */
|
/* If 'when' exists and is false, skip this target */
|
||||||
if (whenxpath){
|
if (whenxpath){
|
||||||
if (xpath_vec_ctx(xw, whenxpath, &xctx) < 0)
|
if (xpath_vec_ctx(xw, nsc, whenxpath, &xctx) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((ret = ctx2boolean(xctx)) < 0)
|
if ((ret = ctx2boolean(xctx)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -265,7 +272,7 @@ changelog_op(clicon_handle h,
|
||||||
}
|
}
|
||||||
/* Now switch on operation */
|
/* Now switch on operation */
|
||||||
if (strcmp(op, "rename") == 0){
|
if (strcmp(op, "rename") == 0){
|
||||||
ret = changelog_rename(h, xt, xw, tag);
|
ret = changelog_rename(h, xt, xw, nsc, tag);
|
||||||
}
|
}
|
||||||
else if (strcmp(op, "replace") == 0){
|
else if (strcmp(op, "replace") == 0){
|
||||||
ret = changelog_replace(h, xt, xw, xnew);
|
ret = changelog_replace(h, xt, xw, xnew);
|
||||||
|
|
@ -277,7 +284,7 @@ changelog_op(clicon_handle h,
|
||||||
ret = changelog_delete(h, xt, xw);
|
ret = changelog_delete(h, xt, xw);
|
||||||
}
|
}
|
||||||
else if (strcmp(op, "move") == 0){
|
else if (strcmp(op, "move") == 0){
|
||||||
ret = changelog_move(h, xt, xw, dst);
|
ret = changelog_move(h, xt, xw, nsc, dst);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
clicon_err(OE_XML, 0, "Unknown operation: %s", op);
|
clicon_err(OE_XML, 0, "Unknown operation: %s", op);
|
||||||
|
|
@ -288,10 +295,11 @@ changelog_op(clicon_handle h,
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
ok:
|
ok:
|
||||||
retval = 1;
|
retval = 1;
|
||||||
done:
|
done:
|
||||||
|
if (nsc)
|
||||||
|
xml_nsctx_free(nsc);
|
||||||
if (wvec)
|
if (wvec)
|
||||||
free(wvec);
|
free(wvec);
|
||||||
if (xctx)
|
if (xctx)
|
||||||
|
|
@ -320,7 +328,7 @@ changelog_iterate(clicon_handle h,
|
||||||
int ret;
|
int ret;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (xpath_vec(xch, "step", &vec, &veclen) < 0)
|
if (xpath_vec(xch, NULL, "step", &vec, &veclen) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Iterate through changelog items */
|
/* Iterate through changelog items */
|
||||||
for (i=0; i<veclen; i++){
|
for (i=0; i<veclen; i++){
|
||||||
|
|
@ -384,7 +392,7 @@ xml_changelog_upgrade(clicon_handle h,
|
||||||
* - find all changelogs in the interval: [from, to]
|
* - find all changelogs in the interval: [from, to]
|
||||||
* - note it t=0 then no changelog is applied
|
* - note it t=0 then no changelog is applied
|
||||||
*/
|
*/
|
||||||
if (xpath_vec(xchlog, "changelog[namespace=\"%s\"]",
|
if (xpath_vec(xchlog, NULL, "changelog[namespace=\"%s\"]",
|
||||||
&vec, &veclen, namespace) < 0)
|
&vec, &veclen, namespace) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Get all changelogs in the interval [from,to]*/
|
/* Get all changelogs in the interval [from,to]*/
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,7 @@
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
#include "clixon_options.h"
|
#include "clixon_options.h"
|
||||||
#include "clixon_plugin.h"
|
#include "clixon_plugin.h"
|
||||||
|
#include "clixon_xml_nsctx.h"
|
||||||
#include "clixon_xpath_ctx.h"
|
#include "clixon_xpath_ctx.h"
|
||||||
#include "clixon_xpath.h"
|
#include "clixon_xpath.h"
|
||||||
#include "clixon_log.h"
|
#include "clixon_log.h"
|
||||||
|
|
@ -252,6 +253,14 @@ xml2cli(FILE *f,
|
||||||
* @retval 1 Validation OK
|
* @retval 1 Validation OK
|
||||||
* @retval 0 Validation failed
|
* @retval 0 Validation failed
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
|
* From rfc7950 Sec 9.9.2
|
||||||
|
* The "path" XPath expression is evaluated in the following context,
|
||||||
|
* in addition to the definition in Section 6.4.1:
|
||||||
|
* o If the "path" statement is defined within a typedef, the context
|
||||||
|
* node is the leaf or leaf-list node in the data tree that
|
||||||
|
* references the typedef.
|
||||||
|
* o Otherwise, the context node is the node in the data tree for which
|
||||||
|
* the "path" statement is defined.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
validate_leafref(cxobj *xt,
|
validate_leafref(cxobj *xt,
|
||||||
|
|
@ -266,7 +275,8 @@ validate_leafref(cxobj *xt,
|
||||||
size_t xlen = 0;
|
size_t xlen = 0;
|
||||||
char *leafrefbody;
|
char *leafrefbody;
|
||||||
char *leafbody;
|
char *leafbody;
|
||||||
|
cvec *nsc = NULL;
|
||||||
|
|
||||||
if ((leafrefbody = xml_body(xt)) == NULL)
|
if ((leafrefbody = xml_body(xt)) == NULL)
|
||||||
goto ok;
|
goto ok;
|
||||||
if ((ypath = yang_find(ytype, Y_PATH, NULL)) == NULL){
|
if ((ypath = yang_find(ytype, Y_PATH, NULL)) == NULL){
|
||||||
|
|
@ -274,7 +284,10 @@ validate_leafref(cxobj *xt,
|
||||||
goto done;
|
goto done;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (xpath_vec(xt, "%s", &xvec, &xlen, yang_argument_get(ypath)) < 0)
|
/* XXX see comment above regarding typeref or not */
|
||||||
|
if (xml_nsctx_yang(ytype, &nsc) < 0)
|
||||||
|
goto done;
|
||||||
|
if (xpath_vec(xt, nsc, "%s", &xvec, &xlen, yang_argument_get(ypath)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
for (i = 0; i < xlen; i++) {
|
for (i = 0; i < xlen; i++) {
|
||||||
x = xvec[i];
|
x = xvec[i];
|
||||||
|
|
@ -291,6 +304,8 @@ validate_leafref(cxobj *xt,
|
||||||
ok:
|
ok:
|
||||||
retval = 1;
|
retval = 1;
|
||||||
done:
|
done:
|
||||||
|
if (nsc)
|
||||||
|
xml_nsctx_free(nsc);
|
||||||
if (xvec)
|
if (xvec)
|
||||||
free(xvec);
|
free(xvec);
|
||||||
return retval;
|
return retval;
|
||||||
|
|
@ -1231,7 +1246,7 @@ xml_yang_validate_all(clicon_handle h,
|
||||||
if (yc->ys_keyword != Y_MUST)
|
if (yc->ys_keyword != Y_MUST)
|
||||||
continue;
|
continue;
|
||||||
xpath = yc->ys_argument; /* "must" has xpath argument */
|
xpath = yc->ys_argument; /* "must" has xpath argument */
|
||||||
if ((nr = xpath_vec_bool(xt, "%s", xpath)) < 0)
|
if ((nr = xpath_vec_bool(xt, NULL, "%s", xpath)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (!nr){
|
if (!nr){
|
||||||
ye = yang_find(yc, Y_ERROR_MESSAGE, NULL);
|
ye = yang_find(yc, Y_ERROR_MESSAGE, NULL);
|
||||||
|
|
@ -1244,7 +1259,7 @@ xml_yang_validate_all(clicon_handle h,
|
||||||
/* "when" sub-node RFC 7950 Sec 7.21.5. Can only be one. */
|
/* "when" sub-node RFC 7950 Sec 7.21.5. Can only be one. */
|
||||||
if ((yc = yang_find(ys, Y_WHEN, NULL)) != NULL){
|
if ((yc = yang_find(ys, Y_WHEN, NULL)) != NULL){
|
||||||
xpath = yc->ys_argument; /* "when" has xpath argument */
|
xpath = yc->ys_argument; /* "when" has xpath argument */
|
||||||
if ((nr = xpath_vec_bool(xt, "%s", xpath)) < 0)
|
if ((nr = xpath_vec_bool(xt, NULL, "%s", xpath)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (!nr){
|
if (!nr){
|
||||||
if (netconf_operation_failed_xml(xret, "application",
|
if (netconf_operation_failed_xml(xret, "application",
|
||||||
|
|
@ -1768,7 +1783,6 @@ yang2api_path_fmt(yang_stmt *ys,
|
||||||
* @param[in] cvv cligen variable vector, one for every wildchar in
|
* @param[in] cvv cligen variable vector, one for every wildchar in
|
||||||
* api_path_fmt
|
* api_path_fmt
|
||||||
* @param[out] api_path api_path, eg /aaa/17. Free after use
|
* @param[out] api_path api_path, eg /aaa/17. Free after use
|
||||||
* @param[out] yang_arg yang-stmt argument name. Free after use
|
|
||||||
* @note first and last elements of cvv are not used,..
|
* @note first and last elements of cvv are not used,..
|
||||||
* @see api_path_fmt2xpath
|
* @see api_path_fmt2xpath
|
||||||
* @example
|
* @example
|
||||||
|
|
@ -1866,7 +1880,9 @@ api_path_fmt2api_path(char *api_path_fmt,
|
||||||
* api_path_fmt: /subif-entry=%s,%s/subid
|
* api_path_fmt: /subif-entry=%s,%s/subid
|
||||||
* cvv: foo
|
* cvv: foo
|
||||||
* xpath: /subif-entry[if-name=foo]/subid"
|
* xpath: /subif-entry[if-name=foo]/subid"
|
||||||
*
|
* @example
|
||||||
|
* api_path_fmt: /a:b/c
|
||||||
|
* xpath : /b/c prefix:a
|
||||||
* "api-path" is "URI-encoded path expression" definition in RFC8040 3.5.3
|
* "api-path" is "URI-encoded path expression" definition in RFC8040 3.5.3
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
|
|
@ -2259,13 +2275,14 @@ xml_spec_populate(cxobj *x,
|
||||||
/*! Translate from restconf api-path in cvv form to xml xpath
|
/*! Translate from restconf api-path in cvv form to xml xpath
|
||||||
* eg a/b=c -> a/[b=c]
|
* eg a/b=c -> a/[b=c]
|
||||||
* eg example:a/b -> ex:a/b
|
* eg example:a/b -> ex:a/b
|
||||||
* @param[in] yspec Yang spec
|
* @param[in] api_path api-path as cvec
|
||||||
* @param[in] cvv api-path as cvec
|
* @param[in] offset Offset of cvec, where api-path starts
|
||||||
* @param[in] offset Offset of cvec, where api-path starts
|
* @param[in] yspec Yang spec
|
||||||
* @param[out] xpath The xpath as cbuf variable string, must be initializeed
|
* @param[in,out] xpath The xpath as cbuf (must be created and may have content)
|
||||||
* @retval 1 OK
|
* @param[out] namespace Namespace of xpath (direct pointer don't free)
|
||||||
* @retval 0 Invalid api_path or associated XML, clicon_err called
|
* @retval 1 OK
|
||||||
* @retval -1 Fatal error, clicon_err called
|
* @retval 0 Invalid api_path or associated XML, clicon_err called
|
||||||
|
* @retval -1 Fatal error, clicon_err called
|
||||||
*
|
*
|
||||||
* @note both retval 0 and -1 set clicon_err, but the later is fatal
|
* @note both retval 0 and -1 set clicon_err, but the later is fatal
|
||||||
* @note Not proper namespace translation from api-path 2 xpath
|
* @note Not proper namespace translation from api-path 2 xpath
|
||||||
|
|
@ -2279,7 +2296,7 @@ xml_spec_populate(cxobj *x,
|
||||||
* cvec *cvv = NULL;
|
* cvec *cvv = NULL;
|
||||||
* if (str2cvec("www.foo.com/restconf/a/b=c", '/', '=', &cvv) < 0)
|
* if (str2cvec("www.foo.com/restconf/a/b=c", '/', '=', &cvv) < 0)
|
||||||
* err;
|
* err;
|
||||||
* if ((ret = api_path2xpath(yspec, cvv, 0, cxpath)) < 0)
|
* if ((ret = api_path2xpath(yspec, cvv, 0, cxpath, NULL)) < 0)
|
||||||
* err;
|
* err;
|
||||||
* if (ret == 0){
|
* if (ret == 0){
|
||||||
* ... access error string in clicon_err_reason
|
* ... access error string in clicon_err_reason
|
||||||
|
|
@ -2293,10 +2310,11 @@ xml_spec_populate(cxobj *x,
|
||||||
* @see api_path2xml For api-path to xml tree
|
* @see api_path2xml For api-path to xml tree
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
api_path2xpath(yang_stmt *yspec,
|
api_path2xpath_cvv(cvec *api_path,
|
||||||
cvec *cvv,
|
int offset,
|
||||||
int offset,
|
yang_stmt *yspec,
|
||||||
cbuf *xpath)
|
cbuf *xpath,
|
||||||
|
char **namespace)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
int i;
|
int i;
|
||||||
|
|
@ -2306,13 +2324,13 @@ api_path2xpath(yang_stmt *yspec,
|
||||||
char *name = NULL;
|
char *name = NULL;
|
||||||
cvec *cvk = NULL; /* vector of index keys */
|
cvec *cvk = NULL; /* vector of index keys */
|
||||||
yang_stmt *y = NULL;
|
yang_stmt *y = NULL;
|
||||||
yang_stmt *ymod;
|
yang_stmt *ymod = NULL;
|
||||||
char *val;
|
char *val;
|
||||||
char *v;
|
char *v;
|
||||||
cg_var *cvi;
|
cg_var *cvi;
|
||||||
|
|
||||||
for (i=offset; i<cvec_len(cvv); i++){
|
for (i=offset; i<cvec_len(api_path); i++){
|
||||||
cv = cvec_i(cvv, i);
|
cv = cvec_i(api_path, i);
|
||||||
nodeid = cv_name_get(cv);
|
nodeid = cv_name_get(cv);
|
||||||
if (nodeid_split(nodeid, &prefix, &name) < 0)
|
if (nodeid_split(nodeid, &prefix, &name) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -2368,6 +2386,9 @@ api_path2xpath(yang_stmt *yspec,
|
||||||
name = NULL;
|
name = NULL;
|
||||||
}
|
}
|
||||||
} /* for */
|
} /* for */
|
||||||
|
/* return values: yang module */
|
||||||
|
if (namespace)
|
||||||
|
*namespace = yang_find_mynamespace(ymod);
|
||||||
retval = 1; /* OK */
|
retval = 1; /* OK */
|
||||||
done:
|
done:
|
||||||
if (prefix)
|
if (prefix)
|
||||||
|
|
@ -2380,6 +2401,48 @@ api_path2xpath(yang_stmt *yspec,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Translate from restconf api-path to xml xpath as cbuf and yang module
|
||||||
|
* @retval 1 OK
|
||||||
|
* @retval 0 Invalid api_path or associated XML, clicon_err called
|
||||||
|
* @retval -1 Fatal error, clicon_err called
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
api_path2xpath(char *api_path,
|
||||||
|
yang_stmt *yspec,
|
||||||
|
char **xpathp,
|
||||||
|
char **namespace)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cvec *cvv = NULL; /* api-path vector */
|
||||||
|
cbuf *xpath = NULL; /* xpath as cbuf (sub-function uses that) */
|
||||||
|
|
||||||
|
/* Split api-path into cligen variable vector */
|
||||||
|
if (str2cvec(api_path, '/', '=', &cvv) < 0)
|
||||||
|
goto done;
|
||||||
|
if ((xpath = cbuf_new()) == NULL)
|
||||||
|
goto done;
|
||||||
|
if ((retval = api_path2xpath_cvv(cvv, 0, yspec, xpath, namespace)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (retval == 0)
|
||||||
|
goto fail;
|
||||||
|
/* prepare output xpath parameter */
|
||||||
|
if (xpathp)
|
||||||
|
if ((*xpathp = strdup(cbuf_get(xpath))) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "strdup");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
retval = 1;
|
||||||
|
done:
|
||||||
|
if (cvv)
|
||||||
|
cvec_free(cvv);
|
||||||
|
if (xpath)
|
||||||
|
cbuf_free(xpath);
|
||||||
|
return retval;
|
||||||
|
fail:
|
||||||
|
retval = 0; /* Validation failed */
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Create xml tree from api-path as vector
|
/*! Create xml tree from api-path as vector
|
||||||
* @param[in] vec APIpath as char* vector
|
* @param[in] vec APIpath as char* vector
|
||||||
* @param[in] nvec Length of vec
|
* @param[in] nvec Length of vec
|
||||||
|
|
@ -2711,7 +2774,7 @@ xml2xpath(cxobj *x,
|
||||||
xt = xml_parent(xt);
|
xt = xml_parent(xt);
|
||||||
xcp = xml_parent(xt);
|
xcp = xml_parent(xt);
|
||||||
xml_parent_set(xt, NULL);
|
xml_parent_set(xt, NULL);
|
||||||
x2 = xpath_first(xt, "%s", xpath); /* +1: skip first / */
|
x2 = xpath_first(xt, NULL, "%s", xpath); /* +1: skip first / */
|
||||||
xml_parent_set(xt, xcp);
|
xml_parent_set(xt, xcp);
|
||||||
assert(x2 && x==x2);
|
assert(x2 && x==x2);
|
||||||
if (x==x2)
|
if (x==x2)
|
||||||
|
|
|
||||||
355
lib/src/clixon_xml_nsctx.c
Normal file
355
lib/src/clixon_xml_nsctx.c
Normal file
|
|
@ -0,0 +1,355 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
|
Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
|
||||||
|
|
||||||
|
This file is part of CLIXON.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
Alternatively, the contents of this file may be used under the terms of
|
||||||
|
the GNU General Public License Version 3 or later (the "GPL"),
|
||||||
|
in which case the provisions of the GPL are applicable instead
|
||||||
|
of those above. If you wish to allow use of your version of this file only
|
||||||
|
under the terms of the GPL, and not to allow others to
|
||||||
|
use your version of this file under the terms of Apache License version 2,
|
||||||
|
indicate your decision by deleting the provisions above and replace them with
|
||||||
|
the notice and other provisions required by the GPL. If you do not delete
|
||||||
|
the provisions above, a recipient may use your version of this file under
|
||||||
|
the terms of any one of the Apache License version 2 or the GPL.
|
||||||
|
|
||||||
|
***** END LICENSE BLOCK *****
|
||||||
|
|
||||||
|
* XML support functions.
|
||||||
|
* @see https://www.w3.org/TR/2009/REC-xml-names-20091208
|
||||||
|
* An xml namespace context is a cligen variable vector containing a list of
|
||||||
|
* <prefix,namespace> pairs.
|
||||||
|
* It is encoded in a cvv as a list of string values, where the c name is the
|
||||||
|
* prefix and the string values are the namespace URI.
|
||||||
|
* The default namespace is decoded as having the name NULL
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "clixon_config.h" /* generated by config & autoconf */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <fnmatch.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
/* cligen */
|
||||||
|
#include <cligen/cligen.h>
|
||||||
|
|
||||||
|
/* clixon */
|
||||||
|
#include "clixon_err.h"
|
||||||
|
#include "clixon_string.h"
|
||||||
|
#include "clixon_queue.h"
|
||||||
|
#include "clixon_hash.h"
|
||||||
|
#include "clixon_handle.h"
|
||||||
|
#include "clixon_log.h"
|
||||||
|
#include "clixon_yang.h"
|
||||||
|
#include "clixon_xml.h"
|
||||||
|
#include "clixon_xml_nsctx.h"
|
||||||
|
|
||||||
|
/*! Get namespace given prefix (or NULL for default) from namespace context
|
||||||
|
* @param[in] cvv Namespace context
|
||||||
|
* @param[in] prefix Namespace prefix, or NULL for default
|
||||||
|
* @retval ns Cached namespace
|
||||||
|
* @retval NULL No namespace found (not cached or not found)
|
||||||
|
*/
|
||||||
|
char*
|
||||||
|
xml_nsctx_get(cvec *cvv,
|
||||||
|
char *prefix)
|
||||||
|
{
|
||||||
|
cg_var *cv;
|
||||||
|
|
||||||
|
if ((cv = cvec_find(cvv, prefix)) != NULL)
|
||||||
|
return cv_string_get(cv);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Reverse get prefix given namespace
|
||||||
|
* @param[in] cvv Namespace context
|
||||||
|
* @param[in] ns Namespace
|
||||||
|
* @param[out] prefix Prefix (direct pointer)
|
||||||
|
* @retval 0 No prefix found
|
||||||
|
* @retval 1 Prefix found
|
||||||
|
* @note NULL is a valid prefix (default)
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml_nsctx_get_prefix(cvec *cvv,
|
||||||
|
char *namespace,
|
||||||
|
char **prefix)
|
||||||
|
{
|
||||||
|
cg_var *cv = NULL;
|
||||||
|
char *ns = NULL;
|
||||||
|
|
||||||
|
while ((cv = cvec_each(cvv, cv)) != NULL){
|
||||||
|
if ((ns = cv_string_get(cv)) != NULL &&
|
||||||
|
strcmp(ns, namespace) == 0){
|
||||||
|
*prefix = cv_name_get(cv); /* can be NULL */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*prefix = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Set or replace namespace in namespace context
|
||||||
|
* @param[in] cvv Namespace context
|
||||||
|
* @param[in] prefix Namespace prefix, or NULL for default
|
||||||
|
* @param[in] namespace Cached namespace to set (assume non-null?)
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml_nsctx_set(cvec *cvv,
|
||||||
|
char *prefix,
|
||||||
|
char *namespace)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cg_var *cv;
|
||||||
|
|
||||||
|
if ((cv = cvec_find(cvv, prefix)) != NULL) /* found, replace that */
|
||||||
|
cv_string_set(cv, namespace);
|
||||||
|
else /* cvec exists, but not prefix */
|
||||||
|
cvec_add_string(cvv, prefix, namespace);
|
||||||
|
retval = 0;
|
||||||
|
// done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Create and initialize XML namespace context
|
||||||
|
* @param[in] prefix Namespace prefix, or NULL for default
|
||||||
|
* @param[in] namespace Cached namespace to set (assume non-null?)
|
||||||
|
* @retval nsc Return namespace context in form of a cvec
|
||||||
|
* @retval NULL Error
|
||||||
|
* @code
|
||||||
|
* cvec *nsc = NULL;
|
||||||
|
* if ((nsc = xml_nsctx_init(NULL, "urn:example:example")) == NULL)
|
||||||
|
* err;
|
||||||
|
* ...
|
||||||
|
* xml_nsctx_free(nsc);
|
||||||
|
* @endcode
|
||||||
|
* @see xml_nsctx_node Use namespace context of an existing XML node
|
||||||
|
* @see xml_nsctx_free Free the reutned handle
|
||||||
|
*/
|
||||||
|
cvec *
|
||||||
|
xml_nsctx_init(char *prefix,
|
||||||
|
char *namespace)
|
||||||
|
{
|
||||||
|
cvec *cvv = NULL;
|
||||||
|
|
||||||
|
if ((cvv = cvec_new(0)) == NULL){
|
||||||
|
clicon_err(OE_XML, errno, "cvec_new");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (xml_nsctx_set(cvv, prefix, namespace) < 0)
|
||||||
|
goto done;
|
||||||
|
done:
|
||||||
|
return cvv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
xml_nsctx_node1(cxobj *xn,
|
||||||
|
cvec *ncs)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cxobj *xa = NULL;
|
||||||
|
char *pf; /* prefix */
|
||||||
|
char *nm; /* name */
|
||||||
|
char *val; /* value */
|
||||||
|
cxobj *xp; /* parent */
|
||||||
|
|
||||||
|
/* xmlns:t="<ns1>" prefix:xmlns, name:t
|
||||||
|
* xmlns="<ns2>" prefix:NULL name:xmlns
|
||||||
|
*/
|
||||||
|
while ((xa = xml_child_each(xn, xa, CX_ATTR)) != NULL){
|
||||||
|
pf = xml_prefix(xa);
|
||||||
|
nm = xml_name(xa);
|
||||||
|
if (pf == NULL){
|
||||||
|
if (strcmp(nm, "xmlns")==0 && /* set default namespace context */
|
||||||
|
xml_nsctx_get(ncs, NULL) == NULL){
|
||||||
|
val = xml_value(xa);
|
||||||
|
if (xml_nsctx_set(ncs, NULL, val) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (strcmp(pf, "xmlns")==0 && /* set prefixed namespace context */
|
||||||
|
xml_nsctx_get(ncs, nm) == NULL){
|
||||||
|
val = xml_value(xa);
|
||||||
|
if (xml_nsctx_set(ncs, nm, val) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((xp = xml_parent(xn)) == NULL){
|
||||||
|
#ifdef USE_NETCONF_NS_AS_DEFAULT
|
||||||
|
/* If not default namespace defined, use the base netconf ns as default */
|
||||||
|
if (xml_nsctx_get(ncs, NULL) == NULL)
|
||||||
|
if (xml_nsctx_set(ncs, NULL, NETCONF_BASE_NAMESPACE) < 0)
|
||||||
|
goto done;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (xml_nsctx_node1(xp, ncs) < 0)
|
||||||
|
goto done;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Create and initialize XML namespace from XML node context
|
||||||
|
* Fully explore all prefix:namespace pairs from context of one node
|
||||||
|
* @param[in] xn XML node
|
||||||
|
* @param[out] ncp XML namespace context
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
|
* @code
|
||||||
|
* cxobj *x; // must initialize
|
||||||
|
* cvec *nsc = NULL;
|
||||||
|
* if (xml_nsctx_node(x, &nsc) < 0)
|
||||||
|
* err
|
||||||
|
* ...
|
||||||
|
* xml_nsctx_free(nsc)
|
||||||
|
* @endcode
|
||||||
|
* @see xml_nsctx_init
|
||||||
|
* @see xml_nsctx_free Free the reutned handle
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml_nsctx_node(cxobj *xn,
|
||||||
|
cvec **ncp)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cvec *nc = NULL;
|
||||||
|
|
||||||
|
if ((nc = cvec_new(0)) == NULL){
|
||||||
|
clicon_err(OE_XML, errno, "cvec_new");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (xml_nsctx_node1(xn, nc) < 0)
|
||||||
|
goto done;
|
||||||
|
*ncp = nc;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Create and initialize XML namespace from Yang node
|
||||||
|
* Primary use is Yang path statements, eg leafrefs and others
|
||||||
|
* Fully explore all prefix:namespace pairs from context of one node
|
||||||
|
* @param[in] xn XML node
|
||||||
|
* @param[out] ncp XML namespace context
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
|
* @code
|
||||||
|
* yang_stmt *y; // must initialize
|
||||||
|
* cvec *nsc = NULL;
|
||||||
|
* if (xml_nsctx_yang(y, &nsc) < 0)
|
||||||
|
* err
|
||||||
|
* ...
|
||||||
|
* xml_nsctx_free(nsc)
|
||||||
|
* @endcode
|
||||||
|
* @see RFC7950 Sections 6.4.1 (and 9.9.2?)
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml_nsctx_yang(yang_stmt *yn,
|
||||||
|
cvec **ncp)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cvec *nc = NULL;
|
||||||
|
yang_stmt *yspec;
|
||||||
|
yang_stmt *ymod; /* yang main module/submodule node */
|
||||||
|
yang_stmt *yp; /* yang prefix node */
|
||||||
|
yang_stmt *ym; /* yang imported module */
|
||||||
|
yang_stmt *yns; /* yang namespace */
|
||||||
|
yang_stmt *y;
|
||||||
|
char *name;
|
||||||
|
char *namespace;
|
||||||
|
char *prefix;
|
||||||
|
char *mynamespace;
|
||||||
|
char *myprefix;
|
||||||
|
|
||||||
|
if ((nc = cvec_new(0)) == NULL){
|
||||||
|
clicon_err(OE_XML, errno, "cvec_new");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if ((myprefix = yang_find_myprefix(yn)) == NULL){
|
||||||
|
clicon_err(OE_YANG, ENOENT, "My yang prefix not found");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if ((mynamespace = yang_find_mynamespace(yn)) == NULL){
|
||||||
|
clicon_err(OE_YANG, ENOENT, "My yang namespace not found");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
/* Add my prefix and default namespace (from real module) */
|
||||||
|
if (xml_nsctx_set(nc, NULL, mynamespace) < 0)
|
||||||
|
goto done;
|
||||||
|
if (xml_nsctx_set(nc, myprefix, mynamespace) < 0)
|
||||||
|
goto done;
|
||||||
|
/* Find top-most module or sub-module and get prefixes from that */
|
||||||
|
if ((ymod = ys_module(yn)) == NULL){
|
||||||
|
clicon_err(OE_YANG, ENOENT, "My yang module not found");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
yspec = yang_parent_get(ymod); /* Assume yspec exists */
|
||||||
|
|
||||||
|
/* Iterate over module and register all import prefixes
|
||||||
|
*/
|
||||||
|
y = NULL;
|
||||||
|
while ((y = yn_each(ymod, y)) != NULL) {
|
||||||
|
if (yang_keyword_get(y) == Y_IMPORT){
|
||||||
|
if ((name = yang_argument_get(y)) == NULL)
|
||||||
|
continue; /* Just skip - shouldnt happen) */
|
||||||
|
if ((yp = yang_find(y, Y_PREFIX, NULL)) == NULL)
|
||||||
|
continue;
|
||||||
|
if ((prefix = yang_argument_get(yp)) == NULL)
|
||||||
|
continue;
|
||||||
|
if ((ym = yang_find(yspec, Y_MODULE, name)) == NULL)
|
||||||
|
continue;
|
||||||
|
if ((yns = yang_find(ym, Y_NAMESPACE, NULL)) == NULL)
|
||||||
|
continue;
|
||||||
|
if ((namespace = yang_argument_get(yns)) == NULL)
|
||||||
|
continue;
|
||||||
|
if (xml_nsctx_set(nc, prefix, namespace) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*ncp = nc;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Free XML namespace context
|
||||||
|
* @param[in] prefix Namespace prefix, or NULL for default
|
||||||
|
* @param[in] namespace Cached namespace to set (assume non-null?)
|
||||||
|
* @retval nsc Return namespace context in form of a cvec
|
||||||
|
* @retval NULL Error
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml_nsctx_free(cvec *ncs)
|
||||||
|
{
|
||||||
|
cvec *cvv = (cvec*)ncs;
|
||||||
|
|
||||||
|
if (cvv)
|
||||||
|
cvec_free(cvv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -32,6 +32,56 @@
|
||||||
***** END LICENSE BLOCK *****
|
***** END LICENSE BLOCK *****
|
||||||
|
|
||||||
* Clixon XML XPATH 1.0 according to https://www.w3.org/TR/xpath-10
|
* Clixon XML XPATH 1.0 according to https://www.w3.org/TR/xpath-10
|
||||||
|
*
|
||||||
|
* Some notes on namespace extensions in Netconf/Yang
|
||||||
|
* RFC6241 8.9.1
|
||||||
|
* The set of namespace declarations are those in scope on the <filter> element.
|
||||||
|
* <rpc message-id="101" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
|
||||||
|
* <get-config>
|
||||||
|
* <filter xmlns:t="http://example.com/schema/1.2/config"
|
||||||
|
* type="xpath"
|
||||||
|
* select="/t:top/t:users/t:user[t:name='fred']"/>
|
||||||
|
* </get-config>
|
||||||
|
* We need to add namespace context to the cpath tree, typically in eval. How do
|
||||||
|
* we do that?
|
||||||
|
* One observation is that the namespace context is static, so it can not be a part
|
||||||
|
* of the xpath-tree, which is context-dependent.
|
||||||
|
* Best is to send it as a (read-only) parameter to the xp_eval family of functions
|
||||||
|
* as an exlicit namespace context.
|
||||||
|
* For that you need an API to get/set namespaces: clixon_xml_nscache.c?
|
||||||
|
* Then you need to fix API functions and this is the real work:
|
||||||
|
* - Replace all existing functions or create new?
|
||||||
|
* - Expose explicit namespace parameter, or xml object, or default namespace?
|
||||||
|
*
|
||||||
|
* On namespaces and xpath
|
||||||
|
* =======================
|
||||||
|
* XPATHs may contain prefixes such as /if:a/if:b
|
||||||
|
* XPATHs excecutes in a "namespace context" (nsc)
|
||||||
|
* The namespace context is either:
|
||||||
|
* (1) the same as the xml that is evaluated, typical for basic XML, or
|
||||||
|
* (2) separate from the XML that is evaluated. typical netconf and yang.
|
||||||
|
* 1. Same nsc as XML
|
||||||
|
* This happens in base XML (not yang), where the nsc is given implicitly by
|
||||||
|
* the XML being evaluated. In node comparisons (eg of ip:a) only name and
|
||||||
|
* prefixes are compared.
|
||||||
|
* XML: <if:a xmlns:if="urn:example:if" xmlns:ip="urn:example:ip"><ip:b/></if>
|
||||||
|
* XPATH: /if:a/ip:b
|
||||||
|
* When you call an xpath function, then call it with nsc=NULL.
|
||||||
|
* 2. Separate nsc.
|
||||||
|
* This happens if the namespace context is independent from the XML. It can
|
||||||
|
* happen for example in NETCONF GET using :xpath when the XML is not known
|
||||||
|
* so that xpath and xml may use different prefixes for the same namespace.
|
||||||
|
* In that case you cannot rely on the prefix but must compare namespaces.
|
||||||
|
* The namespace context of the XML is given (by the XML), but the xpath
|
||||||
|
* nsc must then be explicitly given in the xpath call.
|
||||||
|
* Example:
|
||||||
|
* XML: <if:a xmlns:if="urn:example:if" xmlns:ip="urn:example:ip"><ip:b/></if>
|
||||||
|
* NETCONF:<get-config><filter select="/x:a/y:b"
|
||||||
|
* xmlns:x="urn:example:if" xmlns:y="urn:example:ip/>
|
||||||
|
* Here, x,y are prefixes used for two namespaces that are given by if,ip in
|
||||||
|
* the xml. In this case, the namespaces (eg urn:example:if) must be compared
|
||||||
|
* instead.
|
||||||
|
* Another case is Yang path expressions.
|
||||||
*/
|
*/
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "clixon_config.h" /* generated by config & autoconf */
|
#include "clixon_config.h" /* generated by config & autoconf */
|
||||||
|
|
@ -62,6 +112,7 @@
|
||||||
#include "clixon_handle.h"
|
#include "clixon_handle.h"
|
||||||
#include "clixon_yang.h"
|
#include "clixon_yang.h"
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
|
#include "clixon_xml_nsctx.h"
|
||||||
#include "clixon_xpath_parse.h"
|
#include "clixon_xpath_parse.h"
|
||||||
#include "clixon_xpath_ctx.h"
|
#include "clixon_xpath_ctx.h"
|
||||||
#include "clixon_xpath.h"
|
#include "clixon_xpath.h"
|
||||||
|
|
@ -69,6 +120,9 @@
|
||||||
/*
|
/*
|
||||||
* Variables
|
* Variables
|
||||||
*/
|
*/
|
||||||
|
/* XXX assert break if xpath dont match. Set to 0 if ypu want it to pass */
|
||||||
|
int xpatherrordiff=1;
|
||||||
|
|
||||||
/* Mapping between XPATH operator string <--> int */
|
/* Mapping between XPATH operator string <--> int */
|
||||||
const map_str2int xpopmap[] = {
|
const map_str2int xpopmap[] = {
|
||||||
{"and", XO_AND},
|
{"and", XO_AND},
|
||||||
|
|
@ -141,8 +195,7 @@ xpath_tree_print(cbuf *cb,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
xpath_tree_free(
|
xpath_tree_free(xpath_tree *xs)
|
||||||
xpath_tree *xs)
|
|
||||||
{
|
{
|
||||||
if (xs->xs_s0)
|
if (xs->xs_s0)
|
||||||
free(xs->xs_s0);
|
free(xs->xs_s0);
|
||||||
|
|
@ -156,45 +209,118 @@ xpath_tree_free(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @retval -1 Error XXX: retval -1 not properly handled
|
||||||
|
* @retval 0 No match
|
||||||
|
* @retval 1 Match
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
nodetest_eval_node(cxobj *x,
|
||||||
|
xpath_tree *xs,
|
||||||
|
cvec *nsc)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
char *name1 = xml_name(x);
|
||||||
|
char *prefix1 = xml_prefix(x);
|
||||||
|
char *nsxml = NULL; /* xml body namespace */
|
||||||
|
char *nsxpath = NULL; /* xpath context namespace */
|
||||||
|
char *prefix2 = NULL;
|
||||||
|
char *name2 = NULL;
|
||||||
|
|
||||||
|
/* Namespaces is s0, name is s1 */
|
||||||
|
if (strcmp(xs->xs_s1, "*")==0)
|
||||||
|
return 1;
|
||||||
|
/* get namespace of xml tree */
|
||||||
|
if (xml2ns(x, prefix1, &nsxml) < 0)
|
||||||
|
goto done;
|
||||||
|
prefix2 = xs->xs_s0;
|
||||||
|
name2 = xs->xs_s1;
|
||||||
|
/* Before going into namespaces, check name equality and filter out noteq */
|
||||||
|
if (strcmp(name1, name2) != 0){
|
||||||
|
retval = 0; /* no match */
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
/* here names are equal
|
||||||
|
* Now look for namespaces
|
||||||
|
* 1) prefix1 and prefix2 point to same namespace <<-- try this first
|
||||||
|
* 2) prefix1 is equal to prefix2 <<-- then try this
|
||||||
|
* (1) is strict yang xml
|
||||||
|
* (2) without yang
|
||||||
|
*/
|
||||||
|
if (nsc != NULL) { /* solution (1) */
|
||||||
|
nsxpath = xml_nsctx_get(nsc, prefix2);
|
||||||
|
if (nsxml != NULL && nsxpath != NULL)
|
||||||
|
retval = (strcmp(nsxml, nsxpath) == 0);
|
||||||
|
else
|
||||||
|
retval = (nsxml == nsxpath); /* True only if both are NULL */
|
||||||
|
}
|
||||||
|
else{ /* solution (2) */
|
||||||
|
if (prefix1 == NULL && prefix2 == NULL)
|
||||||
|
retval = 1;
|
||||||
|
else if (prefix1 == NULL || prefix2 == NULL)
|
||||||
|
retval = 0;
|
||||||
|
else
|
||||||
|
retval = strcmp(prefix1, prefix2) == 0;
|
||||||
|
}
|
||||||
|
/* If retval == 0 here, then there is name match, but not ns match */
|
||||||
|
if (retval == 0){
|
||||||
|
fprintf(stderr, "%s NOMATCH xml: (%s)%s\n\t\t xpath: (%s)%s\n", __FUNCTION__,
|
||||||
|
name1, nsxml,
|
||||||
|
name2, nsxpath);
|
||||||
|
if (xpatherrordiff)
|
||||||
|
assert(retval == 1);
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Make a nodetest
|
/*! Make a nodetest
|
||||||
* @param[in] xs XPATH stack of type XP_NODE or XP_NODE_FN
|
* @param[in] xs XPATH stack of type XP_NODE or XP_NODE_FN
|
||||||
* @retval 0 Match
|
* @param[in] nsc XML Namespace context
|
||||||
* @retval 1 No match
|
* @retval -1 Error
|
||||||
|
* @retval 0 No match
|
||||||
|
* @retval 1 Match
|
||||||
* - node() is true for any node of any type whatsoever.
|
* - node() is true for any node of any type whatsoever.
|
||||||
* - text() is true for any text node.
|
* - text() is true for any text node.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
nodetest_eval(cxobj *x,
|
nodetest_eval(cxobj *x,
|
||||||
xpath_tree *xs)
|
xpath_tree *xs,
|
||||||
|
cvec *nsc)
|
||||||
{
|
{
|
||||||
|
int retval = 0; /* NB: no match is default (not error) */
|
||||||
char *fn;
|
char *fn;
|
||||||
|
|
||||||
if (xs->xs_type == XP_NODE){
|
if (xs->xs_type == XP_NODE)
|
||||||
/* Namespaces is s0, name is s1 */
|
retval = nodetest_eval_node(x, xs, nsc);
|
||||||
if (strcmp(xs->xs_s1, "*")==0)
|
|
||||||
return 1;
|
|
||||||
else if (strcmp(xml_name(x), xs->xs_s1)==0)
|
|
||||||
return 1;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else if (xs->xs_type == XP_NODE_FN){
|
else if (xs->xs_type == XP_NODE_FN){
|
||||||
fn = xs->xs_s0;
|
fn = xs->xs_s0;
|
||||||
if (strcmp(fn, "node")==0)
|
if (strcmp(fn, "node")==0)
|
||||||
return 1;
|
retval = 1;
|
||||||
else if (strcmp(fn, "text")==0)
|
else if (strcmp(fn, "text")==0)
|
||||||
return 1;
|
retval = 1;
|
||||||
}
|
}
|
||||||
return 0;
|
/* note, retval set by previous statement */
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @param[in] xn
|
||||||
|
* @param[in] nodetest XPATH stack
|
||||||
|
* @param[in] node_type
|
||||||
|
* @param[in] flags
|
||||||
|
* @param[in] nsc XML Namespace context
|
||||||
|
* @param[out] vec0
|
||||||
|
* @param[out] vec0len
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
nodetest_recursive(cxobj *xn,
|
nodetest_recursive(cxobj *xn,
|
||||||
xpath_tree *nodetest,
|
xpath_tree *nodetest,
|
||||||
int node_type,
|
int node_type,
|
||||||
uint16_t flags,
|
uint16_t flags,
|
||||||
cxobj ***vec0,
|
cvec *nsc,
|
||||||
size_t *vec0len)
|
cxobj ***vec0,
|
||||||
|
size_t *vec0len)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *xsub;
|
cxobj *xsub;
|
||||||
|
|
@ -203,14 +329,14 @@ nodetest_recursive(cxobj *xn,
|
||||||
|
|
||||||
xsub = NULL;
|
xsub = NULL;
|
||||||
while ((xsub = xml_child_each(xn, xsub, node_type)) != NULL) {
|
while ((xsub = xml_child_each(xn, xsub, node_type)) != NULL) {
|
||||||
if (nodetest_eval(xsub, nodetest) == 1){
|
if (nodetest_eval(xsub, nodetest, nsc) == 1){
|
||||||
clicon_debug(2, "%s %x %x", __FUNCTION__, flags, xml_flag(xsub, flags));
|
clicon_debug(2, "%s %x %x", __FUNCTION__, flags, xml_flag(xsub, flags));
|
||||||
if (flags==0x0 || xml_flag(xsub, flags))
|
if (flags==0x0 || xml_flag(xsub, flags))
|
||||||
if (cxvec_append(xsub, &vec, &veclen) < 0)
|
if (cxvec_append(xsub, &vec, &veclen) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
// continue; /* Dont go deeper */
|
// continue; /* Dont go deeper */
|
||||||
}
|
}
|
||||||
if (nodetest_recursive(xsub, nodetest, node_type, flags, &vec, &veclen) < 0)
|
if (nodetest_recursive(xsub, nodetest, node_type, flags, nsc, &vec, &veclen) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
@ -220,12 +346,13 @@ nodetest_recursive(cxobj *xn,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xp_eval(xp_ctx *xc, xpath_tree *xs, xp_ctx **xrp);
|
static int xp_eval(xp_ctx *xc, xpath_tree *xs, cvec *nsc, xp_ctx **xrp);
|
||||||
|
|
||||||
/*! Evaluate xpath step rule of an XML tree
|
/*! Evaluate xpath step rule of an XML tree
|
||||||
*
|
*
|
||||||
* @param[in] xc0 Incoming context
|
* @param[in] xc0 Incoming context
|
||||||
* @param[in] xs XPATH node tree
|
* @param[in] xs XPATH node tree
|
||||||
|
* @param[in] nsc XML Namespace context
|
||||||
* @param[out] xrp Resulting context
|
* @param[out] xrp Resulting context
|
||||||
*
|
*
|
||||||
* - A node test that is a QName is true if and only if the type of the node (see [5 Data Model])
|
* - A node test that is a QName is true if and only if the type of the node (see [5 Data Model])
|
||||||
|
|
@ -237,6 +364,7 @@ static int xp_eval(xp_ctx *xc, xpath_tree *xs, xp_ctx **xrp);
|
||||||
static int
|
static int
|
||||||
xp_eval_step(xp_ctx *xc0,
|
xp_eval_step(xp_ctx *xc0,
|
||||||
xpath_tree *xs,
|
xpath_tree *xs,
|
||||||
|
cvec *nsc,
|
||||||
xp_ctx **xrp)
|
xp_ctx **xrp)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
@ -263,7 +391,7 @@ xp_eval_step(xp_ctx *xc0,
|
||||||
if (xc->xc_descendant){
|
if (xc->xc_descendant){
|
||||||
for (i=0; i<xc->xc_size; i++){
|
for (i=0; i<xc->xc_size; i++){
|
||||||
xv = xc->xc_nodeset[i];
|
xv = xc->xc_nodeset[i];
|
||||||
if (nodetest_recursive(xv, nodetest, CX_ELMNT, 0x0, &vec, &veclen) < 0)
|
if (nodetest_recursive(xv, nodetest, CX_ELMNT, 0x0, nsc, &vec, &veclen) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
xc->xc_descendant = 0;
|
xc->xc_descendant = 0;
|
||||||
|
|
@ -280,7 +408,7 @@ xp_eval_step(xp_ctx *xc0,
|
||||||
x = NULL;
|
x = NULL;
|
||||||
while ((x = xml_child_each(xv, x, CX_ELMNT)) != NULL) {
|
while ((x = xml_child_each(xv, x, CX_ELMNT)) != NULL) {
|
||||||
/* xs->xs_c0 is nodetest */
|
/* xs->xs_c0 is nodetest */
|
||||||
if (nodetest == NULL || nodetest_eval(x, nodetest))
|
if (nodetest == NULL || nodetest_eval(x, nodetest, nsc) == 1)
|
||||||
if (cxvec_append(x, &vec, &veclen) < 0)
|
if (cxvec_append(x, &vec, &veclen) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -292,7 +420,7 @@ xp_eval_step(xp_ctx *xc0,
|
||||||
case A_DESCENDANT_OR_SELF:
|
case A_DESCENDANT_OR_SELF:
|
||||||
for (i=0; i<xc->xc_size; i++){
|
for (i=0; i<xc->xc_size; i++){
|
||||||
xv = xc->xc_nodeset[i];
|
xv = xc->xc_nodeset[i];
|
||||||
if (nodetest_recursive(xv, xs->xs_c0, CX_ELMNT, 0x0, &vec, &veclen) < 0)
|
if (nodetest_recursive(xv, xs->xs_c0, CX_ELMNT, 0x0, nsc, &vec, &veclen) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
ctx_nodeset_replace(xc, vec, veclen);
|
ctx_nodeset_replace(xc, vec, veclen);
|
||||||
|
|
@ -331,7 +459,7 @@ xp_eval_step(xp_ctx *xc0,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (xs->xs_c1){
|
if (xs->xs_c1){
|
||||||
if (xp_eval(xc, xs->xs_c1, xrp) < 0)
|
if (xp_eval(xc, xs->xs_c1, nsc, xrp) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
|
|
@ -351,6 +479,7 @@ xp_eval_step(xp_ctx *xc0,
|
||||||
* pred -> pred expr
|
* pred -> pred expr
|
||||||
* @param[in] xc Incoming context
|
* @param[in] xc Incoming context
|
||||||
* @param[in] xs XPATH node tree
|
* @param[in] xs XPATH node tree
|
||||||
|
* @param[in] nsc XML Namespace context
|
||||||
* @param[out] xrp Resulting context
|
* @param[out] xrp Resulting context
|
||||||
*
|
*
|
||||||
* A predicate filters a node-set with respect to an axis to produce a new
|
* A predicate filters a node-set with respect to an axis to produce a new
|
||||||
|
|
@ -371,6 +500,7 @@ xp_eval_step(xp_ctx *xc0,
|
||||||
static int
|
static int
|
||||||
xp_eval_predicate(xp_ctx *xc,
|
xp_eval_predicate(xp_ctx *xc,
|
||||||
xpath_tree *xs,
|
xpath_tree *xs,
|
||||||
|
cvec *nsc,
|
||||||
xp_ctx **xrp)
|
xp_ctx **xrp)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
@ -386,7 +516,7 @@ xp_eval_predicate(xp_ctx *xc,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else{ /* eval previous predicates */
|
else{ /* eval previous predicates */
|
||||||
if (xp_eval(xc, xs->xs_c0, &xr0) < 0)
|
if (xp_eval(xc, xs->xs_c0, nsc, &xr0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (xs->xs_c1){
|
if (xs->xs_c1){
|
||||||
|
|
@ -415,7 +545,7 @@ xp_eval_predicate(xp_ctx *xc,
|
||||||
* evaluated with that node as the context node */
|
* evaluated with that node as the context node */
|
||||||
if (cxvec_append(x, &xcc->xc_nodeset, &xcc->xc_size) < 0)
|
if (cxvec_append(x, &xcc->xc_nodeset, &xcc->xc_size) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (xp_eval(xcc, xs->xs_c1, &xrc) < 0)
|
if (xp_eval(xcc, xs->xs_c1, nsc, &xrc) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (xcc)
|
if (xcc)
|
||||||
ctx_free(xcc);
|
ctx_free(xcc);
|
||||||
|
|
@ -834,13 +964,16 @@ xp_union(xp_ctx *xc1,
|
||||||
* Each node in that set is used as a context node for the following step.
|
* Each node in that set is used as a context node for the following step.
|
||||||
* @param[in] xc Incoming context
|
* @param[in] xc Incoming context
|
||||||
* @param[in] xs XPATH node tree
|
* @param[in] xs XPATH node tree
|
||||||
|
* @param[in] nsc XML Namespace context
|
||||||
* @param[out] xrp Resulting context
|
* @param[out] xrp Resulting context
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
xp_eval(xp_ctx *xc,
|
xp_eval(xp_ctx *xc,
|
||||||
xpath_tree *xs,
|
xpath_tree *xs,
|
||||||
|
cvec *nsc,
|
||||||
xp_ctx **xrp)
|
xp_ctx **xrp)
|
||||||
|
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *x;
|
cxobj *x;
|
||||||
|
|
@ -880,12 +1013,12 @@ xp_eval(xp_ctx *xc,
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case XP_STEP: /* XP_NODE is first argument -not called explicitly */
|
case XP_STEP: /* XP_NODE is first argument -not called explicitly */
|
||||||
if (xp_eval_step(xc, xs, xrp) < 0)
|
if (xp_eval_step(xc, xs, nsc, xrp) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto ok;
|
goto ok;
|
||||||
break;
|
break;
|
||||||
case XP_PRED:
|
case XP_PRED:
|
||||||
if (xp_eval_predicate(xc, xs, xrp) < 0)
|
if (xp_eval_predicate(xc, xs, nsc, xrp) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto ok;
|
goto ok;
|
||||||
break;
|
break;
|
||||||
|
|
@ -895,7 +1028,7 @@ xp_eval(xp_ctx *xc,
|
||||||
/* Eval first child c0
|
/* Eval first child c0
|
||||||
*/
|
*/
|
||||||
if (xs->xs_c0){
|
if (xs->xs_c0){
|
||||||
if (xp_eval(xc, xs->xs_c0, &xr0) < 0)
|
if (xp_eval(xc, xs->xs_c0, nsc, &xr0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Actions between first and second child
|
/* Actions between first and second child
|
||||||
|
|
@ -973,7 +1106,7 @@ xp_eval(xp_ctx *xc,
|
||||||
* Note, some operators like locationpath, need transitive context (use_xr0)
|
* Note, some operators like locationpath, need transitive context (use_xr0)
|
||||||
*/
|
*/
|
||||||
if (xs->xs_c1)
|
if (xs->xs_c1)
|
||||||
if (xp_eval(use_xr0?xr0:xc, xs->xs_c1, &xr1) < 0)
|
if (xp_eval(use_xr0?xr0:xc, xs->xs_c1, nsc, &xr1) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Actions after second child
|
/* Actions after second child
|
||||||
*/
|
*/
|
||||||
|
|
@ -1032,19 +1165,20 @@ xp_eval(xp_ctx *xc,
|
||||||
if (xr0)
|
if (xr0)
|
||||||
ctx_free(xr0);
|
ctx_free(xr0);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
} /* xp_eval */
|
||||||
|
|
||||||
/*! Given XML tree and xpath, returns xpath context
|
/*! Given XML tree and xpath, parse xpath, eval it and return xpath context,
|
||||||
* This is a raw form of xpath where you can do type conversion, etc,
|
* This is a raw form of xpath where you can do type conversion, etc,
|
||||||
* not just a nodeset.
|
* not just a nodeset.
|
||||||
* @param[in] xcur XML-tree where to search
|
* @param[in] xcur XML-tree where to search
|
||||||
* @param[in] xpath String with XPATH 1.0 syntax
|
* @param[in] xpath String with XPATH 1.0 syntax
|
||||||
|
* @param[in] nsc XML Namespace context
|
||||||
* @param[out] xrp Return XPATH context
|
* @param[out] xrp Return XPATH context
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
* @code
|
* @code
|
||||||
* xp_ctx *xc = NULL;
|
* xp_ctx *xc = NULL;
|
||||||
* if (xpath_vec_ctx(x, xpath, &xc) < 0)
|
* if (xpath_vec_ctx(x, NULL, xpath, &xc) < 0)
|
||||||
* err;
|
* err;
|
||||||
* if (xc)
|
* if (xc)
|
||||||
* ctx_free(xc);
|
* ctx_free(xc);
|
||||||
|
|
@ -1052,6 +1186,7 @@ xp_eval(xp_ctx *xc,
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xpath_vec_ctx(cxobj *xcur,
|
xpath_vec_ctx(cxobj *xcur,
|
||||||
|
cvec *nsc,
|
||||||
char *xpath,
|
char *xpath,
|
||||||
xp_ctx **xrp)
|
xp_ctx **xrp)
|
||||||
{
|
{
|
||||||
|
|
@ -1084,7 +1219,7 @@ xpath_vec_ctx(cxobj *xcur,
|
||||||
xc.xc_initial = xcur;
|
xc.xc_initial = xcur;
|
||||||
if (cxvec_append(xcur, &xc.xc_nodeset, &xc.xc_size) < 0)
|
if (cxvec_append(xcur, &xc.xc_nodeset, &xc.xc_size) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (xp_eval(&xc, xy.xy_top, xrp) < 0)
|
if (xp_eval(&xc, xy.xy_top, nsc, xrp) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (xc.xc_nodeset){
|
if (xc.xc_nodeset){
|
||||||
free(xc.xc_nodeset);
|
free(xc.xc_nodeset);
|
||||||
|
|
@ -1102,23 +1237,27 @@ xpath_vec_ctx(cxobj *xcur,
|
||||||
|
|
||||||
/*! Xpath nodeset function where only the first matching entry is returned
|
/*! Xpath nodeset function where only the first matching entry is returned
|
||||||
* args:
|
* args:
|
||||||
* @param[in] xcur xml-tree where to search
|
* @param[in] xcur XML tree where to search
|
||||||
* @param[in] xpath string with XPATH syntax
|
* @param[in] nsc XML Namespace context
|
||||||
* @retval xml-tree of first match
|
* @param[in] format string with XPATH syntax
|
||||||
* @retval NULL Error or not found
|
* @retval xml-tree XML tree of first match
|
||||||
|
* @retval NULL Error or not found
|
||||||
*
|
*
|
||||||
* @code
|
* @code
|
||||||
* cxobj *x;
|
* cxobj *x;
|
||||||
* if ((x = xpath_first(xtop, "//symbol/foo")) != NULL) {
|
* cvec *nsc; // namespace context
|
||||||
|
* if ((x = xpath_first(xtop, nsc, "//symbol/foo")) != NULL) {
|
||||||
* ...
|
* ...
|
||||||
* }
|
* }
|
||||||
* @endcode
|
* @endcode
|
||||||
* @note the returned pointer points into the original tree so should not be freed fter use.
|
* @note the returned pointer points into the original tree so should not be freed fter use.
|
||||||
* @note return value does not see difference between error and not found
|
* @note return value does not see difference between error and not found
|
||||||
* @see also xpath_vec.
|
* @see also xpath_vec.
|
||||||
|
* @experimental
|
||||||
*/
|
*/
|
||||||
cxobj *
|
cxobj *
|
||||||
xpath_first(cxobj *xcur,
|
xpath_first(cxobj *xcur,
|
||||||
|
cvec *nsc,
|
||||||
char *format,
|
char *format,
|
||||||
...)
|
...)
|
||||||
{
|
{
|
||||||
|
|
@ -1144,9 +1283,8 @@ xpath_first(cxobj *xcur,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
if (xpath_vec_ctx(xcur, xpath, &xr) < 0)
|
if (xpath_vec_ctx(xcur, nsc, xpath, &xr) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (xr && xr->xc_type == XT_NODESET && xr->xc_size)
|
if (xr && xr->xc_type == XT_NODESET && xr->xc_size)
|
||||||
cx = xr->xc_nodeset[0];
|
cx = xr->xc_nodeset[0];
|
||||||
done:
|
done:
|
||||||
|
|
@ -1157,18 +1295,21 @@ xpath_first(cxobj *xcur,
|
||||||
return cx;
|
return cx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Given XML tree and xpath, returns nodeset as xml node vector
|
/*! Given XML tree and xpath, returns nodeset as xml node vector
|
||||||
* If result is not nodeset, return empty nodeset
|
* If result is not nodeset, return empty nodeset
|
||||||
* @param[in] xcur xml-tree where to search
|
* @param[in] xcur xml-tree where to search
|
||||||
* @param[in] xpath stdarg string with XPATH 1.0 syntax
|
* @param[in] format stdarg string with XPATH 1.0 syntax
|
||||||
|
* @param[in] nsc XML Namespace context for XPATH
|
||||||
* @param[out] vec vector of xml-trees. Vector must be free():d after use
|
* @param[out] vec vector of xml-trees. Vector must be free():d after use
|
||||||
* @param[out] veclen returns length of vector in return value
|
* @param[out] veclen returns length of vector in return value
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
* @code
|
* @code
|
||||||
|
* cvec *nsc; // namespace context
|
||||||
* cxobj **vec;
|
* cxobj **vec;
|
||||||
* size_t veclen;
|
* size_t veclen;
|
||||||
* if (xpath_vec(xcur, "//symbol/foo", &vec, &veclen) < 0)
|
* if (xpath_vec(xcur, nsc, "//symbol/foo", &vec, &veclen) < 0)
|
||||||
* goto err;
|
* goto err;
|
||||||
* for (i=0; i<veclen; i++){
|
* for (i=0; i<veclen; i++){
|
||||||
* xn = vec[i];
|
* xn = vec[i];
|
||||||
|
|
@ -1176,9 +1317,11 @@ xpath_first(cxobj *xcur,
|
||||||
* }
|
* }
|
||||||
* free(vec);
|
* free(vec);
|
||||||
* @endcode
|
* @endcode
|
||||||
|
* @note Namespace prefix checking is not properly implemented
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xpath_vec(cxobj *xcur,
|
xpath_vec(cxobj *xcur,
|
||||||
|
cvec *nsc,
|
||||||
char *format,
|
char *format,
|
||||||
cxobj ***vec,
|
cxobj ***vec,
|
||||||
size_t *veclen,
|
size_t *veclen,
|
||||||
|
|
@ -1188,8 +1331,8 @@ xpath_vec(cxobj *xcur,
|
||||||
va_list ap;
|
va_list ap;
|
||||||
size_t len;
|
size_t len;
|
||||||
char *xpath = NULL;
|
char *xpath = NULL;
|
||||||
xp_ctx *xr = NULL;
|
xp_ctx *xr = NULL;
|
||||||
|
|
||||||
va_start(ap, veclen);
|
va_start(ap, veclen);
|
||||||
len = vsnprintf(NULL, 0, format, ap);
|
len = vsnprintf(NULL, 0, format, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
@ -1208,7 +1351,7 @@ xpath_vec(cxobj *xcur,
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
*vec=NULL;
|
*vec=NULL;
|
||||||
*veclen = 0;
|
*veclen = 0;
|
||||||
if (xpath_vec_ctx(xcur, xpath, &xr) < 0)
|
if (xpath_vec_ctx(xcur, nsc, xpath, &xr) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (xr && xr->xc_type == XT_NODESET){
|
if (xr && xr->xc_type == XT_NODESET){
|
||||||
*vec = xr->xc_nodeset;
|
*vec = xr->xc_nodeset;
|
||||||
|
|
@ -1227,6 +1370,7 @@ xpath_vec(cxobj *xcur,
|
||||||
/* Xpath that returns a vector of matches (only nodes marked with flags)
|
/* Xpath that returns a vector of matches (only nodes marked with flags)
|
||||||
* @param[in] xcur xml-tree where to search
|
* @param[in] xcur xml-tree where to search
|
||||||
* @param[in] xpath string with XPATH syntax
|
* @param[in] xpath string with XPATH syntax
|
||||||
|
* @param[in] nsc External XML namespace context, or NULL
|
||||||
* @param[in] flags Set of flags that return nodes must match (0 if all)
|
* @param[in] flags Set of flags that return nodes must match (0 if all)
|
||||||
* @param[out] vec vector of xml-trees. Vector must be free():d after use
|
* @param[out] vec vector of xml-trees. Vector must be free():d after use
|
||||||
* @param[out] veclen returns length of vector in return value
|
* @param[out] veclen returns length of vector in return value
|
||||||
|
|
@ -1235,7 +1379,8 @@ xpath_vec(cxobj *xcur,
|
||||||
* @code
|
* @code
|
||||||
* cxobj **vec;
|
* cxobj **vec;
|
||||||
* size_t veclen;
|
* size_t veclen;
|
||||||
* if (xpath_vec_flag(xcur, "//symbol/foo", XML_FLAG_ADD, &vec, &veclen) < 0)
|
* cvec *nsc; // namespace context (not NULL)
|
||||||
|
* if (xpath_vec_flag(xcur, nsc, "//symbol/foo", XML_FLAG_ADD, &vec, &veclen) < 0)
|
||||||
* goto err;
|
* goto err;
|
||||||
* for (i=0; i<veclen; i++){
|
* for (i=0; i<veclen; i++){
|
||||||
* xn = vec[i];
|
* xn = vec[i];
|
||||||
|
|
@ -1249,8 +1394,9 @@ xpath_vec(cxobj *xcur,
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xpath_vec_flag(cxobj *xcur,
|
xpath_vec_flag(cxobj *xcur,
|
||||||
|
cvec *nsc,
|
||||||
char *format,
|
char *format,
|
||||||
uint16_t flags,
|
uint16_t flags,
|
||||||
cxobj ***vec,
|
cxobj ***vec,
|
||||||
size_t *veclen,
|
size_t *veclen,
|
||||||
...)
|
...)
|
||||||
|
|
@ -1281,7 +1427,7 @@ xpath_vec_flag(cxobj *xcur,
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
*vec=NULL;
|
*vec=NULL;
|
||||||
*veclen = 0;
|
*veclen = 0;
|
||||||
if (xpath_vec_ctx(xcur, xpath, &xr) < 0)
|
if (xpath_vec_ctx(xcur, nsc, xpath, &xr) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (xr && xr->xc_type == XT_NODESET){
|
if (xr && xr->xc_type == XT_NODESET){
|
||||||
for (i=0; i<xr->xc_size; i++){
|
for (i=0; i<xr->xc_size; i++){
|
||||||
|
|
@ -1303,14 +1449,16 @@ xpath_vec_flag(cxobj *xcur,
|
||||||
/*! Given XML tree and xpath, returns boolean
|
/*! Given XML tree and xpath, returns boolean
|
||||||
* Returns true if the nodeset is non-empty
|
* Returns true if the nodeset is non-empty
|
||||||
* @param[in] xcur xml-tree where to search
|
* @param[in] xcur xml-tree where to search
|
||||||
|
* @param[in] nsc External XML namespace context, or NULL
|
||||||
* @param[in] xpath stdarg string with XPATH 1.0 syntax
|
* @param[in] xpath stdarg string with XPATH 1.0 syntax
|
||||||
* @retval 1 True
|
* @retval 1 True
|
||||||
* @retval 0 False
|
* @retval 0 False
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xpath_vec_bool(cxobj *xcur,
|
xpath_vec_bool(cxobj *xcur,
|
||||||
char *format,
|
cvec *nsc,
|
||||||
|
char *format,
|
||||||
...)
|
...)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
@ -1335,7 +1483,7 @@ xpath_vec_bool(cxobj *xcur,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
if (xpath_vec_ctx(xcur, xpath, &xr) < 0)
|
if (xpath_vec_ctx(xcur, nsc, xpath, &xr) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (xr)
|
if (xr)
|
||||||
retval = ctx2boolean(xr);
|
retval = ctx2boolean(xr);
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@
|
||||||
***** END LICENSE BLOCK *****
|
***** END LICENSE BLOCK *****
|
||||||
|
|
||||||
* Clixon XML XPATH 1.0 according to https://www.w3.org/TR/xpath-10
|
* Clixon XML XPATH 1.0 according to https://www.w3.org/TR/xpath-10
|
||||||
* This file defines XPATH contexts using in traversing the XPATH parse tree.
|
* This file defines XPATH contexts used in traversing the XPATH parse tree.
|
||||||
*/
|
*/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
***** END LICENSE BLOCK *****
|
***** END LICENSE BLOCK *****
|
||||||
|
|
||||||
|
* Clixon XML XPATH 1.0 according to https://www.w3.org/TR/xpath-10
|
||||||
*/
|
*/
|
||||||
#ifndef _CLIXON_XPATH_PARSE_H_
|
#ifndef _CLIXON_XPATH_PARSE_H_
|
||||||
#define _CLIXON_XPATH_PARSE_H_
|
#define _CLIXON_XPATH_PARSE_H_
|
||||||
|
|
@ -50,7 +51,7 @@ enum xp_type{
|
||||||
XP_ABSPATH,
|
XP_ABSPATH,
|
||||||
XP_RELLOCPATH,
|
XP_RELLOCPATH,
|
||||||
XP_STEP,
|
XP_STEP,
|
||||||
XP_NODE,
|
XP_NODE, /* s0 is namespace prefix, s1 is name */
|
||||||
XP_NODE_FN,
|
XP_NODE_FN,
|
||||||
XP_PRED,
|
XP_PRED,
|
||||||
XP_PRI0,
|
XP_PRI0,
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
*
|
*
|
||||||
***** BEGIN LICENSE BLOCK *****
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
|
Copyright (C) 2009-2019 Olof Hagsand
|
||||||
|
|
||||||
This file is part of CLIXON.
|
This file is part of CLIXON.
|
||||||
|
|
||||||
|
|
@ -789,12 +789,12 @@ yang_find_mynamespace(yang_stmt *ys)
|
||||||
char *namespace = NULL;
|
char *namespace = NULL;
|
||||||
|
|
||||||
if ((ymod = ys_real_module(ys)) == NULL){
|
if ((ymod = ys_real_module(ys)) == NULL){
|
||||||
clicon_err(OE_YANG, 0, "My yang module not found");
|
clicon_err(OE_YANG, ENOENT, "My yang module not found");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((ynamespace = yang_find(ymod, Y_NAMESPACE, NULL)) == NULL)
|
if ((ynamespace = yang_find(ymod, Y_NAMESPACE, NULL)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
namespace = ynamespace->ys_argument;
|
namespace = yang_argument_get(ynamespace);
|
||||||
done:
|
done:
|
||||||
return namespace;
|
return namespace;
|
||||||
}
|
}
|
||||||
|
|
@ -1176,17 +1176,17 @@ yang_find_module_by_prefix(yang_stmt *ys,
|
||||||
}
|
}
|
||||||
yimport = NULL;
|
yimport = NULL;
|
||||||
while ((yimport = yn_each(my_ymod, yimport)) != NULL) {
|
while ((yimport = yn_each(my_ymod, yimport)) != NULL) {
|
||||||
if (yimport->ys_keyword != Y_IMPORT &&
|
if (yang_keyword_get(yimport) != Y_IMPORT &&
|
||||||
yimport->ys_keyword != Y_INCLUDE)
|
yang_keyword_get(yimport) != Y_INCLUDE)
|
||||||
continue;
|
continue;
|
||||||
if ((yprefix = yang_find(yimport, Y_PREFIX, NULL)) != NULL &&
|
if ((yprefix = yang_find(yimport, Y_PREFIX, NULL)) != NULL &&
|
||||||
strcmp(yprefix->ys_argument, prefix) == 0){
|
strcmp(yang_argument_get(yprefix), prefix) == 0){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (yimport){
|
if (yimport){
|
||||||
if ((ymod = yang_find(yspec, Y_MODULE, yimport->ys_argument)) == NULL &&
|
if ((ymod = yang_find(yspec, Y_MODULE, yang_argument_get(yimport))) == NULL &&
|
||||||
(ymod = yang_find(yspec, Y_SUBMODULE, yimport->ys_argument)) == NULL){
|
(ymod = yang_find(yspec, Y_SUBMODULE, yang_argument_get(yimport))) == NULL){
|
||||||
clicon_err(OE_YANG, 0, "No module or sub-module found with prefix %s",
|
clicon_err(OE_YANG, 0, "No module or sub-module found with prefix %s",
|
||||||
prefix);
|
prefix);
|
||||||
yimport = NULL;
|
yimport = NULL;
|
||||||
|
|
@ -1222,7 +1222,7 @@ yang_find_module_by_namespace(yang_stmt *yspec,
|
||||||
return ymod;
|
return ymod;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Given a yang spec and a module name, return yang module
|
/*! Given a yang spec and a module name, return yang module or submodule
|
||||||
*
|
*
|
||||||
* @param[in] yspec A yang specification
|
* @param[in] yspec A yang specification
|
||||||
* @param[in] name Name of module
|
* @param[in] name Name of module
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
*
|
*
|
||||||
***** BEGIN LICENSE BLOCK *****
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
|
Copyright (C) 2009-2019 Olof Hagsand
|
||||||
|
|
||||||
This file is part of CLIXON.
|
This file is part of CLIXON.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
***** BEGIN LICENSE BLOCK *****
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
|
Copyright (C) 2009-2019 Olof Hagsand
|
||||||
|
|
||||||
This file is part of CLIXON.
|
This file is part of CLIXON.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
*
|
*
|
||||||
***** BEGIN LICENSE BLOCK *****
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
|
Copyright (C) 2009-2019 Olof Hagsand
|
||||||
|
|
||||||
This file is part of CLIXON.
|
This file is part of CLIXON.
|
||||||
|
|
||||||
|
|
@ -80,7 +80,7 @@ struct yang_stmt{
|
||||||
char *ys_argument; /* String / argument depending on keyword */
|
char *ys_argument; /* String / argument depending on keyword */
|
||||||
int ys_flags; /* Flags according to YANG_FLAG_* above */
|
int ys_flags; /* Flags according to YANG_FLAG_* above */
|
||||||
yang_stmt *ys_mymodule; /* Shortcut to "my" module. Augmented
|
yang_stmt *ys_mymodule; /* Shortcut to "my" module. Augmented
|
||||||
nodes can belong to other
|
nodes can belong to other
|
||||||
modules than the ancestor module */
|
modules than the ancestor module */
|
||||||
|
|
||||||
char *ys_extra; /* For unknown */
|
char *ys_extra; /* For unknown */
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
*
|
*
|
||||||
***** BEGIN LICENSE BLOCK *****
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
|
Copyright (C) 2009-2019 Olof Hagsand
|
||||||
|
|
||||||
This file is part of CLIXON.
|
This file is part of CLIXON.
|
||||||
|
|
||||||
|
|
@ -69,6 +69,7 @@
|
||||||
#include "clixon_file.h"
|
#include "clixon_file.h"
|
||||||
#include "clixon_yang.h"
|
#include "clixon_yang.h"
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
|
#include "clixon_xml_nsctx.h"
|
||||||
#include "clixon_xpath_ctx.h"
|
#include "clixon_xpath_ctx.h"
|
||||||
#include "clixon_xpath.h"
|
#include "clixon_xpath.h"
|
||||||
#include "clixon_options.h"
|
#include "clixon_options.h"
|
||||||
|
|
@ -253,6 +254,7 @@ yms_build(clicon_handle h,
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] yspec Yang spec
|
* @param[in] yspec Yang spec
|
||||||
* @param[in] xpath XML Xpath
|
* @param[in] xpath XML Xpath
|
||||||
|
* @param[in] nsc XML Namespace context for xpath
|
||||||
* @param[in] brief Just name, revision and uri (no cache)
|
* @param[in] brief Just name, revision and uri (no cache)
|
||||||
* @param[in,out] xret Existing XML tree, merge x into this
|
* @param[in,out] xret Existing XML tree, merge x into this
|
||||||
* @retval -1 Error (fatal)
|
* @retval -1 Error (fatal)
|
||||||
|
|
@ -281,6 +283,7 @@ int
|
||||||
yang_modules_state_get(clicon_handle h,
|
yang_modules_state_get(clicon_handle h,
|
||||||
yang_stmt *yspec,
|
yang_stmt *yspec,
|
||||||
char *xpath,
|
char *xpath,
|
||||||
|
cvec *nsc,
|
||||||
int brief,
|
int brief,
|
||||||
cxobj **xret)
|
cxobj **xret)
|
||||||
{
|
{
|
||||||
|
|
@ -302,7 +305,7 @@ yang_modules_state_get(clicon_handle h,
|
||||||
/* xc is also original tree, need to copy it */
|
/* xc is also original tree, need to copy it */
|
||||||
if ((xw = xml_wrap(xc, "top")) == NULL)
|
if ((xw = xml_wrap(xc, "top")) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (xpath_first(xw, "%s", xpath)){
|
if (xpath_first(xw, NULL, "%s", xpath)){
|
||||||
if ((x = xml_dup(xc)) == NULL) /* Make copy and use below */
|
if ((x = xml_dup(xc)) == NULL) /* Make copy and use below */
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -334,7 +337,7 @@ yang_modules_state_get(clicon_handle h,
|
||||||
if ((x = xml_wrap(x, "top")) < 0)
|
if ((x = xml_wrap(x, "top")) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* extract xpath part of module-state tree */
|
/* extract xpath part of module-state tree */
|
||||||
if (xpath_vec(x, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
if (xpath_vec(x, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (xvec != NULL){
|
if (xvec != NULL){
|
||||||
for (i=0; i<xlen; i++)
|
for (i=0; i<xlen; i++)
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
*
|
*
|
||||||
***** BEGIN LICENSE BLOCK *****
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
|
Copyright (C) 2009-2019 Olof Hagsand
|
||||||
|
|
||||||
This file is part of CLIXON.
|
This file is part of CLIXON.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
***** BEGIN LICENSE BLOCK *****
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
|
Copyright (C) 2009-2019 Olof Hagsand
|
||||||
|
|
||||||
This file is part of CLIXON.
|
This file is part of CLIXON.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
*
|
*
|
||||||
***** BEGIN LICENSE BLOCK *****
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
|
Copyright (C) 2009-2019 Olof Hagsand
|
||||||
|
|
||||||
This file is part of CLIXON.
|
This file is part of CLIXON.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
*
|
*
|
||||||
***** BEGIN LICENSE BLOCK *****
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
|
Copyright (C) 2009-2019 Olof Hagsand
|
||||||
|
|
||||||
This file is part of CLIXON.
|
This file is part of CLIXON.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -171,7 +171,7 @@ stop_backend(){
|
||||||
|
|
||||||
# Wait for restconf to stop sending 502 Bad Gateway
|
# Wait for restconf to stop sending 502 Bad Gateway
|
||||||
wait_backend(){
|
wait_backend(){
|
||||||
reply=$(echo '<rpc message-id="101" xmlns="http://clicon.org/lib"><ping/></rpc>]]>]]>' | clixon_netconf -qef $cfg 2> /dev/null)
|
reply=$(echo '<rpc message-id="101"><ping xmlns="http://clicon.org/lib"/></rpc>]]>]]>' | clixon_netconf -qef $cfg 2> /dev/null)
|
||||||
let i=0;
|
let i=0;
|
||||||
while [[ $reply != "<rpc-reply"* ]]; do
|
while [[ $reply != "<rpc-reply"* ]]; do
|
||||||
sleep 1
|
sleep 1
|
||||||
|
|
|
||||||
|
|
@ -84,13 +84,13 @@ new "cli configure ip type"
|
||||||
expectfn "$clixon_cli -1 -f $cfg set interfaces interface eth/0/0 type ex:eth" 0 "^$"
|
expectfn "$clixon_cli -1 -f $cfg set interfaces interface eth/0/0 type ex:eth" 0 "^$"
|
||||||
|
|
||||||
new "cli show xpath description"
|
new "cli show xpath description"
|
||||||
expectfn "$clixon_cli -1 -f $cfg -l o show xpath /interfaces/interface/description" 0 "<description>mydesc</description>"
|
expectfn "$clixon_cli -1 -f $cfg -l o show xpath /interfaces/interface/description urn:ietf:params:xml:ns:yang:ietf-interfaces" 0 "<description>mydesc</description>"
|
||||||
|
|
||||||
new "cli delete description"
|
new "cli delete description"
|
||||||
expectfn "$clixon_cli -1 -f $cfg -l o delete interfaces interface eth/0/0 description mydesc" 0 ""
|
expectfn "$clixon_cli -1 -f $cfg -l o delete interfaces interface eth/0/0 description mydesc" 0 ""
|
||||||
|
|
||||||
new "cli show xpath no description"
|
new "cli show xpath no description"
|
||||||
expectfn "$clixon_cli -1 -f $cfg -l o show xpath /interfaces/interface/description" 0 "^$"
|
expectfn "$clixon_cli -1 -f $cfg -l o show xpath /interfaces/interface/description urn:ietf:params:xml:ns:yang:ietf-interfaces" 0 "^$"
|
||||||
|
|
||||||
new "cli copy interface"
|
new "cli copy interface"
|
||||||
expectfn "$clixon_cli -1 -f $cfg copy interface eth/0/0 to eth99" 0 "^$"
|
expectfn "$clixon_cli -1 -f $cfg copy interface eth/0/0 to eth99" 0 "^$"
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,7 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></
|
||||||
# reply since the modules change so often
|
# reply since the modules change so often
|
||||||
new "netconf schema resource, RFC 7895"
|
new "netconf schema resource, RFC 7895"
|
||||||
ret=$($clixon_netconf -qf $cfg<<EOF
|
ret=$($clixon_netconf -qf $cfg<<EOF
|
||||||
<rpc><get><filter type="xpath" select="modules-state/module" xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library"/></get></rpc>]]>]]>
|
<rpc><get><filter type="xpath" select="l:modules-state/l:module" xmlns:l="urn:ietf:params:xml:ns:yang:ietf-yang-library"/></get></rpc>]]>]]>
|
||||||
EOF
|
EOF
|
||||||
)
|
)
|
||||||
#echo $ret
|
#echo $ret
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,14 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# XML Insert unit test
|
# XML Insert elements and test if they are sorted according to yang
|
||||||
# First a list with 0-5 base elements, insert in different places
|
# First a list with 0-5 base elements, insert in different places
|
||||||
# Second varying yangs: container, leaf, list, leaf-list, choice, user-order list
|
# Second varying yangs: container, leaf, list, leaf-list, choice, user-order list
|
||||||
|
|
||||||
|
|
||||||
# Magic line must be first in script (see README.md)
|
# Magic line must be first in script (see README.md)
|
||||||
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||||
|
|
||||||
: ${clixon_util_insert:=clixon_util_insert}
|
: ${clixon_util_insert:=clixon_util_insert}
|
||||||
|
|
||||||
OPTS="-D $DBG -s"
|
OPTS="-D $DBG"
|
||||||
|
|
||||||
APPNAME=example
|
APPNAME=example
|
||||||
|
|
||||||
|
|
@ -63,7 +62,7 @@ testrun(){
|
||||||
err "length of retval is zero"
|
err "length of retval is zero"
|
||||||
fi
|
fi
|
||||||
# echo "rs:$rs"
|
# echo "rs:$rs"
|
||||||
# echo "r0:$r0"
|
# echo "r0:$r0"
|
||||||
# Check they are equal
|
# Check they are equal
|
||||||
if [[ "$r0" != "$rs" ]]; then
|
if [[ "$r0" != "$rs" ]]; then
|
||||||
err "$rs" "$r0"
|
err "$rs" "$r0"
|
||||||
|
|
|
||||||
|
|
@ -45,21 +45,29 @@ module example{
|
||||||
}
|
}
|
||||||
container default-address {
|
container default-address {
|
||||||
leaf absname {
|
leaf absname {
|
||||||
|
description "Absolute references existing interfaces in if module";
|
||||||
type leafref {
|
type leafref {
|
||||||
path "/ip:interfaces/ip:interface/ip:name";
|
path "/if:interfaces/if:interface/if:name";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
leaf relname {
|
leaf relname {
|
||||||
type leafref {
|
type leafref {
|
||||||
path "../../interfaces/interface/name";
|
path "../../if:interfaces/if:interface/if:name";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
leaf address {
|
leaf address {
|
||||||
|
description "From RFC7950 9.9.5";
|
||||||
type leafref {
|
type leafref {
|
||||||
path "../../interfaces/interface[name = current()/../relname]"
|
path "../../if:interfaces/if:interface[if:name = current()/../relname]"
|
||||||
+ "/ipv4/address/ip";
|
+ "/if:ipv4/if:address/if:ip";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
leaf wrong {
|
||||||
|
description "References leading nowhere in yang";
|
||||||
|
type leafref {
|
||||||
|
path "/ip:interfaces/ip:interface/ip:name";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
list sender{
|
list sender{
|
||||||
key name;
|
key name;
|
||||||
|
|
@ -75,6 +83,36 @@ module example{
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
BASEXML=$(cat <<EOF
|
||||||
|
<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
|
||||||
|
<interface>
|
||||||
|
<name>eth0</name>
|
||||||
|
<type>ex:eth</type>
|
||||||
|
<ipv4>
|
||||||
|
<address>
|
||||||
|
<ip>192.0.2.1</ip>
|
||||||
|
<prefix-length>24</prefix-length>
|
||||||
|
</address>
|
||||||
|
<address>
|
||||||
|
<ip>192.0.2.2</ip>
|
||||||
|
<prefix-length>24</prefix-length>
|
||||||
|
</address>
|
||||||
|
</ipv4>
|
||||||
|
</interface>
|
||||||
|
<interface>
|
||||||
|
<name>lo</name>
|
||||||
|
<type>ex:lo</type>
|
||||||
|
<ipv4>
|
||||||
|
<address>
|
||||||
|
<ip>127.0.0.1</ip>
|
||||||
|
<prefix-length>32</prefix-length>
|
||||||
|
</address>
|
||||||
|
</ipv4>
|
||||||
|
</interface>
|
||||||
|
</interfaces>
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
|
||||||
new "test params: -f $cfg"
|
new "test params: -f $cfg"
|
||||||
|
|
||||||
if [ $BE -ne 0 ]; then
|
if [ $BE -ne 0 ]; then
|
||||||
|
|
@ -91,33 +129,40 @@ if [ $BE -ne 0 ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new "leafref base config"
|
new "leafref base config"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth0</name><type>ex:eth</type><ipv4><address><ip>192.0.2.1</ip><prefix-length>24</prefix-length></address><address><ip>192.0.2.2</ip><prefix-length>24</prefix-length></address></ipv4></interface><interface><name>lo</name><type>ex:lo</type><ipv4><address><ip>127.0.0.1</ip><prefix-length>32</prefix-length></address></ipv4></interface></interfaces></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><edit-config><target><candidate/></target><config>$BASEXML</config></edit-config></rpc>]]>]]>" '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "leafref get config"
|
new "leafref get config"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth0</name>'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' "^<rpc-reply><data>$BASEXML</data></rpc-reply>]]>]]>"
|
||||||
|
|
||||||
new "leafref base commit"
|
new "leafref base commit"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "leafref get config"
|
new "leafref add non-existing ref"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth0</name>'
|
|
||||||
|
|
||||||
new "leafref add wrong ref"
|
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><default-address xmlns="urn:example:clixon"><absname>eth3</absname><address>10.0.4.6</address></default-address></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><default-address xmlns="urn:example:clixon"><absname>eth3</absname><address>10.0.4.6</address></default-address></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "leafref validate"
|
new "leafref validate"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>eth3</bad-element></error-info><error-severity>error</error-severity><error-message>Leafref validation failed: No such leaf</error-message></rpc-error></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>eth3</bad-element></error-info><error-severity>error</error-severity><error-message>Leafref validation failed: No such leaf</error-message></rpc-error></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
|
#new "leafref wrong ref"
|
||||||
|
#expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><default-address xmlns="urn:example:clixon"><wrong>eth3</wrong><address>10.0.4.6</address></default-address></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "leafref discard-changes"
|
new "leafref discard-changes"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "leafref add correct absref"
|
new "leafref add correct absref"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><default-address xmlns="urn:example:clixon"><absname>eth0</absname></default-address></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><default-address xmlns="urn:example:clixon"><absname>eth0</absname></default-address></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
|
new "leafref validate (ok)"
|
||||||
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>"
|
||||||
|
|
||||||
new "leafref add correct relref"
|
new "leafref add correct relref"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><default-address xmlns="urn:example:clixon"><relname>eth0</relname></default-address></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><default-address xmlns="urn:example:clixon"><relname>eth0</relname></default-address></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
# XXX add address
|
new "leafref validate (ok)"
|
||||||
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>"
|
||||||
|
|
||||||
|
new "leafref add correct address"
|
||||||
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><default-address xmlns="urn:example:clixon"><address>192.0.2.1</address></default-address></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "leafref validate (ok)"
|
new "leafref validate (ok)"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>"
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>"
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ EOF
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
err
|
err
|
||||||
fi
|
fi
|
||||||
new "start backend -s init -f $cfg"
|
new "start backend -s startup -f $cfg"
|
||||||
start_backend -s startup -f $cfg
|
start_backend -s startup -f $cfg
|
||||||
else
|
else
|
||||||
new "Restart backend as eg follows: -Ff $cfg -s startup"
|
new "Restart backend as eg follows: -Ff $cfg -s startup"
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ module nacm-example{
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
cat <<EOF > $nacmfile
|
cat <<EOF > $nacmfile
|
||||||
<nacm>
|
<nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm">
|
||||||
<enable-nacm>true</enable-nacm>
|
<enable-nacm>true</enable-nacm>
|
||||||
<read-default>permit</read-default>
|
<read-default>permit</read-default>
|
||||||
<write-default>deny</write-default>
|
<write-default>deny</write-default>
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,7 @@ expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/clixon-ex
|
||||||
'
|
'
|
||||||
|
|
||||||
new "admin read netconf ok"
|
new "admin read netconf ok"
|
||||||
expecteof "$clixon_netconf -U andy -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/translate"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><translate xmlns="urn:example:clixon"><k>key42</k><value>val42</value></translate><translate xmlns="urn:example:clixon"><k>key43</k><value>val43</value></translate></data></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -U andy -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/t:translate" xmlns:t="urn:example:clixon" /></get-config></rpc>]]>]]>' '^<rpc-reply><data><translate xmlns="urn:example:clixon"><k>key42</k><value>val42</value></translate><translate xmlns="urn:example:clixon"><k>key43</k><value>val43</value></translate></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "admin read element ok"
|
new "admin read element ok"
|
||||||
expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/clixon-example:translate=key42/value)" 0 '{"clixon-example:value": "val42"}
|
expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/clixon-example:translate=key42/value)" 0 '{"clixon-example:value": "val42"}
|
||||||
|
|
@ -193,7 +193,7 @@ expecteq "$(curl -u wilma:bar -sS -X GET http://localhost/restconf/data/clixon-e
|
||||||
'
|
'
|
||||||
|
|
||||||
new "limit read netconf ok"
|
new "limit read netconf ok"
|
||||||
expecteof "$clixon_netconf -U wilma -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/translate"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><translate xmlns="urn:example:clixon"><k>key42</k><value>val42</value></translate><translate xmlns="urn:example:clixon"><k>key43</k><value>val43</value></translate></data></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -U wilma -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/t:translate" xmlns:t="urn:example:clixon"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><translate xmlns="urn:example:clixon"><k>key42</k><value>val42</value></translate><translate xmlns="urn:example:clixon"><k>key43</k><value>val43</value></translate></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "limit read element ok"
|
new "limit read element ok"
|
||||||
expecteq "$(curl -u wilma:bar -sS -X GET http://localhost/restconf/data/clixon-example:translate=key42/value)" 0 '{"clixon-example:value": "val42"}
|
expecteq "$(curl -u wilma:bar -sS -X GET http://localhost/restconf/data/clixon-example:translate=key42/value)" 0 '{"clixon-example:value": "val42"}
|
||||||
|
|
@ -217,7 +217,7 @@ new "guest read fail"
|
||||||
expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/clixon-example:translate)" 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/clixon-example:translate)" 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
||||||
|
|
||||||
new "guest read netconf fail"
|
new "guest read netconf fail"
|
||||||
expecteof "$clixon_netconf -U guest -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/translate"/></get-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>access-denied</error-tag><error-severity>error</error-severity><error-message>default deny</error-message></rpc-error></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -U guest -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/t:translate" xmlns:t="urn:example:clixon"/></get-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>access-denied</error-tag><error-severity>error</error-severity><error-message>default deny</error-message></rpc-error></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "guest read element fail"
|
new "guest read element fail"
|
||||||
expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/clixon-example:translate=key42/value)" 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/clixon-example:translate=key42/value)" 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></
|
||||||
|
|
||||||
# Too many quotes, (single inside double inside single) need to fool bash
|
# Too many quotes, (single inside double inside single) need to fool bash
|
||||||
cat <<EOF > $tmp # new
|
cat <<EOF > $tmp # new
|
||||||
<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name='eth/0/0']"/></get-config></rpc>]]>]]>
|
<rpc><get-config><source><candidate/></source><filter type="xpath" select="/if:interfaces/if:interface[if:name='eth/0/0']" xmlns:if="urn:ietf:params:xml:ns:yang:ietf-interfaces"/></get-config></rpc>]]>]]>
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
new "Check eth/0/0 added using xpath"
|
new "Check eth/0/0 added using xpath"
|
||||||
|
|
@ -98,7 +98,7 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></
|
||||||
|
|
||||||
# Too many quotes
|
# Too many quotes
|
||||||
cat <<EOF > $tmp # new
|
cat <<EOF > $tmp # new
|
||||||
<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name='eth1']/enabled"/></get-config></rpc>]]>]]>
|
<rpc><get-config><source><candidate/></source><filter type="xpath" select="/if:interfaces/if:interface[if:name='eth1']/if:enabled" xmlns:if="urn:ietf:params:xml:ns:yang:ietf-interfaces"/></get-config></rpc>]]>]]>
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
new "netconf get config xpath"
|
new "netconf get config xpath"
|
||||||
|
|
@ -106,7 +106,7 @@ expecteof "$clixon_netconf -qf $cfg" 0 "$(cat $tmp)" '^<rpc-reply><data><interfa
|
||||||
|
|
||||||
# Too many quotes
|
# Too many quotes
|
||||||
cat <<EOF > $tmp # new
|
cat <<EOF > $tmp # new
|
||||||
<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name='eth1']/enabled/../.."/></get-config></rpc>]]>]]>
|
<rpc><get-config><source><candidate/></source><filter type="xpath" select="/if:interfaces/if:interface[if:name='eth1']/if:enabled/../.." xmlns:if="urn:ietf:params:xml:ns:yang:ietf-interfaces"/></get-config></rpc>]]>]]>
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
new "netconf get config xpath parent"
|
new "netconf get config xpath parent"
|
||||||
|
|
@ -162,7 +162,7 @@ new "netconf edit state operation should fail"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>e0</name><oper-status>up</oper-status></interface></interfaces></config></edit-config></rpc>]]>]]>' "^<rpc-reply><rpc-error><error-type>protocol</error-type><error-tag>invalid-value</error-tag><error-severity>error</error-severity><error-message>State data not allowed</error-message></rpc-error></rpc-reply>]]>]]>"
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>e0</name><oper-status>up</oper-status></interface></interfaces></config></edit-config></rpc>]]>]]>' "^<rpc-reply><rpc-error><error-type>protocol</error-type><error-tag>invalid-value</error-tag><error-severity>error</error-severity><error-message>State data not allowed</error-message></rpc-error></rpc-reply>]]>]]>"
|
||||||
|
|
||||||
new "netconf get state operation"
|
new "netconf get state operation"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get><filter type=\"xpath\" select=\"/interfaces\"/></get></rpc>]]>]]>" '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth1</name><type>ex:eth</type><enabled>true</enabled><oper-status>up</oper-status></interface></interfaces></data></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get><filter type=\"xpath\" select=\"/if:interfaces\" xmlns:if=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\" /></get></rpc>]]>]]>" '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth1</name><type>ex:eth</type><enabled>true</enabled><oper-status>up</oper-status></interface></interfaces></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "netconf lock/unlock"
|
new "netconf lock/unlock"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><lock><target><candidate/></target></lock></rpc>]]>]]><rpc><unlock><target><candidate/></target></unlock></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]><rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><lock><target><candidate/></target></lock></rpc>]]>]]><rpc><unlock><target><candidate/></target></unlock></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]><rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ cat <<EOF > $fyang
|
||||||
module order-example{
|
module order-example{
|
||||||
yang-version 1.1;
|
yang-version 1.1;
|
||||||
namespace "urn:example:order";
|
namespace "urn:example:order";
|
||||||
prefix ex;
|
prefix exo;
|
||||||
import clixon-example { /* for state callback */
|
import clixon-example { /* for state callback */
|
||||||
prefix ex;
|
prefix ex;
|
||||||
}
|
}
|
||||||
|
|
@ -168,7 +168,7 @@ fi
|
||||||
# STATE (should not be ordered)
|
# STATE (should not be ordered)
|
||||||
new "state data (should be unordered: 42,41,43)"
|
new "state data (should be unordered: 42,41,43)"
|
||||||
cat <<EOF > $tmp
|
cat <<EOF > $tmp
|
||||||
<rpc><get><filter type="xpath" select="state"/></get></rpc>]]>]]>
|
<rpc><get><filter type="xpath" select="ex:state" xmlns:ex="urn:example:clixon" /></get></rpc>]]>]]>
|
||||||
EOF
|
EOF
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "$(cat $tmp)" '<rpc-reply><data><state xmlns="urn:example:clixon"><op>42</op><op>41</op><op>43</op></state></data></rpc-reply>]]>]]>'
|
expecteof "$clixon_netconf -qf $cfg" 0 "$(cat $tmp)" '<rpc-reply><data><state xmlns="urn:example:clixon"><op>42</op><op>41</op><op>43</op></state></data></rpc-reply>]]>]]>'
|
||||||
|
|
||||||
|
|
@ -177,16 +177,16 @@ new "verify running from start, should be: c,l,y0,y1,y2,y3; y1 and y3 sorted."
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><running/></source></get-config></rpc>]]>]]>' '^<rpc-reply><data><c xmlns="urn:example:order"><d>hej</d></c><l xmlns="urn:example:order">hopp</l><y0 xmlns="urn:example:order">d</y0><y0 xmlns="urn:example:order">b</y0><y0 xmlns="urn:example:order">c</y0><y0 xmlns="urn:example:order">a</y0><y1 xmlns="urn:example:order">a</y1><y1 xmlns="urn:example:order">b</y1><y1 xmlns="urn:example:order">c</y1><y1 xmlns="urn:example:order">d</y1><y2 xmlns="urn:example:order"><k>d</k><a>bar</a></y2><y2 xmlns="urn:example:order"><k>a</k><a>bar</a></y2><y2 xmlns="urn:example:order"><k>c</k><a>bar</a></y2><y2 xmlns="urn:example:order"><k>b</k><a>bar</a></y2><y3 xmlns="urn:example:order"><k>a</k><a>bar</a></y3><y3 xmlns="urn:example:order"><k>b</k><a>bar</a></y3><y3 xmlns="urn:example:order"><k>c</k><a>bar</a></y3><y3 xmlns="urn:example:order"><k>d</k><a>bar</a></y3></data></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><running/></source></get-config></rpc>]]>]]>' '^<rpc-reply><data><c xmlns="urn:example:order"><d>hej</d></c><l xmlns="urn:example:order">hopp</l><y0 xmlns="urn:example:order">d</y0><y0 xmlns="urn:example:order">b</y0><y0 xmlns="urn:example:order">c</y0><y0 xmlns="urn:example:order">a</y0><y1 xmlns="urn:example:order">a</y1><y1 xmlns="urn:example:order">b</y1><y1 xmlns="urn:example:order">c</y1><y1 xmlns="urn:example:order">d</y1><y2 xmlns="urn:example:order"><k>d</k><a>bar</a></y2><y2 xmlns="urn:example:order"><k>a</k><a>bar</a></y2><y2 xmlns="urn:example:order"><k>c</k><a>bar</a></y2><y2 xmlns="urn:example:order"><k>b</k><a>bar</a></y2><y3 xmlns="urn:example:order"><k>a</k><a>bar</a></y3><y3 xmlns="urn:example:order"><k>b</k><a>bar</a></y3><y3 xmlns="urn:example:order"><k>c</k><a>bar</a></y3><y3 xmlns="urn:example:order"><k>d</k><a>bar</a></y3></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "get each ordered-by user leaf-list"
|
new "get each ordered-by user leaf-list"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y2[k='a']\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><y2 xmlns="urn:example:order"><k>a</k><a>bar</a></y2></data></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/exo:y2[exo:k='a']\" xmlns:exo=\"urn:example:order\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><y2 xmlns="urn:example:order"><k>a</k><a>bar</a></y2></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "get each ordered-by user leaf-list"
|
new "get each ordered-by user leaf-list"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y3[k='a']\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><y3 xmlns="urn:example:order"><k>a</k><a>bar</a></y3></data></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/exo:y3[exo:k='a']\" xmlns:exo=\"urn:example:order\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><y3 xmlns="urn:example:order"><k>a</k><a>bar</a></y3></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "get each ordered-by user leaf-list"
|
new "get each ordered-by user leaf-list"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y2[k='b']\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><y2 xmlns="urn:example:order"><k>b</k><a>bar</a></y2></data></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/exo:y2[exo:k='b']\" xmlns:exo=\"urn:example:order\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><y2 xmlns="urn:example:order"><k>b</k><a>bar</a></y2></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "get each ordered-by user leaf-list"
|
new "get each ordered-by user leaf-list"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y3[k='b']\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><y3 xmlns="urn:example:order"><k>b</k><a>bar</a></y3></data></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/exo:y3[exo:k='b']\" xmlns:exo=\"urn:example:order\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><y3 xmlns="urn:example:order"><k>b</k><a>bar</a></y3></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "delete candidate"
|
new "delete candidate"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><default-operation>none</default-operation><config operation="delete"/></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><default-operation>none</default-operation><config operation="delete"/></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
@ -209,7 +209,7 @@ new "netconf commit"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "verify leaf-list user order in running (as entered: c,b,a,0)"
|
new "verify leaf-list user order in running (as entered: c,b,a,0)"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><running/></source><filter type="xpath" select="/y0"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><y0 xmlns="urn:example:order">c</y0><y0 xmlns="urn:example:order">b</y0><y0 xmlns="urn:example:order">a</y0><y0 xmlns="urn:example:order">0</y0></data></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><running/></source><filter type="xpath" select="/exo:y0" xmlns:exo="urn:example:order"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><y0 xmlns="urn:example:order">c</y0><y0 xmlns="urn:example:order">b</y0><y0 xmlns="urn:example:order">a</y0><y0 xmlns="urn:example:order">0</y0></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
# LISTS
|
# LISTS
|
||||||
|
|
||||||
|
|
@ -220,7 +220,7 @@ new "add one entry to list user order"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><y2 xmlns="urn:example:order"><k>a</k><a>fie</a></y2></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><y2 xmlns="urn:example:order"><k>a</k><a>fie</a></y2></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "verify list user order (as entered)"
|
new "verify list user order (as entered)"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/y2"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><y2 xmlns="urn:example:order"><k>c</k><a>bar</a></y2><y2 xmlns="urn:example:order"><k>b</k><a>foo</a></y2><y2 xmlns="urn:example:order"><k>a</k><a>fie</a></y2></data></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/exo:y2" xmlns:exo="urn:example:order"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><y2 xmlns="urn:example:order"><k>c</k><a>bar</a></y2><y2 xmlns="urn:example:order"><k>b</k><a>foo</a></y2><y2 xmlns="urn:example:order"><k>a</k><a>fie</a></y2></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "Overwrite existing ordered-by user y2->c"
|
new "Overwrite existing ordered-by user y2->c"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><y2 xmlns="urn:example:order">
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><y2 xmlns="urn:example:order">
|
||||||
|
|
@ -238,7 +238,7 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></
|
||||||
</y2></config></edit-config></rpc>]]>]]>'
|
</y2></config></edit-config></rpc>]]>]]>'
|
||||||
|
|
||||||
new "Tests for no duplicates."
|
new "Tests for no duplicates."
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/y2"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><y2 xmlns="urn:example:order"><k>c</k><a>newc</a></y2><y2 xmlns="urn:example:order"><k>b</k><a>newb</a></y2><y2 xmlns="urn:example:order"><k>a</k><a>newa</a></y2></data></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/exo:y2" xmlns:exo="urn:example:order"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><y2 xmlns="urn:example:order"><k>c</k><a>newc</a></y2><y2 xmlns="urn:example:order"><k>b</k><a>newb</a></y2><y2 xmlns="urn:example:order"><k>a</k><a>newa</a></y2></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
#-- order by type rather than strings.
|
#-- order by type rather than strings.
|
||||||
# there are three leaf-lists:strings, ints, and decimal64, and two lists:
|
# there are three leaf-lists:strings, ints, and decimal64, and two lists:
|
||||||
|
|
@ -252,7 +252,7 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></
|
||||||
</types></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
</types></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "check string order (1,10,2)"
|
new "check string order (1,10,2)"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/types/strings"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><types xmlns="urn:example:order"><strings>1</strings><strings>10</strings><strings>2</strings></types></data></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/exo:types/exo:strings" xmlns:exo="urn:example:order"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><types xmlns="urn:example:order"><strings>1</strings><strings>10</strings><strings>2</strings></types></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "put leaf-list int (10,2,1)"
|
new "put leaf-list int (10,2,1)"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><types xmlns="urn:example:order">
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><types xmlns="urn:example:order">
|
||||||
|
|
@ -260,7 +260,7 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></
|
||||||
</types></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
</types></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "check leaf-list int order (1,2,10)"
|
new "check leaf-list int order (1,2,10)"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/types/ints"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><types xmlns="urn:example:order"><ints>1</ints><ints>2</ints><ints>10</ints></types></data></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/exo:types/exo:ints" xmlns:exo="urn:example:order"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><types xmlns="urn:example:order"><ints>1</ints><ints>2</ints><ints>10</ints></types></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "put list int (10,2,1)"
|
new "put list int (10,2,1)"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><types xmlns="urn:example:order">
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><types xmlns="urn:example:order">
|
||||||
|
|
@ -268,7 +268,7 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></
|
||||||
</types></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
</types></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "check list int order (1,2,10)"
|
new "check list int order (1,2,10)"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/types/listints"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><types xmlns="urn:example:order"><listints><a>1</a></listints><listints><a>2</a></listints><listints><a>10</a></listints></types></data></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/exo:types/exo:listints" xmlns:exo="urn:example:order"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><types xmlns="urn:example:order"><listints><a>1</a></listints><listints><a>2</a></listints><listints><a>10</a></listints></types></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "put leaf-list decimal64 (10,2,1)"
|
new "put leaf-list decimal64 (10,2,1)"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><types xmlns="urn:example:order">
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><types xmlns="urn:example:order">
|
||||||
|
|
@ -276,7 +276,7 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></
|
||||||
</types></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
</types></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "check leaf-list decimal64 order (1,2,10)"
|
new "check leaf-list decimal64 order (1,2,10)"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/types/decs"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><types xmlns="urn:example:order"><decs>1.0</decs><decs>2.0</decs><decs>10.0</decs></types></data></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/exo:types/exo:decs" xmlns:exo="urn:example:order"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><types xmlns="urn:example:order"><decs>1.0</decs><decs>2.0</decs><decs>10.0</decs></types></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "put list decimal64 (10,2,1)"
|
new "put list decimal64 (10,2,1)"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><types xmlns="urn:example:order">
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><types xmlns="urn:example:order">
|
||||||
|
|
@ -284,7 +284,7 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></
|
||||||
</types></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
</types></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "check list decimal64 order (1,2,10)"
|
new "check list decimal64 order (1,2,10)"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/types/listdecs"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><types xmlns="urn:example:order"><listdecs><a>1.0</a></listdecs><listdecs><a>2.0</a></listdecs><listdecs><a>10.0</a></listdecs></types></data></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/exo:types/exo:listdecs" xmlns:exo="urn:example:order"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><types xmlns="urn:example:order"><listdecs><a>1.0</a></listdecs><listdecs><a>2.0</a></listdecs><listdecs><a>10.0</a></listdecs></types></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
if [ $BE -eq 0 ]; then
|
if [ $BE -eq 0 ]; then
|
||||||
exit # BE
|
exit # BE
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||||
: ${format:=xml}
|
: ${format:=xml}
|
||||||
|
|
||||||
# Number of list/leaf-list entries in file
|
# Number of list/leaf-list entries in file
|
||||||
: ${perfnr:=5000}
|
: ${perfnr:=1000}
|
||||||
|
|
||||||
# Number of requests made get/put
|
# Number of requests made get/put
|
||||||
: ${perfreq:=100}
|
: ${perfreq:=100}
|
||||||
|
|
@ -27,7 +27,7 @@ cat <<EOF > $fyang
|
||||||
module scaling{
|
module scaling{
|
||||||
yang-version 1.1;
|
yang-version 1.1;
|
||||||
namespace "urn:example:clixon";
|
namespace "urn:example:clixon";
|
||||||
prefix ip;
|
prefix ex;
|
||||||
container x {
|
container x {
|
||||||
list y {
|
list y {
|
||||||
key "a";
|
key "a";
|
||||||
|
|
@ -120,7 +120,7 @@ expecteof "/usr/bin/time -f %e $clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>
|
||||||
new "netconf get $perfreq small config"
|
new "netconf get $perfreq small config"
|
||||||
{ time -p for (( i=0; i<$perfreq; i++ )); do
|
{ time -p for (( i=0; i<$perfreq; i++ )); do
|
||||||
rnd=$(( ( RANDOM % $perfnr ) ))
|
rnd=$(( ( RANDOM % $perfnr ) ))
|
||||||
echo "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/x/y[a=$rnd][b=$rnd]\" /></get-config></rpc>]]>]]>"
|
echo "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/ex:x/ex:y[ex:a=$rnd][ex:b=$rnd]\" xmlns:ex=\"urn:example:clixon\"/></get-config></rpc>]]>]]>"
|
||||||
done | $clixon_netconf -qf $cfg > /dev/null; } 2>&1 | awk '/real/ {print $2}'
|
done | $clixon_netconf -qf $cfg > /dev/null; } 2>&1 | awk '/real/ {print $2}'
|
||||||
|
|
||||||
# NETCONF add
|
# NETCONF add
|
||||||
|
|
|
||||||
|
|
@ -83,23 +83,22 @@ new "netconf commit large config"
|
||||||
expecteof "/usr/bin/time -f %e $clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "/usr/bin/time -f %e $clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
# START actual tests
|
# START actual tests
|
||||||
|
|
||||||
# Having a large db, get single entries many times
|
# Having a large db, get single entries many times
|
||||||
# NETCONF get
|
# NETCONF get
|
||||||
new "netconf get test single req"
|
new "netconf get test single req"
|
||||||
sel="/ietf-interfaces:interfaces/interface[name='e1']"
|
sel="/if:interfaces/if:interface[if:name='e1']"
|
||||||
msg="<rpc><get><filter type=\"xpath\" select=\"$sel\" /></get></rpc>]]>]]>"
|
msg="<rpc><get><filter type=\"xpath\" select=\"$sel\" xmlns:if=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\"/></get></rpc>]]>]]>"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "$msg" '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>e1</name><type>ex:eth</type><enabled>true</enabled><oper-status>up</oper-status></interface></interfaces></data></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 "$msg" '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>e1</name><type>ex:eth</type><enabled>true</enabled><oper-status>up</oper-status></interface></interfaces></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "netconf get $perfreq single reqs"
|
new "netconf get $perfreq single reqs"
|
||||||
{ time -p for (( i=0; i<$perfreq; i++ )); do
|
{ time -p for (( i=0; i<$perfreq; i++ )); do
|
||||||
rnd=$(( ( RANDOM % $perfnr ) ))
|
rnd=$(( ( RANDOM % $perfnr ) ))
|
||||||
sel="/ietf-interfaces:interfaces/interface[name='e$rnd']"
|
sel="/if:interfaces/if:interface[if:name='e$rnd']"
|
||||||
echo "<rpc><get><filter type=\"xpath\" select=\"$sel\" /></get></rpc>]]>]]>"
|
echo "<rpc><get><filter type=\"xpath\" select=\"$sel\" xmlns:if=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\"/></get></rpc>]]>]]>"
|
||||||
done | $clixon_netconf -qf $cfg > /dev/null; } 2>&1 | awk '/real/ {print $2}'
|
done | $clixon_netconf -qf $cfg > /dev/null; } 2>&1 | awk '/real/ {print $2}'
|
||||||
|
|
||||||
# RESTCONF get
|
# RESTCONF get
|
||||||
new "restconf get test single req"
|
new "restconf get test single req XXX"
|
||||||
expecteq "$(curl -s -X GET http://localhost/restconf/data/ietf-interfaces:interfaces/interface=e1)" 0 '{"ietf-interfaces:interface": [{"name": "e1","type": "ex:eth","enabled": true,"oper-status": "up"}]}
|
expecteq "$(curl -s -X GET http://localhost/restconf/data/ietf-interfaces:interfaces/interface=e1)" 0 '{"ietf-interfaces:interface": [{"name": "e1","type": "ex:eth","enabled": true,"oper-status": "up"}]}
|
||||||
'
|
'
|
||||||
|
|
||||||
|
|
@ -129,7 +128,7 @@ done } 2>&1 | awk '/real/ {print $2}'
|
||||||
|
|
||||||
# Get config in one large get
|
# Get config in one large get
|
||||||
new "netconf get large config"
|
new "netconf get large config"
|
||||||
/usr/bin/time -f %e echo "<rpc><get> <filter type=\"xpath\" select=\"/ietf-interfaces:interfaces\" /></get></rpc>]]>]]>" | $clixon_netconf -qf $cfg > /tmp/netconf
|
/usr/bin/time -f %e echo "<rpc><get> <filter type=\"xpath\" select=\"/if:interfaces\" xmlns:if=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\"/></get></rpc>]]>]]>" | $clixon_netconf -qf $cfg > /tmp/netconf
|
||||||
|
|
||||||
new "restconf get large config"
|
new "restconf get large config"
|
||||||
/usr/bin/time -f %e curl -sG http://localhost/restconf/data/ietf-interfaces:interfaces | wc
|
/usr/bin/time -f %e curl -sG http://localhost/restconf/data/ietf-interfaces:interfaces | wc
|
||||||
|
|
|
||||||
|
|
@ -129,10 +129,10 @@ wait_restconf
|
||||||
new "1. Netconf RFC5277 stream testing"
|
new "1. Netconf RFC5277 stream testing"
|
||||||
# 1.1 Stream discovery
|
# 1.1 Stream discovery
|
||||||
new "netconf event stream discovery RFC5277 Sec 3.2.5"
|
new "netconf event stream discovery RFC5277 Sec 3.2.5"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get><filter type="xpath" select="netconf/streams" xmlns="urn:ietf:params:xml:ns:netmod:notification"/></get></rpc>]]>]]>' '<rpc-reply><data><netconf xmlns="urn:ietf:params:xml:ns:netmod:notification"><streams><stream><name>EXAMPLE</name><description>Example event stream</description><replay-support>true</replay-support></stream></streams></netconf></data></rpc-reply>]]>]]>'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get><filter type="xpath" select="n:netconf/n:streams" xmlns:n="urn:ietf:params:xml:ns:netmod:notification"/></get></rpc>]]>]]>' '<rpc-reply><data><netconf xmlns="urn:ietf:params:xml:ns:netmod:notification"><streams><stream><name>EXAMPLE</name><description>Example event stream</description><replay-support>true</replay-support></stream></streams></netconf></data></rpc-reply>]]>]]>'
|
||||||
|
|
||||||
new "netconf event stream discovery RFC8040 Sec 6.2"
|
new "netconf event stream discovery RFC8040 Sec 6.2"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get><filter type="xpath" select="restconf-state/streams"/></get></rpc>]]>]]>' '<rpc-reply><data><restconf-state xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf-monitoring"><streams><stream><name>EXAMPLE</name><description>Example event stream</description><replay-support>true</replay-support><access><encoding>xml</encoding><location>https://localhost/streams/EXAMPLE</location></access></stream></streams></restconf-state></data></rpc-reply>]]>]]>'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get><filter type="xpath" select="r:restconf-state/r:streams" xmlns:r="urn:ietf:params:xml:ns:yang:ietf-restconf-monitoring"/></get></rpc>]]>]]>' '<rpc-reply><data><restconf-state xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf-monitoring"><streams><stream><name>EXAMPLE</name><description>Example event stream</description><replay-support>true</replay-support><access><encoding>xml</encoding><location>https://localhost/streams/EXAMPLE</location></access></stream></streams></restconf-state></data></rpc-reply>]]>]]>'
|
||||||
|
|
||||||
#
|
#
|
||||||
# 1.2 Netconf stream subscription
|
# 1.2 Netconf stream subscription
|
||||||
|
|
|
||||||
|
|
@ -197,7 +197,7 @@ EOF
|
||||||
|
|
||||||
# Type tests.
|
# Type tests.
|
||||||
# Parameters:
|
# Parameters:
|
||||||
# 1: dbcache true/false
|
# 1: dbcache: cache, nocache, cache-zerocopy
|
||||||
testrun(){
|
testrun(){
|
||||||
dbcache=$1
|
dbcache=$1
|
||||||
new "test params: -f $cfg # dbcache: $dbcache"
|
new "test params: -f $cfg # dbcache: $dbcache"
|
||||||
|
|
@ -216,7 +216,7 @@ testrun(){
|
||||||
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
|
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
|
||||||
<CLICON_CLI_GENMODEL_COMPLETION>1</CLICON_CLI_GENMODEL_COMPLETION>
|
<CLICON_CLI_GENMODEL_COMPLETION>1</CLICON_CLI_GENMODEL_COMPLETION>
|
||||||
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
|
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
|
||||||
<CLICON_XMLDB_CACHE>$dbcache</CLICON_XMLDB_CACHE>
|
<CLICON_DATASTORE_CACHE>$dbcache</CLICON_DATASTORE_CACHE>
|
||||||
<CLICON_XMLDB_FORMAT>$format</CLICON_XMLDB_FORMAT>
|
<CLICON_XMLDB_FORMAT>$format</CLICON_XMLDB_FORMAT>
|
||||||
</clixon-config>
|
</clixon-config>
|
||||||
EOF
|
EOF
|
||||||
|
|
@ -614,9 +614,12 @@ EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
# Run without db cache
|
# Run without db cache
|
||||||
testrun false
|
testrun nocache
|
||||||
|
|
||||||
# Run with db cache
|
# Run with db cache
|
||||||
testrun true
|
testrun cache
|
||||||
|
|
||||||
|
# Run with
|
||||||
|
testrun cache-zerocopy
|
||||||
|
|
||||||
rm -rf $dir
|
rm -rf $dir
|
||||||
|
|
|
||||||
|
|
@ -191,7 +191,7 @@ EOF
|
||||||
|
|
||||||
# Changelog of example-a:
|
# Changelog of example-a:
|
||||||
cat <<EOF > $changelog
|
cat <<EOF > $changelog
|
||||||
<changelogs xmlns="http://clicon.org/xml-changelog">
|
<changelogs xmlns="http://clicon.org/xml-changelog" xmlns:a="urn:example:a" xmlns:b="urn:example:b" >
|
||||||
<changelog>
|
<changelog>
|
||||||
<namespace>urn:example:b</namespace>
|
<namespace>urn:example:b</namespace>
|
||||||
<revfrom>2017-12-01</revfrom>
|
<revfrom>2017-12-01</revfrom>
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,7 @@ new "xpath ../type='rt:static'"
|
||||||
expecteof "$clixon_util_xpath -f $xml2 -i /aaa/bbb/here" 0 "../type='rt:static'" "^bool:true$"
|
expecteof "$clixon_util_xpath -f $xml2 -i /aaa/bbb/here" 0 "../type='rt:static'" "^bool:true$"
|
||||||
|
|
||||||
new "xpath rib-name != ../../name"
|
new "xpath rib-name != ../../name"
|
||||||
expecteof "$clixon_util_xpath -f $xml2 -i /aaa/bbb" 0 "rib-name != ../../name" "^bool:true$"
|
expecteof "$clixon_util_xpath -f $xml2 -i /aaa/bbb" 0 "rib-name != ../name" "^bool:true$"
|
||||||
|
|
||||||
new "xpath routing/ribs/rib[name=current()/rib-name]/address-family=../../address-family"
|
new "xpath routing/ribs/rib[name=current()/rib-name]/address-family=../../address-family"
|
||||||
expecteof "$clixon_util_xpath -f $xml2 -i /aaa/bbb" 0 "routing/ribs/rib[name=current()/rib-name]/address-family=../../address-family" "^bool:true$"
|
expecteof "$clixon_util_xpath -f $xml2 -i /aaa/bbb" 0 "routing/ribs/rib[name=current()/rib-name]/address-family=../../address-family" "^bool:true$"
|
||||||
|
|
|
||||||
|
|
@ -193,16 +193,16 @@ new "netconf commit 2nd"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf get config xpath"
|
new "netconf get config xpath"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/x/y[a=1][b=2][c=5]\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><x xmlns="urn:example:clixon"><y><a>1</a><b>2</b><c>5</c><val>one</val></y></x></data></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/c:x/c:y[c:a=1][c:b=2][c:c=5]\" xmlns:c=\"urn:example:clixon\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><x xmlns="urn:example:clixon"><y><a>1</a><b>2</b><c>5</c><val>one</val></y></x></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "netconf edit leaf-list"
|
new "netconf edit leaf-list"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><f><e>hej</e><e>hopp</e></f></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><f><e>hej</e><e>hopp</e></f></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf get leaf-list"
|
new "netconf get leaf-list"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/x/f/e"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><x xmlns="urn:example:clixon"><f><e>hej</e><e>hopp</e></f></x></data></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/c:x/c:f/c:e" xmlns:c="urn:example:clixon"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><x xmlns="urn:example:clixon"><f><e>hej</e><e>hopp</e></f></x></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "netconf get leaf-list path"
|
new "netconf get leaf-list path"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/x/f[e='hej']\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><x xmlns=\"urn:example:clixon\"><f><e>hej</e><e>hopp</e></f></x></data></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/c:x/c:f[c:e='hej']\" xmlns:c=\"urn:example:clixon\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><x xmlns=\"urn:example:clixon\"><f><e>hej</e><e>hopp</e></f></x></data></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf get (should be some)"
|
new "netconf get (should be some)"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get><filter type=\"xpath\" select=\"/\"/></get></rpc>]]>]]>" '^<rpc-reply><data><x xmlns="urn:example:clixon"><y><a>1</a><b>2</b><c>5</c><val>one</val></y><d/></x>'
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get><filter type=\"xpath\" select=\"/\"/></get></rpc>]]>]]>" '^<rpc-reply><data><x xmlns="urn:example:clixon"><y><a>1</a><b>2</b><c>5</c><val>one</val></y><d/></x>'
|
||||||
|
|
@ -211,7 +211,7 @@ new "cli set leaf-list"
|
||||||
expectfn "$clixon_cli -1f $cfg set x f e foo" 0 ""
|
expectfn "$clixon_cli -1f $cfg set x f e foo" 0 ""
|
||||||
|
|
||||||
new "cli show leaf-list"
|
new "cli show leaf-list"
|
||||||
expectfn "$clixon_cli -1f $cfg show xpath /x/f/e" 0 "<e>foo</e>"
|
expectfn "$clixon_cli -1f $cfg show xpath /x/f/e urn:example:clixon" 0 "<e>foo</e>"
|
||||||
|
|
||||||
new "netconf set state data (not allowed)"
|
new "netconf set state data (not allowed)"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><state xmlns="urn:example:clixon"><op>42</op></state></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>protocol</error-type><error-tag>invalid-value</error-tag><error-severity>error</error-severity><error-message>State data not allowed</error-message></rpc-error></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><state xmlns="urn:example:clixon"><op>42</op></state></config></edit-config></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>protocol</error-type><error-tag>invalid-value</error-tag><error-severity>error</error-severity><error-message>State data not allowed</error-message></rpc-error></rpc-reply>]]>]]>$'
|
||||||
|
|
@ -220,10 +220,10 @@ new "netconf set presence and not present"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><nopresence/><presence/></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:clixon"><nopresence/><presence/></x></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf get presence only"
|
new "netconf get presence only"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/x/presence"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><x xmlns="urn:example:clixon"><presence/></x></data></rpc-reply>]]>]]>$'
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/c:x/c:presence" xmlns:c="urn:example:clixon"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><x xmlns="urn:example:clixon"><presence/></x></data></rpc-reply>]]>]]>$'
|
||||||
|
|
||||||
new "netconf get presence only"
|
new "netconf get presence only"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/x/nopresence"/></get-config></rpc>]]>]]>' "^<rpc-reply><data/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/c:x/c:nopresence" xmlns:c="urn:example:clixon"/></get-config></rpc>]]>]]>' "^<rpc-reply><data/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
new "netconf discard-changes"
|
new "netconf discard-changes"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ main(int argc, char **argv)
|
||||||
cxobj *xi = NULL;
|
cxobj *xi = NULL;
|
||||||
int sort = 0;
|
int sort = 0;
|
||||||
clicon_handle h;
|
clicon_handle h;
|
||||||
|
|
||||||
clicon_log_init("clixon_insert", LOG_DEBUG, CLICON_LOG_STDERR);
|
clicon_log_init("clixon_insert", LOG_DEBUG, CLICON_LOG_STDERR);
|
||||||
if ((h = clicon_handle_init()) == NULL)
|
if ((h = clicon_handle_init()) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -154,7 +154,7 @@ main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
if (xml_apply(x0, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
if (xml_apply(x0, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xb = xpath_first(x0, "%s", xpath)) == NULL){
|
if ((xb = xpath_first(x0, NULL, "%s", xpath)) == NULL){
|
||||||
clicon_err(OE_XML, 0, "xpath: %s not found in x0", xpath);
|
clicon_err(OE_XML, 0, "xpath: %s not found in x0", xpath);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -169,7 +169,7 @@ main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
if (xml_apply(xi, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
if (xml_apply(xi, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((xi = xpath_first(xi, "%s", xpath)) == NULL){
|
if ((xi = xpath_first(xi, NULL, "%s", xpath)) == NULL){
|
||||||
clicon_err(OE_XML, 0, "xpath: %s not found in xi", xpath);
|
clicon_err(OE_XML, 0, "xpath: %s not found in xi", xpath);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -191,9 +191,10 @@ main(int argc, char **argv)
|
||||||
fprintf(stderr, "Error: parsing: %s\n", clicon_err_reason);
|
fprintf(stderr, "Error: parsing: %s\n", clicon_err_reason);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If xpath0 given, position current x */
|
/* If xpath0 given, position current x */
|
||||||
if (xpath0){
|
if (xpath0){
|
||||||
if ((x = xpath_first(x0, "%s", xpath0)) == NULL){
|
if ((x = xpath_first(x0, NULL, "%s", xpath0)) == NULL){
|
||||||
fprintf(stderr, "Error: xpath0 returned NULL\n");
|
fprintf(stderr, "Error: xpath0 returned NULL\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -201,8 +202,8 @@ main(int argc, char **argv)
|
||||||
else
|
else
|
||||||
x = x0;
|
x = x0;
|
||||||
|
|
||||||
/* Parse XML */
|
/* Parse XML (use nsc == NULL to indicate dont use) */
|
||||||
if (xpath_vec_ctx(x, xpath, &xc) < 0)
|
if (xpath_vec_ctx(x, NULL, xpath, &xc) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
/* Print results */
|
/* Print results */
|
||||||
cb = cbuf_new();
|
cb = cbuf_new();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue