* NACM module support (RFC8341 A1+A2)
* Recovery user "_nacm_recovery" added.
* Example use is restconf PUT when NACM edit-config is permitted, then automatic commit and discard are permitted using recovery user.
* Example user changed adm1 to andy to comply with RFC8341 example
* Yang code upgrade (RFC7950)
* RPC method input parameters validated
* see https://github.com/clicon/clixon/issues/4
* Correct XML namespace handling
* XML multiple modules was based on "loose" semantics so that yang modules were found by iterating thorugh namespaces until a match was made. This did not adhere to proper [XML namespace handling](https://www.w3.org/TR/2009/REC-xml-names-20091208), and causes problems with overlapping names and false positives. Below see XML accepted (but wrong), and correct namespace declaration:
```
<rpc><my-own-method></rpc> # Wrong but accepted
<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> # Correct
<my-own-method xmlns="http://example.net/me/my-own/1.0">
</rpc>
```
* To keep old loose semantics set config option CLICON_XML_NS_ITERATE (true by default)
* XML to JSON translator support for mapping xmlns attribute to module name prefix.
* Default namespace is still "urn:ietf:params:xml:ns:netconf:base:1.0"
* See https://github.com/clicon/clixon/issues/49
* Changed all make tags --> make TAGS
* Keyvalue datastore removed (it has been disabled since 3.3.3)
* debug rpc added in example application (should be in clixon-config).
93 lines
3.3 KiB
Markdown
93 lines
3.3 KiB
Markdown
# Clixon datastore
|
|
|
|
The Clixon datastore is a stand-alone XML based datastore. The idea is
|
|
to be able to use different datastores backends with the same
|
|
API. There is currently only a plain text-file datastore.
|
|
|
|
The datastore is primarily designed to be used by Clixon but can be used
|
|
separately.
|
|
|
|
A datastore is a dynamic plugin that is loaded at runtime with a
|
|
well-defined API. This means it is possible to create your own
|
|
datastore and plug it in a Clixon backend at runtime.
|
|
|
|
### The functional API
|
|
```
|
|
int xmldb_plugin_load(clicon_handle h, char *filename);
|
|
int xmldb_plugin_unload(clicon_handle h);
|
|
int xmldb_connect(clicon_handle h);
|
|
int xmldb_disconnect(clicon_handle h);
|
|
int xmldb_getopt(clicon_handle h, char *optname, void **value);
|
|
int xmldb_setopt(clicon_handle h, char *optname, void *value);
|
|
int xmldb_get(clicon_handle h, char *db, char *xpath,
|
|
cxobj **xtop, cxobj ***xvec, size_t *xlen);
|
|
int xmldb_put(clicon_handle h, char *db, enum operation_type op,
|
|
char *api_path, cxobj *xt);
|
|
int xmldb_copy(clicon_handle h, char *from, char *to);
|
|
int xmldb_lock(clicon_handle h, char *db, int pid);
|
|
int xmldb_unlock(clicon_handle h, char *db);
|
|
int xmldb_unlock_all(clicon_handle h, int pid);
|
|
int xmldb_islocked(clicon_handle h, char *db);
|
|
int xmldb_exists(clicon_handle h, char *db);
|
|
int xmldb_delete(clicon_handle h, char *db);
|
|
int xmldb_create(clicon_handle h, char *db);
|
|
```
|
|
|
|
### Using the API
|
|
|
|
To use the API, a client needs the following:
|
|
- A clicon handle.
|
|
- A datastore plugin, such as a text.so. These are normally built and installed at Clixon make.
|
|
- A directory where to store databases
|
|
- A yang specification. This needs to be parsed using the Clixon yang_parse() method.
|
|
|
|
A client calling the API needs to:
|
|
1. Load a plugin and
|
|
2. Connect to a datastore.
|
|
You can connect to several datastores, even concurrently,
|
|
but in practice in Clixon, you connect to a single store.
|
|
|
|
After connecting to a datastore, you can create and modify databases
|
|
within the datastore, and set and get options of the datastore itself.
|
|
|
|
When done, you disconnect from the datastore and unload the plugin.
|
|
|
|
Within a datastore, the following four databases may exist:
|
|
- running
|
|
- candidate
|
|
- startup
|
|
- tmp
|
|
|
|
Initially, a database does not exist but is created by
|
|
xmldb_create(). It is deleted by xmldb_delete(). You may check for
|
|
existence with xmldb_exists(). You need to create a database before
|
|
you can perform any data access on it.
|
|
|
|
You may lock a database for exclusive modification according to
|
|
Netconf semantics. You may also unlock a single dabase, unlock all frm
|
|
a specific session.
|
|
|
|
You can read a database with xmldb_get() and modify a database with
|
|
xmldb_put(), and xmldb_copy().
|
|
|
|
A typical datastore session can be as follows, see the source code of
|
|
[datastore_client.c](datastore_client.c) for a more elaborate example.
|
|
|
|
```
|
|
h = clicon_handle_init();
|
|
xmldb_plugin_load(h, plugin);
|
|
xmldb_connect(h);
|
|
xmldb_setopt(h, "dbdir", dbdir);
|
|
xmldb_setopt(h, "yangspec", yspec);
|
|
/* From here databases in the datastore may be accessed */
|
|
xmldb_create(h, "candidate");
|
|
xmldb_copy(h, "running", "candidate");
|
|
xmldb_lock(h, "candidate", 7878);
|
|
xmldb_put(h, "candidate", OP_CREATE, "/interfaces/interface=eth0", xml);
|
|
xmldb_unlock(h, "candidate");
|
|
xmldb_get(h, "candidate", "/", &xml, &xvec, &xlen);
|
|
xmldb_disconnect(h)
|
|
xmdlb_plugin_unload(h);
|
|
```
|
|
|
|
|