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
|
### Features
|
||||||
|
|
||||||
|
* Added yang domains for mount-point isolation
|
||||||
|
* New option: `CLICON_YANG_DOMAIN_DIR`
|
||||||
* Restconf: Support for list of media in Accept header
|
* Restconf: Support for list of media in Accept header
|
||||||
* Refactoring of schema mount-points
|
* Refactoring of schema mount-points
|
||||||
* Add new top-level `Y_MOUNTS` and add top-level yangs and mountpoints in yspecs
|
* 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)
|
* New: [CLI simple alias](https://github.com/clicon/cligen/issues/112)
|
||||||
* See: https://clixon-docs.readthedocs.io/en/latest/cli.html#cli-aliases
|
* See: https://clixon-docs.readthedocs.io/en/latest/cli.html#cli-aliases
|
||||||
* List pagination: Added where, sort-by and direction parameter for configured data
|
* 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
|
* New `clixon-lib@2024-08-01.yang` revision
|
||||||
- Added: list-pagination-partial-state extension
|
- 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
|
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()`
|
* Replaced `clixon_get_logflags()` with `clixon_logflags_get()`
|
||||||
* New `yn_iter()` yang iterator replaces `yn_each()`
|
* New `yn_iter()` yang iterator replaces `yn_each()`
|
||||||
* Use an integer iterator instead of yang object
|
* 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
|
1. Enable CLICON_YANG_SCHEMA_MOUNT
|
||||||
2. Define the mount-point using the ietf-yang-schema-mount mount-point extension
|
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.
|
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
|
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>
|
* Start backend with -- -m <yang> -M <namespace>
|
||||||
* Mount this yang on mountpoint
|
* Mount this yang on mountpoint
|
||||||
|
* Note module-set hard-coded to "mylabel"
|
||||||
*/
|
*/
|
||||||
static char *_mount_yang = NULL;
|
static char *_mount_yang = NULL;
|
||||||
static char *_mount_namespace = NULL;
|
static char *_mount_namespace = NULL;
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@
|
||||||
* argc/argv after -- in clixon_cli:
|
* argc/argv after -- in clixon_cli:
|
||||||
* -m <yang> Mount this yang on mountpoint
|
* -m <yang> Mount this yang on mountpoint
|
||||||
* -M <namespace> Namespace of mountpoint, note both -m and -M must exist
|
* -M <namespace> Namespace of mountpoint, note both -m and -M must exist
|
||||||
|
* Note module-set hard-coded to "mylabel"
|
||||||
*/
|
*/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.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, "<yang-library xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">");
|
||||||
cprintf(cb, "<module-set>");
|
cprintf(cb, "<module-set>");
|
||||||
cprintf(cb, "<name>mount</name>");
|
cprintf(cb, "<name>mylabel</name>");
|
||||||
cprintf(cb, "<module>");
|
cprintf(cb, "<module>");
|
||||||
/* In yang name+namespace is mandatory, but not revision */
|
/* In yang name+namespace is mandatory, but not revision */
|
||||||
cprintf(cb, "<name>%s</name>", _mount_yang); // mandatory
|
cprintf(cb, "<name>%s</name>", _mount_yang); // mandatory
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@ static const char Pad64 = '=';
|
||||||
*
|
*
|
||||||
* Start restconf with -- -m <yang> -M <namespace>
|
* Start restconf with -- -m <yang> -M <namespace>
|
||||||
* Mount this yang on mountpoint
|
* Mount this yang on mountpoint
|
||||||
|
* Note module-set hard-coded to "mylabel"
|
||||||
*/
|
*/
|
||||||
static char *_mount_yang = NULL;
|
static char *_mount_yang = NULL;
|
||||||
static char *_mount_namespace = NULL;
|
static char *_mount_namespace = NULL;
|
||||||
|
|
|
||||||
|
|
@ -33,10 +33,10 @@
|
||||||
|
|
||||||
***** END LICENSE BLOCK *****
|
***** END LICENSE BLOCK *****
|
||||||
|
|
||||||
* This file contains access functions for two types of clixon vars:
|
* This file contains access functions for options, one type of clixon variables
|
||||||
* - options, ie string based variables from Clixon configuration files.
|
* ie string based variables from Clixon configuration files.
|
||||||
* Accessed with clicon_options(h).
|
* 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_
|
#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){
|
static inline char *clicon_yang_main_dir(clixon_handle h){
|
||||||
return clicon_option_str(h, "CLICON_YANG_MAIN_DIR");
|
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){
|
static inline char *clicon_yang_module_main(clixon_handle h){
|
||||||
return clicon_option_str(h, "CLICON_YANG_MODULE_MAIN");
|
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 */
|
/* Other functions */
|
||||||
yang_stmt *yspec_new(clixon_handle h, char *name);
|
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_new(enum rfc_6020 keyw);
|
||||||
yang_stmt *ys_prune(yang_stmt *yp, int i);
|
yang_stmt *ys_prune(yang_stmt *yp, int i);
|
||||||
int ys_prune_self(yang_stmt *ys);
|
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_deviation(yang_stmt *ys, void *arg);
|
||||||
int yang_spec_print(FILE *f, yang_stmt *yspec);
|
int yang_spec_print(FILE *f, yang_stmt *yspec);
|
||||||
int yang_spec_dump(yang_stmt *yspec, int debuglevel);
|
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 if_feature(yang_stmt *yspec, char *module, char *feature);
|
||||||
int ys_populate(yang_stmt *ys, void *arg);
|
int ys_populate(yang_stmt *ys, void *arg);
|
||||||
int ys_populate2(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);
|
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_annotation_check(cxobj *x, yang_stmt *ymod, int *ismeta);
|
||||||
int yang_metadata_init(clixon_handle h);
|
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_ */
|
#endif /* _CLIXON_YANG_MODULE_H_ */
|
||||||
|
|
|
||||||
|
|
@ -53,9 +53,9 @@
|
||||||
*/
|
*/
|
||||||
int ys_grouping_resolve(yang_stmt *yuses, char *prefix, char *name, yang_stmt **ygrouping0);
|
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);
|
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_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_post(clixon_handle h, yang_stmt *yspec, int modmin);
|
||||||
int yang_parse_optimize_uses(clixon_handle h, yang_stmt *yspec);
|
int yang_parse_optimize_uses(clixon_handle h, yang_stmt *yspec);
|
||||||
int yang_spec_parse_module(clixon_handle h, const char *module,
|
int yang_spec_parse_module(clixon_handle h, const char *module,
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@
|
||||||
* @param[out] val Data value as string
|
* @param[out] val Data value as string
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
* @retval -1 Not found (or error)
|
* @retval -1 Not found (or error)
|
||||||
* @see clicon_option_str
|
* @see clicon_option_str For file options
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clicon_data_get(clixon_handle h,
|
clicon_data_get(clixon_handle h,
|
||||||
|
|
|
||||||
|
|
@ -354,7 +354,6 @@ clixon_err_args(clixon_handle h,
|
||||||
* printf("%s", cbuf_get(cb));
|
* printf("%s", cbuf_get(cb));
|
||||||
* cbuf_free(cb);
|
* cbuf_free(cb);
|
||||||
* @endcode
|
* @endcode
|
||||||
* @see clixon_error_netconf
|
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
netconf_err2cb(clixon_handle h,
|
netconf_err2cb(clixon_handle h,
|
||||||
|
|
|
||||||
|
|
@ -823,14 +823,44 @@ yspec_new(clixon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
if (yn_insert(ymounts, yspec) < 0)
|
if (yn_insert(ymounts, yspec) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Special trick for shared yspecs */
|
|
||||||
if (yang_cvec_add(yspec, CGV_STRING, name) < 0)
|
|
||||||
goto done;
|
|
||||||
return yspec;
|
return yspec;
|
||||||
done:
|
done:
|
||||||
return NULL;
|
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
|
/*! Create new yang node/statement given size
|
||||||
*
|
*
|
||||||
* Size parameter for variable size, eg extended YANG struct
|
* Size parameter for variable size, eg extended YANG struct
|
||||||
|
|
@ -2199,7 +2229,7 @@ yang_print(FILE *f,
|
||||||
/*! Print yang top-level modules only
|
/*! Print yang top-level modules only
|
||||||
*
|
*
|
||||||
* @param[in] f File to print to.
|
* @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
|
* @see yang_print_cbuf
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
|
|
@ -2211,7 +2241,7 @@ yang_spec_print(FILE *f,
|
||||||
int inext;
|
int inext;
|
||||||
|
|
||||||
if (yspec == NULL || yang_keyword_get(yspec) != Y_SPEC){
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
inext = 0;
|
inext = 0;
|
||||||
|
|
@ -2227,6 +2257,39 @@ yang_spec_print(FILE *f,
|
||||||
return 0;
|
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
|
/* Log/debug info about top-level (sub)modules no recursion
|
||||||
* @param[in] yspec Yang spec
|
* @param[in] yspec Yang spec
|
||||||
* @param[in] dbglevel Debug level
|
* @param[in] dbglevel Debug level
|
||||||
|
|
|
||||||
|
|
@ -108,14 +108,11 @@ struct yang_stmt {
|
||||||
Y_UNIQUE: vector of descendant schema node ids
|
Y_UNIQUE: vector of descendant schema node ids
|
||||||
Y_UNKNOWN: app-dep: yang-mount-points
|
Y_UNKNOWN: app-dep: yang-mount-points
|
||||||
*/
|
*/
|
||||||
|
|
||||||
yang_stmt *ys_orig; /* Pointer to original (for uses/augment copies) */
|
yang_stmt *ys_orig; /* Pointer to original (for uses/augment copies) */
|
||||||
union { /* Depends on ys_keyword */
|
union { /* Depends on ys_keyword */
|
||||||
rpc_callback_t *ysu_action_cb; /* Y_ACTION: Action callback list*/
|
rpc_callback_t *ysu_action_cb; /* Y_ACTION: Action callback list*/
|
||||||
char *ysu_filename; /* Y_MODULE/Y_SUBMODULE: For debug/errors: filename */
|
char *ysu_filename; /* Y_MODULE/Y_SUBMODULE: For debug/errors: filename */
|
||||||
yang_type_cache *ysu_typecache; /* Y_TYPE: cache all typedef data except unions */
|
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;
|
} u;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -123,6 +120,5 @@ struct yang_stmt {
|
||||||
#define ys_action_cb u.ysu_action_cb
|
#define ys_action_cb u.ysu_action_cb
|
||||||
#define ys_filename u.ysu_filename
|
#define ys_filename u.ysu_filename
|
||||||
#define ys_typecache u.ysu_typecache
|
#define ys_typecache u.ysu_typecache
|
||||||
#define ys_ref u.ysu_ref
|
|
||||||
|
|
||||||
#endif /* _CLIXON_YANG_INTERNAL_H_ */
|
#endif /* _CLIXON_YANG_INTERNAL_H_ */
|
||||||
|
|
|
||||||
|
|
@ -853,6 +853,7 @@ yang_metadata_init(clixon_handle h)
|
||||||
* @param[in] h Clixon handle
|
* @param[in] h Clixon handle
|
||||||
* @param[in] xyanglib XML tree on the form <yang-lib>...
|
* @param[in] xyanglib XML tree on the form <yang-lib>...
|
||||||
* @param[in] mntpnt Name of mount-point for logs
|
* @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
|
* @param[in] yspec Will be populated with YANGs, is consumed
|
||||||
* @retval 1 OK
|
* @retval 1 OK
|
||||||
* @retval 0 Parse error
|
* @retval 0 Parse error
|
||||||
|
|
@ -864,6 +865,7 @@ int
|
||||||
yang_lib2yspec(clixon_handle h,
|
yang_lib2yspec(clixon_handle h,
|
||||||
cxobj *xyanglib,
|
cxobj *xyanglib,
|
||||||
char *mntpnt,
|
char *mntpnt,
|
||||||
|
char *domain,
|
||||||
yang_stmt *yspec)
|
yang_stmt *yspec)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
@ -902,7 +904,7 @@ yang_lib2yspec(clixon_handle h,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (yang_parse_module(h, name, revision, yspec, NULL) == NULL)
|
if (yang_parse_module(h, name, revision, yspec, domain, NULL) == NULL)
|
||||||
goto fail;
|
goto fail;
|
||||||
/* Sanity check: if given namespace differs from namespace in file */
|
/* Sanity check: if given namespace differs from namespace in file */
|
||||||
if (ns != NULL &&
|
if (ns != NULL &&
|
||||||
|
|
@ -920,7 +922,7 @@ yang_lib2yspec(clixon_handle h,
|
||||||
strcmp(yang_argument_get(yrev), "2019-01-04") == 0){
|
strcmp(yang_argument_get(yrev), "2019-01-04") == 0){
|
||||||
modmin++;
|
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;
|
goto fail;
|
||||||
#endif
|
#endif
|
||||||
if ((modmin = yang_len_get(yspec) - (1+veclen - modmin)) < 0)
|
if ((modmin = yang_len_get(yspec) - (1+veclen - modmin)) < 0)
|
||||||
|
|
|
||||||
|
|
@ -1002,31 +1002,44 @@ filename2revision(const char *filename,
|
||||||
return retval;
|
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] h CLICON handle
|
||||||
* @param[in] module Name of main YANG module.
|
* @param[in] module Name of main YANG module.
|
||||||
* @param[in] revision Revision or NULL
|
* @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)
|
* @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 0 No matching entry found
|
||||||
* @retval -1 Error
|
* @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
|
int
|
||||||
yang_file_find_match(clixon_handle h,
|
yang_file_find_match(clixon_handle h,
|
||||||
const char *module,
|
const char *module,
|
||||||
const char *revision,
|
const char *revision,
|
||||||
|
const char *domain,
|
||||||
cbuf *fbuf)
|
cbuf *fbuf)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cbuf *regex = NULL;
|
cbuf *regex = NULL;
|
||||||
cxobj *x;
|
cxobj *x;
|
||||||
cxobj *xc;
|
cxobj *xc;
|
||||||
char *dir;
|
char *dir;
|
||||||
cvec *cvv = NULL;
|
cvec *cvv = NULL;
|
||||||
cg_var *cv = NULL;
|
cg_var *cv = NULL;
|
||||||
cg_var *bestcv = NULL;
|
cg_var *bestcv = NULL;
|
||||||
|
cbuf *cb = NULL;
|
||||||
|
struct dirent *dp = NULL;
|
||||||
|
int ndp;
|
||||||
|
|
||||||
/* get clicon config file in xml form */
|
/* get clicon config file in xml form */
|
||||||
if ((x = clicon_conf_xml(h)) == NULL)
|
if ((x = clicon_conf_xml(h)) == NULL)
|
||||||
|
|
@ -1044,35 +1057,38 @@ yang_file_find_match(clixon_handle h,
|
||||||
else
|
else
|
||||||
cprintf(regex, "^%s(@[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9])?(.yang)$",
|
cprintf(regex, "^%s(@[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9])?(.yang)$",
|
||||||
module);
|
module);
|
||||||
xc = NULL;
|
/* First look in Main YANG dir, either MAIN or DOMAIN */
|
||||||
|
if (domain != NULL &&
|
||||||
while ((xc = xml_child_each(x, xc, CX_ELMNT)) != NULL) {
|
(dir = clicon_yang_domain_dir(h)) != NULL){
|
||||||
if (strcmp(xml_name(xc), "CLICON_YANG_MAIN_DIR") == 0){
|
if ((cb = cbuf_new()) == NULL){
|
||||||
struct dirent *dp = NULL;
|
clixon_err(OE_UNIX, errno, "cbuf_new");
|
||||||
int ndp;
|
goto done;
|
||||||
|
|
||||||
dir = xml_body(xc);
|
|
||||||
/* get all matching files in this directory */
|
|
||||||
if ((ndp = clicon_file_dirent(dir,
|
|
||||||
&dp,
|
|
||||||
cbuf_get(regex),
|
|
||||||
S_IFREG)) < 0)
|
|
||||||
goto done;
|
|
||||||
/* Entries are sorted, last entry should be most recent date
|
|
||||||
*/
|
|
||||||
if (ndp != 0){
|
|
||||||
if (fbuf)
|
|
||||||
cprintf(fbuf, "%s/%s", dir, dp[ndp-1].d_name);
|
|
||||||
if (dp)
|
|
||||||
free(dp);
|
|
||||||
retval = 1;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (dp)
|
|
||||||
free(dp);
|
|
||||||
}
|
}
|
||||||
else if (strcmp(xml_name(xc), "CLICON_YANG_DIR") == 0 &&
|
cprintf(cb, "%s/%s", dir, domain);
|
||||||
(dir = xml_body(xc)) != NULL){
|
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,
|
||||||
|
cbuf_get(regex),
|
||||||
|
S_IFREG)) < 0)
|
||||||
|
goto done;
|
||||||
|
/* Entries are sorted, last entry should be most recent date
|
||||||
|
*/
|
||||||
|
if (ndp != 0){
|
||||||
|
if (fbuf)
|
||||||
|
cprintf(fbuf, "%s/%s", dir, dp[ndp-1].d_name);
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 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 */
|
/* get all matching files in this directory recursively */
|
||||||
if ((cvv = cvec_new(0)) == NULL){
|
if ((cvv = cvec_new(0)) == NULL){
|
||||||
clixon_err(OE_UNIX, errno, "cvec_new");
|
clixon_err(OE_UNIX, errno, "cvec_new");
|
||||||
|
|
@ -1094,8 +1110,7 @@ yang_file_find_match(clixon_handle h,
|
||||||
if (bestcv){
|
if (bestcv){
|
||||||
if (fbuf)
|
if (fbuf)
|
||||||
cprintf(fbuf, "%s", cv_string_get(bestcv)); /* file path */
|
cprintf(fbuf, "%s", cv_string_get(bestcv)); /* file path */
|
||||||
retval = 1; /* found */
|
goto found;
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
if (cvv){
|
if (cvv){
|
||||||
cvec_free(cvv);
|
cvec_free(cvv);
|
||||||
|
|
@ -1106,11 +1121,18 @@ yang_file_find_match(clixon_handle h,
|
||||||
ok:
|
ok:
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
if (dp)
|
||||||
|
free(dp);
|
||||||
|
if (cb)
|
||||||
|
cbuf_free(cb);
|
||||||
if (cvv)
|
if (cvv)
|
||||||
cvec_free(cvv);
|
cvec_free(cvv);
|
||||||
if (regex)
|
if (regex)
|
||||||
cbuf_free(regex);
|
cbuf_free(regex);
|
||||||
return retval;
|
return retval;
|
||||||
|
found:
|
||||||
|
retval = 1;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Open a file, read into a string and invoke yang parsing
|
/*! 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] module Module name
|
||||||
* @param[in] revision Revision (or NULL)
|
* @param[in] revision Revision (or NULL)
|
||||||
* @param[in] yspec Yang statement
|
* @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
|
* @param[in] origname Name of yang module triggering this parsing, for logging
|
||||||
* @retval ymod YANG (sub)module
|
* @retval ymod YANG (sub)module
|
||||||
* @retval NULL Failed
|
* @retval NULL Failed
|
||||||
|
|
@ -1173,6 +1196,7 @@ yang_parse_module(clixon_handle h,
|
||||||
const char *module,
|
const char *module,
|
||||||
const char *revision,
|
const char *revision,
|
||||||
yang_stmt *yspec,
|
yang_stmt *yspec,
|
||||||
|
char *domain,
|
||||||
char *origname)
|
char *origname)
|
||||||
{
|
{
|
||||||
cbuf *fbuf = NULL;
|
cbuf *fbuf = NULL;
|
||||||
|
|
@ -1189,7 +1213,7 @@ yang_parse_module(clixon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Match a yang file with or without revision in yang-dir list */
|
/* 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;
|
goto done;
|
||||||
if (nr == 0){
|
if (nr == 0){
|
||||||
if ((cb = cbuf_new()) == NULL){
|
if ((cb = cbuf_new()) == NULL){
|
||||||
|
|
@ -1289,7 +1313,7 @@ yang_parse_recurse(clixon_handle h,
|
||||||
keyw==Y_IMPORT?Y_MODULE:Y_SUBMODULE,
|
keyw==Y_IMPORT?Y_MODULE:Y_SUBMODULE,
|
||||||
submodule) == NULL){
|
submodule) == NULL){
|
||||||
/* recursive call */
|
/* 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;
|
goto done;
|
||||||
/* Sanity check: if submodule, its belongs-to statement shall point to the module */
|
/* Sanity check: if submodule, its belongs-to statement shall point to the module */
|
||||||
if (keyw == Y_INCLUDE){
|
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)
|
if (yang_find_module_by_name_revision(yspec, name, revision) != NULL)
|
||||||
goto ok;
|
goto ok;
|
||||||
/* Find a yang module and parse it and all its submodules */
|
/* 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;
|
goto done;
|
||||||
if (yang_parse_post(h, yspec, modmin) < 0)
|
if (yang_parse_post(h, yspec, modmin) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@
|
||||||
* container root{ (ymnt)
|
* container root{ (ymnt)
|
||||||
* yangmnt:mount-point "mylabel"; (yext)
|
* yangmnt:mount-point "mylabel"; (yext)
|
||||||
* }
|
* }
|
||||||
|
* (note the argument "mylabel" defines an optional isolated YANG domain
|
||||||
*
|
*
|
||||||
* <config> # Your XML config
|
* <config> # Your XML config
|
||||||
* ...
|
* ...
|
||||||
|
|
@ -813,14 +814,14 @@ yang_schema_find_share(clixon_handle h,
|
||||||
cxobj *xyanglib,
|
cxobj *xyanglib,
|
||||||
yang_stmt **yspecp)
|
yang_stmt **yspecp)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cvec *cvv = NULL;
|
cvec *cvv = NULL;
|
||||||
cg_var *cv;
|
cg_var *cv;
|
||||||
cxobj *xroot;
|
cxobj *xroot;
|
||||||
cxobj *xmnt;
|
cxobj *xmnt;
|
||||||
cxobj *xylib;
|
cxobj *xylib;
|
||||||
int config = 1;
|
int config = 1;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
xroot = xml_root(xt);
|
xroot = xml_root(xt);
|
||||||
/* Get all XML mtpoints */
|
/* Get all XML mtpoints */
|
||||||
|
|
@ -870,10 +871,12 @@ yang_schema_yanglib_parse_mount(clixon_handle h,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *xyanglib = NULL;
|
cxobj *xyanglib = NULL;
|
||||||
yang_stmt *yspec = NULL;
|
cxobj *xb;
|
||||||
int ret;
|
yang_stmt *yspec0 = NULL;
|
||||||
int shared = 0;
|
yang_stmt *yspec1 = NULL;
|
||||||
char *xpath = NULL;
|
char *xpath = NULL;
|
||||||
|
char *domain = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
/* 1. Get modstate (xyanglib) of node: xyanglib, by querying backend state (via callback)
|
/* 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?
|
* 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;
|
goto done;
|
||||||
if (xyanglib == NULL)
|
if (xyanglib == NULL)
|
||||||
goto anydata;
|
goto anydata;
|
||||||
/* Optimization: find equal yspec from other mount-point */
|
if ((xb = xpath_first(xyanglib, NULL, "module-set/name")) != NULL)
|
||||||
if (clicon_option_bool(h, "CLICON_YANG_SCHEMA_MOUNT_SHARE")) {
|
domain = xml_body(xb);
|
||||||
if (yang_schema_find_share(h, xt, xyanglib, &yspec) < 0)
|
if (domain == NULL){
|
||||||
goto done;
|
clixon_err(OE_YANG, 0, "domain not found");
|
||||||
if (yspec)
|
goto done;
|
||||||
shared++;
|
|
||||||
}
|
}
|
||||||
/* XXX done later too */
|
/* Get xpath */
|
||||||
if ((ret = yang_mount_xmnt2ymnt_xpath(h, xt, NULL, &xpath)) < 0)
|
if ((ret = yang_mount_xmnt2ymnt_xpath(h, xt, NULL, &xpath)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0){
|
if (ret == 0){
|
||||||
clixon_err(OE_YANG, 0, "Mapping xmnt to ymnt and xpath");
|
clixon_err(OE_YANG, 0, "Mapping xmnt to ymnt and xpath");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (yspec == NULL){
|
/* Optimization: find equal yspec from other mount-point */
|
||||||
/* Parse it and set mount-point */
|
if (clicon_option_bool(h, "CLICON_YANG_SCHEMA_MOUNT_SHARE")) {
|
||||||
if ((yspec = yspec_new(h, xpath)) == NULL)
|
if (yang_schema_find_share(h, xt, xyanglib, &yspec0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
yang_flag_set(yspec, YANG_FLAG_SPEC_MOUNT);
|
}
|
||||||
clixon_debug(CLIXON_DBG_YANG, "new yang-spec: %p", yspec);
|
if ((yspec1 = yspec_new_shared(h, xpath, yspec0)) < 0)
|
||||||
if ((ret = yang_lib2yspec(h, xyanglib, xpath, yspec)) < 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;
|
goto done;
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
goto anydata;
|
goto anydata;
|
||||||
}
|
}
|
||||||
else
|
if (xml_yang_mount_set(h, xt, yspec1) < 0)
|
||||||
clixon_debug(CLIXON_DBG_YANG, "shared yang-spec: %p", yspec);
|
|
||||||
if (xml_yang_mount_set(h, xt, yspec) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
if (shared)
|
yspec1 = NULL;
|
||||||
if (yang_cvec_add(yspec, CGV_STRING, xpath) < 0)
|
|
||||||
goto done;
|
|
||||||
yspec = NULL;
|
|
||||||
retval = 1;
|
retval = 1;
|
||||||
done:
|
done:
|
||||||
if (xpath)
|
if (xpath)
|
||||||
free(xpath);
|
free(xpath);
|
||||||
if (yspec)
|
if (yspec1)
|
||||||
ys_free(yspec);
|
ys_free(yspec1);
|
||||||
if (xyanglib)
|
if (xyanglib)
|
||||||
xml_free(xyanglib);
|
xml_free(xyanglib);
|
||||||
return retval;
|
return retval;
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ DATASTORE_TOP="config"
|
||||||
# clixon yang revisions occuring in tests (see eg yang/clixon/Makefile.in)
|
# clixon yang revisions occuring in tests (see eg yang/clixon/Makefile.in)
|
||||||
CLIXON_AUTOCLI_REV="2024-08-01"
|
CLIXON_AUTOCLI_REV="2024-08-01"
|
||||||
CLIXON_LIB_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_RESTCONF_REV="2022-08-01"
|
||||||
CLIXON_EXAMPLE_REV="2022-11-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@
|
YANG_INSTALLDIR = @YANG_INSTALLDIR@
|
||||||
|
|
||||||
# Note: mirror these to test/config.sh.in
|
# 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-lib@2024-08-01.yang # 7.2
|
||||||
YANGSPECS += clixon-rfc5277@2008-07-01.yang
|
YANGSPECS += clixon-rfc5277@2008-07-01.yang
|
||||||
YANGSPECS += clixon-xml-changelog@2019-03-21.yang
|
YANGSPECS += clixon-xml-changelog@2019-03-21.yang
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,26 @@ module clixon-config {
|
||||||
|
|
||||||
***** END LICENSE BLOCK *****";
|
***** 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 {
|
revision 2024-01-01 {
|
||||||
description
|
description
|
||||||
"Changed semantics:
|
"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 clixon-config {
|
||||||
container restconf {
|
container restconf {
|
||||||
uses clrc:clixon-restconf;
|
uses clrc:clixon-restconf;
|
||||||
|
|
@ -445,6 +492,7 @@ module clixon-config {
|
||||||
Ensure that YANG_INSTALLDIR (default
|
Ensure that YANG_INSTALLDIR (default
|
||||||
/usr/local/share/clixon) is present in the path";
|
/usr/local/share/clixon) is present in the path";
|
||||||
}
|
}
|
||||||
|
/* Configuration */
|
||||||
leaf CLICON_CONFIGFILE{
|
leaf CLICON_CONFIGFILE{
|
||||||
type string;
|
type string;
|
||||||
description
|
description
|
||||||
|
|
@ -462,7 +510,9 @@ module clixon-config {
|
||||||
AFTER the main config file (CLICON_CONFIGFILE) in the following way:
|
AFTER the main config file (CLICON_CONFIGFILE) in the following way:
|
||||||
- leaf values are overwritten
|
- leaf values are overwritten
|
||||||
- leaf-list values are appended
|
- 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.
|
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.
|
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";
|
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.
|
This field is a 'bootstrap' field.
|
||||||
";
|
";
|
||||||
}
|
}
|
||||||
|
/* YANG */
|
||||||
leaf CLICON_YANG_MAIN_FILE {
|
leaf CLICON_YANG_MAIN_FILE {
|
||||||
type string;
|
type string;
|
||||||
description
|
description
|
||||||
|
|
@ -489,6 +540,18 @@ module clixon-config {
|
||||||
"If given, load all modules in this directory (all .yang files)
|
"If given, load all modules in this directory (all .yang files)
|
||||||
See also CLICON_YANG_DIR which specifies a path of dirs";
|
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 {
|
leaf CLICON_YANG_MODULE_MAIN {
|
||||||
type string;
|
type string;
|
||||||
description
|
description
|
||||||
|
|
@ -526,12 +589,6 @@ module clixon-config {
|
||||||
Note this is similar to what happens to YANG nodes that are disabled by a false
|
Note this is similar to what happens to YANG nodes that are disabled by a false
|
||||||
if-feature statement.";
|
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{
|
leaf CLICON_YANG_SCHEMA_MOUNT{
|
||||||
type boolean;
|
type boolean;
|
||||||
description
|
description
|
||||||
|
|
@ -544,12 +601,102 @@ module clixon-config {
|
||||||
Further, autocli syntax is added by definining a tree resolve wrapper";
|
Further, autocli syntax is added by definining a tree resolve wrapper";
|
||||||
default false;
|
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 {
|
leaf CLICON_BACKEND_REGEXP {
|
||||||
type string;
|
type string;
|
||||||
description
|
description
|
||||||
"Regexp of matching backend plugins in CLICON_BACKEND_DIR";
|
"Regexp of matching backend plugins in CLICON_BACKEND_DIR";
|
||||||
default "(.so)$";
|
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{
|
leaf CLICON_NETCONF_DIR{
|
||||||
type string;
|
type string;
|
||||||
description "Location of netconf (frontend) .so plugins";
|
description "Location of netconf (frontend) .so plugins";
|
||||||
|
|
@ -607,6 +754,32 @@ module clixon-config {
|
||||||
config";
|
config";
|
||||||
status obsolete;
|
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 {
|
leaf CLICON_RESTCONF_API_ROOT {
|
||||||
type string;
|
type string;
|
||||||
default "/restconf";
|
default "/restconf";
|
||||||
|
|
@ -722,6 +895,7 @@ module clixon-config {
|
||||||
Both feature clixon-restconf:http-data and restconf/enable-http-data
|
Both feature clixon-restconf:http-data and restconf/enable-http-data
|
||||||
must be enabled for this match to occur.";
|
must be enabled for this match to occur.";
|
||||||
}
|
}
|
||||||
|
/* Clixon CLI */
|
||||||
leaf CLICON_CLI_DIR {
|
leaf CLICON_CLI_DIR {
|
||||||
type string;
|
type string;
|
||||||
description
|
description
|
||||||
|
|
@ -760,8 +934,8 @@ module clixon-config {
|
||||||
type int32;
|
type int32;
|
||||||
default 1;
|
default 1;
|
||||||
description
|
description
|
||||||
"Set to 0 if you want CLI to wrap to next line.
|
"Set to 0 if you want CLI INPUT to wrap to next line.
|
||||||
Set to 1 if you want CLI to scroll sideways when approaching
|
Set to 1 if you want CLI INPUT to scroll sideways when approaching
|
||||||
right margin";
|
right margin";
|
||||||
}
|
}
|
||||||
leaf CLICON_CLI_LINES_DEFAULT {
|
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
|
While setting this value makes sense for adding new values, it makes less sense for
|
||||||
deleting.";
|
deleting.";
|
||||||
}
|
}
|
||||||
|
leaf CLICON_CLI_OUTPUT_FORMAT {
|
||||||
|
type cl:datastore_format;
|
||||||
|
default xml;
|
||||||
|
description
|
||||||
|
"Default CLI output format.";
|
||||||
|
}
|
||||||
|
/* Internal socket */
|
||||||
leaf CLICON_SOCK_FAMILY {
|
leaf CLICON_SOCK_FAMILY {
|
||||||
type socket_address_family;
|
type socket_address_family;
|
||||||
default UNIX;
|
default UNIX;
|
||||||
|
|
@ -900,46 +1081,17 @@ module clixon-config {
|
||||||
"Group membership to access clixon_backend unix socket and gid for
|
"Group membership to access clixon_backend unix socket and gid for
|
||||||
deamon";
|
deamon";
|
||||||
}
|
}
|
||||||
leaf CLICON_BACKEND_USER {
|
leaf CLICON_SOCK_PRIO {
|
||||||
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 {
|
|
||||||
type boolean;
|
type boolean;
|
||||||
default false;
|
default false;
|
||||||
description
|
description
|
||||||
"If set, enable process-control of restconf daemon, ie start/stop restconf
|
"Enable socket event priority.
|
||||||
daemon internally from backend daemon.
|
If enabled, a file-descriptor can be registered as high prio.
|
||||||
Also, if set, restconf daemon queries backend for its config
|
Presently, the backend socket has higher prio than others.
|
||||||
if not set, restconf daemon reads its config from main config file
|
(should be made more generic)
|
||||||
It uses clixon-restconf.yang for config and clixon-lib.yang for RPC
|
Note that a side-effect of enabling this option is that fairness of
|
||||||
Process control of restconf daemon is as follows:
|
non-prio events is disabled
|
||||||
- on RPC start, if enable is true, start the service, if false, error or ignore it
|
This is useful if the backend opens other sockets, such as the controller";
|
||||||
- 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.";
|
|
||||||
}
|
}
|
||||||
leaf CLICON_AUTOCOMMIT {
|
leaf CLICON_AUTOCOMMIT {
|
||||||
type int32;
|
type int32;
|
||||||
|
|
@ -951,12 +1103,17 @@ module clixon-config {
|
||||||
persistent confirming commit.
|
persistent confirming commit.
|
||||||
(consider boolean)";
|
(consider boolean)";
|
||||||
}
|
}
|
||||||
leaf CLICON_XMLDB_DIR {
|
leaf CLICON_AUTOLOCK {
|
||||||
type string;
|
type boolean;
|
||||||
mandatory true;
|
default false;
|
||||||
description
|
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 {
|
leaf CLICON_DATASTORE_CACHE {
|
||||||
type datastore_cache;
|
type datastore_cache;
|
||||||
default cache;
|
default cache;
|
||||||
|
|
@ -968,6 +1125,16 @@ module clixon-config {
|
||||||
Note that from 7.0 this is OBSOLETED, only datastore_cache is supported";
|
Note that from 7.0 this is OBSOLETED, only datastore_cache is supported";
|
||||||
status obsolete;
|
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 {
|
leaf CLICON_XMLDB_FORMAT {
|
||||||
type cl:datastore_format;
|
type cl:datastore_format;
|
||||||
default xml;
|
default xml;
|
||||||
|
|
@ -986,7 +1153,9 @@ module clixon-config {
|
||||||
default false;
|
default false;
|
||||||
description
|
description
|
||||||
"If set, tag datastores with RFC 8525 YANG Module Library
|
"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.";
|
yang modules match.";
|
||||||
}
|
}
|
||||||
leaf CLICON_XMLDB_UPGRADE_CHECKOLD {
|
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.
|
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.";
|
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 {
|
leaf CLICON_XML_CHANGELOG {
|
||||||
type boolean;
|
type boolean;
|
||||||
default false;
|
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‐
|
If true: The symbols defined by this shared object will be made available for symbol res‐
|
||||||
olution of subsequently loaded shared objects.";
|
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 {
|
leaf CLICON_NAMESPACE_NETCONF_DEFAULT {
|
||||||
type boolean;
|
type boolean;
|
||||||
default false;
|
default false;
|
||||||
|
|
@ -1080,7 +1248,6 @@ module clixon-config {
|
||||||
If defined, top-level rpc calls need not have namespaces (eg using xmlns=<ns>)
|
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).
|
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.";
|
See rfc6241 3.1: urn:ietf:params:xml:ns:netconf:base:1.0.";
|
||||||
|
|
||||||
}
|
}
|
||||||
leaf CLICON_STARTUP_MODE {
|
leaf CLICON_STARTUP_MODE {
|
||||||
type 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
|
The current only case where such a user is used is in RESTCONF authentication when
|
||||||
auth-type=none and no known user is known.";
|
auth-type=none and no known user is known.";
|
||||||
}
|
}
|
||||||
|
/* Network Configuration Access Control Model (NACM) */
|
||||||
leaf CLICON_NACM_MODE {
|
leaf CLICON_NACM_MODE {
|
||||||
type nacm_mode;
|
type nacm_mode;
|
||||||
default disabled;
|
default disabled;
|
||||||
|
|
@ -1136,20 +1304,6 @@ module clixon-config {
|
||||||
If this option is set, Clixon disables NACM if a datastore does NOT contain a
|
If this option is set, Clixon disables NACM if a datastore does NOT contain a
|
||||||
NACM config on load.";
|
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 {
|
leaf CLICON_MODULE_SET_ID {
|
||||||
type string;
|
type string;
|
||||||
default "0";
|
default "0";
|
||||||
|
|
@ -1162,21 +1316,7 @@ module clixon-config {
|
||||||
If CLICON_MODULE_LIBRARY_RFC7895 is enabled, it sets the modules-state/module-set-id
|
If CLICON_MODULE_LIBRARY_RFC7895 is enabled, it sets the modules-state/module-set-id
|
||||||
instead";
|
instead";
|
||||||
}
|
}
|
||||||
leaf CLICON_NETCONF_MONITORING {
|
/* Notification streams */
|
||||||
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_STREAM_DISCOVERY_RFC5277 {
|
leaf CLICON_STREAM_DISCOVERY_RFC5277 {
|
||||||
type boolean;
|
type boolean;
|
||||||
default false;
|
default false;
|
||||||
|
|
@ -1232,7 +1372,27 @@ module clixon-config {
|
||||||
units s;
|
units s;
|
||||||
description "Retention for stream replay buffers in seconds, ie how much
|
description "Retention for stream replay buffers in seconds, ie how much
|
||||||
data to store before dropping. 0 means no retention";
|
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 {
|
leaf CLICON_LOG_STRING_LIMIT {
|
||||||
type uint32;
|
type uint32;
|
||||||
|
|
@ -1241,8 +1401,8 @@ module clixon-config {
|
||||||
"Length limitation of debug and log strings.
|
"Length limitation of debug and log strings.
|
||||||
Especially useful for dynamic debug strings, such as packet dumps.
|
Especially useful for dynamic debug strings, such as packet dumps.
|
||||||
0 means no limit";
|
0 means no limit";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
/* SNMP */
|
||||||
leaf-list CLICON_SNMP_MIB {
|
leaf-list CLICON_SNMP_MIB {
|
||||||
description
|
description
|
||||||
"Names of MIBs that are used by clixon_snmp.
|
"Names of MIBs that are used by clixon_snmp.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue