From 609e27e0c26e0e6138e1d19523de178864bdb8f0 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Wed, 8 Jun 2022 11:19:50 +0200 Subject: [PATCH] Augmented XML uses default namespace * Instead of using prefixes for augmented XML, assign the default namespace Test: moved datastore format tests from test_cli to new test_datastore_format --- CHANGELOG.md | 6 + lib/src/clixon_text_syntax_parse.y | 2 +- lib/src/clixon_xml_map.c | 52 ++++---- test/test_augment.sh | 2 +- test/test_cli.sh | 41 ++----- test/test_datastore_format.sh | 189 +++++++++++++++++++++++++++++ test/test_datastore_repair.sh | 2 +- test/test_netconf.sh | 2 +- 8 files changed, 229 insertions(+), 67 deletions(-) create mode 100755 test/test_datastore_format.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b450c7a..f3d96261 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,12 @@ Planned: July 2022 Users may have to change how they access the system +* Augmented XML uses default namespace + * Instead of using prefixes for augmented XML, assign the default namespace + * This does not change the semantics, but changes the way XML rpefixes are used + * Example augmented ipv4 into interface: + * Previously: `...` + * Now: `...` * TEXT file format changed * With new parsing of TEXT format, the output is changed * Namespace/modulename added to top-level diff --git a/lib/src/clixon_text_syntax_parse.y b/lib/src/clixon_text_syntax_parse.y index 12eb58bb..cf22980c 100644 --- a/lib/src/clixon_text_syntax_parse.y +++ b/lib/src/clixon_text_syntax_parse.y @@ -124,7 +124,7 @@ static cxobj* text_create_node(clixon_text_syntax_yacc *ts, char *name) { - cxobj *xn; + cxobj *xn = NULL; yang_stmt *ymod; char *ns; char *prefix = NULL; diff --git a/lib/src/clixon_xml_map.c b/lib/src/clixon_xml_map.c index 7dc03fcd..e8be1d40 100644 --- a/lib/src/clixon_xml_map.c +++ b/lib/src/clixon_xml_map.c @@ -1359,23 +1359,24 @@ xmlns_assign(cxobj *x) } /*! Given a src element node x0 and a target node x1, assign (optional) prefix and namespace + * @param[in] x1 XML tree + * @param[in] x1p XML tree parent + * @retval 0 OK + * @retval -1 OK * @see assign_namespace_element this is a subroutine */ static int -assign_namespace(cxobj *x0, /* source */ - cxobj *x1, /* target */ - cxobj *x1p, - int isroot, - char *ns, - char *prefix0) +assign_namespace(cxobj *x1, /* target */ + cxobj *x1p, + int isroot, + char *ns, + char *prefix0) { - int retval = -1; - char *prefix1 = NULL; - char *pexist = NULL; - cvec *nsc0 = NULL; - cvec *nsc = NULL; - yang_stmt *y; - int ret; + int retval = -1; + char *prefix1 = NULL; + char *pexist = NULL; + cvec *nsc0 = NULL; + cvec *nsc = NULL; /* 2a. Detect if namespace is declared in x1 target parent */ if (xml2prefix(x1p, ns, &pexist) == 1){ @@ -1416,8 +1417,7 @@ assign_namespace(cxobj *x0, /* source */ } goto ok; /* skip */ } - else { /* namespace does not exist in target x1, use source prefix - * use the prefix defined in the module + else { /* namespace does not exist in target x1, */ if (isroot){ if (prefix0 && (prefix1 = strdup(prefix0)) == NULL){ @@ -1426,20 +1426,11 @@ assign_namespace(cxobj *x0, /* source */ } } else{ - char *ptmp; - if ((y = xml_spec(x0)) == NULL){ - clicon_err(OE_YANG, ENOENT, "XML %s does not have yang spec", - xml_name(x0)); - goto done; + if (prefix0 == NULL){ /* Use default namespace, may break use of previous default + * somewhere in x1 + */ + prefix1 = NULL; } - /* Find local (imported) prefix for that module namespace */ - if ((ret = yang_find_prefix_by_namespace(y, ns, &ptmp)) < 0) - goto done; - if (ret == 1 && (prefix1 = strdup(ptmp)) == NULL){ - clicon_err(OE_UNIX, errno, "strdup"); - goto done; - } - } } if (add_namespace(x1, x1, prefix1, ns) < 0) @@ -1465,7 +1456,8 @@ assign_namespace(cxobj *x0, /* source */ * 1. Find N=namespace(x0) * 2. Detect if N is declared in x1 parent * 3. If yes, assign prefix to x1 - * 4. If no, create new prefix/namespace binding and assign that to x1p (x1 if x1p is root) + * 4. If no, if default namespace use that, otherwise create new prefix/namespace binding and assign + * that to x1p * 5. Add prefix to x1, if any * 6. Ensure x1 cache is updated * @note switch use of x0 and x1 compared to datastore text_modify @@ -1493,7 +1485,7 @@ assign_namespace_element(cxobj *x0, /* source */ prefix0?prefix0:"NULL"); goto done; } - if (assign_namespace(x0, x1, x1p, isroot, namespace, prefix0) < 0) + if (assign_namespace(x1, x1p, isroot, namespace, prefix0) < 0) goto done; /* 6. Ensure x1 cache is updated (I think it is done w xmlns_set above) */ retval = 0; diff --git a/test/test_augment.sh b/test/test_augment.sh index fa3b17aa..a96b28d9 100755 --- a/test/test_augment.sh +++ b/test/test_augment.sh @@ -307,7 +307,7 @@ new "delete interfaces" expectpart "$(curl $CURLOPTS -X DELETE $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces)" 0 "HTTP/$HVER 204" # augmented lists -XML="22nisse44kalle" +XML="22nisse44kalle" new "netconf PUT augmented list" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "merge$XML" "" "" diff --git a/test/test_cli.sh b/test/test_cli.sh index 870378bf..4b7966f0 100755 --- a/test/test_cli.sh +++ b/test/test_cli.sh @@ -16,7 +16,6 @@ APPNAME=example cfg=$dir/conf_yang.xml clidir=$dir/cli - fyang=$dir/clixon-example.yang test -d ${clidir} || rm -rf ${clidir} @@ -71,12 +70,6 @@ module clixon-example { leaf value{ type string; } - leaf-list array1{ - type string; - } - leaf-list array2{ - type string; - } } } rpc example { @@ -241,35 +234,17 @@ expectpart "$($clixon_cli -1 -f $cfg -l o show compare text)" 0 "+ ad 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 save" +expectpart "$($clixon_cli -1 -f $cfg -l o save $dir/foo cli)" 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 delete all" +expectpart "$($clixon_cli -1 -f $cfg -l o delete all)" 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 load" +expectpart "$($clixon_cli -1 -f $cfg -l o load $dir/foo cli)" 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 check load" +expectpart "$($clixon_cli -1 -f $cfg -l o show conf cli)" 0 "interfaces interface eth/0/0 ipv4 enabled true" new "cli debug set" expectpart "$($clixon_cli -1 -f $cfg -l o debug cli 1)" 0 "^$" diff --git a/test/test_datastore_format.sh b/test/test_datastore_format.sh new file mode 100755 index 00000000..821b2248 --- /dev/null +++ b/test/test_datastore_format.sh @@ -0,0 +1,189 @@ +#!/usr/bin/env bash +# Datastore format tests +# Go through all formats and save and load a simple config via the CLI +# Add as appropriate + +# 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 +fyang1=$dir/clixon-augment.yang + +formatdir=$dir/format +test -d ${formatdir} || rm -rf ${formatdir} +mkdir $formatdir + +test -d ${clidir} || rm -rf ${clidir} +mkdir $clidir + +# Use yang in example + +cat < $cfg + + ietf-netconf:startup + $cfg + ${YANG_INSTALLDIR} + $IETFRFC + $dir + /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; + /* 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; + } +*/ + } + } +} +EOF + +cat < $fyang1 +module clixon-augment { + yang-version 1.1; + namespace "urn:example:augment"; + prefix aug; + import clixon-example { + prefix ex; + } + augment "/ex:table/ex:parameter" { + leaf-list array2{ + 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(); +discard("Discard edits (rollback 0)"), discard_changes(); +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"); +} + +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 startup -f $cfg +fi + +new "wait backend" +wait_backend + +# 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 $formatdir/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 $formatdir/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 + +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 diff --git a/test/test_datastore_repair.sh b/test/test_datastore_repair.sh index 045638ec..9e6b91e0 100755 --- a/test/test_datastore_repair.sh +++ b/test/test_datastore_repair.sh @@ -77,7 +77,7 @@ sudo chmod 666 $dir/startup_db # This is how it should look after repair, using prefixes AFTER=$(cat <foo +foo EOF ) diff --git a/test/test_netconf.sh b/test/test_netconf.sh index 5f5d83a3..96239b5f 100755 --- a/test/test_netconf.sh +++ b/test/test_netconf.sh @@ -143,7 +143,7 @@ expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "$rpc" "" "" new "netconf get config xpath parent" -expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "$rpc" "" "eth/0/0trueeth1truetruefalse9.2.3.424" +expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "$rpc" "" "eth/0/0trueeth1truetruefalse
9.2.3.424
" new "netconf validate missing type" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" ""