From 4d265d63bd43d001a6ffcea010e6b1d865a424a1 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Tue, 3 Aug 2021 11:15:45 +0200 Subject: [PATCH] Fixed: The auto-cli identityref did not expand identities in grouping/usecases properly. --- CHANGELOG.md | 1 + apps/cli/cli_generate.c | 72 ++++++++++++++++++----------------- test/test_identity.sh | 83 +++++++++++++++++++++++++++++++++++------ 3 files changed, 109 insertions(+), 47 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d27b9226..ad0067a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,7 @@ Users may have to change how they access the system ### Corrected Bugs +* Fixed: The auto-cli identityref did not expand identities in grouping/usecases properly. * Fixed: [OpenConfig BGP afi-safi and when condition issues #249](https://github.com/clicon/clixon/issues/249) * YANG when was not properly implemented for default values * Fixed: SEGV in clixon_netconf_lib functions from internal errors including validation. diff --git a/apps/cli/cli_generate.c b/apps/cli/cli_generate.c index 701288cc..2f37a5aa 100644 --- a/apps/cli/cli_generate.c +++ b/apps/cli/cli_generate.c @@ -184,7 +184,7 @@ yang2cli_helptext(cbuf *cb, /*! Generate identityref statements for CLI variables * @param[in] ys Yang statement - * @param[in] ytype Yang union type being resolved + * @param[in] ytype Resolved yang type. * @param[in] helptext CLI help text * @param[out] cb Buffer where cligen code is written * @see yang2cli_var_sub Its sub-function @@ -208,42 +208,44 @@ yang2cli_var_identityref(yang_stmt *ys, yang_stmt *yprefix; yang_stmt *yspec; - if ((ybaseref = yang_find(ytype, Y_BASE, NULL)) != NULL && - (ybaseid = yang_find_identity(ys, yang_argument_get(ybaseref))) != NULL){ - idrefvec = yang_cvec_get(ybaseid); - if (cvec_len(idrefvec) > 0){ - /* Add a wildchar string first -let validate take it for default prefix */ - cprintf(cb, ">"); - yang2cli_helptext(cb, helptext); - cprintf(cb, "|<%s:%s choice:", yang_argument_get(ys), cvtypestr); - yspec = ys_spec(ys); - i = 0; - while ((cv = cvec_each(idrefvec, cv)) != NULL){ - if (nodeid_split(cv_name_get(cv), &prefix, &id) < 0) - goto done; - /* Translate from module-name(prefix) to global prefix - * This is really a kludge for true identityref prefix handling - * IDENTITYREF_KLUDGE - * This is actually quite complicated: the cli needs to generate - * a netconf statement with correct xmlns binding - */ - if ((ymod = yang_find_module_by_name(yspec, prefix)) != NULL && - (yprefix = yang_find(ymod, Y_PREFIX, NULL)) != NULL){ - if (i++) - cprintf(cb, "|"); - cprintf(cb, "%s:%s", yang_argument_get(yprefix), id); - } - if (prefix){ - free(prefix); - prefix = NULL; - } - if (id){ - free(id); - id = NULL; - } + if ((ybaseref = yang_find(ytype, Y_BASE, NULL)) == NULL) + goto ok; + if ((ybaseid = yang_find_identity(ytype, yang_argument_get(ybaseref))) == NULL) + goto ok; + idrefvec = yang_cvec_get(ybaseid); + if (cvec_len(idrefvec) > 0){ + /* Add a wildchar string first -let validate take it for default prefix */ + cprintf(cb, ">"); + yang2cli_helptext(cb, helptext); + cprintf(cb, "|<%s:%s choice:", yang_argument_get(ys), cvtypestr); + yspec = ys_spec(ys); + i = 0; + while ((cv = cvec_each(idrefvec, cv)) != NULL){ + if (nodeid_split(cv_name_get(cv), &prefix, &id) < 0) + goto done; + /* Translate from module-name(prefix) to global prefix + * This is really a kludge for true identityref prefix handling + * IDENTITYREF_KLUDGE + * This is actually quite complicated: the cli needs to generate + * a netconf statement with correct xmlns binding + */ + if ((ymod = yang_find_module_by_name(yspec, prefix)) != NULL && + (yprefix = yang_find(ymod, Y_PREFIX, NULL)) != NULL){ + if (i++) + cprintf(cb, "|"); + cprintf(cb, "%s:%s", yang_argument_get(yprefix), id); + } + if (prefix){ + free(prefix); + prefix = NULL; + } + if (id){ + free(id); + id = NULL; } } } + ok: retval = 0; done: if (prefix) @@ -371,7 +373,7 @@ static int yang2cli_var_union(clicon_handle h, yang_stmt *ys, char *origtype, * patterns, (eg regexp:"[0.9]*"). * @param[in] h Clixon handle * @param[in] ys Yang statement - * @param[in] ytype Yang union type being resolved + * @param[in] ytype Resolved yang type. * @param[in] helptext CLI help text * @param[in] cvtype * @param[in] options Flags field of optional values, see YANG_OPTIONS_* diff --git a/test/test_identity.sh b/test/test_identity.sh index d520205d..bd9d3b9f 100755 --- a/test/test_identity.sh +++ b/test/test_identity.sh @@ -1,6 +1,7 @@ #!/usr/bin/env bash # Identity and identityref tests # Example from RFC7950 Sec 7.18 and 9.10 +# Extended with a submodule # Magic line must be first in script (see README.md) s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi @@ -39,7 +40,7 @@ EOF # with two changes: the leaf statement is in the original module and # a transitive dependent identifier (foo) cat < $dir/example-crypto-base.yang - module example-crypto-base { +module example-crypto-base { yang-version 1.1; namespace "urn:example:crypto-base"; prefix "crypto"; @@ -59,8 +60,7 @@ cat < $dir/example-crypto-base.yang "Base identity used to identify public-key crypto algorithms."; } - } - +} EOF cat < $dir/example-des.yang @@ -85,10 +85,11 @@ cat < $dir/example-des.yang EOF cat < $fyang - module example { +module example-my-crypto { yang-version 1.1; namespace "urn:example:my-crypto"; prefix mc; + include "example-sub"; import "example-crypto-base" { prefix "crypto"; } @@ -141,7 +142,46 @@ cat < $fyang base mc:empty; } } + uses myname; +} +EOF + +# Only included from sub-module +# Introduce an identity only visible by example-sub submodule +cat < $dir/example-extra.yang +module example-extra { + yang-version 1.1; + namespace "urn:example:extra"; + prefix ee; + identity extra-base; + identity extra-new{ + base ee:extra-base; + } + identity extra-old{ + base ee:extra-base; + } +} +EOF + +# Sub-module +cat < $dir/example-sub.yang +submodule example-sub { + yang-version 1.1; + belongs-to example-my-crypto { + prefix mc; } + import example-extra { + prefix ee; + } + grouping myname { + leaf sub-name { + description "Uses identity accessed by only the submodule"; + type identityref { + base ee:extra-base; + } + } + } +} EOF new "test params: -f $cfg" @@ -269,42 +309,61 @@ expectpart "$($clixon_cli -1 -f $cfg -l o validate)" 255 "Validate failed. Edit new "netconf discard-changes" expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO]]>]]>" "^]]>]]>$" +# Special case sub-module +new "auto-cli cli expansion submodule identity" +expectpart "$(echo "set sub-name ?" | $clixon_cli -f $cfg 2>&1)" 0 "set sub-name" "ee:extra-new" "ee:extra-old" + +new "cli add identity" +expectpart "$($clixon_cli -1 -f $cfg -l o set sub-name ee:extra-new)" 0 "" + +new "cli validate submodule identity" +expectpart "$($clixon_cli -1 -f $cfg -l o validate)" 0 "" + +new "cli add wrong identity" +expectpart "$($clixon_cli -1 -f $cfg -l o set sub-name ee:foo)" 0 "" + +new "cli validate wrong id (expect fail)" +expectpart "$($clixon_cli -1 -f $cfg -l o validate 2>&1)" 255 "Identityref validation failed, ee:foo not derived from extra-base" + +new "netconf discard-changes" +expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO]]>]]>" "^]]>]]>$" + # restconf and identities: # 1. set identity in own module with restconf (PUT and POST), read it with restconf and netconf # 2. set identity in other module with restconf , read it with restconf and netconf # 3. set identity in other module with netconf, read it with restconf and netconf new "restconf add own identity" -expectpart "$(curl $CURLOPTS -X PUT -H "Content-Type: application/yang-data+json" $RCPROTO://localhost/restconf/data/example:crypto -d '{"example:crypto":"example:aes"}')" 0 "HTTP/$HVER 201" +expectpart "$(curl $CURLOPTS -X PUT -H "Content-Type: application/yang-data+json" $RCPROTO://localhost/restconf/data/example-my-crypto:crypto -d '{"example-my-crypto:crypto":"example-my-crypto:aes"}')" 0 "HTTP/$HVER 201" new "restconf get own identity" -expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/example:crypto)" 0 "HTTP/$HVER 200" '{"example:crypto":"aes"}' +expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/example-my-crypto:crypto)" 0 "HTTP/$HVER 200" '{"example-my-crypto:crypto":"aes"}' new "netconf get own identity as set by restconf" expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO]]>]]>" "^aes" new "restconf delete identity" -expectpart "$(curl $CURLOPTS -X DELETE $RCPROTO://localhost/restconf/data/example:crypto)" 0 "HTTP/$HVER 204" +expectpart "$(curl $CURLOPTS -X DELETE $RCPROTO://localhost/restconf/data/example-my-crypto:crypto)" 0 "HTTP/$HVER 204" # 2. set identity in other module with restconf , read it with restconf and netconf if ! $YANG_UNKNOWN_ANYDATA ; then new "restconf add POST instead of PUT (should fail)" -expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" $RCPROTO://localhost/restconf/data/example:crypto -d '{"example:crypto":"example-des:des3"}')" 0 "HTTP/$HVER 400" '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"crypto"},"error-severity":"error","error-message":"Failed to find YANG spec of XML node: crypto with parent: crypto in namespace: urn:example:my-crypto"}}}' +expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" $RCPROTO://localhost/restconf/data/example-my-crypto:crypto -d '{"example-my-crypto:crypto":"example-des:des3"}')" 0 "HTTP/$HVER 400" '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"crypto"},"error-severity":"error","error-message":"Failed to find YANG spec of XML node: crypto with parent: crypto in namespace: urn:example:my-crypto"}}}' fi # Alternative error: #'{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"crypto"},"error-severity":"error","error-message":"Leaf contains sub-element"}}}' new "restconf add other (des) identity using POST" -expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" $RCPROTO://localhost/restconf/data -d '{"example:crypto":"example-des:des3"}')" 0 "HTTP/$HVER 201" "Location: $RCPROTO://localhost/restconf/data/example:crypto" +expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" $RCPROTO://localhost/restconf/data -d '{"example-my-crypto:crypto":"example-des:des3"}')" 0 "HTTP/$HVER 201" "Location: $RCPROTO://localhost/restconf/data/example-my-crypto:crypto" new "restconf get other identity" -expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/example:crypto)" 0 "HTTP/$HVER 200" '{"example:crypto":"example-des:des3"}' +expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/example-my-crypto:crypto)" 0 "HTTP/$HVER 200" '{"example-my-crypto:crypto":"example-des:des3"}' new "netconf get other identity" expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO]]>]]>" "^des:des3" new "restconf delete identity" -expectpart "$(curl $CURLOPTS -X DELETE $RCPROTO://localhost/restconf/data/example:crypto)" 0 "HTTP/$HVER 204" +expectpart "$(curl $CURLOPTS -X DELETE $RCPROTO://localhost/restconf/data/example-my-crypto:crypto)" 0 "HTTP/$HVER 204" # 3. set identity in other module with netconf, read it with restconf and netconf new "netconf set other identity" @@ -314,7 +373,7 @@ new "netconf commit" expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO]]>]]>" "^]]>]]>$" new "restconf get other identity (set by netconf)" -expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/example:crypto)" 0 "HTTP/$HVER 200" '{"example:crypto":"example-des:des3"}' +expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/example-my-crypto:crypto)" 0 "HTTP/$HVER 200" '{"example-my-crypto:crypto":"example-des:des3"}' new "netconf get other identity" expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO]]>]]>" "^des:des3"