[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)

This commit is contained in:
Olof hagsand 2022-04-01 18:05:19 +02:00
parent 3d648bc08f
commit 1a9def2f6e
4 changed files with 102 additions and 2 deletions

View file

@ -64,6 +64,7 @@ Users may have to change how they access the system
### Minor features ### 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) * [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` * 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 * YANG unique: added single descendant node ids as special case

View file

@ -68,6 +68,7 @@
#include <clixon/clixon.h> #include <clixon/clixon.h>
#include "clixon_cli_api.h" #include "clixon_cli_api.h"
#include "cli_plugin.h"
#include "cli_common.h" #include "cli_common.h"
/*! Register log notification stream /*! Register log notification stream
@ -867,6 +868,36 @@ load_config_file(clicon_handle h,
goto done; goto done;
} }
break; 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: default:
clicon_err(OE_PLUGIN, 0, "format: %s not implemented", formatstr); clicon_err(OE_PLUGIN, 0, "format: %s not implemented", formatstr);
goto done; goto done;
@ -888,6 +919,7 @@ load_config_file(clicon_handle h,
cbuf_get(cbxml)) < 0) cbuf_get(cbxml)) < 0)
goto done; goto done;
cbuf_free(cbxml); cbuf_free(cbxml);
ok:
ret = 0; ret = 0;
done: done:
if (xerr) if (xerr)

View file

@ -83,7 +83,7 @@ show("Show a particular state of the system"){
} }
configuration("Show configuration"), cli_auto_show("datamodel", "candidate", "text", true, false);{ configuration("Show configuration"), cli_auto_show("datamodel", "candidate", "text", true, false);{
xml("Show configuration as XML"), cli_auto_show("datamodel", "candidate", "xml", 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); 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); 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); 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:string>("Filename (lo
} }
load("Load configuration from XML file") <filename:string>("Filename (local filename)"),load_config_file("filename", "replace");{ load("Load configuration from XML file") <filename:string>("Filename (local filename)"),load_config_file("filename", "replace");{
replace("Replace candidate with file contents"), 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"); 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"); json("Replace candidate with file containing JSON"), load_config_file("","filename", "replace", "json");
} }
merge("Merge file with existent candidate"), load_config_file("filename", "merge");{ 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"); 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"); json("Merge candidate with file containing JSON"), load_config_file("","filename", "merge", "json");
} }

View file

@ -15,6 +15,12 @@ APPNAME=example
# include err() and new() functions and creates $dir # include err() and new() functions and creates $dir
cfg=$dir/conf_yang.xml cfg=$dir/conf_yang.xml
clidir=$dir/cli
if [ -d $clidir ]; then
rm -rf $clidir/*
else
mkdir $clidir
fi
# Use yang in example # Use yang in example
@ -27,13 +33,62 @@ cat <<EOF > $cfg
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR> <CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE> <CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR> <CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR> <CLICON_CLISPEC_DIR>$clidir</CLICON_CLISPEC_DIR>
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK> <CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE> <CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR> <CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
</clixon-config> </clixon-config>
EOF EOF
cat <<EOF > $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") <source:rest>, cli_start_shell();
copy("Copy and create a new object"){
interface("Copy interface"){
(<name:string>|<name:string expand_dbvar("candidate","/ietf-interfaces:interfaces/interface=%s/name")>("name of interface to copy from")) to("Copy to interface") <toname:string>("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") <level:int32>("Set debug level (0..n)"), cli_debug_cli();
}
show("Show a particular state of the system"){
xpath("Show configuration") <xpath:string>("XPATH expression") <ns:string>("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:string>("Filename (local filename)"), save_config_file("candidate","filename", "xml");
load("Load configuration from XML file") <filename:string>("Filename (local filename)"),load_config_file("filename", "replace");
rpc("example rpc") <a:string>("routing instance"), example_client_rpc("");
# Special cli bug with choice+dbexpand, part1 set db symbol
choicebug {
<name:string choice:foobar>;
<name:string expand_dbvar("candidate","/clixon-example:table/parameter/name")>;
}
EOF
new "test params: -f $cfg" new "test params: -f $cfg"
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "kill old backend" new "kill old backend"
@ -132,6 +187,16 @@ new "cli rpc"
# We dont know which message-id the cli app uses # We dont know which message-id the cli app uses
expectpart "$($clixon_cli -1 -f $cfg -l o rpc ipv4)" 0 "<rpc-reply $DEFAULTONLY message-id=" "><x xmlns=\"urn:example:clixon\">ipv4</x><y xmlns=\"urn:example:clixon\">42</y></rpc-reply>" expectpart "$($clixon_cli -1 -f $cfg -l o rpc ipv4)" 0 "<rpc-reply $DEFAULTONLY message-id=" "><x xmlns=\"urn:example:clixon\">ipv4</x><y xmlns=\"urn:example:clixon\">42</y></rpc-reply>"
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 if [ $BE -ne 0 ]; then
new "Kill backend" new "Kill backend"
# Check if premature kill # Check if premature kill