diff --git a/apps/cli/cli_auto.c b/apps/cli/cli_auto.c index c51b6f79..5e4e4f6d 100644 --- a/apps/cli/cli_auto.c +++ b/apps/cli/cli_auto.c @@ -353,7 +353,7 @@ cli_xml2cli(cxobj *xn, yang_keyword_get(ys) == Y_LEAF_LIST){ if (prepend) (*fn)(stdout, "%s", prepend); - if (gt == GT_ALL || gt == GT_VARS || gt == GT_HIDE) + if (gt == GT_ALL || gt == GT_VARS || gt == GT_HIDE || gt == GT_OC_COMPRESS) (*fn)(stdout, "%s ", xml_name(xn)); if ((body = xml_body(xn)) != NULL){ if (index(body, ' ')) diff --git a/apps/cli/cli_generate.c b/apps/cli/cli_generate.c index ac6527df..2f042ead 100644 --- a/apps/cli/cli_generate.c +++ b/apps/cli/cli_generate.c @@ -764,7 +764,7 @@ yang2cli_leaf(clicon_handle h, /* Look for autocli-op defined in clixon-lib.yang */ if (yang_extension_value(ys, "autocli-op", CLIXON_LIB_NS, NULL, &opext) < 0) goto done; - if (gt == GT_VARS|| gt == GT_ALL || gt == GT_HIDE){ + if (gt == GT_VARS || gt == GT_ALL || gt == GT_HIDE || gt == GT_OC_COMPRESS){ cprintf(cb, "%s", yang_argument_get(ys)); yang2cli_helptext(cb, helptext); cprintf(cb, " "); @@ -833,13 +833,27 @@ yang2cli_container(clicon_handle h, char *helptext = NULL; char *s; int hide = 0; + int hide_oc = 0; + int exist = 0; char *opext = NULL; + yang_stmt *ymod = NULL; + + + if (ys_real_module(ys, &ymod) < 0) + goto done; + if (yang_extension_value(ymod, "openconfig-version", "http://openconfig.net/yang/openconfig-ext", &exist, NULL) < 0) + goto done; + if (exist) { + if (strcmp(yang_argument_get(ys), "config") == 0){ + hide_oc = 1; + } + } /* If non-presence container && HIDE mode && only child is * a list, then skip container keyword * See also xml2cli */ - if ((hide = yang_container_cli_hide(ys, gt)) == 0){ + if ((hide = yang_container_cli_hide(ys, gt)) == 0 && hide_oc == 0){ cprintf(cb, "%*s%s", level*3, "", yang_argument_get(ys)); if ((yd = yang_find(ys, Y_DESCRIPTION, NULL)) != NULL){ if ((helptext = strdup(yang_argument_get(yd))) == NULL){ @@ -868,10 +882,10 @@ yang2cli_container(clicon_handle h, yc = NULL; while ((yc = yn_each(ys, yc)) != NULL) if (yang2cli_stmt(h, yc, gt, level+1, state, show_tree, cb) < 0) - goto done; - if (hide == 0) - cprintf(cb, "%*s}\n", level*3, ""); - retval = 0; + goto done; + if (hide == 0 && hide_oc == 0) + cprintf(cb, "%*s}\n", level*3, ""); + retval = 0; done: if (helptext) free(helptext); @@ -956,7 +970,7 @@ yang2cli_list(clicon_handle h, cprintf(cb, "{\n"); } if (yang2cli_leaf(h, yleaf, - (gt==GT_VARS||gt==GT_HIDE)?GT_NONE:gt, level+1, + (gt==GT_VARS||gt==GT_HIDE||gt==GT_OC_COMPRESS)?GT_NONE:gt, level+1, last_key, show_tree, 1, cb) < 0) goto done; diff --git a/lib/clixon/clixon_options.h b/lib/clixon/clixon_options.h index 72073f09..ddec1eb8 100644 --- a/lib/clixon/clixon_options.h +++ b/lib/clixon/clixon_options.h @@ -77,6 +77,7 @@ enum genmodel_type{ GT_VARS, /* Keywords on non-key variables */ GT_ALL, /* Keywords on all variables */ GT_HIDE, /* Keywords on all variables and hide container around lists */ + GT_OC_COMPRESS, /* OpenConfig */ }; typedef enum genmodel_type genmodel_type; diff --git a/lib/src/clixon_options.c b/lib/src/clixon_options.c index aa2bcc3b..886781a8 100644 --- a/lib/src/clixon_options.c +++ b/lib/src/clixon_options.c @@ -89,6 +89,7 @@ static const map_str2int cli_genmodel_map[] = { {"VARS", GT_VARS}, {"ALL", GT_ALL}, {"HIDE", GT_HIDE}, + {"OC_COMPRESS", GT_OC_COMPRESS}, {NULL, -1} }; diff --git a/lib/src/clixon_xml_map.c b/lib/src/clixon_xml_map.c index aaf2c233..9abbf774 100644 --- a/lib/src/clixon_xml_map.c +++ b/lib/src/clixon_xml_map.c @@ -286,7 +286,7 @@ xml2cli_recurse(FILE *f, /* If presence container, then print as leaf (but continue to children) */ if (prepend) (*fn)(f, "%s", prepend); - if (gt == GT_ALL || gt == GT_VARS || gt == GT_HIDE) + if (gt == GT_ALL || gt == GT_VARS || gt == GT_HIDE || gt == GT_OC_COMPRESS) (*fn)(f, "%s ", xml_name(x)); if ((body = xml_body(x)) != NULL){ if (index(body, ' ')) diff --git a/lib/src/clixon_yang.c b/lib/src/clixon_yang.c index d4e70dea..b4b364fa 100644 --- a/lib/src/clixon_yang.c +++ b/lib/src/clixon_yang.c @@ -3255,7 +3255,7 @@ yang_container_cli_hide(yang_stmt *ys, keyw = yang_keyword_get(ys); /* HIDE mode */ - if (gt != GT_HIDE) + if (gt != GT_HIDE && gt != GT_OC_COMPRESS) return 0; /* A container */ if (yang_keyword_get(ys) != Y_CONTAINER) diff --git a/test/test_cli_auto_genmodel.sh b/test/test_cli_auto_genmodel.sh index 9f77fe47..7af005a1 100755 --- a/test/test_cli_auto_genmodel.sh +++ b/test/test_cli_auto_genmodel.sh @@ -1,6 +1,7 @@ + #!/usr/bin/env bash # Tests for using the auto cli. -# In particular setting a config, displaying as cli commands and reconfigure it +# In particular setting a config, displaying as cli commands and reconfigure it # Tests: # Make a config in CLI. Show output as CLI, save it and ensure it is the same # Try the different GENMODEL settings @@ -25,11 +26,20 @@ fi # Use yang in example +if [ ! -d "$OPENCONFIG" ]; then +# err "Hmm Openconfig dir does not seem to exist, try git clone https://github.com/openconfig/public?" + echo "...skipped: OPENCONFIG not set" + if [ "$s" = $0 ]; then exit 0; else return 0; fi +fi + +OCDIR=$OPENCONFIG/release/models + cat < $cfg $cfg /usr/local/share/clixon $dir + $OCDIR/ $fyang /usr/local/lib/$APPNAME/backend $clidir @@ -49,6 +59,7 @@ cat < $fyang module $APPNAME { namespace "urn:example:clixon"; prefix ex; + import openconfig-extensions { prefix oc-ext; } container table{ list parameter{ key name; @@ -69,6 +80,42 @@ module $APPNAME { } } } + container interfaces { + oc-ext:openconfig-version; + list interface { + key name; + leaf name { + type string; + } + container config { + leaf enabled { + type boolean; + default false; + description "Whether the interface is enabled or not."; + } + } + container state { + config false; + leaf oper-status { + type enumeration { + enum UP { + value 1; + description "Ready to pass packets."; + } + enum DOWN { + value 2; + description "The interface does not pass any packets."; + } + } + } + } + leaf enabled { + type boolean; + default false; + description "Whether the interface is enabled or not."; + } + } + } } EOF @@ -127,6 +174,9 @@ function testrun() elif [ $mode = HIDE ]; then table= name= + elif [ $mode = OC_COMPRESS ]; then + table= + name= else table=" table" name= @@ -159,7 +209,7 @@ SAVED=$($clixon_cli -1 -o CLICON_CLI_GENMODEL_TYPE=$mode -f $cfg show config) new "delete a x" expectpart "$($clixon_cli -1 -o CLICON_CLI_GENMODEL_TYPE=$mode -f $cfg delete$table parameter$name a value x)" 0 "" - new "show match a & b xml" + new "show match a & b xml" expectpart "$($clixon_cli -1 -o CLICON_CLI_GENMODEL_TYPE=$mode -f $cfg show xml)" 0 "" "" "a" "" "" "b" "z" "" "
" --not-- "x" new "delete a" @@ -190,6 +240,9 @@ testrun HIDE new "keywords=ALL" testrun ALL +new "keywords=OC_COMPRESS" +testrun OC_COMPRESS + new "keywords=VARS" testrun VARS @@ -201,7 +254,7 @@ new "commit" expectpart "$($clixon_cli -1 -f $cfg commit)" 0 "" new "show state" -expectpart "$($clixon_cli -1 -f $cfg show state)" 0 "exstate sender x" "table parameter a" "table parameter a value x" +expectpart "$($clixon_cli -1 -f $cfg show state)" 0 "exstate sender x" "table parameter a" "table parameter a value x" new "show state exstate" expectpart "$($clixon_cli -1 -f $cfg show state exstate)" 0 "state sender x" --not-- "table parameter a" "table parameter a value x" diff --git a/yang/clixon/clixon-config@2021-07-11.yang b/yang/clixon/clixon-config@2021-07-11.yang index 50bad2cc..1364455a 100644 --- a/yang/clixon/clixon-config@2021-07-11.yang +++ b/yang/clixon/clixon-config@2021-07-11.yang @@ -1,3 +1,4 @@ + module clixon-config { yang-version 1.1; namespace "http://clicon.org/config"; @@ -247,6 +248,9 @@ module clixon-config { enum HIDE{ description "Keywords on non-key variables and hide container around lists: a y "; } + enum OC_COMPRESS{ + description "See: https://github.com/openconfig/ygot/blob/master/docs/design.md#openconfig-path-compression"; + } } } typedef nacm_mode{