Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions apps/backend/backend_clixon_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,8 @@ from_client_restart_plugin(clixon_handle h,
* from y is used. Unless the element is .., .
* @param[in,out] cb0 Result XPath as cbuf
* @param[in] xpath1 Input XPath
* @param[in] y Yang of xpath1
* @param[in] y Context node for unprefixed identifiers
* @param[in] ypath Path statement defining explicit prefixes
* @param[in,out] nsc Namespace
* @retval 0 OK
* @retval -1 Error
Expand All @@ -407,6 +408,7 @@ static int
xpath_append(cbuf *cb0,
char *xpath1,
yang_stmt *y,
yang_stmt *ypath,
cvec *nsc)
{
int retval = -1;
Expand Down Expand Up @@ -471,7 +473,7 @@ xpath_append(cbuf *cb0,
/* If prefix is not in nsc, it needs to be added */
if (prefix && cvec_find(nsc, prefix) == NULL){
ns = NULL;
if ((ret = yang_find_namespace_by_prefix(y, prefix, &ns)) < 0)
if ((ret = yang_find_namespace_by_prefix(ypath, prefix, &ns)) < 0)
goto done;
if (ret == 0){
clixon_err(OE_DB, 0, "Prefix %s does not have an associated namespace", prefix);
Expand Down Expand Up @@ -545,7 +547,7 @@ leafref_append_path(yang_stmt *yn,
clixon_err(OE_DB, 0, "Leafref %s requires path statement", resolved_name);
goto done;
}
if (xpath_append(cbxpath, yang_argument_get(ypath), yn, nsc) < 0)
if (xpath_append(cbxpath, yang_argument_get(ypath), yn, ypath, nsc) < 0)
goto done;
}
else if (strcmp(resolved_name, "union") == 0){
Expand Down Expand Up @@ -577,7 +579,7 @@ leafref_append_path(yang_stmt *yn,
goto done;
}
cbuf_append_str(cb_one, cbuf_get(cb_orig));
if (xpath_append(cb_one, yang_argument_get(ypath), yn, nsc) < 0)
if (xpath_append(cb_one, yang_argument_get(ypath), yn, ypath, nsc) < 0)
goto done;
if (!first)
cprintf(cbxpath, " | ");
Expand Down
13 changes: 13 additions & 0 deletions lib/src/clixon_autocli_generate.c
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ gen_mtpoint_add(cbuf *cb,
* @retval -1 Error
* @param[in] leafref_refer If set, add "leafref-refer" as a 3rd argument to
* expand_dbvar() to signal that leafrefs should be followed.
* @param[in] preference Optional CLIgen preference override (zero uses the default)
* @see expand_dbvar This is where the expand string is used
* @see CLIXON_AUTOCLI_NS "expand" extension Overrides expand_dbvar() with a custom callback
* @note XXX only fraction_digits handled,should also have mincv, maxcv, pattern
Expand All @@ -251,6 +252,7 @@ cli_expand_var_generate(clixon_handle h,
uint8_t fraction_digits,
int pre,
int leafref_refer,
uint32_t preference,
cbuf *cb)
{
int retval = -1;
Expand All @@ -271,6 +273,8 @@ cli_expand_var_generate(clixon_handle h,
if (pre)
cprintf(cb, "|");
cprintf(cb, "<%s:%s", yang_argument_get(ys), cvtypestr);
if (preference)
cprintf(cb, " preference:%u", preference);
if (options & YANG_OPTIONS_FRACTION_DIGITS)
cprintf(cb, " fraction-digits:%u", fraction_digits);
cprintf(cb, " %s(\"candidate\",\"%s\"",
Expand Down Expand Up @@ -909,6 +913,10 @@ yang2cli_var_union_one(clixon_handle h,
else {
if (clicon_type2cv(origtype, restype, ys, &cvtype) < 0)
goto done;
/* Leafrefs in unions are single values, not the rest of the command.
* The backend validates the value against the referenced type. */
if (restype && strcmp(restype, "leafref") == 0)
cvtype = CGV_STRING;
if ((retval = yang2cli_leaf_var_sub(h, ys, ytype, helptext, cvtype,
options, cvv, patterns, fraction_digits, patpref, cb)) < 0)
goto done;
Expand Down Expand Up @@ -1187,11 +1195,16 @@ yang2cli_leaf_var(clixon_handle h,
* Note: also set when restype=="leafref" because yang_path_arg may fail to resolve the
* referred node client-side (e.g. grouping with submodule prefix scope); the backend
* handles leafref resolution independently. */
/* Preserve child commands, but retain the rest variable's preference
* so expanded values do not compete with explicit union alternatives. */
if (strcmp(restype, "union") == 0)
cvtypestr = "string";
if ((ret = cli_expand_var_generate(h, ys, cvtypestr,
options, fraction_digits, regular_value,
leafref_refer ||
strcmp(restype, "union") == 0 ||
strcmp(restype, "leafref") == 0,
strcmp(restype, "union") == 0 ? COV_PREF_REST : 0,
cb)) < 0)
goto done;
if (ret == 1)
Expand Down
119 changes: 119 additions & 0 deletions test/test_cli_union_leafref.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
#!/usr/bin/env bash
# Union leafref keys must preserve child commands and the typedef's prefix scope.

# 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
cfg=$dir/conf_yang.xml

cat <<EOF1 > $dir/example-targets.yang
module example-targets {
yang-version 1.1;
namespace "urn:example:targets";
prefix t;
list port {
key name;
leaf name { type string; }
}
list lag {
key name;
leaf name { type string; }
}
typedef port-ref {
type leafref { path "/t:port/t:name"; }
}
typedef relative-ref {
type leafref { path "../name"; }
}
typedef endpoint-ref {
type union {
type port-ref;
type leafref { path "/t:lag/t:name"; }
}
}
}
EOF1

cat <<EOF1 > $dir/example.yang
module example {
yang-version 1.1;
namespace "urn:example:clixon";
prefix ex;
// The defining module's prefix t is deliberately unavailable here.
import example-targets { prefix target; }
leaf primary { type target:port-ref; }
list endpoint {
key name;
leaf name { type target:endpoint-ref; }
leaf cost { type uint32; }
leaf alias { type target:relative-ref; }
}
}
EOF1

AUTOCLI=$(autocli_config 'example*' kw-nokey false | sed 's|<autocli>|<autocli><completion-default>true</completion-default>|')
cat <<EOF1 > $cfg
<clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>${YANG_INSTALLDIR}</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_DIR>$dir</CLICON_YANG_MAIN_DIR>
<CLICON_CLI_MODE>example</CLICON_CLI_MODE>
<CLICON_CLISPEC_DIR>$dir</CLICON_CLISPEC_DIR>
<CLICON_SOCK>$dir/backend.sock</CLICON_SOCK>
<CLICON_BACKEND_PIDFILE>$dir/backend.pid</CLICON_BACKEND_PIDFILE>
<CLICON_XMLDB_DIR>$dir</CLICON_XMLDB_DIR>
<CLICON_XMLDB_PRETTY>false</CLICON_XMLDB_PRETTY>
${AUTOCLI}
</clixon-config>
EOF1

cat <<EOF1 > $dir/example.cli
CLICON_MODE="example";
set @datamodel, cli_auto_set();
validate, cli_validate();
show, cli_show_auto_mode("candidate", "xml", false, false);
quit, cli_quit();
EOF1

new "test params: -f $cfg"
if [ $BE -ne 0 ]; then
new "start backend"
start_backend -s init -f $cfg
fi
new "wait backend"
wait_backend

new "populate both leafref targets"
expectpart "$($clixon_cli -1 -f $cfg set port p1 2>&1)" 0 '^$'
expectpart "$($clixon_cli -1 -f $cfg set lag lag1 2>&1)" 0 '^$'

new "completion of imported union leafref typedef"
expectpart "$(printf 'set endpoint ?\025quit\n' | $clixon_cli -f $cfg 2>&1)" 0 'p1' 'lag1' --not-- 'Netconf error' 'Syntax error'

new "completion of imported ordinary leafref typedef"
expectpart "$(printf 'set primary ?\025quit\n' | $clixon_cli -f $cfg 2>&1)" 0 'p1' --not-- 'Netconf error' 'Syntax error'

for completion in false true; do
new "union keys retain child commands with completion=$completion"
sed -i "s|<completion-default>.*</completion-default>|<completion-default>$completion</completion-default>|" $cfg
expectpart "$($clixon_cli -1 -f $cfg set endpoint p1 cost 10 2>&1)" 0 '^$'
expectpart "$($clixon_cli -1 -f $cfg set endpoint lag1 cost 20 2>&1)" 0 '^$'
expectpart "$($clixon_cli -1 -f $cfg show 2>&1)" 0 '<name>p1</name><cost>10</cost>' '<name>lag1</name><cost>20</cost>'
done

new "unprefixed typedef paths use the consuming node namespace"
expectpart "$(printf 'set endpoint p1 alias ?\025quit\n' | $clixon_cli -f $cfg 2>&1)" 0 ' p1' --not-- 'Netconf error' 'Syntax error'

new "union leafrefs validate against existing targets"
expectpart "$($clixon_cli -1 -f $cfg validate 2>&1)" 0 '^$'
expectpart "$($clixon_cli -1 -f $cfg set endpoint absent cost 30 2>&1)" 0 '^$'
expectpart "$($clixon_cli -1 -f $cfg validate 2>&1)" 255 'instance-required'

if [ $BE -ne 0 ]; then
new "kill backend"
stop_backend -f $cfg
fi
rm -rf $dir
new "endtest"
endtest
Loading