From b8641f30bde5cf1d71a0f73d4c21754294ccac50 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Tue, 8 Dec 2020 17:21:37 +0100 Subject: [PATCH] * 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 --- CHANGELOG.md | 5 + apps/cli/cli_generate.c | 79 ++++--- lib/clixon/clixon_yang.h | 2 +- lib/src/clixon_yang.c | 63 +++++- lib/src/clixon_yang_parse.y | 1 + lib/src/clixon_yang_parse_lib.c | 21 +- test/test_cli_auto_extension.sh | 288 +++++++++++++++++++++++++ test/test_cli_auto_sub.sh | 2 +- test/test_restconf.sh | 2 +- test/test_restconf_jukebox.sh | 2 +- test/test_upgrade_quit.sh | 2 +- test/test_yang_extension.sh | 2 + yang/clixon/Makefile.in | 2 +- yang/clixon/clixon-lib@2020-12-08.yang | 126 +++++++++++ 14 files changed, 547 insertions(+), 50 deletions(-) create mode 100755 test/test_cli_auto_extension.sh create mode 100644 yang/clixon/clixon-lib@2020-12-08.yang diff --git a/CHANGELOG.md b/CHANGELOG.md index 2534f737..5aefe207 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. diff --git a/apps/cli/cli_generate.c b/apps/cli/cli_generate.c index b756b8a9..22581dd6 100644 --- a/apps/cli/cli_generate.c +++ b/apps/cli/cli_generate.c @@ -659,10 +659,12 @@ yang2cli_leaf(clicon_handle h, int key_leaf, cbuf *cb) { - yang_stmt *yd; /* description */ - int retval = -1; - char *helptext = NULL; - char *s; + yang_stmt *yd; /* description */ + 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) { - if (cli_callback_generate(h, ys, cb) < 0) - goto done; - cprintf(cb, ";\n"); - cprintf(cb, "{\n"); - } + 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. diff --git a/lib/clixon/clixon_yang.h b/lib/clixon/clixon_yang.h index 22d5ad1e..72b76f16 100644 --- a/lib/clixon/clixon_yang.h +++ b/lib/clixon/clixon_yang.h @@ -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_ */ diff --git a/lib/src/clixon_yang.c b/lib/src/clixon_yang.c index d986426d..3c7fd56d 100644 --- a/lib/src/clixon_yang.c +++ b/lib/src/clixon_yang.c @@ -985,8 +985,8 @@ yang_find_schemanode(yang_stmt *yn, * @retval NULL No prefix found. This is an error * @retval prefix OK: Prefix as char* pointer into yang tree * @code - * char *myprefix; - * myprefix = yang_find_myprefix(ys); + * char *myprefix; + * myprefix = yang_find_myprefix(ys); * @endcode */ char * @@ -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 diff --git a/lib/src/clixon_yang_parse.y b/lib/src/clixon_yang_parse.y index a28d55eb..04fbc1ed 100644 --- a/lib/src/clixon_yang_parse.y +++ b/lib/src/clixon_yang_parse.y @@ -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 -> "); } ; diff --git a/lib/src/clixon_yang_parse_lib.c b/lib/src/clixon_yang_parse_lib.c index 54ca4200..cca55d71 100644 --- a/lib/src/clixon_yang_parse_lib.c +++ b/lib/src/clixon_yang_parse_lib.c @@ -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", @@ -300,8 +292,9 @@ yang_augment_node(yang_stmt *ys) notification node, the "container", "leaf", "list", "leaf-list", "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){ + if (childkey != Y_CONTAINER && childkey != Y_LEAF && childkey != Y_LIST && + 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), diff --git a/test/test_cli_auto_extension.sh b/test/test_cli_auto_extension.sh new file mode 100755 index 00000000..1a463800 --- /dev/null +++ b/test/test_cli_auto_extension.sh @@ -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 < $cfg + + $cfg + ietf-netconf:startup + /usr/local/share/clixon + $dir + $dir + /usr/local/lib/$APPNAME/backend + $clidir + /usr/local/lib/$APPNAME/cli + $APPNAME + 2 + VARS + /usr/local/var/$APPNAME/$APPNAME.sock + /usr/local/var/$APPNAME/$APPNAME.pidfile + $dir + false + +EOF + + +cat < $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 < $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 < $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" "" --not-- "parameter" + + cat < $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" "x
" + +} + +testvalue() +{ + # Try not hidden parameter list + new "query table parameter hidden" + expectpart "$(echo "set table ?" | $clixon_cli -f $cfg 2>&1)" 0 "set table" "" "parameter" + + # Try hidden value + new "query table leaf" + expectpart "$(echo "set table parameter x ?" | $clixon_cli -f $cfg 2>&1)" 0 "index" "" --not-- "value" + + cat < $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 "x42
" + +} + +# INLINE MODE + +new "Test hidden parameter in table/param inline" +testparam + +# Second annotate /table/parameter/value +cat < $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 < $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 < $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 < $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 diff --git a/test/test_cli_auto_sub.sh b/test/test_cli_auto_sub.sh index d0f0eecb..9e90b369 100755 --- a/test/test_cli_auto_sub.sh +++ b/test/test_cli_auto_sub.sh @@ -81,7 +81,7 @@ enter1 , 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(); diff --git a/test/test_restconf.sh b/test/test_restconf.sh index ba62d649..fe2ebed4 100755 --- a/test/test_restconf.sh +++ b/test/test_restconf.sh @@ -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" diff --git a/test/test_restconf_jukebox.sh b/test/test_restconf_jukebox.sh index bcb5373c..089ee1d7 100755 --- a/test/test_restconf_jukebox.sh +++ b/test/test_restconf_jukebox.sh @@ -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' 'urn:ietf:params:restconf:capability:defaults:1.0?basic-mode=expliciturn:ietf:params:restconf:capability:depth diff --git a/test/test_upgrade_quit.sh b/test/test_upgrade_quit.sh index 641c392c..1965e1a6 100755 --- a/test/test_upgrade_quit.sh +++ b/test/test_upgrade_quit.sh @@ -301,7 +301,7 @@ cat < $dir/startup_db EOF -MODSTATE1='0clixon-lib2020-04-23http://clicon.org/lib' +MODSTATE1='0clixon-lib2020-12-08http://clicon.org/lib' MODSTATE2='interfaces2018-02-20urn:example:interfaces' diff --git a/test/test_yang_extension.sh b/test/test_yang_extension.sh index a6577e2c..b819e812 100755 --- a/test/test_yang_extension.sh +++ b/test/test_yang_extension.sh @@ -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 diff --git a/yang/clixon/Makefile.in b/yang/clixon/Makefile.in index 5cd3e054..75fd9347 100644 --- a/yang/clixon/Makefile.in +++ b/yang/clixon/Makefile.in @@ -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 diff --git a/yang/clixon/clixon-lib@2020-12-08.yang b/yang/clixon/clixon-lib@2020-12-08.yang new file mode 100644 index 00000000..d2678bde --- /dev/null +++ b/yang/clixon/clixon-lib@2020-12-08.yang @@ -0,0 +1,126 @@ +module clixon-lib { + yang-version 1.1; + namespace "http://clicon.org/lib"; + prefix cl; + + organization + "Clicon / Clixon"; + + contact + "Olof Hagsand "; + + 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; + } + } + } +}