* 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:
Olof hagsand 2020-12-08 17:21:37 +01:00
parent e1b94d94d2
commit b8641f30bd
14 changed files with 547 additions and 50 deletions

View file

@ -64,6 +64,11 @@ Developers may need to change their code
### Minor changes ### 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` * Added new revision of main example yang: `clixon-example@2020-12-01.yang`
* Support for building static lib: `LINKAGE=static configure` * Support for building static lib: `LINKAGE=static configure`
* Change comment character to be active anywhere to beginning of _word_ only. * Change comment character to be active anywhere to beginning of _word_ only.

View file

@ -659,10 +659,12 @@ yang2cli_leaf(clicon_handle h,
int key_leaf, int key_leaf,
cbuf *cb) cbuf *cb)
{ {
yang_stmt *yd; /* description */ yang_stmt *yd; /* description */
int retval = -1; int retval = -1;
char *helptext = NULL; char *helptext = NULL;
char *s; char *s;
char *opext = NULL;
int extralevel = 0;
/* description */ /* description */
if ((yd = yang_find(ys, Y_DESCRIPTION, NULL)) != NULL){ if ((yd = yang_find(ys, Y_DESCRIPTION, NULL)) != NULL){
@ -674,27 +676,40 @@ yang2cli_leaf(clicon_handle h,
*s = '\0'; *s = '\0';
} }
cprintf(cb, "%*s", level*3, ""); 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){ if (gt == GT_VARS|| gt == GT_ALL || gt == GT_HIDE){
cprintf(cb, "%s", yang_argument_get(ys)); cprintf(cb, "%s", yang_argument_get(ys));
yang2cli_helptext(cb, helptext); yang2cli_helptext(cb, helptext);
cprintf(cb, " "); 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) if (yang2cli_var(h, ys, helptext, cb) < 0)
goto done; goto done;
} }
} }
else
if ((show_tree == 0) || (key_leaf == 1)) {
if (yang2cli_var(h, ys, helptext, cb) < 0)
goto done;
}
if (callback){ if (callback){
if (cli_callback_generate(h, ys, cb) < 0) if (cli_callback_generate(h, ys, cb) < 0)
goto done; goto done;
cprintf(cb, ";\n"); cprintf(cb, ";\n");
} }
if (extralevel)
cprintf(cb, "}\n");
retval = 0; retval = 0;
done: done:
if (helptext) if (helptext)
@ -787,9 +802,18 @@ yang2cli_list(clicon_handle h,
int retval = -1; int retval = -1;
char *helptext = NULL; char *helptext = NULL;
char *s; 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)); 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 ((yd = yang_find(ys, Y_DESCRIPTION, NULL)) != NULL){
if ((helptext = strdup(yang_argument_get(yd))) == NULL){ if ((helptext = strdup(yang_argument_get(yd))) == NULL){
clicon_err(OE_UNIX, errno, "strdup"); clicon_err(OE_UNIX, errno, "strdup");
@ -811,25 +835,25 @@ yang2cli_list(clicon_handle h,
goto done; goto done;
} }
/* Print key variable now, and skip it in loop below /* 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; last_key = cvec_next(cvk, cvi)?0:1;
if (show_tree == 1) { if (last_key){
if (list_has_callback) { if (show_tree) {
if (cli_callback_generate(h, ys, cb) < 0) if (cli_callback_generate(h, ys, cb) < 0)
goto done; goto done;
cprintf(cb, ";\n"); cprintf(cb, ";\n");
cprintf(cb, "{\n"); cprintf(cb, "{\n");
} }
else if (extralevel)
cprintf(cb, "{\n");
} }
if (yang2cli_leaf(h, yleaf, if (yang2cli_leaf(h, yleaf,
(gt==GT_VARS||gt==GT_HIDE)?GT_NONE:gt, level+1, (gt==GT_VARS||gt==GT_HIDE)?GT_NONE:gt, level+1,
list_has_callback, show_tree, 1, last_key, show_tree, 1,
cb) < 0) cb) < 0)
goto done; goto done;
} }
cprintf(cb, "{\n"); cprintf(cb, "{\n");
yc = NULL; yc = NULL;
while ((yc = yn_each(ys, yc)) != NULL) { while ((yc = yn_each(ys, yc)) != NULL) {
@ -848,7 +872,7 @@ yang2cli_list(clicon_handle h,
goto done; goto done;
} }
cprintf(cb, "%*s}\n", level*3, ""); 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, ""); cprintf(cb, "%*s}\n", level*3, "");
} }
retval = 0; retval = 0;
@ -1013,8 +1037,7 @@ yang2cli(clicon_handle h,
if ((globals = cvec_new(0)) == NULL) if ((globals = cvec_new(0)) == NULL)
goto done; goto done;
/* load cli syntax */ /* load cli syntax */
if (cligen_parse_str(cli_cligen(h), cbuf_get(cb), if (cligen_parse_str(cli_cligen(h), cbuf_get(cb), "yang2cli", pt, globals) < 0)
"yang2cli", pt, globals) < 0)
goto done; goto done;
cvec_free(globals); cvec_free(globals);
/* Resolve the expand callback functions in the generated syntax. /* Resolve the expand callback functions in the generated syntax.

View file

@ -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, int yang_type_cache_set(yang_stmt *ys, yang_stmt *resolved, int options, cvec *cvv,
cvec *patterns, uint8_t fraction); cvec *patterns, uint8_t fraction);
yang_stmt *yang_anydata_add(yang_stmt *yp, char *name); 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_ */ #endif /* _CLIXON_YANG_H_ */

View file

@ -985,8 +985,8 @@ yang_find_schemanode(yang_stmt *yn,
* @retval NULL No prefix found. This is an error * @retval NULL No prefix found. This is an error
* @retval prefix OK: Prefix as char* pointer into yang tree * @retval prefix OK: Prefix as char* pointer into yang tree
* @code * @code
* char *myprefix; * char *myprefix;
* myprefix = yang_find_myprefix(ys); * myprefix = yang_find_myprefix(ys);
* @endcode * @endcode
*/ */
char * char *
@ -3236,6 +3236,65 @@ yang_anydata_add(yang_stmt *yp,
return ys; 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 #ifdef XML_EXPLICIT_INDEX
/*! Mark element as search_index in list /*! Mark element as search_index in list
* @retval 0 OK * @retval 0 OK

View file

@ -1393,6 +1393,7 @@ augment_substmt : when_stmt { clicon_debug(3,"augment-substmt -> when-s
| case_stmt { clicon_debug(3,"augment-substmt -> case-stmt");} | case_stmt { clicon_debug(3,"augment-substmt -> case-stmt");}
| action_stmt { clicon_debug(3,"augment-substmt -> action-stmt");} | action_stmt { clicon_debug(3,"augment-substmt -> action-stmt");}
| notification_stmt { clicon_debug(3,"augment-substmt -> notification-stmt");} | notification_stmt { clicon_debug(3,"augment-substmt -> notification-stmt");}
| unknown_stmt { clicon_debug(3,"augment-substmt -> unknown-stmt");}
| { clicon_debug(3,"augment-substmt -> "); } | { clicon_debug(3,"augment-substmt -> "); }
; ;

View file

@ -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. /* 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 ? */ * which means it is slightly different than a schema-nodeid ? */
targetkey = yang_keyword_get(ytarget); 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 */ /* Find when statement, if present */
if ((ywhen = yang_find(ys, Y_WHEN, NULL)) != NULL){ 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 */ /* Extend ytarget with ys' schemanode children */
yc0 = NULL; yc0 = NULL;
while ((yc0 = yn_each(ys, yc0)) != NULL) { while ((yc0 = yn_each(ys, yc0)) != NULL) {
if (!yang_schemanode(yc0))
continue;
childkey = yang_keyword_get(yc0); childkey = yang_keyword_get(yc0);
/* Only shemanodes and extensions */
if (!yang_schemanode(yc0) && childkey != Y_UNKNOWN)
continue;
switch (targetkey){ switch (targetkey){
case Y_CONTAINER: case Y_CONTAINER:
case Y_LIST: case Y_LIST:
/* If the target node is a container or list node, the "action" and /* If the target node is a container or list node, the "action" and
"notification" statements can be used within the "augment" statement. "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_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){
clicon_log(LOG_WARNING, "Warning: A Augment failed in module %s: node %s %d cannot be added to target node %s", clicon_log(LOG_WARNING, "Warning: A Augment failed in module %s: node %s %d cannot be added to target node %s",
@ -300,8 +292,9 @@ yang_augment_node(yang_stmt *ys)
notification node, the "container", "leaf", "list", "leaf-list", notification node, the "container", "leaf", "list", "leaf-list",
"uses", and "choice" statements can be used within the "augment" "uses", and "choice" statements can be used within the "augment"
statement. */ statement. */
if (childkey != Y_CONTAINER && childkey != Y_LEAF && childkey != Y_LIST && 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", 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_argument_get(ys_module(ys)),
yang_key2str(childkey), yang_key2str(childkey),

288
test/test_cli_auto_extension.sh Executable file
View 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

View file

@ -81,7 +81,7 @@ enter1 <string>, cli_auto_sub_enter("datamodel", "/example:table/parameter=%s/in
leave, cli_auto_top("datamodel", "candidate"); leave, cli_auto_top("datamodel", "candidate");
# Autocli syntax tree operations # Autocli syntax tree operations
edit @datamodel, cli_auto_edit("interface"); edit @datamodel, cli_auto_edit("datamodel");
up, cli_auto_up("datamodel"); up, cli_auto_up("datamodel");
top, cli_auto_top("datamodel"); top, cli_auto_top("datamodel");
set @datamodel, cli_auto_set(); set @datamodel, cli_auto_set();

View file

@ -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"}\]}' 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" 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" 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" expectpart "$(curl $CURLOPTS -X OPTIONS $proto://$addr/restconf/data)" 0 "HTTP/1.1 200 OK" "Allow: OPTIONS,HEAD,GET,POST,PUT,PATCH,DELETE"

View file

@ -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 # This just catches the header and the jukebox module, the RFC has foo and bar which
# seems wrong to recreate # seems wrong to recreate
new "B.1.2. Retrieve the Server Module Information" 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" 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> 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>

View file

@ -301,7 +301,7 @@ cat <<EOF > $dir/startup_db
</config> </config>
EOF 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>' MODSTATE2='<module><name>interfaces</name><revision>2018-02-20</revision><namespace>urn:example:interfaces</namespace></module>'

View file

@ -14,6 +14,8 @@
# #
# 2) The extensions results in in a node data definition. # 2) The extensions results in in a node data definition.
# Second, the example is run without the extension enabled, then it is enabled. # 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) # Magic line must be first in script (see README.md)
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi

View file

@ -43,7 +43,7 @@ datarootdir = @datarootdir@
YANG_INSTALLDIR = @YANG_INSTALLDIR@ YANG_INSTALLDIR = @YANG_INSTALLDIR@
YANGSPECS = clixon-config@2020-11-03.yang 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-rfc5277@2008-07-01.yang
YANGSPECS += clixon-xml-changelog@2019-03-21.yang YANGSPECS += clixon-xml-changelog@2019-03-21.yang
YANGSPECS += clixon-restconf@2020-10-30.yang YANGSPECS += clixon-restconf@2020-10-30.yang

View 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;
}
}
}
}