#!/usr/bin/env bash # Backend and cli basic functionality # Start backend server # Add an ethernet interface and an address # Show configuration # Validate without a mandatory type # Set the mandatory type # Commit # 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 clidir=$dir/cli fyang=$dir/clixon-example.yang test -d ${clidir} || rm -rf ${clidir} mkdir $clidir # Use yang in example cat < $cfg $cfg ${YANG_INSTALLDIR} $IETFRFC $fyang /usr/local/lib/$APPNAME/backend $APPNAME /usr/local/lib/$APPNAME/cli $clidir /usr/local/var/$APPNAME/$APPNAME.sock /usr/local/var/$APPNAME/$APPNAME.pidfile /usr/local/var/$APPNAME EOF cat < $fyang module clixon-example { yang-version 1.1; namespace "urn:example:clixon"; prefix ex; import ietf-interfaces { prefix if; } import ietf-ip { prefix ip; } import iana-if-type { prefix ianaift; } import clixon-autocli{ prefix autocli; } /* Example interface type for tests, local callbacks, etc */ identity eth { base if:interface-type; } /* Generic config data */ container table{ list parameter{ key name; leaf name{ type string; } leaf value{ type string; } leaf-list array1{ type string; } leaf-list array2{ type string; } } } rpc example { description "Some example input/output for testing RFC7950 7.14. RPC simply echoes the input for debugging."; input { leaf x { description "If a leaf in the input tree has a 'mandatory' statement with the value 'true', the leaf MUST be present in an RPC invocation."; type string; mandatory true; } leaf y { description "If a leaf in the input tree has a 'mandatory' statement with the value 'true', the leaf MUST be present in an RPC invocation."; type string; default "42"; } } output { leaf x { type string; } leaf y { type string; } } } } 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("bash"); 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 "); xml("Show configuration as XML"), cli_auto_show("datamodel", "candidate", "xml", true, false, "set "); text("Show configuration as TEXT"), cli_auto_show("datamodel", "candidate", "text", true, false, "set "); } } save("Save candidate configuration to XML file") ("Filename (local filename)"), save_config_file("candidate","filename", "xml"){ cli("Save configuration as CLI commands"), save_config_file("candidate","filename", "cli"); xml("Save configuration as XML"), save_config_file("candidate","filename", "xml"); json("Save configuration as JSON"), save_config_file("candidate","filename", "json"); text("Save configuration as TEXT"), save_config_file("candidate","filename", "text"); } load("Load configuration from XML file") ("Filename (local filename)"),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"); text("Replace candidate with file containing TEXT"), load_config_file("filename", "replace", "text"); } 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" 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 fi new "wait backend" wait_backend new "cli configure top" expectpart "$($clixon_cli -1 -f $cfg set interfaces)" 0 "^$" new "cli show configuration top (no presence)" expectpart "$($clixon_cli -1 -f $cfg show conf cli)" 0 "^$" new "cli configure delete top" expectpart "$($clixon_cli -1 -f $cfg delete interfaces)" 0 "^$" new "cli show configuration delete top" expectpart "$($clixon_cli -1 -f $cfg show conf cli)" 0 "^$" new "cli configure set interfaces" expectpart "$($clixon_cli -1 -f $cfg set interfaces interface eth/0/0)" 0 "^$" new "cli show configuration" expectpart "$($clixon_cli -1 -f $cfg show conf cli)" 0 "^set interfaces interface eth/0/0" "^set interfaces interface eth/0/0 enabled true" new "cli configure using encoded chars data <&" # problems in changing to expectpart with escapes expectpart "$($clixon_cli -1 -f $cfg set interfaces interface eth/0/0 description "\"foo<&bar\"")" 0 "" new "cli configure using encoded chars name <&" expectpart "$($clixon_cli -1 -f $cfg set interfaces interface "fddi&<" type ianaift:ethernetCsmacd)" 0 "" new "cli failed validate" expectpart "$($clixon_cli -1 -f $cfg -l o validate)" 255 "Validate failed. Edit and try again or discard changes: application missing-element Mandatory variable of interface in module ietf-interfaces type" new "cli configure ip addr" expectpart "$($clixon_cli -1 -f $cfg set interfaces interface eth/0/0 ipv4 address 1.2.3.4 prefix-length 24)" 0 "^$" new "cli configure ip descr" expectpart "$($clixon_cli -1 -f $cfg set interfaces interface eth/0/0 description mydesc)" 0 "^$" new "cli configure ip type" expectpart "$($clixon_cli -1 -f $cfg set interfaces interface eth/0/0 type ex:eth)" 0 "^$" new "cli show xpath description" expectpart "$($clixon_cli -1 -f $cfg -l o show xpath /interfaces/interface/description urn:ietf:params:xml:ns:yang:ietf-interfaces)" 0 "mydesc" new "cli delete description" expectpart "$($clixon_cli -1 -f $cfg -l o delete interfaces interface eth/0/0 description mydesc)" 0 "" new "cli show xpath no description" expectpart "$($clixon_cli -1 -f $cfg -l o show xpath /interfaces/interface/description urn:ietf:params:xml:ns:yang:ietf-interfaces)" 0 "^$" new "cli copy interface" expectpart "$($clixon_cli -1 -f $cfg copy interface eth/0/0 to eth99)" 0 "^$" new "cli success validate" expectpart "$($clixon_cli -1 -f $cfg -l o validate)" 0 "^$" new "cli compare diff" expectpart "$($clixon_cli -1 -f $cfg -l o show compare text)" 0 "+ address 1.2.3.4" new "cli start shell" expectpart "$($clixon_cli -1 -f $cfg -l o shell echo foo)" 0 "foo" # For formats, create three leaf-lists new "cli create leaflist array1 a" expectpart "$($clixon_cli -1 -f $cfg -l o set table parameter a array1 a)" 0 "^$" new "cli create leaflist array1 b1 b2" expectpart "$($clixon_cli -1 -f $cfg -l o set table parameter a array1 \"b1 b2\")" 0 "^$" new "cli create leaflist array2 c1 c2" expectpart "$($clixon_cli -1 -f $cfg -l o set table parameter a array2 \"c1 c2\")" 0 "^$" new "cli commit" expectpart "$($clixon_cli -1 -f $cfg -l o commit)" 0 "^$" for format in cli text xml json; do new "cli save $format" expectpart "$($clixon_cli -1 -f $cfg -l o save $dir/config.$format $format)" 0 "^$" new "cli delete all" expectpart "$($clixon_cli -1 -f $cfg -l o delete all)" 0 "^$" new "cli load $format" expectpart "$($clixon_cli -1 -f $cfg -l o load $dir/config.$format $format)" 0 "^$" if [ $format != json ]; then # XXX JSON identity problem new "cli check compare $format" expectpart "$($clixon_cli -1 -f $cfg -l o show compare xml)" 0 "^$" --not-- "i" # interface? fi done new "cli debug set" expectpart "$($clixon_cli -1 -f $cfg -l o debug cli 1)" 0 "^$" # How to test this? new "cli debug reset" expectpart "$($clixon_cli -1 -f $cfg -l o debug cli 0)" 0 "^$" 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 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