Added yang domains for mount-point isolation
New option: `CLICON_YANG_DOMAIN_DIR` New `clixon-config@2024-08-01.yang` revision
This commit is contained in:
parent
f5372fb124
commit
cc194ac7c5
21 changed files with 696 additions and 198 deletions
|
|
@ -16,6 +16,8 @@ Expected: October 2024
|
|||
|
||||
### Features
|
||||
|
||||
* Added yang domains for mount-point isolation
|
||||
* New option: `CLICON_YANG_DOMAIN_DIR`
|
||||
* Restconf: Support for list of media in Accept header
|
||||
* Refactoring of schema mount-points
|
||||
* Add new top-level `Y_MOUNTS` and add top-level yangs and mountpoints in yspecs
|
||||
|
|
@ -28,6 +30,8 @@ Expected: October 2024
|
|||
* New: [CLI simple alias](https://github.com/clicon/cligen/issues/112)
|
||||
* See: https://clixon-docs.readthedocs.io/en/latest/cli.html#cli-aliases
|
||||
* List pagination: Added where, sort-by and direction parameter for configured data
|
||||
* New `clixon-config@2024-08-01.yang` revision
|
||||
- Added: CLICON_YANG_DOMAIN_DIR
|
||||
* New `clixon-lib@2024-08-01.yang` revision
|
||||
- Added: list-pagination-partial-state extension
|
||||
|
||||
|
|
@ -47,6 +51,9 @@ Users may have to change how they access the system
|
|||
|
||||
Developers may need to change their code
|
||||
|
||||
* Added `domain` argument to yang parse functions. Upgrade as follows:
|
||||
* `yang_file_find_match(h, m, r, f)` -> `yang_file_find_match(h, m, r, NULL, f)`
|
||||
* `yang_parse_module(h, m, r, y, o)` -> `yang_parse_module(h, m, r, y, NULL, o)`
|
||||
* Replaced `clixon_get_logflags()` with `clixon_logflags_get()`
|
||||
* New `yn_iter()` yang iterator replaces `yn_each()`
|
||||
* Use an integer iterator instead of yang object
|
||||
|
|
|
|||
|
|
@ -466,6 +466,7 @@ You can set-up the example for a simple RFC 8528 Yang schema mount. A single top
|
|||
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.
|
||||
4. Note that the module-set name is hard-coded to "mylabel". If you support isolated domains this must be changed.
|
||||
|
||||
A simple example on how to define a mount-point
|
||||
```
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ static char *_action_instanceid = NULL;
|
|||
*
|
||||
* Start backend with -- -m <yang> -M <namespace>
|
||||
* Mount this yang on mountpoint
|
||||
* Note module-set hard-coded to "mylabel"
|
||||
*/
|
||||
static char *_mount_yang = NULL;
|
||||
static char *_mount_namespace = NULL;
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
* argc/argv after -- in clixon_cli:
|
||||
* -m <yang> Mount this yang on mountpoint
|
||||
* -M <namespace> Namespace of mountpoint, note both -m and -M must exist
|
||||
* Note module-set hard-coded to "mylabel"
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
|
@ -221,7 +222,7 @@ example_cli_yang_mount(clixon_handle h,
|
|||
}
|
||||
cprintf(cb, "<yang-library xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">");
|
||||
cprintf(cb, "<module-set>");
|
||||
cprintf(cb, "<name>mount</name>");
|
||||
cprintf(cb, "<name>mylabel</name>");
|
||||
cprintf(cb, "<module>");
|
||||
/* In yang name+namespace is mandatory, but not revision */
|
||||
cprintf(cb, "<name>%s</name>", _mount_yang); // mandatory
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ static const char Pad64 = '=';
|
|||
*
|
||||
* Start restconf with -- -m <yang> -M <namespace>
|
||||
* Mount this yang on mountpoint
|
||||
* Note module-set hard-coded to "mylabel"
|
||||
*/
|
||||
static char *_mount_yang = NULL;
|
||||
static char *_mount_namespace = NULL;
|
||||
|
|
|
|||
|
|
@ -33,10 +33,10 @@
|
|||
|
||||
***** END LICENSE BLOCK *****
|
||||
|
||||
* This file contains access functions for two types of clixon vars:
|
||||
* - options, ie string based variables from Clixon configuration files.
|
||||
* This file contains access functions for options, one type of clixon variables
|
||||
* ie string based variables from Clixon configuration files.
|
||||
* Accessed with clicon_options(h).
|
||||
* @see clixon_data.[ch] for free-type runtime get/set *
|
||||
* @see clixon_data.[ch] for the other type: free-type runtime get/set *
|
||||
*/
|
||||
|
||||
#ifndef _CLIXON_OPTIONS_H_
|
||||
|
|
@ -143,6 +143,9 @@ static inline char *clicon_yang_main_file(clixon_handle h){
|
|||
static inline char *clicon_yang_main_dir(clixon_handle h){
|
||||
return clicon_option_str(h, "CLICON_YANG_MAIN_DIR");
|
||||
}
|
||||
static inline char *clicon_yang_domain_dir(clixon_handle h){
|
||||
return clicon_option_str(h, "CLICON_YANG_DOMAIN_DIR");
|
||||
}
|
||||
static inline char *clicon_yang_module_main(clixon_handle h){
|
||||
return clicon_option_str(h, "CLICON_YANG_MODULE_MAIN");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -285,6 +285,7 @@ int yang_stats(yang_stmt *y, enum rfc_6020 keyw, uint64_t *nrp, size_t *s
|
|||
|
||||
/* Other functions */
|
||||
yang_stmt *yspec_new(clixon_handle h, char *name);
|
||||
yang_stmt *yspec_new_shared(clixon_handle h, char *name, yang_stmt *yspec0);
|
||||
yang_stmt *ys_new(enum rfc_6020 keyw);
|
||||
yang_stmt *ys_prune(yang_stmt *yp, int i);
|
||||
int ys_prune_self(yang_stmt *ys);
|
||||
|
|
@ -320,6 +321,7 @@ int yang_print_cbuf(cbuf *cb, yang_stmt *yn, int marginal, int pretty);
|
|||
int yang_deviation(yang_stmt *ys, void *arg);
|
||||
int yang_spec_print(FILE *f, yang_stmt *yspec);
|
||||
int yang_spec_dump(yang_stmt *yspec, int debuglevel);
|
||||
int yang_mounts_print(FILE *f, yang_stmt *ymounts);
|
||||
int if_feature(yang_stmt *yspec, char *module, char *feature);
|
||||
int ys_populate(yang_stmt *ys, void *arg);
|
||||
int ys_populate2(yang_stmt *ys, void *arg);
|
||||
|
|
|
|||
|
|
@ -79,6 +79,6 @@ yang_stmt *yang_find_module_by_name_revision(yang_stmt *yspec, const char *name,
|
|||
yang_stmt *yang_find_module_by_name(yang_stmt *yspec, char *name);
|
||||
int yang_metadata_annotation_check(cxobj *x, yang_stmt *ymod, int *ismeta);
|
||||
int yang_metadata_init(clixon_handle h);
|
||||
int yang_lib2yspec(clixon_handle h, cxobj *yanglib, char *mntpnt, yang_stmt *yspec);
|
||||
int yang_lib2yspec(clixon_handle h, cxobj *yanglib, char *mntpnt, char *domain, yang_stmt *yspec);
|
||||
|
||||
#endif /* _CLIXON_YANG_MODULE_H_ */
|
||||
|
|
|
|||
|
|
@ -53,9 +53,9 @@
|
|||
*/
|
||||
int ys_grouping_resolve(yang_stmt *yuses, char *prefix, char *name, yang_stmt **ygrouping0);
|
||||
yang_stmt *yang_parse_file(FILE *fp, const char *name, yang_stmt *ysp);
|
||||
int yang_file_find_match(clixon_handle h, const char *module, const char *revision, cbuf *fbuf);
|
||||
int yang_file_find_match(clixon_handle h, const char *module, const char *revision, const char *domain, cbuf *fbuf);
|
||||
yang_stmt *yang_parse_filename(clixon_handle h, const char *filename, yang_stmt *ysp);
|
||||
yang_stmt *yang_parse_module(clixon_handle h, const char *module, const char *revision, yang_stmt *yspec, char *origname);
|
||||
yang_stmt *yang_parse_module(clixon_handle h, const char *module, const char *revision, yang_stmt *yspec, char *domain, char *origname);
|
||||
int yang_parse_post(clixon_handle h, yang_stmt *yspec, int modmin);
|
||||
int yang_parse_optimize_uses(clixon_handle h, yang_stmt *yspec);
|
||||
int yang_spec_parse_module(clixon_handle h, const char *module,
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@
|
|||
* @param[out] val Data value as string
|
||||
* @retval 0 OK
|
||||
* @retval -1 Not found (or error)
|
||||
* @see clicon_option_str
|
||||
* @see clicon_option_str For file options
|
||||
*/
|
||||
int
|
||||
clicon_data_get(clixon_handle h,
|
||||
|
|
|
|||
|
|
@ -354,7 +354,6 @@ clixon_err_args(clixon_handle h,
|
|||
* printf("%s", cbuf_get(cb));
|
||||
* cbuf_free(cb);
|
||||
* @endcode
|
||||
* @see clixon_error_netconf
|
||||
*/
|
||||
int
|
||||
netconf_err2cb(clixon_handle h,
|
||||
|
|
|
|||
|
|
@ -823,14 +823,44 @@ yspec_new(clixon_handle h,
|
|||
goto done;
|
||||
if (yn_insert(ymounts, yspec) < 0)
|
||||
goto done;
|
||||
/* Special trick for shared yspecs */
|
||||
if (yang_cvec_add(yspec, CGV_STRING, name) < 0)
|
||||
goto done;
|
||||
return yspec;
|
||||
done:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*! Create or add a shared yspec
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] name Typically an xpath
|
||||
* @param[in] yspec0 Input NULL if no previous shared exist, otherwise a shared yspec but new name
|
||||
* @retval yspec1 New or (previously shared)
|
||||
* @retval NULL Error
|
||||
*/
|
||||
yang_stmt *
|
||||
yspec_new_shared(clixon_handle h,
|
||||
char *name,
|
||||
yang_stmt *yspec0)
|
||||
{
|
||||
yang_stmt *yspec1 = NULL;
|
||||
|
||||
if (yspec0 != NULL){ /* shared */
|
||||
assert(clicon_option_bool(h, "CLICON_YANG_SCHEMA_MOUNT_SHARE") != 0);
|
||||
yspec1 = yspec0;
|
||||
}
|
||||
else {
|
||||
if ((yspec1 = yspec_new(h, name)) == NULL)
|
||||
goto done;
|
||||
yang_flag_set(yspec1, YANG_FLAG_SPEC_MOUNT);
|
||||
clixon_debug(CLIXON_DBG_YANG, "new yang-spec: %p", yspec1);
|
||||
}
|
||||
if (yang_cvec_add(yspec1, CGV_STRING, name) < 0){
|
||||
yspec1 = NULL;
|
||||
goto done;
|
||||
}
|
||||
done:
|
||||
return yspec1;
|
||||
}
|
||||
|
||||
/*! Create new yang node/statement given size
|
||||
*
|
||||
* Size parameter for variable size, eg extended YANG struct
|
||||
|
|
@ -2199,7 +2229,7 @@ yang_print(FILE *f,
|
|||
/*! Print yang top-level modules only
|
||||
*
|
||||
* @param[in] f File to print to.
|
||||
* @param[in] yn Yang node to print
|
||||
* @param[in] yspec Yang spec to print
|
||||
* @see yang_print_cbuf
|
||||
*/
|
||||
int
|
||||
|
|
@ -2211,7 +2241,7 @@ yang_spec_print(FILE *f,
|
|||
int inext;
|
||||
|
||||
if (yspec == NULL || yang_keyword_get(yspec) != Y_SPEC){
|
||||
clixon_err(OE_YANG, EINVAL, "yspec is not of type YSPEC");
|
||||
clixon_err(OE_YANG, EINVAL, "yspec is not of type Y_SPEC");
|
||||
return -1;
|
||||
}
|
||||
inext = 0;
|
||||
|
|
@ -2227,6 +2257,39 @@ yang_spec_print(FILE *f,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*! Print yang top-level specs
|
||||
*
|
||||
* @param[in] f File to print to.
|
||||
* @param[in] ymounts Yang mounts to print
|
||||
*/
|
||||
int
|
||||
yang_mounts_print(FILE *f,
|
||||
yang_stmt *ymounts)
|
||||
{
|
||||
yang_stmt *yspec;
|
||||
int inext;
|
||||
cg_var *cv;
|
||||
cvec *cvv;
|
||||
|
||||
if (ymounts == NULL || yang_keyword_get(ymounts) != Y_MOUNTS){
|
||||
clixon_err(OE_YANG, EINVAL, "yspec is not of type Y_MOUNTS");
|
||||
return -1;
|
||||
}
|
||||
inext = 0;
|
||||
while ((yspec = yn_iter(ymounts, &inext)) != NULL) {
|
||||
fprintf(f, " %s\n", yang_argument_get(yspec));
|
||||
if ((cv = yang_cv_get(yspec)) != NULL){
|
||||
cv_print(f, yang_cv_get(yspec));
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
if ((cvv = yang_cvec_get(yspec)) != NULL){
|
||||
cvec_print(f, cvv);
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Log/debug info about top-level (sub)modules no recursion
|
||||
* @param[in] yspec Yang spec
|
||||
* @param[in] dbglevel Debug level
|
||||
|
|
|
|||
|
|
@ -108,14 +108,11 @@ struct yang_stmt {
|
|||
Y_UNIQUE: vector of descendant schema node ids
|
||||
Y_UNKNOWN: app-dep: yang-mount-points
|
||||
*/
|
||||
|
||||
yang_stmt *ys_orig; /* Pointer to original (for uses/augment copies) */
|
||||
union { /* Depends on ys_keyword */
|
||||
rpc_callback_t *ysu_action_cb; /* Y_ACTION: Action callback list*/
|
||||
char *ysu_filename; /* Y_MODULE/Y_SUBMODULE: For debug/errors: filename */
|
||||
yang_type_cache *ysu_typecache; /* Y_TYPE: cache all typedef data except unions */
|
||||
int ysu_ref; /* Y_SPEC: Reference count for free: 0 means
|
||||
* no sharing, 1: two references */
|
||||
} u;
|
||||
};
|
||||
|
||||
|
|
@ -123,6 +120,5 @@ struct yang_stmt {
|
|||
#define ys_action_cb u.ysu_action_cb
|
||||
#define ys_filename u.ysu_filename
|
||||
#define ys_typecache u.ysu_typecache
|
||||
#define ys_ref u.ysu_ref
|
||||
|
||||
#endif /* _CLIXON_YANG_INTERNAL_H_ */
|
||||
|
|
|
|||
|
|
@ -853,6 +853,7 @@ yang_metadata_init(clixon_handle h)
|
|||
* @param[in] h Clixon handle
|
||||
* @param[in] xyanglib XML tree on the form <yang-lib>...
|
||||
* @param[in] mntpnt Name of mount-point for logs
|
||||
* @param[in] domain YANG domain (NULL is default)
|
||||
* @param[in] yspec Will be populated with YANGs, is consumed
|
||||
* @retval 1 OK
|
||||
* @retval 0 Parse error
|
||||
|
|
@ -864,6 +865,7 @@ int
|
|||
yang_lib2yspec(clixon_handle h,
|
||||
cxobj *xyanglib,
|
||||
char *mntpnt,
|
||||
char *domain,
|
||||
yang_stmt *yspec)
|
||||
{
|
||||
int retval = -1;
|
||||
|
|
@ -902,7 +904,7 @@ yang_lib2yspec(clixon_handle h,
|
|||
continue;
|
||||
}
|
||||
}
|
||||
if (yang_parse_module(h, name, revision, yspec, NULL) == NULL)
|
||||
if (yang_parse_module(h, name, revision, yspec, domain, NULL) == NULL)
|
||||
goto fail;
|
||||
/* Sanity check: if given namespace differs from namespace in file */
|
||||
if (ns != NULL &&
|
||||
|
|
@ -920,7 +922,7 @@ yang_lib2yspec(clixon_handle h,
|
|||
strcmp(yang_argument_get(yrev), "2019-01-04") == 0){
|
||||
modmin++;
|
||||
}
|
||||
else if (yang_parse_module(h, "ietf-yang-library", "2019-01-04", yspec, NULL) < 0)
|
||||
else if (yang_parse_module(h, "ietf-yang-library", "2019-01-04", yspec, domain, NULL) < 0)
|
||||
goto fail;
|
||||
#endif
|
||||
if ((modmin = yang_len_get(yspec) - (1+veclen - modmin)) < 0)
|
||||
|
|
|
|||
|
|
@ -1002,21 +1002,31 @@ filename2revision(const char *filename,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! No specific revision give. Match a yang file given module
|
||||
/*! Find matching YANG file given module name. No specific revision given
|
||||
*
|
||||
* Look first in CLICON_YANG_MAIN_DIR for top-level, or CLICON_YANG_DOMAIN_DIR for specific domains.
|
||||
* Then look in recursive CLICON_YANG_DIRs
|
||||
* @param[in] h CLICON handle
|
||||
* @param[in] module Name of main YANG module.
|
||||
* @param[in] revision Revision or NULL
|
||||
* @param[in] domain YANG isolation device-domain or NULL for yang main
|
||||
* @param[out] fbuf Buffer containing filename or NULL (if retval=1)
|
||||
* @retval 1 Match found, Most recent entry returned in fbuf
|
||||
* @retval 1 Match found, Entry returned in fbuf if given
|
||||
* @retval 0 No matching entry found
|
||||
* @retval -1 Error
|
||||
* @note for bootstrapping, dir may have to be set.
|
||||
* Returned entry in fbuf according to the following algorithm:
|
||||
* 1) Exact or most recent revision match in CLICON_YANG_MAIN_DIR or CLICON_YANG_DOMAIN_DIR
|
||||
* 2) Exact or most recent revision match in first CLICON_YANG_DIR recursively
|
||||
* 3) Exact or most recent revision match in second CLICON_YANG_DIR
|
||||
* 4) ...
|
||||
* @note This means that the most recent revision entry globally may not be returned,
|
||||
* only most recent in first first match
|
||||
*/
|
||||
int
|
||||
yang_file_find_match(clixon_handle h,
|
||||
const char *module,
|
||||
const char *revision,
|
||||
const char *domain,
|
||||
cbuf *fbuf)
|
||||
{
|
||||
int retval = -1;
|
||||
|
|
@ -1027,6 +1037,9 @@ yang_file_find_match(clixon_handle h,
|
|||
cvec *cvv = NULL;
|
||||
cg_var *cv = NULL;
|
||||
cg_var *bestcv = NULL;
|
||||
cbuf *cb = NULL;
|
||||
struct dirent *dp = NULL;
|
||||
int ndp;
|
||||
|
||||
/* get clicon config file in xml form */
|
||||
if ((x = clicon_conf_xml(h)) == NULL)
|
||||
|
|
@ -1044,14 +1057,19 @@ yang_file_find_match(clixon_handle h,
|
|||
else
|
||||
cprintf(regex, "^%s(@[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9])?(.yang)$",
|
||||
module);
|
||||
xc = NULL;
|
||||
|
||||
while ((xc = xml_child_each(x, xc, CX_ELMNT)) != NULL) {
|
||||
if (strcmp(xml_name(xc), "CLICON_YANG_MAIN_DIR") == 0){
|
||||
struct dirent *dp = NULL;
|
||||
int ndp;
|
||||
|
||||
dir = xml_body(xc);
|
||||
/* First look in Main YANG dir, either MAIN or DOMAIN */
|
||||
if (domain != NULL &&
|
||||
(dir = clicon_yang_domain_dir(h)) != NULL){
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clixon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
cprintf(cb, "%s/%s", dir, domain);
|
||||
dir = cbuf_get(cb);
|
||||
}
|
||||
else
|
||||
dir = clicon_yang_main_dir(h);
|
||||
if (dir != NULL) {
|
||||
/* get all matching files in this directory */
|
||||
if ((ndp = clicon_file_dirent(dir,
|
||||
&dp,
|
||||
|
|
@ -1063,15 +1081,13 @@ yang_file_find_match(clixon_handle h,
|
|||
if (ndp != 0){
|
||||
if (fbuf)
|
||||
cprintf(fbuf, "%s/%s", dir, dp[ndp-1].d_name);
|
||||
if (dp)
|
||||
free(dp);
|
||||
retval = 1;
|
||||
goto done;
|
||||
goto found;
|
||||
}
|
||||
if (dp)
|
||||
free(dp);
|
||||
}
|
||||
else if (strcmp(xml_name(xc), "CLICON_YANG_DIR") == 0 &&
|
||||
/* Second look in recursive YANG lib dirs */
|
||||
xc = NULL;
|
||||
while ((xc = xml_child_each(x, xc, CX_ELMNT)) != NULL) {
|
||||
if (strcmp(xml_name(xc), "CLICON_YANG_DIR") == 0 &&
|
||||
(dir = xml_body(xc)) != NULL){
|
||||
/* get all matching files in this directory recursively */
|
||||
if ((cvv = cvec_new(0)) == NULL){
|
||||
|
|
@ -1094,8 +1110,7 @@ yang_file_find_match(clixon_handle h,
|
|||
if (bestcv){
|
||||
if (fbuf)
|
||||
cprintf(fbuf, "%s", cv_string_get(bestcv)); /* file path */
|
||||
retval = 1; /* found */
|
||||
goto done;
|
||||
goto found;
|
||||
}
|
||||
if (cvv){
|
||||
cvec_free(cvv);
|
||||
|
|
@ -1106,11 +1121,18 @@ yang_file_find_match(clixon_handle h,
|
|||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
if (dp)
|
||||
free(dp);
|
||||
if (cb)
|
||||
cbuf_free(cb);
|
||||
if (cvv)
|
||||
cvec_free(cvv);
|
||||
if (regex)
|
||||
cbuf_free(regex);
|
||||
return retval;
|
||||
found:
|
||||
retval = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Open a file, read into a string and invoke yang parsing
|
||||
|
|
@ -1161,6 +1183,7 @@ yang_parse_filename(clixon_handle h,
|
|||
* @param[in] module Module name
|
||||
* @param[in] revision Revision (or NULL)
|
||||
* @param[in] yspec Yang statement
|
||||
* @param[in] domain YANG isolation device-domain or NULL for yang-main
|
||||
* @param[in] origname Name of yang module triggering this parsing, for logging
|
||||
* @retval ymod YANG (sub)module
|
||||
* @retval NULL Failed
|
||||
|
|
@ -1173,6 +1196,7 @@ yang_parse_module(clixon_handle h,
|
|||
const char *module,
|
||||
const char *revision,
|
||||
yang_stmt *yspec,
|
||||
char *domain,
|
||||
char *origname)
|
||||
{
|
||||
cbuf *fbuf = NULL;
|
||||
|
|
@ -1189,7 +1213,7 @@ yang_parse_module(clixon_handle h,
|
|||
goto done;
|
||||
}
|
||||
/* Match a yang file with or without revision in yang-dir list */
|
||||
if ((nr = yang_file_find_match(h, module, revision, fbuf)) < 0)
|
||||
if ((nr = yang_file_find_match(h, module, revision, domain, fbuf)) < 0)
|
||||
goto done;
|
||||
if (nr == 0){
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
|
|
@ -1289,7 +1313,7 @@ yang_parse_recurse(clixon_handle h,
|
|||
keyw==Y_IMPORT?Y_MODULE:Y_SUBMODULE,
|
||||
submodule) == NULL){
|
||||
/* recursive call */
|
||||
if ((subymod = yang_parse_module(h, submodule, subrevision, ysp, yang_argument_get(ymod))) == NULL)
|
||||
if ((subymod = yang_parse_module(h, submodule, subrevision, ysp, NULL, yang_argument_get(ymod))) == NULL)
|
||||
goto done;
|
||||
/* Sanity check: if submodule, its belongs-to statement shall point to the module */
|
||||
if (keyw == Y_INCLUDE){
|
||||
|
|
@ -1683,7 +1707,7 @@ yang_spec_parse_module(clixon_handle h,
|
|||
if (yang_find_module_by_name_revision(yspec, name, revision) != NULL)
|
||||
goto ok;
|
||||
/* Find a yang module and parse it and all its submodules */
|
||||
if (yang_parse_module(h, name, revision, yspec, NULL) == NULL)
|
||||
if (yang_parse_module(h, name, revision, yspec, NULL, NULL) == NULL)
|
||||
goto done;
|
||||
if (yang_parse_post(h, yspec, modmin) < 0)
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
* container root{ (ymnt)
|
||||
* yangmnt:mount-point "mylabel"; (yext)
|
||||
* }
|
||||
* (note the argument "mylabel" defines an optional isolated YANG domain
|
||||
*
|
||||
* <config> # Your XML config
|
||||
* ...
|
||||
|
|
@ -870,10 +871,12 @@ yang_schema_yanglib_parse_mount(clixon_handle h,
|
|||
{
|
||||
int retval = -1;
|
||||
cxobj *xyanglib = NULL;
|
||||
yang_stmt *yspec = NULL;
|
||||
int ret;
|
||||
int shared = 0;
|
||||
cxobj *xb;
|
||||
yang_stmt *yspec0 = NULL;
|
||||
yang_stmt *yspec1 = NULL;
|
||||
char *xpath = NULL;
|
||||
char *domain = NULL;
|
||||
int ret;
|
||||
|
||||
/* 1. Get modstate (xyanglib) of node: xyanglib, by querying backend state (via callback)
|
||||
* XXX this xyanglib is not proper RFC8525, submodules appear as modules WHY?
|
||||
|
|
@ -882,45 +885,42 @@ yang_schema_yanglib_parse_mount(clixon_handle h,
|
|||
goto done;
|
||||
if (xyanglib == NULL)
|
||||
goto anydata;
|
||||
/* Optimization: find equal yspec from other mount-point */
|
||||
if (clicon_option_bool(h, "CLICON_YANG_SCHEMA_MOUNT_SHARE")) {
|
||||
if (yang_schema_find_share(h, xt, xyanglib, &yspec) < 0)
|
||||
if ((xb = xpath_first(xyanglib, NULL, "module-set/name")) != NULL)
|
||||
domain = xml_body(xb);
|
||||
if (domain == NULL){
|
||||
clixon_err(OE_YANG, 0, "domain not found");
|
||||
goto done;
|
||||
if (yspec)
|
||||
shared++;
|
||||
}
|
||||
/* XXX done later too */
|
||||
/* Get xpath */
|
||||
if ((ret = yang_mount_xmnt2ymnt_xpath(h, xt, NULL, &xpath)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
clixon_err(OE_YANG, 0, "Mapping xmnt to ymnt and xpath");
|
||||
goto done;
|
||||
}
|
||||
if (yspec == NULL){
|
||||
/* Parse it and set mount-point */
|
||||
if ((yspec = yspec_new(h, xpath)) == NULL)
|
||||
/* Optimization: find equal yspec from other mount-point */
|
||||
if (clicon_option_bool(h, "CLICON_YANG_SCHEMA_MOUNT_SHARE")) {
|
||||
if (yang_schema_find_share(h, xt, xyanglib, &yspec0) < 0)
|
||||
goto done;
|
||||
yang_flag_set(yspec, YANG_FLAG_SPEC_MOUNT);
|
||||
clixon_debug(CLIXON_DBG_YANG, "new yang-spec: %p", yspec);
|
||||
if ((ret = yang_lib2yspec(h, xyanglib, xpath, yspec)) < 0)
|
||||
}
|
||||
if ((yspec1 = yspec_new_shared(h, xpath, yspec0)) < 0)
|
||||
goto done;
|
||||
/* Either yspec0 = NULL and yspec1 is new, or yspec0 == yspec1 != NULL (shared) */
|
||||
if (yspec0 == NULL && yspec1 != NULL){
|
||||
if ((ret = yang_lib2yspec(h, xyanglib, xpath, domain, yspec1)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto anydata;
|
||||
}
|
||||
else
|
||||
clixon_debug(CLIXON_DBG_YANG, "shared yang-spec: %p", yspec);
|
||||
if (xml_yang_mount_set(h, xt, yspec) < 0)
|
||||
if (xml_yang_mount_set(h, xt, yspec1) < 0)
|
||||
goto done;
|
||||
if (shared)
|
||||
if (yang_cvec_add(yspec, CGV_STRING, xpath) < 0)
|
||||
goto done;
|
||||
yspec = NULL;
|
||||
yspec1 = NULL;
|
||||
retval = 1;
|
||||
done:
|
||||
if (xpath)
|
||||
free(xpath);
|
||||
if (yspec)
|
||||
ys_free(yspec);
|
||||
if (yspec1)
|
||||
ys_free(yspec1);
|
||||
if (xyanglib)
|
||||
xml_free(xyanglib);
|
||||
return retval;
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ DATASTORE_TOP="config"
|
|||
# clixon yang revisions occuring in tests (see eg yang/clixon/Makefile.in)
|
||||
CLIXON_AUTOCLI_REV="2024-08-01"
|
||||
CLIXON_LIB_REV="2024-08-01"
|
||||
CLIXON_CONFIG_REV="2024-04-01"
|
||||
CLIXON_CONFIG_REV="2024-08-01"
|
||||
CLIXON_RESTCONF_REV="2022-08-01"
|
||||
CLIXON_EXAMPLE_REV="2022-11-01"
|
||||
|
||||
|
|
|
|||
238
test/test_yang_mount_isolate.sh
Executable file
238
test/test_yang_mount_isolate.sh
Executable file
|
|
@ -0,0 +1,238 @@
|
|||
#!/usr/bin/env bash
|
||||
# Test for isolating modules between mount-points.
|
||||
# That is, so that two modules with same name, revision and namespaces can have different content
|
||||
# in two separate mount-points.
|
||||
# Note the mylabel domain is hardcoded in example_backend.c ca_yang_mount callback
|
||||
|
||||
# Magic line must be first in script (see README.md)
|
||||
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||
|
||||
APPNAME=example
|
||||
|
||||
cfg=$dir/conf_mount.xml
|
||||
clispec=$dir/automode.cli
|
||||
test -d $dir/main || mkdir $dir/main
|
||||
fyang=$dir/main/clixon-example.yang
|
||||
test -d $dir/domains/mylabel || mkdir -p $dir/domains/mylabel
|
||||
#fyang0=$dir/domains/mylabel/clixon-mount0.yang
|
||||
fyang0=$dir/domains/mylabel/clixon-example.yang
|
||||
fyang1=$dir/domains/mylabel/clixon-mount1.yang
|
||||
fyang2=$dir/domains/mylabel/clixon-mount2.yang
|
||||
|
||||
CFD=$dir/conf.d
|
||||
test -d $CFD || mkdir -p $CFD
|
||||
|
||||
AUTOCLI=$(autocli_config clixon-\* kw-nokey false)
|
||||
if [ $? -ne 0 ]; then
|
||||
err1 "Error when generating certs"
|
||||
fi
|
||||
|
||||
cat <<EOF > $cfg
|
||||
<clixon-config xmlns="http://clicon.org/config">
|
||||
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
|
||||
<CLICON_CONFIGDIR>$CFD</CLICON_CONFIGDIR>
|
||||
<CLICON_FEATURE>clixon-restconf:allow-auth-none</CLICON_FEATURE> <!-- Use auth-type=none -->
|
||||
<CLICON_YANG_DIR>${YANG_INSTALLDIR}</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_DIR>${dir}</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
|
||||
<CLICON_YANG_DOMAIN_DIR>$dir/domains</CLICON_YANG_DOMAIN_DIR>
|
||||
<CLICON_YANG_LIBRARY>true</CLICON_YANG_LIBRARY>
|
||||
<CLICON_CLISPEC_DIR>$dir</CLICON_CLISPEC_DIR>
|
||||
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
|
||||
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
|
||||
<CLICON_SOCK>/usr/local/var/run/$APPNAME.sock</CLICON_SOCK>
|
||||
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
|
||||
<CLICON_BACKEND_PIDFILE>/usr/local/var/run/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
|
||||
<CLICON_XMLDB_DIR>$dir</CLICON_XMLDB_DIR>
|
||||
<CLICON_NETCONF_MONITORING>true</CLICON_NETCONF_MONITORING>
|
||||
<CLICON_VALIDATE_STATE_XML>true</CLICON_VALIDATE_STATE_XML>
|
||||
<CLICON_STREAM_DISCOVERY_RFC5277>true</CLICON_STREAM_DISCOVERY_RFC5277>
|
||||
<CLICON_YANG_SCHEMA_MOUNT>true</CLICON_YANG_SCHEMA_MOUNT>
|
||||
</clixon-config>
|
||||
EOF
|
||||
|
||||
cat <<EOF > $CFD/autocli.xml
|
||||
<clixon-config xmlns="http://clicon.org/config">
|
||||
<autocli>
|
||||
<module-default>false</module-default>
|
||||
<list-keyword-default>kw-nokey</list-keyword-default>
|
||||
<grouping-treeref>true</grouping-treeref>
|
||||
<rule>
|
||||
<name>include clixon</name>
|
||||
<operation>enable</operation>
|
||||
<module-name>clixon-*</module-name>
|
||||
</rule>
|
||||
</autocli>
|
||||
</clixon-config>
|
||||
EOF
|
||||
|
||||
cat <<EOF > $fyang
|
||||
module clixon-example{
|
||||
yang-version 1.1;
|
||||
namespace "urn:example:clixon";
|
||||
prefix ex;
|
||||
import ietf-yang-schema-mount {
|
||||
prefix yangmnt;
|
||||
}
|
||||
container top{
|
||||
list mylist{
|
||||
key name;
|
||||
leaf name{
|
||||
type string;
|
||||
}
|
||||
container root{
|
||||
presence "Otherwise root is not visible";
|
||||
yangmnt:mount-point "mylabel"{
|
||||
description "Root for other yang models";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
cat <<EOF > $fyang0
|
||||
module clixon-example{
|
||||
yang-version 1.1;
|
||||
namespace "urn:example:clixon";
|
||||
prefix m0;
|
||||
import clixon-mount1 {
|
||||
prefix m1;
|
||||
}
|
||||
import clixon-mount2 {
|
||||
prefix m2;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
cat <<EOF > $fyang1
|
||||
module clixon-mount1{
|
||||
yang-version 1.1;
|
||||
namespace "urn:example:mount1";
|
||||
prefix m1;
|
||||
container mount1{
|
||||
list mylist1{
|
||||
key name1;
|
||||
leaf name1{
|
||||
type string;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
cat <<EOF > $fyang2
|
||||
module clixon-mount2{
|
||||
yang-version 1.1;
|
||||
namespace "urn:example:mount2";
|
||||
prefix m2;
|
||||
import clixon-mount1 {
|
||||
prefix m1;
|
||||
}
|
||||
grouping ag2 {
|
||||
leaf option2{
|
||||
type string;
|
||||
}
|
||||
}
|
||||
grouping ag1 {
|
||||
container options {
|
||||
leaf option1{
|
||||
type string;
|
||||
}
|
||||
uses ag2;
|
||||
}
|
||||
}
|
||||
augment /m1:mount1/m1:mylist1 {
|
||||
uses ag1;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
cat <<EOF > $clispec
|
||||
CLICON_MODE="example";
|
||||
CLICON_PROMPT="%U@%H %W> ";
|
||||
CLICON_PLUGIN="example_cli";
|
||||
|
||||
# Autocli syntax tree operations
|
||||
set @datamodel, cli_auto_set();
|
||||
merge @datamodel, cli_auto_merge();
|
||||
create @datamodel, cli_auto_create();
|
||||
delete("Delete a configuration item") @datamodel, cli_auto_del();
|
||||
validate("Validate changes"), cli_validate();
|
||||
commit("Commit the changes"), cli_commit();
|
||||
quit("Quit"), cli_quit();
|
||||
show("Show a particular state of the system"){
|
||||
configuration("Show configuration"), cli_show_auto_mode("candidate", "xml", true, false);{
|
||||
xml("Show configuration as XML"), cli_show_auto_mode("candidate", "xml", false, false);
|
||||
cli("Show configuration as CLI commands"), cli_show_auto_mode("candidate", "cli", false, false, "report-all", "set ");
|
||||
netconf("Show configuration as netconf edit-config operation"), cli_show_auto_mode("candidate", "netconf", false, false);
|
||||
text("Show configuration as text"), cli_show_auto_mode("candidate", "text", false, false);
|
||||
json("Show configuration as JSON"), cli_show_auto_mode("candidate", "json", false, false);
|
||||
}
|
||||
state("Show configuration and state"), cli_show_auto_mode("running", "xml", false, true);
|
||||
}
|
||||
EOF
|
||||
|
||||
new "test params: -f $cfg"
|
||||
|
||||
if [ $BE -ne 0 ]; then
|
||||
new "kill old backend"
|
||||
sudo clixon_backend -zf $cfg
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
new "start backend -s init -f $cfg -- -m clixon-example -M urn:example:clixon"
|
||||
start_backend -s init -f $cfg -- -m clixon-example -M urn:example:clixon
|
||||
fi
|
||||
|
||||
new "wait backend"
|
||||
wait_backend
|
||||
|
||||
new "Add two mountpoints: x and y"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><top xmlns=\"urn:example:clixon\"><mylist><name>x</name><root/></mylist><mylist><name>y</name><root/></mylist></top></config></edit-config></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||
|
||||
new "netconf commit"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><commit/></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||
|
||||
new "Retrieve schema-mounts with <get> Operation"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get><filter type=\"subtree\"><schema-mounts xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount\"></schema-mounts></filter></get></rpc>" "<rpc-reply $DEFAULTNS><data><schema-mounts xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount\"><mount-point><module>clixon-example</module><label>mylabel</label><config>true</config><inline/></mount-point></schema-mounts></data></rpc-reply>"
|
||||
|
||||
new "get yang-lib at mountpoint"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get><filter type=\"subtree\"><top xmlns=\"urn:example:clixon\"><mylist/></top>></filter></get></rpc>" "<rpc-reply $DEFAULTNS><data><top xmlns=\"urn:example:clixon\"><mylist><name>x</name><root><yang-library xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\"><module-set><name>mylabel</name><module><name>clixon-example</name><namespace>urn:example:clixon</namespace></module></module-set></yang-library></root></mylist><mylist><name>y</name><root><yang-library xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\"><module-set><name>mylabel</name><module><name>clixon-example</name><namespace>urn:example:clixon</namespace></module></module-set></yang-library></root></mylist></top></data></rpc-reply>"
|
||||
|
||||
new "check there is statistics from mountpoint"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><stats xmlns=\"http://clicon.org/lib\"></stats></rpc>" '<module-set><name>mountpoint: /top/mylist\[name="x"\]/root</name><nr>'
|
||||
|
||||
new "Add data to mounts"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><top xmlns=\"urn:example:clixon\"><mylist><name>x</name><root><mount1 xmlns=\"urn:example:mount1\"><mylist1><name1>x1</name1></mylist1></mount1></root></mylist></top></config></edit-config></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||
|
||||
new "netconf commit"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><commit/></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||
|
||||
new "Add mounted augment data 2"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><top xmlns=\"urn:example:clixon\"><mylist><name>x</name><root><mount1 xmlns=\"urn:example:mount1\"><mylist1><name1>x1</name1><options xmlns=\"urn:example:mount2\"><option2>bar</option2></options></mylist1></mount1></root></mylist></top></config></edit-config></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||
|
||||
new "netconf commit"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><commit/></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||
|
||||
new "get mounted augment data"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get-config><source><running/></source></get-config></rpc>" "<rpc-reply $DEFAULTNS><data><top xmlns=\"urn:example:clixon\"><mylist><name>x</name><root><mount1 xmlns=\"urn:example:mount1\"><mylist1><name1>x1</name1><options xmlns=\"urn:example:mount2\"><option2>bar</option2></options></mylist1></mount1></root></mylist><mylist><name>y</name><root/></mylist></top></data></rpc-reply>"
|
||||
|
||||
new "cli show config"
|
||||
expectpart "$($clixon_cli -1 -f $cfg show config xml -- -m clixon-example -M urn:example:clixon)" 0 "<top xmlns=\"urn:example:clixon\"><mylist><name>x</name><root><mount1 xmlns=\"urn:example:mount1\"><mylist1><name1>x1</name1><options xmlns=\"urn:example:mount2\"><option2>bar</option2></options></mylist1></mount1></root></mylist><mylist><name>y</name><root/></mylist></top>"
|
||||
|
||||
if [ $BE -ne 0 ]; then
|
||||
new "Kill backend"
|
||||
# Check if premature kill
|
||||
pid=$(pgrep -u root -f clixon_backend)
|
||||
if [ -z "$pid" ]; then
|
||||
err "backend already dead"
|
||||
fi
|
||||
# kill backend
|
||||
stop_backend -f $cfg
|
||||
fi
|
||||
|
||||
sudo rm -rf $dir
|
||||
|
||||
new "endtest"
|
||||
endtest
|
||||
|
|
@ -42,7 +42,7 @@ datarootdir = @datarootdir@
|
|||
YANG_INSTALLDIR = @YANG_INSTALLDIR@
|
||||
|
||||
# Note: mirror these to test/config.sh.in
|
||||
YANGSPECS = clixon-config@2024-04-01.yang # 7.1
|
||||
YANGSPECS = clixon-config@2024-08-01.yang # 7.2
|
||||
YANGSPECS += clixon-lib@2024-08-01.yang # 7.2
|
||||
YANGSPECS += clixon-rfc5277@2008-07-01.yang
|
||||
YANGSPECS += clixon-xml-changelog@2019-03-21.yang
|
||||
|
|
|
|||
|
|
@ -49,6 +49,26 @@ module clixon-config {
|
|||
|
||||
***** END LICENSE BLOCK *****";
|
||||
|
||||
revision 2024-08-01 {
|
||||
description
|
||||
"Added options:
|
||||
CLICON_YANG_DOMAIN_DIR
|
||||
Released in Clixon 7.2";
|
||||
}
|
||||
revision 2024-04-01 {
|
||||
description
|
||||
"Added options:
|
||||
CLICON_NETCONF_DUPLICATE_ALLOW: Disable duplicate check in NETCONF messages.
|
||||
CLICON_LOG_DESTINATION: Default log destination
|
||||
CLICON_LOG_FILE: Which file to log to if file logging
|
||||
CLICON_DEBUG: Debug flags.
|
||||
CLICON_YANG_SCHEMA_MOUNT_SHARE: Share same YANGs of equal moint-points.
|
||||
CLICON_SOCK_PRIO: Enable socket event priority
|
||||
CLICON_XMLDB_MULTI: Split datastore into multiple sub files
|
||||
CLICON_CLI_OUTPUT_FORMAT: Default CLI output format
|
||||
CLICON_AUTOLOCK: Implicit locks
|
||||
Released in Clixon 7.1";
|
||||
}
|
||||
revision 2024-01-01 {
|
||||
description
|
||||
"Changed semantics:
|
||||
|
|
@ -415,6 +435,33 @@ module clixon-config {
|
|||
}
|
||||
}
|
||||
}
|
||||
typedef log_destination_t {
|
||||
description
|
||||
"Log destination flags
|
||||
Can also be given directly as -l <flag> to clixon commands
|
||||
Note there are also constants in the code (logdstmap) that need to be
|
||||
in sync with these values.
|
||||
The duplication is because of bootstrapping, logging is needed before YANG
|
||||
loaded";
|
||||
type bits {
|
||||
bit syslog {
|
||||
position 0;
|
||||
description "Syslog";
|
||||
}
|
||||
bit stderr {
|
||||
position 1;
|
||||
description "Standard I/O Error";
|
||||
}
|
||||
bit stdout {
|
||||
position 2;
|
||||
description "Standard I/O Output";
|
||||
}
|
||||
bit file {
|
||||
position 3;
|
||||
description "Log to file. By default clixon.log int current directory";
|
||||
}
|
||||
}
|
||||
}
|
||||
container clixon-config {
|
||||
container restconf {
|
||||
uses clrc:clixon-restconf;
|
||||
|
|
@ -445,6 +492,7 @@ module clixon-config {
|
|||
Ensure that YANG_INSTALLDIR (default
|
||||
/usr/local/share/clixon) is present in the path";
|
||||
}
|
||||
/* Configuration */
|
||||
leaf CLICON_CONFIGFILE{
|
||||
type string;
|
||||
description
|
||||
|
|
@ -462,7 +510,9 @@ module clixon-config {
|
|||
AFTER the main config file (CLICON_CONFIGFILE) in the following way:
|
||||
- leaf values are overwritten
|
||||
- leaf-list values are appended
|
||||
The files in this directory will be loaded alphabetically.
|
||||
The files in this directory are loaded alphabetically.
|
||||
Only files ending with .xml are read
|
||||
Sub-structures, eg <autocli> are replaced with the latest (alphabetically)
|
||||
If the dir is given but does not exist will result in an error.
|
||||
You can override file setting with -E <dir> command-line option.
|
||||
Note that due to bootstraping this value is only meaningful in the main config file";
|
||||
|
|
@ -476,6 +526,7 @@ module clixon-config {
|
|||
This field is a 'bootstrap' field.
|
||||
";
|
||||
}
|
||||
/* YANG */
|
||||
leaf CLICON_YANG_MAIN_FILE {
|
||||
type string;
|
||||
description
|
||||
|
|
@ -489,6 +540,18 @@ module clixon-config {
|
|||
"If given, load all modules in this directory (all .yang files)
|
||||
See also CLICON_YANG_DIR which specifies a path of dirs";
|
||||
}
|
||||
leaf CLICON_YANG_DOMAIN_DIR {
|
||||
type string;
|
||||
description
|
||||
"Virtual domain directory for RFC 8528 mount-points.
|
||||
If set and domain is given, instead of loading from CLICON_YANG_MAIN_DIR,
|
||||
look for .yang files first in CLICON_YANG_DOMAIN_DIR/domain,
|
||||
where domain is given as yangmnt:mount-point <domain>;
|
||||
Useful in eg mountpoints where another YANG domain may be required,
|
||||
even isolated from the main YANG context, as well as from other moint-points.
|
||||
Note that CLICON_YANG_DIR that may be given as library YANGs are not isolated.
|
||||
If not set, use CLICON_YANG_MAIN_DIR as default.";
|
||||
}
|
||||
leaf CLICON_YANG_MODULE_MAIN {
|
||||
type string;
|
||||
description
|
||||
|
|
@ -526,12 +589,6 @@ module clixon-config {
|
|||
Note this is similar to what happens to YANG nodes that are disabled by a false
|
||||
if-feature statement.";
|
||||
}
|
||||
leaf CLICON_BACKEND_DIR {
|
||||
type string;
|
||||
description
|
||||
"Location of backend .so plugins. Load all .so
|
||||
plugins in this dir as backend plugins";
|
||||
}
|
||||
leaf CLICON_YANG_SCHEMA_MOUNT{
|
||||
type boolean;
|
||||
description
|
||||
|
|
@ -544,12 +601,102 @@ module clixon-config {
|
|||
Further, autocli syntax is added by definining a tree resolve wrapper";
|
||||
default false;
|
||||
}
|
||||
leaf CLICON_YANG_SCHEMA_MOUNT_SHARE {
|
||||
type boolean;
|
||||
description
|
||||
"For optimization purposes, share same YANGs of equal moint-points.
|
||||
The mount-points need to be 'equal' in the sense that it has the same YANG
|
||||
(yangmnt:mount-point is on same node).
|
||||
A comparison is made between yang modules and revision and must match exactly.
|
||||
If so, a new yang-spec is not created, instead the other is used.
|
||||
Only if CLICON_YANG_SCHEMA_MOUNT is enabled";
|
||||
default false;
|
||||
}
|
||||
leaf CLICON_YANG_AUGMENT_ACCEPT_BROKEN {
|
||||
type boolean;
|
||||
default false;
|
||||
description
|
||||
"Debug option. If enabled, accept broken augments on the form:
|
||||
augment <target> { ... }
|
||||
where <target> is an XPath which MUST be an existing node but for many
|
||||
yangmodels do not.
|
||||
There are several cases why this may be the case:
|
||||
- syntax errors,
|
||||
- features that need to be enabled
|
||||
- wrong XPaths, etc
|
||||
This option should be enabled only for passing some testcases it should
|
||||
normally never be enabled in system YANGs that are used in a system.";
|
||||
}
|
||||
leaf CLICON_YANG_LIBRARY {
|
||||
type boolean;
|
||||
default true;
|
||||
description
|
||||
"Enable YANG library support as state data according to RFC8525.
|
||||
If enabled, module info will appear when doing netconf get or
|
||||
restconf GET.
|
||||
The module state data is on the form:
|
||||
<yang-library><module-set>...
|
||||
instead where the module state is on the form:
|
||||
<modules-state>...
|
||||
See also CLICON_XMLDB_MODSTATE where the module state info is used to tag datastores
|
||||
with module information.";
|
||||
}
|
||||
/* Backend */
|
||||
leaf CLICON_BACKEND_DIR {
|
||||
type string;
|
||||
description
|
||||
"Location of backend .so plugins. Load all .so
|
||||
plugins in this dir as backend plugins";
|
||||
}
|
||||
leaf CLICON_BACKEND_REGEXP {
|
||||
type string;
|
||||
description
|
||||
"Regexp of matching backend plugins in CLICON_BACKEND_DIR";
|
||||
default "(.so)$";
|
||||
}
|
||||
leaf CLICON_BACKEND_USER {
|
||||
type string;
|
||||
description
|
||||
"User name for backend (both foreground and daemonized).
|
||||
If you set this value the backend if started as root will lower
|
||||
the privileges after initialization.
|
||||
The ownership of files created by the backend will also be set to this
|
||||
user (eg datastores).
|
||||
It also sets the backend unix socket owner to this user, but its group
|
||||
is set by CLICON_SOCK_GROUP.
|
||||
See also CLICON_BACKEND_PRIVILEGES setting";
|
||||
}
|
||||
leaf CLICON_BACKEND_PRIVILEGES {
|
||||
type priv_mode;
|
||||
default none;
|
||||
description
|
||||
"Backend privileges mode.
|
||||
If CLICON_BACKEND_USER user is set, mode can be set to drop_perm or
|
||||
drop_temp.
|
||||
Drop privs may not be used together with CLICON_XMLDB_MULTI";
|
||||
}
|
||||
leaf CLICON_BACKEND_PIDFILE {
|
||||
type string;
|
||||
mandatory true;
|
||||
description "Process-id file of backend daemon";
|
||||
}
|
||||
leaf CLICON_BACKEND_RESTCONF_PROCESS {
|
||||
type boolean;
|
||||
default false;
|
||||
description
|
||||
"If set, enable process-control of restconf daemon, ie start/stop restconf
|
||||
daemon internally from backend daemon.
|
||||
Also, if set, restconf daemon queries backend for its config
|
||||
if not set, restconf daemon reads its config from main config file
|
||||
It uses clixon-restconf.yang for config and clixon-lib.yang for RPC
|
||||
Process control of restconf daemon is as follows:
|
||||
- on RPC start, if enable is true, start the service, if false, error or ignore it
|
||||
- on RPC stop, stop the service
|
||||
- on backend start make the state as configured
|
||||
- on enable change, make the state as configured
|
||||
Disable if you start the restconf daemon by other means.";
|
||||
}
|
||||
/* Netconf */
|
||||
leaf CLICON_NETCONF_DIR{
|
||||
type string;
|
||||
description "Location of netconf (frontend) .so plugins";
|
||||
|
|
@ -607,6 +754,32 @@ module clixon-config {
|
|||
config";
|
||||
status obsolete;
|
||||
}
|
||||
leaf CLICON_NETCONF_MONITORING {
|
||||
type boolean;
|
||||
default true;
|
||||
description
|
||||
"Enable Netconf monitoring support as state data according to RFC6022.
|
||||
If enabled, netconf monitoring info will appear when doing netconf get or
|
||||
restconf GET.";
|
||||
}
|
||||
leaf CLICON_NETCONF_MONITORING_LOCATION {
|
||||
type string;
|
||||
description
|
||||
"Extra Netconf monitoring location directory where schemas can be retrieved
|
||||
apart from NETCONF.
|
||||
Only if CLICON_NETCONF_MONITORING";
|
||||
}
|
||||
leaf CLICON_NETCONF_DUPLICATE_ALLOW {
|
||||
type boolean;
|
||||
default false;
|
||||
description
|
||||
"Disable duplicate check in NETCONF messages.
|
||||
In Clixon 7.0, a stricter check of duplicate entries in incoming NETCONF messages was made.
|
||||
More specifically: lists and leaf-lists with non-unique entries.
|
||||
Enable to disable this check, and to allow duplicates in incoming NETCONF messages.
|
||||
Note that this is an error by such a client, but there is some legacy code that uses this";
|
||||
}
|
||||
/* HTTP and Restconf */
|
||||
leaf CLICON_RESTCONF_API_ROOT {
|
||||
type string;
|
||||
default "/restconf";
|
||||
|
|
@ -722,6 +895,7 @@ module clixon-config {
|
|||
Both feature clixon-restconf:http-data and restconf/enable-http-data
|
||||
must be enabled for this match to occur.";
|
||||
}
|
||||
/* Clixon CLI */
|
||||
leaf CLICON_CLI_DIR {
|
||||
type string;
|
||||
description
|
||||
|
|
@ -760,8 +934,8 @@ module clixon-config {
|
|||
type int32;
|
||||
default 1;
|
||||
description
|
||||
"Set to 0 if you want CLI to wrap to next line.
|
||||
Set to 1 if you want CLI to scroll sideways when approaching
|
||||
"Set to 0 if you want CLI INPUT to wrap to next line.
|
||||
Set to 1 if you want CLI INPUT to scroll sideways when approaching
|
||||
right margin";
|
||||
}
|
||||
leaf CLICON_CLI_LINES_DEFAULT {
|
||||
|
|
@ -863,6 +1037,13 @@ module clixon-config {
|
|||
While setting this value makes sense for adding new values, it makes less sense for
|
||||
deleting.";
|
||||
}
|
||||
leaf CLICON_CLI_OUTPUT_FORMAT {
|
||||
type cl:datastore_format;
|
||||
default xml;
|
||||
description
|
||||
"Default CLI output format.";
|
||||
}
|
||||
/* Internal socket */
|
||||
leaf CLICON_SOCK_FAMILY {
|
||||
type socket_address_family;
|
||||
default UNIX;
|
||||
|
|
@ -900,46 +1081,17 @@ module clixon-config {
|
|||
"Group membership to access clixon_backend unix socket and gid for
|
||||
deamon";
|
||||
}
|
||||
leaf CLICON_BACKEND_USER {
|
||||
type string;
|
||||
description
|
||||
"User name for backend (both foreground and daemonized).
|
||||
If you set this value the backend if started as root will lower
|
||||
the privileges after initialization.
|
||||
The ownership of files created by the backend will also be set to this
|
||||
user (eg datastores).
|
||||
It also sets the backend unix socket owner to this user, but its group
|
||||
is set by CLICON_SOCK_GROUP.
|
||||
See also CLICON_BACKEND_PRIVILEGES setting";
|
||||
}
|
||||
leaf CLICON_BACKEND_PRIVILEGES {
|
||||
type priv_mode;
|
||||
default none;
|
||||
description
|
||||
"Backend privileges mode.
|
||||
If CLICON_BACKEND_USER user is set, mode can be set to drop_perm or
|
||||
drop_temp.";
|
||||
}
|
||||
leaf CLICON_BACKEND_PIDFILE {
|
||||
type string;
|
||||
mandatory true;
|
||||
description "Process-id file of backend daemon";
|
||||
}
|
||||
leaf CLICON_BACKEND_RESTCONF_PROCESS {
|
||||
leaf CLICON_SOCK_PRIO {
|
||||
type boolean;
|
||||
default false;
|
||||
description
|
||||
"If set, enable process-control of restconf daemon, ie start/stop restconf
|
||||
daemon internally from backend daemon.
|
||||
Also, if set, restconf daemon queries backend for its config
|
||||
if not set, restconf daemon reads its config from main config file
|
||||
It uses clixon-restconf.yang for config and clixon-lib.yang for RPC
|
||||
Process control of restconf daemon is as follows:
|
||||
- on RPC start, if enable is true, start the service, if false, error or ignore it
|
||||
- on RPC stop, stop the service
|
||||
- on backend start make the state as configured
|
||||
- on enable change, make the state as configured
|
||||
Disable if you start the restconf daemon by other means.";
|
||||
"Enable socket event priority.
|
||||
If enabled, a file-descriptor can be registered as high prio.
|
||||
Presently, the backend socket has higher prio than others.
|
||||
(should be made more generic)
|
||||
Note that a side-effect of enabling this option is that fairness of
|
||||
non-prio events is disabled
|
||||
This is useful if the backend opens other sockets, such as the controller";
|
||||
}
|
||||
leaf CLICON_AUTOCOMMIT {
|
||||
type int32;
|
||||
|
|
@ -951,12 +1103,17 @@ module clixon-config {
|
|||
persistent confirming commit.
|
||||
(consider boolean)";
|
||||
}
|
||||
leaf CLICON_XMLDB_DIR {
|
||||
type string;
|
||||
mandatory true;
|
||||
leaf CLICON_AUTOLOCK {
|
||||
type boolean;
|
||||
default false;
|
||||
description
|
||||
"Directory where \"running\", \"candidate\" and \"startup\" are placed.";
|
||||
"Set if all edit-config implicitly locks without the need of an explicit lock-db
|
||||
In short, the lock is obtained by edit-config and copy-config and released by
|
||||
discard and commit.
|
||||
Also, any edits in candidate are discarded if the client closes the connection.
|
||||
This effectively disables shared candidate";
|
||||
}
|
||||
/* Datastore XMLDB */
|
||||
leaf CLICON_DATASTORE_CACHE {
|
||||
type datastore_cache;
|
||||
default cache;
|
||||
|
|
@ -968,6 +1125,16 @@ module clixon-config {
|
|||
Note that from 7.0 this is OBSOLETED, only datastore_cache is supported";
|
||||
status obsolete;
|
||||
}
|
||||
leaf CLICON_XMLDB_DIR {
|
||||
type string;
|
||||
mandatory true;
|
||||
description
|
||||
"Directory where datastores such as \"running\", \"candidate\" and \"startup\"
|
||||
are placed.
|
||||
If CLICON_XMLDB_MULTI is enabled, this is the directory where a datastore
|
||||
subdir is stored, such as \"running.d/\"
|
||||
";
|
||||
}
|
||||
leaf CLICON_XMLDB_FORMAT {
|
||||
type cl:datastore_format;
|
||||
default xml;
|
||||
|
|
@ -986,7 +1153,9 @@ module clixon-config {
|
|||
default false;
|
||||
description
|
||||
"If set, tag datastores with RFC 8525 YANG Module Library
|
||||
info. When loaded at startup, a check is made if the system
|
||||
info.
|
||||
By default, modstate is added last in datastore.
|
||||
When loaded at startup, a check is made if the system
|
||||
yang modules match.";
|
||||
}
|
||||
leaf CLICON_XMLDB_UPGRADE_CHECKOLD {
|
||||
|
|
@ -999,6 +1168,20 @@ module clixon-config {
|
|||
Will fail startup if old yang not found or if old config does not match.
|
||||
If not set, no yang check of old config is made until it is upgraded to new yang.";
|
||||
}
|
||||
leaf CLICON_XMLDB_MULTI {
|
||||
type boolean;
|
||||
default false;
|
||||
description
|
||||
"Split configure datastore into multiple sub files
|
||||
Uses .d/ directory structure with <digest>.xml and 0.xml as root
|
||||
JSON not supported.
|
||||
Splits are marked in YANG using extension xl:xmldb-split, (typical usage is
|
||||
mount-points).
|
||||
Note that algorithm for not updating unchanged files only applies to edits,
|
||||
commit copies all files regardless.
|
||||
May not work together with CLICON_BACKEND_PRIVILEGES=drop and root, since
|
||||
new files need to be created in XMLDB_DIR";
|
||||
}
|
||||
leaf CLICON_XML_CHANGELOG {
|
||||
type boolean;
|
||||
default false;
|
||||
|
|
@ -1056,21 +1239,6 @@ module clixon-config {
|
|||
If true: The symbols defined by this shared object will be made available for symbol res‐
|
||||
olution of subsequently loaded shared objects.";
|
||||
}
|
||||
leaf CLICON_YANG_AUGMENT_ACCEPT_BROKEN {
|
||||
type boolean;
|
||||
default false;
|
||||
description
|
||||
"Debug option. If enabled, accept broken augments on the form:
|
||||
augment <target> { ... }
|
||||
where <target> is an XPath which MUST be an existing node but for many
|
||||
yangmodels do not.
|
||||
There are several cases why this may be the case:
|
||||
- syntax errors,
|
||||
- features that need to be enabled
|
||||
- wrong XPaths, etc
|
||||
This option should be enabled only for passing some testcases it should
|
||||
normally never be enabled in system YANGs that are used in a system.";
|
||||
}
|
||||
leaf CLICON_NAMESPACE_NETCONF_DEFAULT {
|
||||
type boolean;
|
||||
default false;
|
||||
|
|
@ -1080,7 +1248,6 @@ module clixon-config {
|
|||
If defined, top-level rpc calls need not have namespaces (eg using xmlns=<ns>)
|
||||
since the default NETCONF namespace will be assumed. (This is not standard).
|
||||
See rfc6241 3.1: urn:ietf:params:xml:ns:netconf:base:1.0.";
|
||||
|
||||
}
|
||||
leaf CLICON_STARTUP_MODE {
|
||||
type startup_mode;
|
||||
|
|
@ -1094,6 +1261,7 @@ module clixon-config {
|
|||
The current only case where such a user is used is in RESTCONF authentication when
|
||||
auth-type=none and no known user is known.";
|
||||
}
|
||||
/* Network Configuration Access Control Model (NACM) */
|
||||
leaf CLICON_NACM_MODE {
|
||||
type nacm_mode;
|
||||
default disabled;
|
||||
|
|
@ -1136,20 +1304,6 @@ module clixon-config {
|
|||
If this option is set, Clixon disables NACM if a datastore does NOT contain a
|
||||
NACM config on load.";
|
||||
}
|
||||
leaf CLICON_YANG_LIBRARY {
|
||||
type boolean;
|
||||
default true;
|
||||
description
|
||||
"Enable YANG library support as state data according to RFC8525.
|
||||
If enabled, module info will appear when doing netconf get or
|
||||
restconf GET.
|
||||
The module state data is on the form:
|
||||
<yang-library><module-set>...
|
||||
instead where the module state is on the form:
|
||||
<modules-state>...
|
||||
See also CLICON_XMLDB_MODSTATE where the module state info is used to tag datastores
|
||||
with module information.";
|
||||
}
|
||||
leaf CLICON_MODULE_SET_ID {
|
||||
type string;
|
||||
default "0";
|
||||
|
|
@ -1162,21 +1316,7 @@ module clixon-config {
|
|||
If CLICON_MODULE_LIBRARY_RFC7895 is enabled, it sets the modules-state/module-set-id
|
||||
instead";
|
||||
}
|
||||
leaf CLICON_NETCONF_MONITORING {
|
||||
type boolean;
|
||||
default true;
|
||||
description
|
||||
"Enable Netconf monitoring support as state data according to RFC6022.
|
||||
If enabled, netconf monitoring info will appear when doing netconf get or
|
||||
restconf GET.";
|
||||
}
|
||||
leaf CLICON_NETCONF_MONITORING_LOCATION {
|
||||
type string;
|
||||
description
|
||||
"Extra Netconf monitoring location directory where schemas can be retrieved
|
||||
apart from NETCONF.
|
||||
Only if CLICON_NETCONF_MONITORING";
|
||||
}
|
||||
/* Notification streams */
|
||||
leaf CLICON_STREAM_DISCOVERY_RFC5277 {
|
||||
type boolean;
|
||||
default false;
|
||||
|
|
@ -1232,7 +1372,27 @@ module clixon-config {
|
|||
units s;
|
||||
description "Retention for stream replay buffers in seconds, ie how much
|
||||
data to store before dropping. 0 means no retention";
|
||||
|
||||
}
|
||||
/* Log and debug */
|
||||
leaf CLICON_DEBUG{
|
||||
type cl:clixon_debug_t;
|
||||
description
|
||||
"Debug flags as bitfields.
|
||||
Can also be given directly as -D <flag> to clixon commands (which overrides this).";
|
||||
}
|
||||
leaf CLICON_LOG_DESTINATION {
|
||||
type log_destination_t;
|
||||
description
|
||||
"Log destination.
|
||||
If not given, default log destination is syslog for all applications,
|
||||
except clixon_cli where default is stderr.
|
||||
See also command-line option -l <s|e|o|n|f>";
|
||||
}
|
||||
leaf CLICON_LOG_FILE {
|
||||
type string;
|
||||
description
|
||||
"Which file to log to if log destination is file
|
||||
That is CLIXON_LOG_DESTINATION is FILE or command started with -l f";
|
||||
}
|
||||
leaf CLICON_LOG_STRING_LIMIT {
|
||||
type uint32;
|
||||
|
|
@ -1241,8 +1401,8 @@ module clixon-config {
|
|||
"Length limitation of debug and log strings.
|
||||
Especially useful for dynamic debug strings, such as packet dumps.
|
||||
0 means no limit";
|
||||
|
||||
}
|
||||
/* SNMP */
|
||||
leaf-list CLICON_SNMP_MIB {
|
||||
description
|
||||
"Names of MIBs that are used by clixon_snmp.
|
||||
Loading…
Add table
Add a link
Reference in a new issue