Mount-point support for restconf

This commit is contained in:
Olof hagsand 2023-11-15 12:12:42 +01:00
parent 597cbe882b
commit 2e6d9167f2
9 changed files with 164 additions and 22 deletions

View file

@ -13,6 +13,7 @@
* [Systemd](#systemd)
* [Docker](#docker)
* [Plugins](#plugins)
* [Mount-points](#mount-points)
## Background
@ -446,3 +447,27 @@ static clixon_plugin_api api = {
.ca_interrupt=NULL, /* cligen_interrupt_cb_t */
};
```
## Mount-points
You can set-up the example for a simple RFC 8528 Yang schema mount. A single top-level yang can be defined to be mounted.:
1. Enable CLICON_YANG_SCHEMA_MOUNT
2. Define the mount-point using the ietf-yang-schema-mount mount-point extension
3. Start the backend, cli and restconf with `-- -m <name> -M <urn>`, where `name` and `urn` is the name and namespace of the mounted YANG, respectively.
A simple example on how to define a mount-point
```
import ietf-yang-schema-mount {
prefix yangmnt;
}
container root{
presence "Otherwise root is not visible";
yangmnt:mount-point "mylabel"{
description "Root for other yang models";
}
}
```
CLI completion of the mounted part is not implemented in the example, see the
clixon-controller `controller_cligen_treeref_wrap()` for an example.

View file

@ -58,7 +58,7 @@
/*! Yang schema mount
*
* Start backend with -- -m <yang> -M <namespace>
* Start cli with -- -m <yang> -M <namespace>
* Mount this yang on mountpoint
*/
static char *_mount_yang = NULL;
@ -313,6 +313,8 @@ clixon_plugin_init(clicon_handle h)
clicon_err(OE_PLUGIN, EINVAL, "Both -m and -M must be given for mounts");
goto done;
}
/* XXX Not implemented: CLI completion for mountpoints, see clixon-controller
*/
return &api;
done:
return NULL;

View file

@ -51,12 +51,20 @@
/* Command line options to be passed to getopt(3)
*/
#define RESTCONF_EXAMPLE_OPTS ""
#define RESTCONF_EXAMPLE_OPTS "m:M:"
static const char Base64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const char Pad64 = '=';
/*! Yang schema mount
*
* Start restconf with -- -m <yang> -M <namespace>
* Mount this yang on mountpoint
*/
static char *_mount_yang = NULL;
static char *_mount_namespace = NULL;
/* skips all whitespace anywhere.
converts characters, four at a time, starting at (or after)
src from base - 64 numbers into three 8 bit bytes in the target area.
@ -350,6 +358,62 @@ example_restconf_start(clicon_handle h)
return 0;
}
/*! Example YANG schema mount
*
* Given an XML mount-point xt, return XML yang-lib modules-set
* @param[in] h Clixon handle
* @param[in] xt XML mount-point in XML tree
* @param[out] config If '0' all data nodes in the mounted schema are read-only
* @param[out] validate Do or dont do full RFC 7950 validation
* @param[out] yanglib XML yang-lib module-set tree
* @retval 0 OK
* @retval -1 Error
* XXX hardcoded to clixon-example@2022-11-01.yang regardless of xt
* @see RFC 8528
*/
int
restconf_yang_mount(clicon_handle h,
cxobj *xt,
int *config,
validate_level *vl,
cxobj **yanglib)
{
int retval = -1;
cbuf *cb = NULL;
if (config)
*config = 1;
if (vl)
*vl = VL_FULL;
if (yanglib && _mount_yang){
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
cprintf(cb, "<yang-library xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">");
cprintf(cb, "<module-set>");
cprintf(cb, "<name>mylabel</name>"); // XXX label in test_yang_schema_mount
cprintf(cb, "<module>");
/* In yang name+namespace is mandatory, but not revision */
cprintf(cb, "<name>%s</name>", _mount_yang); // mandatory
cprintf(cb, "<namespace>%s</namespace>", _mount_namespace); // mandatory
// cprintf(cb, "<revision>2022-11-01</revision>");
cprintf(cb, "</module>");
cprintf(cb, "</module-set>");
cprintf(cb, "</yang-library>");
if (clixon_xml_parse_string(cbuf_get(cb), YB_NONE, NULL, yanglib, NULL) < 0)
goto done;
if (xml_rootchild(*yanglib, 0, yanglib) < 0)
goto done;
}
retval = 0;
done:
if (cb)
cbuf_free(cb);
return retval;
}
clixon_plugin_api * clixon_plugin_init(clicon_handle h);
static clixon_plugin_api api = {
@ -357,7 +421,8 @@ static clixon_plugin_api api = {
clixon_plugin_init, /* init */
example_restconf_start,/* start */
NULL, /* exit */
.ca_auth=example_restconf_credentials /* auth */
.ca_auth=example_restconf_credentials, /* auth */
.ca_yang_mount=restconf_yang_mount, /* RFC 8528 schema mount */
};
/*! Restconf plugin initialization
@ -382,11 +447,23 @@ clixon_plugin_init(clicon_handle h)
optind = 1;
while ((c = getopt(argc, argv, RESTCONF_EXAMPLE_OPTS)) != -1)
switch (c) {
case 'm':
_mount_yang = optarg;
break;
case 'M':
_mount_namespace = optarg;
break;
default:
break;
}
if ((_mount_yang && !_mount_namespace) || (!_mount_yang && _mount_namespace)){
clicon_err(OE_PLUGIN, EINVAL, "Both -m and -M must be given for mounts");
goto done;
}
/* Register local netconf rpc client (note not backend rpc client) */
if (rpc_callback_register(h, restconf_client_rpc, NULL, "urn:example:clixon", "client-rpc") < 0)
return NULL;
return &api;
done:
return NULL;
}