From 0ef0970c04188161b6e049c7193668910ececfc9 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Tue, 14 Feb 2023 15:57:17 +0100 Subject: [PATCH] Implemented: [Request to suppress auto-completion for "deprecated" / "obsolete" status and warn the user.](https://github.com/clicon/clixon/issues/410) --- CHANGELOG.md | 4 + apps/cli/cli_generate.c | 38 +++++- include/clixon_custom.h | 10 ++ test/test_autocli_obsolete.sh | 228 ++++++++++++++++++++++++++++++++++ 4 files changed, 276 insertions(+), 4 deletions(-) create mode 100755 test/test_autocli_obsolete.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index d535fd97..f8cc52e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -100,6 +100,10 @@ Developers may need to change their code ### Minor features +* [Request to suppress auto-completion for "deprecated" / "obsolete" status and warn the user.](https://github.com/clicon/clixon/issues/410) + * Solved by: + * Not generating any autocli syntax for obsolete YANG statements, + * Hide statements for deprecated YANG statements. * New plugin callbacks * `ca_yang_mount` - see the RFC 8528 support * `ca_yang_patch` - for modifying existing YANG modules diff --git a/apps/cli/cli_generate.c b/apps/cli/cli_generate.c index 7649d9a0..9960673f 100644 --- a/apps/cli/cli_generate.c +++ b/apps/cli/cli_generate.c @@ -137,7 +137,11 @@ cli_expand_var_generate(clicon_handle h, if (yang_extension_value(ys, "hide", CLIXON_AUTOCLI_NS, &extvalue, NULL) < 0) goto done; - if (extvalue) { + if (extvalue +#ifdef AUTOCLI_DEPRECATED_HIDE + || yang_find(ys, Y_STATUS, "deprecated") != NULL +#endif + ) { retval = 1; goto done; } @@ -810,8 +814,13 @@ yang2cli_leaf(clicon_handle h, cprintf(cb, " "); if (yang_extension_value(ys, "hide", CLIXON_AUTOCLI_NS, &hideext, NULL) < 0) goto done; - if (hideext) + if (hideext +#ifdef AUTOCLI_DEPRECATED_HIDE + || yang_find(ys, Y_STATUS, "deprecated") != NULL +#endif + ){ cprintf(cb, ", hide"); /* XXX ensure always { */ + } if (extralevel){ if (callback){ if (cli_callback_generate(h, ys, cb) < 0) @@ -901,8 +910,13 @@ yang2cli_container(clicon_handle h, goto done; if (yang_extension_value(ys, "hide", CLIXON_AUTOCLI_NS, &extvalue, NULL) < 0) goto done; - if (extvalue) + if (extvalue +#ifdef AUTOCLI_DEPRECATED_HIDE + || yang_find(ys, Y_STATUS, "deprecated") != NULL +#endif + ){ cprintf(cb, ", hide"); + } #ifdef NYI /* This is for the mode extension, not yet supported */ { int mode = 0; @@ -967,7 +981,11 @@ yang2cli_list(clicon_handle h, } if (yang_extension_value(ys, "hide", CLIXON_AUTOCLI_NS, &exist, NULL) < 0) goto done; - if (exist){ + if (exist +#ifdef AUTOCLI_DEPRECATED_HIDE + || yang_find(ys, Y_STATUS, "deprecated") != NULL +#endif + ){ cprintf(cb, ",hide"); } /* Loop over all key variables */ @@ -1091,6 +1109,17 @@ yang2cli_stmt(clicon_handle h, int retval = -1; int treeref_state = 0; + if (ys == NULL){ + clicon_err(OE_YANG, EINVAL, "No yang spec"); + goto done; + } + if (yang_find(ys, Y_STATUS, "obsolete") != NULL){ + clicon_debug(4, "%s obsolete: %s %s, skipped", __FUNCTION__, yang_argument_get(ys), yang_argument_get(ys_module(ys))); + goto ok; + } + 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))); + } /* Only produce autocli for YANG non-config only if autocli-treeref-state is true */ if (autocli_treeref_state(h, &treeref_state) < 0) goto done; @@ -1128,6 +1157,7 @@ yang2cli_stmt(clicon_handle h, break; } } + ok: retval = 0; done: return retval; diff --git a/include/clixon_custom.h b/include/clixon_custom.h index 4415a22f..b51b3216 100644 --- a/include/clixon_custom.h +++ b/include/clixon_custom.h @@ -191,3 +191,13 @@ * To keep the previous behavior (as in 6.0) set this option with #define */ #undef NETCONF_DEFAULT_RETRIEVAL_REPORT_ALL + +/*! Temporary backward-compatible option for not generating CLI for obsolete YANG + * Introduced in 6.1, remove in 6.2 + */ +#define AUTOCLI_OBSOLETE_SKIP + +/*! Temporary backward-compatible option for hiding CLI for deprecated YANG + * Introduced in 6.1, remove in 6.2 + */ +#define AUTOCLI_DEPRECATED_HIDE diff --git a/test/test_autocli_obsolete.sh b/test/test_autocli_obsolete.sh new file mode 100755 index 00000000..b30d5d56 --- /dev/null +++ b/test/test_autocli_obsolete.sh @@ -0,0 +1,228 @@ +#!/usr/bin/env bash +# Test of autocli for yang status value: +# - depreceted - hidden +# - obsolete - skipped + +# 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 + +# include err() and new() functions and creates $dir + +cfg=$dir/conf_yang.xml +clispec=$dir/automode.cli +fyang=$dir/clixon-example.yang + +cat < $fyang +module clixon-example { + yang-version 1.1; + namespace "urn:example:clixon"; + prefix ex; + /* Generic config data */ + container table{ + list parameter{ + key name; + leaf name{ + type string; + } + leaf value{ + type string; + } + } + } + container container-obsolete{ + status obsolete; + list parameter{ + key name; + leaf name{ + type string; + } + leaf value{ + type string; + } + } + } + container list-obsolete{ + list parameter{ + key name; + status obsolete; + leaf name{ + type string; + } + leaf value{ + type string; + } + } + } + container leaf-obsolete{ + list parameter{ + key name; + leaf name{ + type string; + } + leaf value{ + status obsolete; + type string; + } + } + } + container container-deprecated{ + status deprecated; + list parameter{ + key name; + leaf name{ + type string; + } + leaf value{ + type string; + } + } + } + container list-deprecated{ + list parameter{ + key name; + status deprecated; + leaf name{ + type string; + } + leaf value{ + type string; + } + } + } + container leaf-deprecated{ + list parameter{ + key name; + leaf name{ + type string; + } + leaf value{ + status deprecated; + type string; + } + } + } + +} +EOF + +cat < $clispec +CLICON_MODE="example"; +CLICON_PROMPT="%U@%H %W> "; +CLICON_PLUGIN="example_cli"; + +# Autocli syntax tree operations +set @datamodel, cli_auto_set(); +merge @datamodel, cli_auto_merge(); +create @datamodel, cli_auto_create(); +delete("Delete a configuration item") @datamodel, cli_auto_del(); +validate("Validate changes"), cli_validate(); +commit("Commit the changes"), cli_commit(); +quit("Quit"), cli_quit(); +show("Show a particular state of the system"){ + configuration("Show configuration"), cli_show_auto_mode("candidate", "text", true, false);{ + xml("Show configuration as XML"), cli_show_auto_mode("candidate", "xml", false, false); + cli("Show configuration as CLI commands"), cli_show_auto_mode("candidate", "cli", false, false, "report-all", "set "); + netconf("Show configuration as netconf edit-config operation"), cli_show_auto_mode("candidate", "netconf", false, false); + text("Show configuration as text"), cli_show_auto_mode("candidate", "text", false, false); + json("Show configuration as JSON"), cli_show_auto_mode("candidate", "json", false, false); + } + state("Show configuration and state"), cli_show_auto_mode("running", "xml", false, true); +} +EOF + +# Use yang in example +cat < $cfg + + $cfg + ietf-netconf:startup + ${YANG_INSTALLDIR} + $IETFRFC + $dir + /usr/local/lib/$APPNAME/backend + $APPNAME + /usr/local/lib/$APPNAME/cli + $dir + /usr/local/var/$APPNAME/$APPNAME.sock + /usr/local/var/$APPNAME/$APPNAME.pidfile + $dir + false + ${AUTOCLI} + +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 startup -f $cfg" + start_backend -s startup -f $cfg +fi + +new "wait backend" +wait_backend + +new "set table expected ok" +expectpart "$($clixon_cli -1 -f $cfg set table parameter x value 42)" 0 "^$" + +new "check completion on query" +expectpart "$(echo "set ?" | $clixon_cli -f $cfg 2>&1)" 0 "table" "list-obsolete" "list-deprecated" "leaf-obsolete" "leaf-deprecated" --not-- "container-obsolete" "container-deprecated" + +new "set container obsolete expected fail" +expectpart "$($clixon_cli -1 -f $cfg set container-obsolete 2>&1)" 255 "CLI syntax error" + +new "set list obsolete expected ok" +expectpart "$($clixon_cli -1 -f $cfg set list-obsolete 2>&1)" 0 "^$" + +new "set list obsolete expected fail" +expectpart "$($clixon_cli -1 -f $cfg set list-obsolete parameter x 2>&1)" 255 "CLI syntax error" + +new "set leaf obsolete expected ok" +expectpart "$($clixon_cli -1 -f $cfg set leaf-obsolete parameter x 2>&1)" 0 "^$" + +new "set leaf obsolete expected fail" +expectpart "$($clixon_cli -1 -f $cfg set leaf-obsolete parameter x value 42 2>&1)" 255 "CLI syntax error" + +# deprecated +new "set container deprecated expected fail" +expectpart "$($clixon_cli -1 -f $cfg set container-deprecated parameter x value 33 2>&1)" 0 "^$" + +new "check container depreatced ?" +expectpart "$(echo "set container-deprecated ? " | $clixon_cli -f $cfg 2>&1)" 0 --not-- "parameter" + +new "set list deprecated expected ok" +expectpart "$($clixon_cli -1 -f $cfg set list-deprecated parameter x value 32 2>&1)" 0 "^$" + +new "check list deprecated ?" +expectpart "$(echo "set list-deprecated ? " | $clixon_cli -f $cfg 2>&1)" 0 --not-- "parameter" + +new "set leaf deprecated expected ok" +expectpart "$($clixon_cli -1 -f $cfg set leaf-deprecated parameter x value 44 2>&1)" 0 "^$" + +new "check leaf deprecated ?" +expectpart "$(echo "set leaf-deprecated ? " | $clixon_cli -f $cfg 2>&1)" 0 "parameter" + +new "check leaf deprecated ?" +expectpart "$(echo "set leaf-deprecated parameter x ? " | $clixon_cli -f $cfg 2>&1)" 0 --not-- 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