From 1a9def2f6eac9fb9d7c29f4b09adf33273a5dde7 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Fri, 1 Apr 2022 18:05:19 +0200 Subject: [PATCH] [provide support for load config of cli format along with json and xml format as save config is supported for all 3 formats](https://github.com/clicon/clixon/issues/320) --- CHANGELOG.md | 1 + apps/cli/cli_common.c | 32 +++++++++++++++++ example/main/example_cli.cli | 4 ++- test/test_cli.sh | 67 +++++++++++++++++++++++++++++++++++- 4 files changed, 102 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5e9fe75..3755a445 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,7 @@ Users may have to change how they access the system ### Minor features +* [provide support for load config of cli format along with json and xml format as save config is supported for all 3 formats](https://github.com/clicon/clixon/issues/320) * [prevent clixon-restconf@2021-05-20.yang module from loading](https://github.com/clicon/clixon/issues/318) * Instead of always loading it, load it to datastore YANGs only if `CLICON_BACKEND_RESTCONF_PROCESS` is `true` * YANG unique: added single descendant node ids as special case diff --git a/apps/cli/cli_common.c b/apps/cli/cli_common.c index bb02a6a3..ff2e8001 100644 --- a/apps/cli/cli_common.c +++ b/apps/cli/cli_common.c @@ -68,6 +68,7 @@ #include #include "clixon_cli_api.h" +#include "cli_plugin.h" #include "cli_common.h" /*! Register log notification stream @@ -867,6 +868,36 @@ load_config_file(clicon_handle h, goto done; } break; + case FORMAT_CLI: + { + char *mode = cli_syntax_mode(h); + cligen_result result; /* match result */ + int evalresult = 0; /* if result == 1, calback result */ + char *lineptr = NULL; + size_t n; + + while(!cligen_exiting(cli_cligen(h))) { + lineptr = NULL; n = 0; + if (getline(&lineptr, &n, fp) < 0){ + if (errno){ + clicon_err(OE_UNIX, errno, "getline"); + goto done; + } + goto ok; /* eof, skip backend rpc since this is done by cli code */ + } + if (clicon_parse(h, lineptr, &mode, &result, &evalresult) < 0) + goto done; + if (result != 1) /* Not unique match */ + goto done; + if (evalresult < 0) + goto done; + if (lineptr){ + free(lineptr); + lineptr = NULL; + } + } + break; + } default: clicon_err(OE_PLUGIN, 0, "format: %s not implemented", formatstr); goto done; @@ -888,6 +919,7 @@ load_config_file(clicon_handle h, cbuf_get(cbxml)) < 0) goto done; cbuf_free(cbxml); + ok: ret = 0; done: if (xerr) diff --git a/example/main/example_cli.cli b/example/main/example_cli.cli index 1668587a..07b529b7 100644 --- a/example/main/example_cli.cli +++ b/example/main/example_cli.cli @@ -83,7 +83,7 @@ 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", true, false); - cli("Show configuration as CLI commands"), cli_auto_show("datamodel", "candidate", "cli", true, false, "set "); +oad cli("Show configuration as CLI commands"), cli_auto_show("datamodel", "candidate", "cli", true, false, "set "); netconf("Show configuration as netconf edit-config operation"), cli_auto_show("datamodel", "candidate", "netconf", true, false); text("Show configuration as text"), cli_auto_show("datamodel", "candidate", "text", true, false); json("Show configuration as JSON"), cli_auto_show("datamodel", "candidate", "json", true, false); @@ -105,10 +105,12 @@ save("Save candidate configuration to XML file") ("Filename (lo } load("Load configuration from XML file") ("Filename (local filename)"),load_config_file("filename", "replace");{ replace("Replace candidate with file contents"), load_config_file("filename", "replace");{ + cli("Replace candidate with file containing CLI commands"), load_config_file("","filename", "replace", "cli"); xml("Replace candidate with file containing XML"), load_config_file("","filename", "replace", "xml"); json("Replace candidate with file containing JSON"), load_config_file("","filename", "replace", "json"); } merge("Merge file with existent candidate"), load_config_file("filename", "merge");{ + cli("Merge candidate with file containing CLI commands"), load_config_file("","filename", "merge", "cli"); xml("Merge candidate with file containing XML"), load_config_file("","filename", "merge", "xml"); json("Merge candidate with file containing JSON"), load_config_file("","filename", "merge", "json"); } diff --git a/test/test_cli.sh b/test/test_cli.sh index a572e5df..3e55b3a1 100755 --- a/test/test_cli.sh +++ b/test/test_cli.sh @@ -15,6 +15,12 @@ APPNAME=example # include err() and new() functions and creates $dir cfg=$dir/conf_yang.xml +clidir=$dir/cli +if [ -d $clidir ]; then + rm -rf $clidir/* +else + mkdir $clidir +fi # Use yang in example @@ -27,13 +33,62 @@ cat < $cfg /usr/local/lib/$APPNAME/backend $APPNAME /usr/local/lib/$APPNAME/cli - /usr/local/lib/$APPNAME/clispec + $clidir /usr/local/var/$APPNAME/$APPNAME.sock /usr/local/var/$APPNAME/$APPNAME.pidfile /usr/local/var/$APPNAME EOF +cat < $clidir/ex.cli +# Clixon example specification +CLICON_MODE="example"; +CLICON_PROMPT="%U@%H %W> "; +CLICON_PLUGIN="example_cli"; + +set @datamodel, cli_auto_set(); +delete("Delete a configuration item") { + @datamodel, cli_auto_del(); + all("Delete whole candidate configuration"), delete_all("candidate"); +} +validate("Validate changes"), cli_validate(); +commit("Commit the changes"), cli_commit(); +quit("Quit"), cli_quit(); +shell("System command") , cli_start_shell(); +copy("Copy and create a new object"){ + interface("Copy interface"){ + (|("name of interface to copy from")) to("Copy to interface") ("Name of interface to copy to"), cli_copy_config("candidate","//interface[%s='%s']","urn:ietf:params:xml:ns:yang:ietf-interfaces","name","name","toname"); + } +} +discard("Discard edits (rollback 0)"), discard_changes(); + + +debug("Debugging parts of the system"){ + cli("Set cli debug") ("Set debug level (0..n)"), cli_debug_cli(); +} +show("Show a particular state of the system"){ + xpath("Show configuration") ("XPATH expression") ("Namespace"), show_conf_xpath("candidate"); + compare("Compare candidate and running databases"), compare_dbs((int32)0);{ + xml("Show comparison in xml"), compare_dbs((int32)0); + text("Show comparison in text"), compare_dbs((int32)1); + } + configuration("Show configuration"), cli_auto_show("datamodel", "candidate", "text", true, false);{ + cli("Show configuration as CLI commands"), cli_auto_show("datamodel", "candidate", "cli", true, false, "set "); + } +} +save("Save candidate configuration to XML file") ("Filename (local filename)"), save_config_file("candidate","filename", "xml"); +load("Load configuration from XML file") ("Filename (local filename)"),load_config_file("filename", "replace"); + +rpc("example rpc") ("routing instance"), example_client_rpc(""); + +# Special cli bug with choice+dbexpand, part1 set db symbol +choicebug { + ; + ; +} + +EOF + new "test params: -f $cfg" if [ $BE -ne 0 ]; then new "kill old backend" @@ -132,6 +187,16 @@ new "cli rpc" # We dont know which message-id the cli app uses expectpart "$($clixon_cli -1 -f $cfg -l o rpc ipv4)" 0 "ipv442" +new "cli bug with choice+dbexpand, part1 set db symbol" +expectpart "$($clixon_cli -1 -f $cfg set table parameter foobar)" 0 "^$" + +# Here can be error: ambiguous +new "cli bug with choice+dbexpand: part2, make same choice" +expectpart "$($clixon_cli -1 -f $cfg choicebug foobar)" 0 "^$" + +new "cli discard" +expectpart "$($clixon_cli -1 -f $cfg discard)" 0 "^$" + if [ $BE -ne 0 ]; then new "Kill backend" # Check if premature kill