* More YANG extension functionality,
* See [Augment auto-cli for hiding/modifying cli syntax #156](https://github.com/clicon/clixon/issues/156) and [hiding auto-generated CLI entries #153](https://github.com/clicon/clixon/issues/153) * Extensions can be used in augmentations * Extension `autocli-op` has been added to add "hidden" commands in the autocli * Documentation: https://clixon-docs.readthedocs.io/en/latest/misc.html#extensions
This commit is contained in:
parent
e1b94d94d2
commit
b8641f30bd
14 changed files with 547 additions and 50 deletions
|
|
@ -64,6 +64,11 @@ Developers may need to change their code
|
|||
|
||||
### Minor changes
|
||||
|
||||
* More YANG extension functionality,
|
||||
* See [Augment auto-cli for hiding/modifying cli syntax #156](https://github.com/clicon/clixon/issues/156) and [hiding auto-generated CLI entries #153](https://github.com/clicon/clixon/issues/153)
|
||||
* Extensions can be used in augmentations
|
||||
* Extension `autocli-op` has been added to add "hidden" commands in the autocli
|
||||
* Documentation: https://clixon-docs.readthedocs.io/en/latest/misc.html#extensions
|
||||
* Added new revision of main example yang: `clixon-example@2020-12-01.yang`
|
||||
* Support for building static lib: `LINKAGE=static configure`
|
||||
* Change comment character to be active anywhere to beginning of _word_ only.
|
||||
|
|
|
|||
|
|
@ -663,6 +663,8 @@ yang2cli_leaf(clicon_handle h,
|
|||
int retval = -1;
|
||||
char *helptext = NULL;
|
||||
char *s;
|
||||
char *opext = NULL;
|
||||
int extralevel = 0;
|
||||
|
||||
/* description */
|
||||
if ((yd = yang_find(ys, Y_DESCRIPTION, NULL)) != NULL){
|
||||
|
|
@ -674,27 +676,40 @@ yang2cli_leaf(clicon_handle h,
|
|||
*s = '\0';
|
||||
}
|
||||
cprintf(cb, "%*s", level*3, "");
|
||||
/* Look for autocli-op defined in clixon-lib.yang */
|
||||
if (yang_extension_value(ys, "autocli-op", CLIXON_LIB_NS, &opext) < 0)
|
||||
goto done;
|
||||
if (gt == GT_VARS|| gt == GT_ALL || gt == GT_HIDE){
|
||||
cprintf(cb, "%s", yang_argument_get(ys));
|
||||
yang2cli_helptext(cb, helptext);
|
||||
cprintf(cb, " ");
|
||||
if ((show_tree == 0) || (key_leaf == 1)) {
|
||||
if (!show_tree || key_leaf) {
|
||||
if (opext && strcmp(opext, "hide") == 0){
|
||||
cprintf(cb, ",hide{");
|
||||
extralevel = 1;
|
||||
}
|
||||
if (yang2cli_var(h, ys, helptext, cb) < 0)
|
||||
goto done;
|
||||
}
|
||||
else{
|
||||
if (opext && strcmp(opext, "hide") == 0){
|
||||
cprintf(cb, ",hide");
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
if (!show_tree || key_leaf) {
|
||||
if (yang2cli_var(h, ys, helptext, cb) < 0)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else
|
||||
if ((show_tree == 0) || (key_leaf == 1)) {
|
||||
if (yang2cli_var(h, ys, helptext, cb) < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (callback){
|
||||
if (cli_callback_generate(h, ys, cb) < 0)
|
||||
goto done;
|
||||
cprintf(cb, ";\n");
|
||||
}
|
||||
|
||||
if (extralevel)
|
||||
cprintf(cb, "}\n");
|
||||
retval = 0;
|
||||
done:
|
||||
if (helptext)
|
||||
|
|
@ -787,9 +802,18 @@ yang2cli_list(clicon_handle h,
|
|||
int retval = -1;
|
||||
char *helptext = NULL;
|
||||
char *s;
|
||||
int list_has_callback = 0;
|
||||
int last_key = 0;
|
||||
int extralevel = 0;
|
||||
char *opext = NULL;
|
||||
|
||||
cprintf(cb, "%*s%s", level*3, "", yang_argument_get(ys));
|
||||
/* Look for autocli-op defined in clixon-lib.yang */
|
||||
if (yang_extension_value(ys, "autocli-op", CLIXON_LIB_NS, &opext) < 0)
|
||||
goto done;
|
||||
if (opext != NULL && strcmp(opext, "hide") == 0){
|
||||
cprintf(cb, ",hide");
|
||||
extralevel = 1;
|
||||
}
|
||||
if ((yd = yang_find(ys, Y_DESCRIPTION, NULL)) != NULL){
|
||||
if ((helptext = strdup(yang_argument_get(yd))) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
|
|
@ -811,25 +835,25 @@ yang2cli_list(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
/* Print key variable now, and skip it in loop below
|
||||
Note, only print callback on last statement
|
||||
* Note, only print callback on last statement
|
||||
*/
|
||||
list_has_callback = cvec_next(cvk, cvi)?0:1;
|
||||
if (show_tree == 1) {
|
||||
if (list_has_callback) {
|
||||
last_key = cvec_next(cvk, cvi)?0:1;
|
||||
if (last_key){
|
||||
if (show_tree) {
|
||||
if (cli_callback_generate(h, ys, cb) < 0)
|
||||
goto done;
|
||||
cprintf(cb, ";\n");
|
||||
cprintf(cb, "{\n");
|
||||
}
|
||||
else if (extralevel)
|
||||
cprintf(cb, "{\n");
|
||||
}
|
||||
|
||||
if (yang2cli_leaf(h, yleaf,
|
||||
(gt==GT_VARS||gt==GT_HIDE)?GT_NONE:gt, level+1,
|
||||
list_has_callback, show_tree, 1,
|
||||
last_key, show_tree, 1,
|
||||
cb) < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
cprintf(cb, "{\n");
|
||||
yc = NULL;
|
||||
while ((yc = yn_each(ys, yc)) != NULL) {
|
||||
|
|
@ -848,7 +872,7 @@ yang2cli_list(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
cprintf(cb, "%*s}\n", level*3, "");
|
||||
if ((show_tree == 1) && (list_has_callback)) {
|
||||
if (last_key && (show_tree||extralevel)) {
|
||||
cprintf(cb, "%*s}\n", level*3, "");
|
||||
}
|
||||
retval = 0;
|
||||
|
|
@ -1013,8 +1037,7 @@ yang2cli(clicon_handle h,
|
|||
if ((globals = cvec_new(0)) == NULL)
|
||||
goto done;
|
||||
/* load cli syntax */
|
||||
if (cligen_parse_str(cli_cligen(h), cbuf_get(cb),
|
||||
"yang2cli", pt, globals) < 0)
|
||||
if (cligen_parse_str(cli_cligen(h), cbuf_get(cb), "yang2cli", pt, globals) < 0)
|
||||
goto done;
|
||||
cvec_free(globals);
|
||||
/* Resolve the expand callback functions in the generated syntax.
|
||||
|
|
|
|||
|
|
@ -257,6 +257,6 @@ int yang_type_cache_get(yang_stmt *ytype, yang_stmt **resolved, int *opti
|
|||
int yang_type_cache_set(yang_stmt *ys, yang_stmt *resolved, int options, cvec *cvv,
|
||||
cvec *patterns, uint8_t fraction);
|
||||
yang_stmt *yang_anydata_add(yang_stmt *yp, char *name);
|
||||
|
||||
int yang_extension_value(yang_stmt *ys, char *name, char *ns, char **value);
|
||||
|
||||
#endif /* _CLIXON_YANG_H_ */
|
||||
|
|
|
|||
|
|
@ -3236,6 +3236,65 @@ yang_anydata_add(yang_stmt *yp,
|
|||
return ys;
|
||||
}
|
||||
|
||||
/*! Find extension argument and return extension argument value
|
||||
* @param[in] ys Yang statement
|
||||
* @param[in] name Name of the extension
|
||||
* @param[in] ns The namespace
|
||||
* @param[out] value clispec operator (hide/none) - direct pointer into yang, dont free
|
||||
* This is for extensions with an argument
|
||||
* @code
|
||||
* char *value = NULL;
|
||||
* if (yang_extension_value(ys, "mymode", "urn:example:lib", &value) < 0)
|
||||
* err;
|
||||
* if (value != NULL){
|
||||
* // use extension value
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
int
|
||||
yang_extension_value(yang_stmt *ys,
|
||||
char *name,
|
||||
char *ns,
|
||||
char **value)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt *yext;
|
||||
yang_stmt *ymod;
|
||||
cg_var *cv;
|
||||
char *prefix = NULL;
|
||||
cbuf *cb = NULL;
|
||||
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
yext = NULL; /* This loop gets complicated in trhe case the extension is augmented */
|
||||
while ((yext = yn_each(ys, yext)) != NULL) {
|
||||
if (yang_keyword_get(yext) != Y_UNKNOWN)
|
||||
continue;
|
||||
if ((ymod = ys_module(yext)) == NULL)
|
||||
continue;
|
||||
if (yang_find_prefix_by_namespace(ymod, ns, &prefix) < 0)
|
||||
goto ok;
|
||||
cprintf(cb, "%s:%s", prefix, name);
|
||||
if (strcmp(yang_argument_get(yext), cbuf_get(cb)) != 0)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
if (yext != NULL){ /* Found */
|
||||
if ((cv = yang_cv_get(yext)) == NULL)
|
||||
goto ok;
|
||||
if (value)
|
||||
*value = cv_string_get(cv);
|
||||
}
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
if (cb)
|
||||
cbuf_free(cb);
|
||||
return retval;
|
||||
}
|
||||
|
||||
#ifdef XML_EXPLICIT_INDEX
|
||||
/*! Mark element as search_index in list
|
||||
* @retval 0 OK
|
||||
|
|
|
|||
|
|
@ -1393,6 +1393,7 @@ augment_substmt : when_stmt { clicon_debug(3,"augment-substmt -> when-s
|
|||
| case_stmt { clicon_debug(3,"augment-substmt -> case-stmt");}
|
||||
| action_stmt { clicon_debug(3,"augment-substmt -> action-stmt");}
|
||||
| notification_stmt { clicon_debug(3,"augment-substmt -> notification-stmt");}
|
||||
| unknown_stmt { clicon_debug(3,"augment-substmt -> unknown-stmt");}
|
||||
| { clicon_debug(3,"augment-substmt -> "); }
|
||||
;
|
||||
|
||||
|
|
|
|||
|
|
@ -253,15 +253,6 @@ yang_augment_node(yang_stmt *ys)
|
|||
/* The target node MUST be either a container, list, choice, case, input, output, or notification node.
|
||||
* which means it is slightly different than a schema-nodeid ? */
|
||||
targetkey = yang_keyword_get(ytarget);
|
||||
if (targetkey != Y_CONTAINER && targetkey != Y_LIST && targetkey != Y_CHOICE &&
|
||||
targetkey != Y_CASE && targetkey != Y_INPUT &&
|
||||
targetkey != Y_OUTPUT && targetkey != Y_NOTIFICATION){
|
||||
clicon_log(LOG_WARNING, "Warning: Augment failed in module %s: target node %s has wrong type %s",
|
||||
yang_argument_get(ys_module(ys)),
|
||||
schema_nodeid,
|
||||
yang_key2str(targetkey));
|
||||
goto ok;
|
||||
}
|
||||
|
||||
/* Find when statement, if present */
|
||||
if ((ywhen = yang_find(ys, Y_WHEN, NULL)) != NULL){
|
||||
|
|
@ -272,16 +263,17 @@ yang_augment_node(yang_stmt *ys)
|
|||
/* Extend ytarget with ys' schemanode children */
|
||||
yc0 = NULL;
|
||||
while ((yc0 = yn_each(ys, yc0)) != NULL) {
|
||||
if (!yang_schemanode(yc0))
|
||||
continue;
|
||||
childkey = yang_keyword_get(yc0);
|
||||
/* Only shemanodes and extensions */
|
||||
if (!yang_schemanode(yc0) && childkey != Y_UNKNOWN)
|
||||
continue;
|
||||
switch (targetkey){
|
||||
case Y_CONTAINER:
|
||||
case Y_LIST:
|
||||
/* If the target node is a container or list node, the "action" and
|
||||
"notification" statements can be used within the "augment" statement.
|
||||
*/
|
||||
if (childkey != Y_ACTION && childkey != Y_NOTIFICATION &&
|
||||
if (childkey != Y_ACTION && childkey != Y_NOTIFICATION && childkey != Y_UNKNOWN &&
|
||||
childkey != Y_CONTAINER && childkey != Y_LEAF && childkey != Y_LIST &&
|
||||
childkey != Y_LEAF_LIST && childkey != Y_USES && childkey != Y_CHOICE){
|
||||
clicon_log(LOG_WARNING, "Warning: A Augment failed in module %s: node %s %d cannot be added to target node %s",
|
||||
|
|
@ -301,7 +293,8 @@ yang_augment_node(yang_stmt *ys)
|
|||
"uses", and "choice" statements can be used within the "augment"
|
||||
statement. */
|
||||
if (childkey != Y_CONTAINER && childkey != Y_LEAF && childkey != Y_LIST &&
|
||||
childkey != Y_LEAF_LIST && childkey != Y_USES && childkey != Y_CHOICE){
|
||||
childkey != Y_LEAF_LIST && childkey != Y_USES && childkey != Y_CHOICE &&
|
||||
childkey != Y_UNKNOWN){
|
||||
clicon_log(LOG_WARNING, "Warning: B Augment failed in module %s: node %s %d cannot be added to target node %s",
|
||||
yang_argument_get(ys_module(ys)),
|
||||
yang_key2str(childkey),
|
||||
|
|
|
|||
288
test/test_cli_auto_extension.sh
Executable file
288
test/test_cli_auto_extension.sh
Executable file
|
|
@ -0,0 +1,288 @@
|
|||
#!/usr/bin/env bash
|
||||
# Tests for using autocli extension defined in clixon-lib
|
||||
# This is both a test of yang extensions and autocli
|
||||
# The extension is autocli-op and can take the value "hide" (maybe more)
|
||||
# Try both inline and augmented mode
|
||||
# @see https://clixon-docs.readthedocs.io/en/latest/misc.html#extensions
|
||||
# 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
|
||||
|
||||
fin=$dir/in
|
||||
cfg=$dir/conf_yang.xml
|
||||
fyang=$dir/example.yang
|
||||
fyang2=$dir/$APPNAME-augment.yang
|
||||
clidir=$dir/cli
|
||||
if [ -d $clidir ]; then
|
||||
rm -rf $clidir/*
|
||||
else
|
||||
mkdir $clidir
|
||||
fi
|
||||
|
||||
# Use yang in example
|
||||
|
||||
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>/usr/local/share/clixon</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_CLI_GENMODEL>2</CLICON_CLI_GENMODEL>
|
||||
<CLICON_CLI_GENMODEL_TYPE>VARS</CLICON_CLI_GENMODEL_TYPE>
|
||||
<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_MODULE_LIBRARY_RFC7895>false</CLICON_MODULE_LIBRARY_RFC7895>
|
||||
</clixon-config>
|
||||
EOF
|
||||
|
||||
|
||||
cat <<EOF > $clidir/ex.cli
|
||||
CLICON_MODE="example";
|
||||
CLICON_PROMPT="%U@%H %W> ";
|
||||
|
||||
# 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("Show configuration"), cli_auto_show("datamodel", "candidate", "text", true, false);{
|
||||
xml("Show configuration as XML"), cli_auto_show("datamodel", "candidate", "xml", false, false);
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Yang specs must be here first for backend. But then the specs are changed but just for CLI
|
||||
# Annotate original Yang spec example directly
|
||||
# First annotate /table/parameter
|
||||
cat <<EOF > $fyang
|
||||
module example {
|
||||
namespace "urn:example:clixon";
|
||||
prefix ex;
|
||||
import clixon-lib{
|
||||
prefix cl;
|
||||
}
|
||||
container table{
|
||||
list parameter{
|
||||
key name;
|
||||
leaf name{
|
||||
type string;
|
||||
}
|
||||
cl:autocli-op hide; /* This is the extension */
|
||||
leaf value{
|
||||
description "a value";
|
||||
type string;
|
||||
}
|
||||
list index{
|
||||
key i;
|
||||
leaf i{
|
||||
type string;
|
||||
}
|
||||
leaf iv{
|
||||
type string;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Original no annotations for backend
|
||||
cat <<EOF > $fyang2
|
||||
module example-augment {
|
||||
namespace "urn:example:augment";
|
||||
prefix aug;
|
||||
import example{
|
||||
prefix ex;
|
||||
}
|
||||
import clixon-lib{
|
||||
prefix cl;
|
||||
}
|
||||
}
|
||||
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
|
||||
|
||||
new "waiting"
|
||||
wait_backend
|
||||
fi
|
||||
|
||||
testparam()
|
||||
{
|
||||
|
||||
# Try hidden parameter list
|
||||
new "query table parameter hidden"
|
||||
expectpart "$(echo "set table ?" | $clixon_cli -f $cfg 2>&1)" 0 "set table" "<cr>" --not-- "parameter"
|
||||
|
||||
cat <<EOF > $fin
|
||||
set table parameter x
|
||||
show config xml
|
||||
EOF
|
||||
new "set table parameter hidden"
|
||||
expectpart "$(cat $fin | $clixon_cli -f $cfg 2>&1)" 0 "set table parameter x" "<table xmlns=\"urn:example:clixon\"><parameter><name>x</name></parameter></table>"
|
||||
|
||||
}
|
||||
|
||||
testvalue()
|
||||
{
|
||||
# Try not hidden parameter list
|
||||
new "query table parameter hidden"
|
||||
expectpart "$(echo "set table ?" | $clixon_cli -f $cfg 2>&1)" 0 "set table" "<cr>" "parameter"
|
||||
|
||||
# Try hidden value
|
||||
new "query table leaf"
|
||||
expectpart "$(echo "set table parameter x ?" | $clixon_cli -f $cfg 2>&1)" 0 "index" "<cr>" --not-- "value"
|
||||
|
||||
cat <<EOF > $fin
|
||||
set table parameter x value 42
|
||||
show config xml
|
||||
EOF
|
||||
new "set table parameter hidden leaf"
|
||||
expectpart "$(cat $fin | $clixon_cli -f $cfg 2>&1)" 0 "<table xmlns=\"urn:example:clixon\"><parameter><name>x</name><value>42</value></parameter></table>"
|
||||
|
||||
}
|
||||
|
||||
# INLINE MODE
|
||||
|
||||
new "Test hidden parameter in table/param inline"
|
||||
testparam
|
||||
|
||||
# Second annotate /table/parameter/value
|
||||
cat <<EOF > $fyang
|
||||
module example {
|
||||
namespace "urn:example:clixon";
|
||||
prefix ex;
|
||||
import clixon-lib{
|
||||
prefix cl;
|
||||
}
|
||||
container table{
|
||||
list parameter{
|
||||
key name;
|
||||
leaf name{
|
||||
type string;
|
||||
}
|
||||
leaf value{
|
||||
cl:autocli-op hide; /* Here is the example */
|
||||
description "a value";
|
||||
type string;
|
||||
}
|
||||
list index{
|
||||
key i;
|
||||
leaf i{
|
||||
type string;
|
||||
}
|
||||
leaf iv{
|
||||
type string;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
new "Test hidden parameter in table/param/value inline"
|
||||
testvalue
|
||||
|
||||
# AUGMENT MODE
|
||||
# Here use a new yang module that augments, keep original example intact
|
||||
cat <<EOF > $fyang
|
||||
module example {
|
||||
namespace "urn:example:clixon";
|
||||
prefix ex;
|
||||
container table{
|
||||
list parameter{
|
||||
key name;
|
||||
leaf name{
|
||||
type string;
|
||||
}
|
||||
leaf value{
|
||||
description "a value";
|
||||
type string;
|
||||
}
|
||||
list index{
|
||||
key i;
|
||||
leaf i{
|
||||
type string;
|
||||
}
|
||||
leaf iv{
|
||||
type string;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# First annotate /table/parameter
|
||||
cat <<EOF > $fyang2
|
||||
module example-augment {
|
||||
namespace "urn:example:augment";
|
||||
prefix aug;
|
||||
import example{
|
||||
prefix ex;
|
||||
}
|
||||
import clixon-lib{
|
||||
prefix cl;
|
||||
}
|
||||
augment "/ex:table/ex:parameter" {
|
||||
cl:autocli-op hide;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
|
||||
new "Test hidden parameter in table/param augment"
|
||||
testparam
|
||||
|
||||
# Try hidden specific parameter key (note only cli yang)
|
||||
# Second annotate /table/parameter/value
|
||||
cat <<EOF > $fyang2
|
||||
module example-augment {
|
||||
namespace "urn:example:augment";
|
||||
prefix aug;
|
||||
import example{
|
||||
prefix ex;
|
||||
}
|
||||
import clixon-lib{
|
||||
prefix cl;
|
||||
}
|
||||
augment "/ex:table/ex:parameter/ex:value" {
|
||||
cl:autocli-op hide;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
new "Test hidden parameter in table/param/value augment"
|
||||
testvalue
|
||||
|
||||
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
|
||||
|
||||
rm -rf $dir
|
||||
|
|
@ -81,7 +81,7 @@ enter1 <string>, cli_auto_sub_enter("datamodel", "/example:table/parameter=%s/in
|
|||
leave, cli_auto_top("datamodel", "candidate");
|
||||
|
||||
# Autocli syntax tree operations
|
||||
edit @datamodel, cli_auto_edit("interface");
|
||||
edit @datamodel, cli_auto_edit("datamodel");
|
||||
up, cli_auto_up("datamodel");
|
||||
top, cli_auto_top("datamodel");
|
||||
set @datamodel, cli_auto_set();
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ testrun()
|
|||
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+json' $proto://$addr/restconf/data/ietf-yang-library:modules-state/module=ietf-interfaces,2018-02-20)" 0 'HTTP/1.1 200 OK' '{"ietf-yang-library:module":\[{"name":"ietf-interfaces","revision":"2018-02-20","namespace":"urn:ietf:params:xml:ns:yang:ietf-interfaces","conformance-type":"implement"}\]}'
|
||||
|
||||
new "restconf schema resource, mod-state top-level"
|
||||
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+json' $proto://$addr/restconf/data/ietf-yang-library:modules-state)" 0 'HTTP/1.1 200 OK' '{"ietf-yang-library:modules-state":{"module-set-id":"0","module":\[{"name":"clixon-example","revision":"2020-12-01","namespace":"urn:example:clixon","conformance-type":"implement"},{"name":"clixon-lib","revision":"2020-04-23","'
|
||||
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+json' $proto://$addr/restconf/data/ietf-yang-library:modules-state)" 0 'HTTP/1.1 200 OK' '{"ietf-yang-library:modules-state":{"module-set-id":"0","module":\[{"name":"clixon-example","revision":"2020-12-01","namespace":"urn:example:clixon","conformance-type":"implement"},{"name":"clixon-lib","revision":"2020-12-08","'
|
||||
|
||||
new "restconf options. RFC 8040 4.1"
|
||||
expectpart "$(curl $CURLOPTS -X OPTIONS $proto://$addr/restconf/data)" 0 "HTTP/1.1 200 OK" "Allow: OPTIONS,HEAD,GET,POST,PUT,PATCH,DELETE"
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+xml' $RCPR
|
|||
# This just catches the header and the jukebox module, the RFC has foo and bar which
|
||||
# seems wrong to recreate
|
||||
new "B.1.2. Retrieve the Server Module Information"
|
||||
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+json' $RCPROTO://localhost/restconf/data/ietf-yang-library:modules-state)" 0 "HTTP/1.1 200 OK" 'Cache-Control: no-cache' "Content-Type: application/yang-data+json" '{"ietf-yang-library:modules-state":{"module-set-id":"0","module":\[{"name":"clixon-lib","revision":"2020-04-23","namespace":"http://clicon.org/lib","conformance-type":"implement"}' '{"name":"example-events","revision":"","namespace":"urn:example:events","conformance-type":"implement"}' '{"name":"example-jukebox","revision":"2016-08-15","namespace":"http://example.com/ns/example-jukebox","conformance-type":"implement"}' '{"name":"example-system","revision":"","namespace":"http://example.com/ns/example-system","conformance-type":"implement"}'
|
||||
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+json' $RCPROTO://localhost/restconf/data/ietf-yang-library:modules-state)" 0 "HTTP/1.1 200 OK" 'Cache-Control: no-cache' "Content-Type: application/yang-data+json" '{"ietf-yang-library:modules-state":{"module-set-id":"0","module":\[{"name":"clixon-lib","revision":"2020-12-08","namespace":"http://clicon.org/lib","conformance-type":"implement"}' '{"name":"example-events","revision":"","namespace":"urn:example:events","conformance-type":"implement"}' '{"name":"example-jukebox","revision":"2016-08-15","namespace":"http://example.com/ns/example-jukebox","conformance-type":"implement"}' '{"name":"example-system","revision":"","namespace":"http://example.com/ns/example-system","conformance-type":"implement"}'
|
||||
|
||||
new "B.1.3. Retrieve the Server Capability Information"
|
||||
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+xml' $RCPROTO://localhost/restconf/data/ietf-restconf-monitoring:restconf-state/capabilities)" 0 "HTTP/1.1 200 OK" "Content-Type: application/yang-data+xml" 'Cache-Control: no-cache' '<capabilities xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf-monitoring"><capability>urn:ietf:params:restconf:capability:defaults:1.0?basic-mode=explicit</capability><capability>urn:ietf:params:restconf:capability:depth</capability>
|
||||
|
|
|
|||
|
|
@ -301,7 +301,7 @@ cat <<EOF > $dir/startup_db
|
|||
</config>
|
||||
EOF
|
||||
|
||||
MODSTATE1='<modules-state xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library"><module-set-id>0</module-set-id><module><name>clixon-lib</name><revision>2020-04-23</revision><namespace>http://clicon.org/lib</namespace></module>'
|
||||
MODSTATE1='<modules-state xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library"><module-set-id>0</module-set-id><module><name>clixon-lib</name><revision>2020-12-08</revision><namespace>http://clicon.org/lib</namespace></module>'
|
||||
|
||||
MODSTATE2='<module><name>interfaces</name><revision>2018-02-20</revision><namespace>urn:example:interfaces</namespace></module>'
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@
|
|||
#
|
||||
# 2) The extensions results in in a node data definition.
|
||||
# Second, the example is run without the extension enabled, then it is enabled.
|
||||
#
|
||||
# @see test_cli_auto_extension
|
||||
|
||||
# Magic line must be first in script (see README.md)
|
||||
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ datarootdir = @datarootdir@
|
|||
YANG_INSTALLDIR = @YANG_INSTALLDIR@
|
||||
|
||||
YANGSPECS = clixon-config@2020-11-03.yang
|
||||
YANGSPECS += clixon-lib@2020-04-23.yang
|
||||
YANGSPECS += clixon-lib@2020-12-08.yang
|
||||
YANGSPECS += clixon-rfc5277@2008-07-01.yang
|
||||
YANGSPECS += clixon-xml-changelog@2019-03-21.yang
|
||||
YANGSPECS += clixon-restconf@2020-10-30.yang
|
||||
|
|
|
|||
126
yang/clixon/clixon-lib@2020-12-08.yang
Normal file
126
yang/clixon/clixon-lib@2020-12-08.yang
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
module clixon-lib {
|
||||
yang-version 1.1;
|
||||
namespace "http://clicon.org/lib";
|
||||
prefix cl;
|
||||
|
||||
organization
|
||||
"Clicon / Clixon";
|
||||
|
||||
contact
|
||||
"Olof Hagsand <olof@hagsand.se>";
|
||||
|
||||
description
|
||||
"Clixon Netconf extensions for communication between clients and backend.
|
||||
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
Copyright (C) 2009-2019 Olof Hagsand
|
||||
Copyright (C) 2020 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 2020-12-08 {
|
||||
description
|
||||
"Added: autocli-op extension.
|
||||
Released in clixon 4.9";
|
||||
}
|
||||
revision 2020-04-23 {
|
||||
description
|
||||
"Added: stats RPC for clixon XML and memory statistics.
|
||||
Added: restart-plugin RPC for restarting individual plugins without restarting backend.";
|
||||
}
|
||||
revision 2019-08-13 {
|
||||
description
|
||||
"No changes (reverted change)";
|
||||
}
|
||||
revision 2019-06-05 {
|
||||
description
|
||||
"ping rpc added for liveness";
|
||||
}
|
||||
revision 2019-01-02 {
|
||||
description
|
||||
"Released in Clixon 3.9";
|
||||
}
|
||||
extension autocli-op {
|
||||
description
|
||||
"Takes an argument an operation defing how to modify the clispec at
|
||||
this point in the YANG tree for the automated generated CLI.
|
||||
Note that this extension is only used in clixon_cli.
|
||||
Operations is expected to be extended, but the following operations are defined:
|
||||
- hide This command is active but not shown by ? or TAB";
|
||||
argument cliop;
|
||||
}
|
||||
rpc debug {
|
||||
description "Set debug level of backend.";
|
||||
input {
|
||||
leaf level {
|
||||
type uint32;
|
||||
}
|
||||
}
|
||||
}
|
||||
rpc ping {
|
||||
description "Check aliveness of backend daemon.";
|
||||
}
|
||||
rpc stats {
|
||||
description "Clixon XML statistics.";
|
||||
output {
|
||||
container global{
|
||||
description "Clixon global statistics";
|
||||
leaf xmlnr{
|
||||
description "Number of XML objects: number of residing xml/json objects
|
||||
in the internal 'cxobj' representation.";
|
||||
type uint64;
|
||||
}
|
||||
}
|
||||
list datastore{
|
||||
description "Datastore statistics";
|
||||
key "name";
|
||||
leaf name{
|
||||
description "name of datastore (eg running).";
|
||||
type string;
|
||||
}
|
||||
leaf nr{
|
||||
description "Number of XML objects. That is number of residing xml/json objects
|
||||
in the internal 'cxobj' representation.";
|
||||
type uint64;
|
||||
}
|
||||
leaf size{
|
||||
description "Size in bytes of internal datastore cache of datastore tree.";
|
||||
type uint64;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
rpc restart-plugin {
|
||||
description "Restart specific backend plugins.";
|
||||
input {
|
||||
leaf-list plugin {
|
||||
description "Name of plugin to restart";
|
||||
type string;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue