Added: [Feature request: node's alias for CLI](https://github.com/clicon/clixon/issues/434)
New `clixon-autocli@2023-09-01.yang` revision Misc typos
This commit is contained in:
parent
4e79ac43fb
commit
3b08653eb4
13 changed files with 344 additions and 295 deletions
|
|
@ -44,6 +44,12 @@
|
||||||
## 6.4.0
|
## 6.4.0
|
||||||
Expected: October 2023
|
Expected: October 2023
|
||||||
|
|
||||||
|
### API changes on existing protocol/config features
|
||||||
|
Users may have to change how they access the system
|
||||||
|
|
||||||
|
* New `clixon-autocli@2023-09-01.yang` revision
|
||||||
|
* Added argument to alias extension
|
||||||
|
|
||||||
### C/CLI-API changes on existing features
|
### C/CLI-API changes on existing features
|
||||||
Developers may need to change their code
|
Developers may need to change their code
|
||||||
|
|
||||||
|
|
@ -52,6 +58,8 @@ Developers may need to change their code
|
||||||
### Minor features
|
### Minor features
|
||||||
|
|
||||||
* Example cli pipe grep command quotes vertical bar for OR function
|
* Example cli pipe grep command quotes vertical bar for OR function
|
||||||
|
* Added: [Feature request: node's alias for CLI](https://github.com/clicon/clixon/issues/434)
|
||||||
|
* Note: "Skip" is for all nodes, but "Alias" is only for leafs
|
||||||
* New command-line option for dumping configuration options for all clixon applications after load
|
* New command-line option for dumping configuration options for all clixon applications after load
|
||||||
* Syntax is `-C <format>`
|
* Syntax is `-C <format>`
|
||||||
* Example: `clixon_backend -1C json`
|
* Example: `clixon_backend -1C json`
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,9 @@ static int myfn(int par1, my_structure *par2);
|
||||||
|
|
||||||
### Errors
|
### Errors
|
||||||
|
|
||||||
|
Error handling follows the "fail early and loud" principle. That is, unless a specific error-handling
|
||||||
|
is identified, exit as soon as possible and with an explicit error log.
|
||||||
|
|
||||||
Errors are typically declared as follows:
|
Errors are typically declared as follows:
|
||||||
```
|
```
|
||||||
if (myfn(0) < 0){
|
if (myfn(0) < 0){
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,6 @@ Clixon has a master branch continuously tested with CI, but releases with more t
|
||||||
Clixon interaction is best done posting issues, pull requests, or joining the
|
Clixon interaction is best done posting issues, pull requests, or joining the
|
||||||
Matrix clixon forum https://matrix.to/#/#clixonforum:matrix.org.
|
Matrix clixon forum https://matrix.to/#/#clixonforum:matrix.org.
|
||||||
|
|
||||||
Other clixon projects include [CLIgen](https://github.com/clicon/cligen), [the Clixon controller](https://github.com/clicon/clixon-controller), [clixon applications](https://github.com/clicon/clixon-examples) and others.
|
Other clixon projects include [CLIgen](https://github.com/clicon/cligen), [the Clixon controller](https://github.com/clicon/clixon-controller), [Clixon applications](https://github.com/clicon/clixon-examples) and others.
|
||||||
|
|
||||||
Clixon is sponsored by [Rubicon Communications LLC(Netgate)](https://www.netgate.com/) and [Akamai Technologies, Inc.](https://www.akamai.com).
|
Clixon is sponsored by [Rubicon Communications LLC(Netgate)](https://www.netgate.com/) and [Akamai Technologies, Inc.](https://www.akamai.com).
|
||||||
|
|
|
||||||
|
|
@ -214,7 +214,7 @@ restconf_rpc_wrapper(clicon_handle h,
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
/* Get debug flag of restconf config, set the restconf start -D daemon flag according
|
/* Get debug flag of restconf config, set the restconf start -D daemon flag according
|
||||||
* to it. The restconf daemon cannoit read its debug flag from config initially,
|
* to it. The restconf daemon cannot read its debug flag from config initially,
|
||||||
* but in this way it is set directly in its input args.
|
* but in this way it is set directly in its input args.
|
||||||
* Its a trick.
|
* Its a trick.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -115,8 +115,8 @@ You can see which CLISPEC it generates via clixon_cli -D 2:
|
||||||
* @param[in] options
|
* @param[in] options
|
||||||
* @param[in] fraction_digits
|
* @param[in] fraction_digits
|
||||||
* @param[out] cb The string where the result format string is inserted.
|
* @param[out] cb The string where the result format string is inserted.
|
||||||
* @retval 1 Hide, dont show helptext etc
|
* @retval 1 OK
|
||||||
* @retval 0 OK
|
* @retval 0 Hide, dont show helptext etc
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
* @see expand_dbvar This is where the expand string is used
|
* @see expand_dbvar This is where the expand string is used
|
||||||
* @note XXX only fraction_digits handled,should also have mincv, maxcv, pattern
|
* @note XXX only fraction_digits handled,should also have mincv, maxcv, pattern
|
||||||
|
|
@ -140,10 +140,8 @@ cli_expand_var_generate(clicon_handle h,
|
||||||
cv = yang_cv_get(yspec);
|
cv = yang_cv_get(yspec);
|
||||||
if (yang_extension_value(ys, "hide", CLIXON_AUTOCLI_NS, &extvalue, NULL) < 0)
|
if (yang_extension_value(ys, "hide", CLIXON_AUTOCLI_NS, &extvalue, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (extvalue || yang_find(ys, Y_STATUS, "deprecated") != NULL) {
|
if (extvalue || yang_find(ys, Y_STATUS, "deprecated") != NULL)
|
||||||
retval = 1;
|
goto hide;
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (yang2api_path_fmt(ys, 1, &api_path_fmt) < 0)
|
if (yang2api_path_fmt(ys, 1, &api_path_fmt) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (pre)
|
if (pre)
|
||||||
|
|
@ -158,11 +156,14 @@ cli_expand_var_generate(clicon_handle h,
|
||||||
cprintf(cb, ",\"%s%s\"", MTPOINT_PREFIX, cv_string_get(cv));
|
cprintf(cb, ",\"%s%s\"", MTPOINT_PREFIX, cv_string_get(cv));
|
||||||
}
|
}
|
||||||
cprintf(cb, ")>");
|
cprintf(cb, ")>");
|
||||||
retval = 0;
|
retval = 1;
|
||||||
done:
|
done:
|
||||||
if (api_path_fmt)
|
if (api_path_fmt)
|
||||||
free(api_path_fmt);
|
free(api_path_fmt);
|
||||||
return retval;
|
return retval;
|
||||||
|
hide:
|
||||||
|
retval = 0;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Create callback with api_path format string as argument
|
/*! Create callback with api_path format string as argument
|
||||||
|
|
@ -211,6 +212,36 @@ yang2cli_helptext(cbuf *cb,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Print yang argument to cbuf, or aliased via extension
|
||||||
|
*
|
||||||
|
* This is only implemented for leafs.
|
||||||
|
* the reason it does not work for non-terminals is somewhat complex:
|
||||||
|
* If alias, the CLIgen command is instead given as a "keyword" variable: <orig:string keyword:alias>
|
||||||
|
* This in turn is treated as a single-value choice in cligen_parse.y
|
||||||
|
* But then in cli_dbxml, choice is treated as a variable which is correct on other cases.
|
||||||
|
* So one needs to distinguish between "keyword" as given here, and a choice with one argument.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
yang2cli_print_alias(cbuf *cb,
|
||||||
|
yang_stmt *ys)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
int extvalue = 0;
|
||||||
|
char *name;
|
||||||
|
char *alias = NULL;
|
||||||
|
|
||||||
|
if (yang_extension_value(ys, "alias", CLIXON_AUTOCLI_NS, &extvalue, &alias) < 0)
|
||||||
|
goto done;
|
||||||
|
name = yang_argument_get(ys);
|
||||||
|
if (extvalue)
|
||||||
|
cprintf(cb, "<%s:string keyword:%s>", name, alias);
|
||||||
|
else
|
||||||
|
cprintf(cb, "%s", name);
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Generate identityref statements for CLI variables
|
/*! Generate identityref statements for CLI variables
|
||||||
* @param[in] ys Yang statement
|
* @param[in] ys Yang statement
|
||||||
* @param[in] ytype Resolved yang type.
|
* @param[in] ytype Resolved yang type.
|
||||||
|
|
@ -646,7 +677,7 @@ yang2cli_var_leafref(clicon_handle h,
|
||||||
options, fraction_digits, regular_value,
|
options, fraction_digits, regular_value,
|
||||||
cb)) < 0)
|
cb)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0)
|
if (ret == 1)
|
||||||
yang2cli_helptext(cb, helptext);
|
yang2cli_helptext(cb, helptext);
|
||||||
}
|
}
|
||||||
if (completionp && regular_value)
|
if (completionp && regular_value)
|
||||||
|
|
@ -690,9 +721,9 @@ yang2cli_var(clicon_handle h,
|
||||||
enum cv_type cvtype;
|
enum cv_type cvtype;
|
||||||
const char *cvtypestr;
|
const char *cvtypestr;
|
||||||
int options = 0;
|
int options = 0;
|
||||||
int result;
|
|
||||||
int completionp;
|
int completionp;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if ((patterns = cvec_new(0)) == NULL){
|
if ((patterns = cvec_new(0)) == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "cvec_new");
|
clicon_err(OE_UNIX, errno, "cvec_new");
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -716,10 +747,10 @@ yang2cli_var(clicon_handle h,
|
||||||
if (autocli_completion(h, &completionp) < 0)
|
if (autocli_completion(h, &completionp) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (completionp){
|
if (completionp){
|
||||||
if ((result = cli_expand_var_generate(h, ys, cvtypestr,
|
if ((ret = cli_expand_var_generate(h, ys, cvtypestr,
|
||||||
options, fraction_digits, 1, cb)) < 0)
|
options, fraction_digits, 1, cb)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (result == 0)
|
if (ret == 1)
|
||||||
yang2cli_helptext(cb, helptext);
|
yang2cli_helptext(cb, helptext);
|
||||||
}
|
}
|
||||||
cprintf(cb, ")");
|
cprintf(cb, ")");
|
||||||
|
|
@ -819,7 +850,8 @@ yang2cli_leaf(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
if (listkw == AUTOCLI_LISTKW_ALL ||
|
if (listkw == AUTOCLI_LISTKW_ALL ||
|
||||||
(key_leaf==0 && listkw == AUTOCLI_LISTKW_NOKEY)){
|
(key_leaf==0 && listkw == AUTOCLI_LISTKW_NOKEY)){
|
||||||
cprintf(cb, "%s", yang_argument_get(ys));
|
if (yang2cli_print_alias(cb, ys) < 0)
|
||||||
|
goto done;
|
||||||
yang2cli_helptext(cb, helptext);
|
yang2cli_helptext(cb, helptext);
|
||||||
cprintf(cb, " ");
|
cprintf(cb, " ");
|
||||||
if (yang_extension_value(ys, "hide", CLIXON_AUTOCLI_NS, &hideext, NULL) < 0)
|
if (yang_extension_value(ys, "hide", CLIXON_AUTOCLI_NS, &hideext, NULL) < 0)
|
||||||
|
|
@ -920,18 +952,6 @@ yang2cli_container(clicon_handle h,
|
||||||
if (extvalue || yang_find(ys, Y_STATUS, "deprecated") != NULL){
|
if (extvalue || yang_find(ys, Y_STATUS, "deprecated") != NULL){
|
||||||
cprintf(cb, ", hide");
|
cprintf(cb, ", hide");
|
||||||
}
|
}
|
||||||
#ifdef NYI /* This is for the mode extension, not yet supported */
|
|
||||||
{
|
|
||||||
int mode = 0;
|
|
||||||
/* First see if extension mode, if not, check if default mode */
|
|
||||||
if (yang_extension_value(ys, "mode", CLIXON_AUTOCLI_NS, &mode, NULL) < 0)
|
|
||||||
goto done;
|
|
||||||
if (mode == 0 && autocli_edit_mode(h, Y_CONTAINER, &mode) < 0)
|
|
||||||
goto done;
|
|
||||||
if (mode)
|
|
||||||
cprintf(cb, ", mode");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
cprintf(cb, ", act-container;{\n");
|
cprintf(cb, ", act-container;{\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1203,6 +1223,7 @@ yang2cli_stmt(clicon_handle h,
|
||||||
yang_stmt *yc;
|
yang_stmt *yc;
|
||||||
int treeref_state = 0;
|
int treeref_state = 0;
|
||||||
int grouping_treeref = 0;
|
int grouping_treeref = 0;
|
||||||
|
int extvalue = 0;
|
||||||
|
|
||||||
if (ys == NULL){
|
if (ys == NULL){
|
||||||
clicon_err(OE_YANG, EINVAL, "No yang spec");
|
clicon_err(OE_YANG, EINVAL, "No yang spec");
|
||||||
|
|
@ -1215,6 +1236,11 @@ yang2cli_stmt(clicon_handle h,
|
||||||
if (yang_find(ys, Y_STATUS, "deprecated") != NULL){
|
if (yang_find(ys, Y_STATUS, "deprecated") != NULL){
|
||||||
clicon_debug(4, "%s deprecated: %s %s", __FUNCTION__, yang_argument_get(ys), yang_argument_get(ys_module(ys)));
|
clicon_debug(4, "%s deprecated: %s %s", __FUNCTION__, yang_argument_get(ys), yang_argument_get(ys_module(ys)));
|
||||||
}
|
}
|
||||||
|
/* Check if autocli skip */
|
||||||
|
if (yang_extension_value(ys, "skip", CLIXON_AUTOCLI_NS, &extvalue, NULL) < 0)
|
||||||
|
goto done;
|
||||||
|
if (extvalue == 1)
|
||||||
|
goto ok;
|
||||||
/* Only produce autocli for YANG non-config only if autocli-treeref-state is true */
|
/* Only produce autocli for YANG non-config only if autocli-treeref-state is true */
|
||||||
if (autocli_treeref_state(h, &treeref_state) < 0)
|
if (autocli_treeref_state(h, &treeref_state) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -294,7 +294,6 @@ autocli_trees_default(clicon_handle h)
|
||||||
if (cligen_ph_parsetree_set(ph, pt) < 0)
|
if (cligen_ph_parsetree_set(ph, pt) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
|
||||||
/* Create backward compatible tree: @datamodelshow */
|
/* Create backward compatible tree: @datamodelshow */
|
||||||
if ((ph = cligen_ph_add(cli_cligen(h), "datamodelshow")) == NULL)
|
if ((ph = cligen_ph_add(cli_cligen(h), "datamodelshow")) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -1345,15 +1345,16 @@ xml2cli1(clicon_handle h,
|
||||||
char *prepend,
|
char *prepend,
|
||||||
clicon_output_cb *fn)
|
clicon_output_cb *fn)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *xe = NULL;
|
cxobj *xe = NULL;
|
||||||
cbuf *cbpre = NULL;
|
cbuf *cbpre = NULL;
|
||||||
yang_stmt *ys;
|
yang_stmt *ys;
|
||||||
int match;
|
int match;
|
||||||
char *body;
|
char *body;
|
||||||
int compress = 0;
|
int compress = 0;
|
||||||
autocli_listkw_t listkw;
|
autocli_listkw_t listkw;
|
||||||
int exist = 0;
|
int exist = 0;
|
||||||
|
char *name;
|
||||||
|
|
||||||
if (autocli_list_keyword(h, &listkw) < 0)
|
if (autocli_list_keyword(h, &listkw) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -1365,13 +1366,18 @@ xml2cli1(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
if (exist)
|
if (exist)
|
||||||
goto ok;
|
goto ok;
|
||||||
|
exist = 0;
|
||||||
|
if (yang_extension_value(ys, "alias", CLIXON_AUTOCLI_NS, &exist, &name) < 0)
|
||||||
|
goto done;
|
||||||
|
if (!exist)
|
||||||
|
name = xml_name(xn);
|
||||||
/* If leaf/leaf-list or presence container, then print line */
|
/* If leaf/leaf-list or presence container, then print line */
|
||||||
if (yang_keyword_get(ys) == Y_LEAF ||
|
if (yang_keyword_get(ys) == Y_LEAF ||
|
||||||
yang_keyword_get(ys) == Y_LEAF_LIST){
|
yang_keyword_get(ys) == Y_LEAF_LIST){
|
||||||
if (prepend)
|
if (prepend)
|
||||||
(*fn)(f, "%s", prepend);
|
(*fn)(f, "%s", prepend);
|
||||||
if (listkw != AUTOCLI_LISTKW_NONE)
|
if (listkw != AUTOCLI_LISTKW_NONE)
|
||||||
(*fn)(f, "%s ", xml_name(xn));
|
(*fn)(f, "%s ", name);
|
||||||
if ((body = xml_body(xn)) != NULL){
|
if ((body = xml_body(xn)) != NULL){
|
||||||
if (index(body, ' '))
|
if (index(body, ' '))
|
||||||
(*fn)(f, "\"%s\"", body);
|
(*fn)(f, "\"%s\"", body);
|
||||||
|
|
|
||||||
|
|
@ -3780,7 +3780,7 @@ yang_anydata_add(yang_stmt *yp,
|
||||||
* if (yang_extension_value(ys, "mymode", "urn:example:lib", &exist, &value) < 0)
|
* if (yang_extension_value(ys, "mymode", "urn:example:lib", &exist, &value) < 0)
|
||||||
* err;
|
* err;
|
||||||
* if (value != NULL){
|
* if (value != NULL){
|
||||||
* // use extension value
|
* // use extension argument
|
||||||
* }
|
* }
|
||||||
* @endcode
|
* @endcode
|
||||||
* @see ys_populate_unknown Called when parsing YANG
|
* @see ys_populate_unknown Called when parsing YANG
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ CLIXON_VERSION=@CLIXON_VERSION@
|
||||||
DATASTORE_TOP="config"
|
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="2023-05-01"
|
CLIXON_AUTOCLI_REV="2023-09-01"
|
||||||
CLIXON_LIB_REV="2023-05-01"
|
CLIXON_LIB_REV="2023-05-01"
|
||||||
CLIXON_CONFIG_REV="2023-05-01"
|
CLIXON_CONFIG_REV="2023-05-01"
|
||||||
CLIXON_RESTCONF_REV="2022-08-01"
|
CLIXON_RESTCONF_REV="2022-08-01"
|
||||||
|
|
|
||||||
254
test/test_autocli_alias_skip.sh
Executable file
254
test/test_autocli_alias_skip.sh
Executable file
|
|
@ -0,0 +1,254 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Tests for using autocli skip and alias extension
|
||||||
|
# Test augment mode only
|
||||||
|
# Test skip for leaf, container and list
|
||||||
|
# Test alias only for leaf, since it is not implemented for container+list
|
||||||
|
# see also test_autocli_hide.sh
|
||||||
|
set -u
|
||||||
|
# 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
|
||||||
|
|
||||||
|
: ${clixon_util_datastore:=clixon_util_datastore}
|
||||||
|
|
||||||
|
fin=$dir/in
|
||||||
|
cfg=$dir/conf_yang.xml
|
||||||
|
fyang=$dir/example.yang
|
||||||
|
fyang1=$dir/$APPNAME-augment.yang
|
||||||
|
clidir=$dir/cli
|
||||||
|
if [ -d $clidir ]; then
|
||||||
|
rm -rf $clidir/*
|
||||||
|
else
|
||||||
|
mkdir $clidir
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use yang in example
|
||||||
|
|
||||||
|
# Generate autocli for these modules
|
||||||
|
AUTOCLI=$(autocli_config ${APPNAME}\* kw-nokey false)
|
||||||
|
|
||||||
|
cat <<EOF > $cfg
|
||||||
|
<clixon-config xmlns="http://clicon.org/config">
|
||||||
|
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
|
||||||
|
<CLICON_FEATURE>ietf-netconf:startup</CLICON_FEATURE>
|
||||||
|
<CLICON_YANG_DIR>${YANG_INSTALLDIR}</CLICON_YANG_DIR>
|
||||||
|
<CLICON_YANG_DIR>$dir</CLICON_YANG_DIR>
|
||||||
|
<CLICON_YANG_MAIN_DIR>$dir</CLICON_YANG_MAIN_DIR>
|
||||||
|
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
|
||||||
|
<CLICON_CLISPEC_DIR>$clidir</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/$APPNAME/$APPNAME.sock</CLICON_SOCK>
|
||||||
|
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
|
||||||
|
<CLICON_XMLDB_DIR>$dir</CLICON_XMLDB_DIR>
|
||||||
|
<CLICON_YANG_LIBRARY>false</CLICON_YANG_LIBRARY>
|
||||||
|
${AUTOCLI}
|
||||||
|
</clixon-config>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat <<EOF > $clidir/ex.cli
|
||||||
|
CLICON_MODE="example";
|
||||||
|
CLICON_PROMPT="%U@%H %W> ";
|
||||||
|
CLICON_PIPETREE="|mypipe";
|
||||||
|
|
||||||
|
# Autocli syntax tree operations
|
||||||
|
edit @datamodel, cli_auto_edit("datamodel");
|
||||||
|
up, cli_auto_up("datamodel");
|
||||||
|
top, cli_auto_top("datamodel");
|
||||||
|
set @datamodel, cli_auto_set();
|
||||||
|
merge @datamodel, cli_auto_merge();
|
||||||
|
create @datamodel, cli_auto_create();
|
||||||
|
delete("Delete a configuration item") {
|
||||||
|
@datamodel, cli_auto_del();
|
||||||
|
all("Delete whole candidate configuration"), delete_all("candidate");
|
||||||
|
}
|
||||||
|
show("Show a particular state of the system") configuration,
|
||||||
|
cli_show_auto_mode("candidate", "xml", false, false);
|
||||||
|
cli, cli_show_auto_mode("candidate", "cli", false, false);
|
||||||
|
EOF
|
||||||
|
# @datamodelshow, cli_show_auto("candidate", "xml", false, false, "explicit");
|
||||||
|
|
||||||
|
# Yang specs must be here first for backend. But then the specs are changed but just for CLI
|
||||||
|
# Augment original Yang spec example directly
|
||||||
|
# First augment /table/parameter
|
||||||
|
# Had a problem with unknown in grouping -> test uses uses/grouping
|
||||||
|
cat <<EOF > $fyang
|
||||||
|
module example {
|
||||||
|
namespace "urn:example:clixon";
|
||||||
|
prefix ex;
|
||||||
|
import clixon-autocli{
|
||||||
|
prefix autocli;
|
||||||
|
}
|
||||||
|
container table{
|
||||||
|
list parameter{
|
||||||
|
key name;
|
||||||
|
leaf name{
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
leaf same{
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
leaf skipped{
|
||||||
|
description "leaf skip";
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
leaf orig{
|
||||||
|
description "leaf alias";
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list skipped{
|
||||||
|
description "list skip";
|
||||||
|
key name;
|
||||||
|
leaf name{
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
leaf value{
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
container skipped{
|
||||||
|
description "container skip";
|
||||||
|
list parameter{
|
||||||
|
key name;
|
||||||
|
leaf name{
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
leaf value{
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Skip /table/parameter
|
||||||
|
cat <<EOF > $fyang1
|
||||||
|
module example-augment {
|
||||||
|
namespace "urn:example:augment";
|
||||||
|
prefix aug;
|
||||||
|
import example{
|
||||||
|
prefix ex;
|
||||||
|
}
|
||||||
|
import clixon-autocli{
|
||||||
|
prefix autocli;
|
||||||
|
}
|
||||||
|
/* Leafs */
|
||||||
|
augment "/ex:table/ex:parameter/ex:skipped" {
|
||||||
|
autocli:skip;
|
||||||
|
}
|
||||||
|
augment "/ex:table/ex:parameter/ex:orig" {
|
||||||
|
autocli:alias "alias";
|
||||||
|
}
|
||||||
|
/* Lists */
|
||||||
|
augment "/ex:table/ex:skipped" {
|
||||||
|
autocli:skip;
|
||||||
|
}
|
||||||
|
/* Containers */
|
||||||
|
augment "/ex:skipped" {
|
||||||
|
autocli:skip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat <<EOF > $clidir/clipipe.cli
|
||||||
|
CLICON_MODE="|mypipe"; # Must start with |
|
||||||
|
as {
|
||||||
|
xml, pipe_showas_fn("xml", "false");
|
||||||
|
cli, pipe_showas_fn("cli", "true", "set ");
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
new "test params: -f $cfg"
|
||||||
|
if [ $BE -ne 0 ]; then
|
||||||
|
new "kill old backend"
|
||||||
|
sudo clixon_backend -z -f $cfg
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
err
|
||||||
|
fi
|
||||||
|
new "start backend -s init -f $cfg"
|
||||||
|
start_backend -s init -f $cfg
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set a value, show it
|
||||||
|
# Arguments:
|
||||||
|
# 1 : contorig Container field shown in xml
|
||||||
|
# 2 : listorig List field shown in xml
|
||||||
|
# 3 : leaforig Leaf field shown in xml
|
||||||
|
# 4 : contfield Container name to set/show
|
||||||
|
# 5 : listfield List name to set/show
|
||||||
|
# 6 : leaffield Leaf field to set/show
|
||||||
|
function testok()
|
||||||
|
{
|
||||||
|
contorig=$1
|
||||||
|
listorig=$2
|
||||||
|
leaforig=$3
|
||||||
|
contfield=$4
|
||||||
|
listfield=$5
|
||||||
|
leaffield=$6
|
||||||
|
|
||||||
|
new "Set $contfield $listfield $leaffield"
|
||||||
|
expectpart "$($clixon_cli -1f $cfg set $contfield $listfield x $leaffield abc)" 0 "^$"
|
||||||
|
|
||||||
|
new "Show config as xml"
|
||||||
|
expectpart "$($clixon_cli -1f $cfg show config as xml)" 0 "<$contorig xmlns=\"urn:example:clixon\"><$listorig><name>x</name><$leaforig>abc</$leaforig></$listorig></$contorig>"
|
||||||
|
|
||||||
|
new "Show config as cli"
|
||||||
|
expectpart "$($clixon_cli -1f $cfg show config as cli)" 0 "set $contfield $listfield x $leaffield abc"
|
||||||
|
|
||||||
|
new "Delete $contfield $listfield $leaffield"
|
||||||
|
expectpart "$($clixon_cli -1f $cfg delete $contfield $listfield x $leaffield abc)" 0 "^$"
|
||||||
|
}
|
||||||
|
|
||||||
|
function testfail()
|
||||||
|
{
|
||||||
|
contfield=$1
|
||||||
|
listfield=$2
|
||||||
|
leaffield=$3
|
||||||
|
|
||||||
|
new "Set $contfield $listfield $leaffield"
|
||||||
|
# echo "$clixon_cli -1f -1f $cfg set $contfield $listfield x $leaffield abc"
|
||||||
|
expectpart "$($clixon_cli -1f $cfg set $contfield $listfield x $leaffield abc 2>&1)" 255 "Unknown command"
|
||||||
|
}
|
||||||
|
|
||||||
|
new "wait backend"
|
||||||
|
wait_backend
|
||||||
|
|
||||||
|
# Leaf
|
||||||
|
new "Test same"
|
||||||
|
testok table parameter same table parameter same
|
||||||
|
|
||||||
|
new "Test leaf skipped"
|
||||||
|
testfail table parameter skipped
|
||||||
|
|
||||||
|
new "Test leaf aliases old fail"
|
||||||
|
testfail table parameter orig
|
||||||
|
|
||||||
|
new "Test leaf aliases new ok"
|
||||||
|
testok table parameter orig table parameter alias
|
||||||
|
|
||||||
|
# Lists
|
||||||
|
new "Test list skipped"
|
||||||
|
testfail table skipped value
|
||||||
|
|
||||||
|
# Container
|
||||||
|
new "Test skipped"
|
||||||
|
testfail skipped parameter value
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
rm -rf $dir
|
||||||
|
|
||||||
|
new "endtest"
|
||||||
|
endtest
|
||||||
|
|
@ -68,8 +68,8 @@ show("Show a particular state of the system"){
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Yang specs must be here first for backend. But then the specs are changed but just for CLI
|
# Yang specs must be here first for backend. But then the specs are changed but just for CLI
|
||||||
# Annotate original Yang spec example directly
|
# Augment original Yang spec example directly
|
||||||
# First annotate /table/parameter
|
# First augment /table/parameter
|
||||||
# Had a problem with unknown in grouping -> test uses uses/grouping
|
# Had a problem with unknown in grouping -> test uses uses/grouping
|
||||||
cat <<EOF > $fyang
|
cat <<EOF > $fyang
|
||||||
module example {
|
module example {
|
||||||
|
|
@ -125,9 +125,9 @@ function testparam()
|
||||||
set table parameter x
|
set table parameter x
|
||||||
show config xml
|
show config xml
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
new "set table parameter hidden"
|
new "set table parameter hidden"
|
||||||
expectpart "$(cat $fin | $clixon_cli -f $cfg 2>&1)" 0 "set table parameter x" "<table xmlns=\"urn:example:clixon\"></table>"
|
expectpart "$(cat $fin | $clixon_cli -f $cfg 2>&1)" 0 "set table parameter x" "<table xmlns=\"urn:example:clixon\"></table>"
|
||||||
|
|
||||||
XML="<table xmlns=\"urn:example:clixon\"><parameter><name>x</name></parameter></table>"
|
XML="<table xmlns=\"urn:example:clixon\"><parameter><name>x</name></parameter></table>"
|
||||||
|
|
||||||
new "check datastore using netconf"
|
new "check datastore using netconf"
|
||||||
|
|
@ -186,7 +186,7 @@ sudo chmod a+r $dir/candidate_db
|
||||||
new "Test hidden parameter in table/param inline"
|
new "Test hidden parameter in table/param inline"
|
||||||
testparam
|
testparam
|
||||||
|
|
||||||
# Second annotate /table/parameter/value
|
# Second augment /table/parameter/value
|
||||||
cat <<EOF > $fyang
|
cat <<EOF > $fyang
|
||||||
module example {
|
module example {
|
||||||
namespace "urn:example:clixon";
|
namespace "urn:example:clixon";
|
||||||
|
|
@ -253,7 +253,7 @@ module example {
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# First annotate /table/parameter
|
# First augment /table/parameter
|
||||||
cat <<EOF > $fyang2
|
cat <<EOF > $fyang2
|
||||||
module example-augment {
|
module example-augment {
|
||||||
namespace "urn:example:augment";
|
namespace "urn:example:augment";
|
||||||
|
|
@ -275,7 +275,7 @@ new "Test hidden parameter in table/param augment"
|
||||||
testparam
|
testparam
|
||||||
|
|
||||||
# Try hidden specific parameter key (note only cli yang)
|
# Try hidden specific parameter key (note only cli yang)
|
||||||
# Second annotate /table/parameter/value
|
# Second augment /table/parameter/value
|
||||||
cat <<EOF > $fyang2
|
cat <<EOF > $fyang2
|
||||||
module example-augment {
|
module example-augment {
|
||||||
namespace "urn:example:augment";
|
namespace "urn:example:augment";
|
||||||
|
|
@ -319,7 +319,7 @@ module example {
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Use this as grouping (not annotate)
|
# Use this as grouping (not augment)
|
||||||
cat <<EOF > $fyang2
|
cat <<EOF > $fyang2
|
||||||
module example-augment {
|
module example-augment {
|
||||||
namespace "urn:example:augment";
|
namespace "urn:example:augment";
|
||||||
|
|
@ -47,7 +47,7 @@ YANGSPECS += clixon-lib@2023-05-01.yang # 6.3
|
||||||
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
|
||||||
YANGSPECS += clixon-restconf@2022-08-01.yang # 5.9
|
YANGSPECS += clixon-restconf@2022-08-01.yang # 5.9
|
||||||
YANGSPECS += clixon-autocli@2023-05-01.yang # 6.3
|
YANGSPECS += clixon-autocli@2023-09-01.yang # 6.4
|
||||||
|
|
||||||
all:
|
all:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,247 +0,0 @@
|
||||||
module clixon-autocli{
|
|
||||||
yang-version 1.1;
|
|
||||||
namespace "http://clicon.org/autocli";
|
|
||||||
prefix autocli;
|
|
||||||
|
|
||||||
organization
|
|
||||||
"Clicon / Clixon";
|
|
||||||
|
|
||||||
contact
|
|
||||||
"Olof Hagsand <olof@hagsand.se>";
|
|
||||||
|
|
||||||
description
|
|
||||||
"Clixon CLIgen specification declarations, including autocli.
|
|
||||||
Design inspired by ietf-netconf-acm.yang
|
|
||||||
|
|
||||||
***** BEGIN LICENSE BLOCK *****
|
|
||||||
Copyright (C) 2020-2021 Olof Hagsand and Rubicon Communications, LLC(Netgate)
|
|
||||||
|
|
||||||
This file is part of CLIXON
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the \"License\");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an \"AS IS\" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
Alternatively, the contents of this file may be used under the terms of
|
|
||||||
the GNU General Public License Version 3 or later (the \"GPL\"),
|
|
||||||
in which case the provisions of the GPL are applicable instead
|
|
||||||
of those above. If you wish to allow use of your version of this file only
|
|
||||||
under the terms of the GPL, and not to allow others to
|
|
||||||
use your version of this file under the terms of Apache License version 2,
|
|
||||||
indicate your decision by deleting the provisions above and replace them with
|
|
||||||
the notice and other provisions required by the GPL. If you do not delete
|
|
||||||
the provisions above, a recipient may use your version of this file under
|
|
||||||
the terms of any one of the Apache License version 2 or the GPL.
|
|
||||||
|
|
||||||
***** END LICENSE BLOCK *****";
|
|
||||||
|
|
||||||
revision 2022-02-11 {
|
|
||||||
description
|
|
||||||
"Initial version
|
|
||||||
Released in Clixon 5.6";
|
|
||||||
}
|
|
||||||
revision 2021-12-05 {
|
|
||||||
description
|
|
||||||
"Initial version
|
|
||||||
Released in Clixon 5.5";
|
|
||||||
}
|
|
||||||
extension hide {
|
|
||||||
description
|
|
||||||
"Modify the autocli by hiding the command associated with a YANG node and its
|
|
||||||
sub-commands.
|
|
||||||
The command is active but not shown by ? or TAB. In other words, it hides the
|
|
||||||
auto-completion of commands";
|
|
||||||
}
|
|
||||||
extension hide-show {
|
|
||||||
description
|
|
||||||
"Modify the autocli by hiding the command associated with a YANG node and its
|
|
||||||
sub-commands in CLI show commands.";
|
|
||||||
}
|
|
||||||
extension strict-expand {
|
|
||||||
description
|
|
||||||
"Modify the autocli by only showing exactly the expanded values of a variable.
|
|
||||||
It should not be possible to add a new value that is not in the expanded list.";
|
|
||||||
}
|
|
||||||
typedef autocli-op {
|
|
||||||
description
|
|
||||||
"Autocli rule-type operation, each rule use different fields as
|
|
||||||
described in the individual enums below.";
|
|
||||||
type enumeration {
|
|
||||||
enum enable {
|
|
||||||
description
|
|
||||||
"Include a complete subtree to rendering of autocli.
|
|
||||||
Example:
|
|
||||||
<module-default>false</module-default>
|
|
||||||
<rule>
|
|
||||||
<name>wifi</name>
|
|
||||||
<operation>enable</operation>
|
|
||||||
<module-name>openconfig-wifi</module-name>
|
|
||||||
</rule>
|
|
||||||
Only on module-level and if module-default is false,
|
|
||||||
Rule fields used: module-name";
|
|
||||||
}
|
|
||||||
enum compress {
|
|
||||||
description
|
|
||||||
"Skip a keyword from a command.
|
|
||||||
Keep the command, only make it shorter by omitting a part.
|
|
||||||
Example: compress containers if single list child
|
|
||||||
<rule>
|
|
||||||
<name>container compress</name>
|
|
||||||
<operation>compress</operation>
|
|
||||||
<yang-keyword>container</yang-keyword>
|
|
||||||
<yang-keyword-child>list</yang-keyword-child>
|
|
||||||
</rule>
|
|
||||||
Rule fields used:
|
|
||||||
module-name, yang-keyword, schema-nodeid, yang-keyword-child, extension";
|
|
||||||
}
|
|
||||||
enum edit-mode {
|
|
||||||
description
|
|
||||||
"Autocli CLI edit modes for YANG symbols.
|
|
||||||
For example,
|
|
||||||
edit interface eth0<CR>
|
|
||||||
enters a new mode with local context.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
typedef list-keyword-type {
|
|
||||||
description
|
|
||||||
"Autocli CLI keyword behaviour in YANG lists.
|
|
||||||
With 'keyword' is meant CLIgen 'constants' rather than 'variables'.
|
|
||||||
Assume a YANG LIST: list a{ key x; leaf x; leaf y;} and how to generate
|
|
||||||
the autocli";
|
|
||||||
type enumeration {
|
|
||||||
enum kw-none{
|
|
||||||
description "No extra keywords, only variables: a <x> <y>";
|
|
||||||
}
|
|
||||||
enum kw-nokey{
|
|
||||||
description "Keywords on non-key variables: a <x> y <y>";
|
|
||||||
}
|
|
||||||
enum kw-all{
|
|
||||||
description "Keywords on all variables: a x <x> y <y>";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
typedef yang-keywords {
|
|
||||||
type bits {
|
|
||||||
bit list;
|
|
||||||
bit listall{ /* NYI */
|
|
||||||
description
|
|
||||||
"Variant of list encompassing all list entries, not just an instance";
|
|
||||||
}
|
|
||||||
bit container;
|
|
||||||
bit leaf; /* Also leaf-list (NYI) */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
grouping clixon-autocli{
|
|
||||||
/* options */
|
|
||||||
leaf module-default {
|
|
||||||
description
|
|
||||||
"Include YANG modules for generation of autocli.
|
|
||||||
If true, all modules with a top-level datanode are generated, ie
|
|
||||||
they get a top-level entry in the @basemodel tree.
|
|
||||||
If false, you need to explicitly enable modules for autocli generation
|
|
||||||
using 'enable' rules";
|
|
||||||
type boolean;
|
|
||||||
default true;
|
|
||||||
}
|
|
||||||
leaf list-keyword-default {
|
|
||||||
description
|
|
||||||
"Autocli CLI keyword behaviour in YANG lists.";
|
|
||||||
type list-keyword-type;
|
|
||||||
default kw-nokey;
|
|
||||||
}
|
|
||||||
leaf treeref-state-default {
|
|
||||||
description
|
|
||||||
"If 'true', generate CLI from YANG state/non-config statements as well, not only config data.
|
|
||||||
Many specs have very large state parts, for example openconfig has ca 10 times
|
|
||||||
larger state than config parts, see for example openconfig-isis.yang.";
|
|
||||||
type boolean;
|
|
||||||
default false;
|
|
||||||
}
|
|
||||||
leaf edit-mode-default {
|
|
||||||
description
|
|
||||||
"Open automatic edit-modes for some YANG keywords and do not allow others.
|
|
||||||
A CLI edit mode opens a carriage-return option and changes the context to be
|
|
||||||
in that local context.
|
|
||||||
For example:
|
|
||||||
cli> interfaces interface e0<cr>
|
|
||||||
eth0>
|
|
||||||
Default is to generate edit-modes for all containers and lists.";
|
|
||||||
type yang-keywords;
|
|
||||||
default "list container";
|
|
||||||
}
|
|
||||||
leaf completion-default {
|
|
||||||
description
|
|
||||||
"Generate code for CLI completion of existing db symbols.
|
|
||||||
That is, check existing configure database for completion options.
|
|
||||||
This is normally always enabled.";
|
|
||||||
type boolean;
|
|
||||||
default true;
|
|
||||||
}
|
|
||||||
/* rules */
|
|
||||||
list rule {
|
|
||||||
description
|
|
||||||
"Represents a modification rule of a clixon clispec.";
|
|
||||||
key name;
|
|
||||||
leaf name {
|
|
||||||
description
|
|
||||||
"Arbitrary name assigned for the rule, must be unique";
|
|
||||||
type string;
|
|
||||||
}
|
|
||||||
leaf description {
|
|
||||||
description
|
|
||||||
"Rule description";
|
|
||||||
type string;
|
|
||||||
}
|
|
||||||
leaf operation {
|
|
||||||
description "Rule operation";
|
|
||||||
type autocli-op;
|
|
||||||
}
|
|
||||||
leaf module-name {
|
|
||||||
description
|
|
||||||
"Name of the module associated with this rule.
|
|
||||||
Wildchars '*' and '?' can be used (glob pattern).
|
|
||||||
Revision and yang suffix are omitted
|
|
||||||
Example: 'openconfig-*'";
|
|
||||||
type string;
|
|
||||||
}
|
|
||||||
leaf yang-keyword {
|
|
||||||
description
|
|
||||||
"If present identifes a YANG keyword which the rule applies to
|
|
||||||
Example: 'container'
|
|
||||||
";
|
|
||||||
type string;
|
|
||||||
}
|
|
||||||
leaf schema-nodeid {
|
|
||||||
description
|
|
||||||
"path in the form of /<id>/<id> or just a single <id> identifying a YANG
|
|
||||||
schema-node identifier as defined in RFC 7950 Sec 6.5
|
|
||||||
Example: 'config', '/interfaces/interface'";
|
|
||||||
type string;
|
|
||||||
}
|
|
||||||
leaf yang-keyword-child {
|
|
||||||
description
|
|
||||||
"The YANG statement has a single child, and the yang type of the child is the
|
|
||||||
value of this option
|
|
||||||
A (maybe too) specific property to cover openconfig compressions
|
|
||||||
as defined here:
|
|
||||||
https://github.com/openconfig/ygot/blob/master/docs/design.md#openconfig-path-compression";
|
|
||||||
type string;
|
|
||||||
}
|
|
||||||
leaf extension {
|
|
||||||
/* Consider making this a container with name/module/value instead */
|
|
||||||
description
|
|
||||||
"The extension is set either in the node itself, or in this module
|
|
||||||
Extension prefix must be set
|
|
||||||
Example: oc-ext:openconfig-version";
|
|
||||||
type string;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue