diff --git a/CHANGELOG.md b/CHANGELOG.md index 81dc1a13..6688382b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -82,6 +82,7 @@ Developers may need to change their code ### Corrected Bugs +* [cl:autocli-op hide has no effect in yang submodule](https://github.com/clicon/clixon/issues/282) * [Doxygen - Typo in Input #275](https://github.com/clicon/clixon/issues/275) ## 5.3.0 @@ -105,7 +106,7 @@ The 5.3 release has pagination support, Linkref changes in validation and auto-c * Updated state callback signature containing parameters for pagination * See API changes below * Work-in-progress - * Enable remaining attriute with LIST_PAGINATION_REMAINING compile-time option + * Enable remaining attribute with LIST_PAGINATION_REMAINING compile-time option * sort/direction/where etc not supported * For documentation: [User manual pagination](https://clixon-docs.readthedocs.io/en/latest/misc.html#pagination) * YANG Leafref feature update 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/apps/cli/cli_main.c b/apps/cli/cli_main.c index 0264490e..f085d539 100644 --- a/apps/cli/cli_main.c +++ b/apps/cli/cli_main.c @@ -620,7 +620,7 @@ main(int argc, Should be 0 but default is 1 since all legacy apps use 1 Test legacy before shifting default to 0 */ - cv_exclude_keys(clicon_cli_varonly(h)); + cligen_exclude_keys_set(cli_cligen(h), clicon_cli_varonly(h)); /* Initialize plugin module by creating a handle holding plugin and callback lists */ if (clixon_plugin_module_init(h) < 0) diff --git a/apps/cli/cli_plugin.c b/apps/cli/cli_plugin.c index 77b60cbe..f83a99e6 100644 --- a/apps/cli/cli_plugin.c +++ b/apps/cli/cli_plugin.c @@ -525,34 +525,50 @@ cli_handler_err(FILE *f) /*! Variant of eval for context checking * @see cligen_eval */ -int -cligen_clixon_eval(cligen_handle h, +static int +clixon_cligen_eval(cligen_handle h, cg_obj *co, cvec *cvv) { struct cg_callback *cc; - int retval = 0; + int retval = -1; cvec *argv; - plugin_context_t *pc = NULL; + cvec *cvv1 = NULL; /* Modified */ + plugin_context_t *pc = NULL; /* Clixon-specific */ + + /* Save matched object for plugin use */ if (h) cligen_co_match_set(h, co); + /* Make a copy of var argument for modifications */ + if ((cvv1 = cvec_dup(cvv)) == NULL) + goto done; + /* Make modifications to cvv */ + if (cligen_expand_first_get(h) && + cvec_expand_first(cvv1) < 0) + goto done; + if (cligen_exclude_keys_get(h) && + cvec_exclude_keys(cvv1) < 0) + goto done; + /* Traverse callbacks */ for (cc = co->co_callbacks; cc; cc=cc->cc_next){ /* Vector cvec argument to callback */ if (cc->cc_fn_vec){ argv = cc->cc_cvec ? cvec_dup(cc->cc_cvec) : NULL; cligen_fn_str_set(h, cc->cc_fn_str); - if ((pc = plugin_context_get()) == NULL) + /* Clixon-specific */ + if ((pc = plugin_context_get()) == NULL) break; if ((retval = (*cc->cc_fn_vec)( cligen_userhandle(h)?cligen_userhandle(h):h, - cvv, + cvv1, argv)) < 0){ if (argv != NULL) cvec_free(argv); cligen_fn_str_set(h, NULL); - break; + goto done; } + /* Clixon-specific */ if (plugin_context_check(pc, "CLIgen", cc->cc_fn_str) < 0) break; if (pc){ @@ -564,8 +580,12 @@ cligen_clixon_eval(cligen_handle h, cligen_fn_str_set(h, NULL); } } - if (pc) + retval = 0; + done: + if (pc) /* Clixon-specific */ free(pc); + if (cvv1) + cvec_free(cvv1); return retval; } @@ -589,7 +609,7 @@ clicon_eval(clicon_handle h, if (!cligen_exiting(cli_cligen(h))) { clicon_err_reset(); - if ((retval = cligen_clixon_eval(cli_cligen(h), match_obj, cvv)) < 0) { + if ((retval = clixon_cligen_eval(cli_cligen(h), match_obj, cvv)) < 0) { #if 0 /* This is removed since we get two error messages on failure. But maybe only sometime? Both a real log when clicon_err is called, and the here again. @@ -631,7 +651,7 @@ clicon_parse(clicon_handle h, cli_syntax_t *stx = NULL; cli_syntaxmode_t *csm; parse_tree *pt; /* Orig */ - cg_obj *match_obj; + cg_obj *match_obj = NULL; cvec *cvv = NULL; FILE *f; char *reason = NULL; @@ -663,12 +683,15 @@ clicon_parse(clicon_handle h, fprintf(stderr, "No such parse-tree registered: %s\n", modename); goto done; } - if ((cvv = cvec_new(0)) == NULL){ - clicon_err(OE_UNIX, errno, "cvec_new"); +#if 0 // switch after 5.4 + if (cliread_parse2(cli_cligen(h), cmd, pt, &match_obj, &cvv, result, &reason) < 0) + goto done; +#else + if ((cvv = cvec_new(0)) == NULL) goto done;; - } if (cliread_parse(cli_cligen(h), cmd, pt, &match_obj, cvv, result, &reason) < 0) goto done; +#endif /* Debug command and result code */ clicon_debug(1, "%s result:%d command: \"%s\"", __FUNCTION__, *result, cmd); if (*result != CG_MATCH) @@ -708,6 +731,8 @@ done: free(reason); if (cvv) cvec_free(cvv); + if (match_obj) + co_free(match_obj, 0); return retval; } 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_json_parse.y b/lib/src/clixon_json_parse.y index 019942c4..947cf538 100644 --- a/lib/src/clixon_json_parse.y +++ b/lib/src/clixon_json_parse.y @@ -223,12 +223,27 @@ json_current_clone(clixon_json_yacc *jy) clicon_debug(2, "%s", __FUNCTION__); if (jy->jy_current == NULL){ - return -1; + return -1; } xn = jy->jy_current; json_current_pop(jy); - if (jy->jy_current) - json_current_new(jy, xml_name(xn)); + + if (jy->jy_current) { + char* name = xml_name(xn); + char* prefix = xml_prefix(xn); + char* maybe_prefixed_name = NULL; + + if (prefix) { + char* name_parts[] = {prefix, name}; + maybe_prefixed_name = clicon_strjoin(2, name_parts, ":"); + } else { + maybe_prefixed_name = strdup(name); + } + json_current_new(jy, maybe_prefixed_name); + + if (maybe_prefixed_name) + free(maybe_prefixed_name); + } return 0; } 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_sig.c b/lib/src/clixon_sig.c index 611a27a8..80f305b7 100644 --- a/lib/src/clixon_sig.c +++ b/lib/src/clixon_sig.c @@ -156,7 +156,7 @@ clixon_signal_restore(sigset_t *sigset, int retval = -1; int i; - if (sigprocmask(0, sigset, NULL) < 0){ + if (sigprocmask(SIG_SETMASK, sigset, NULL) < 0){ clicon_err(OE_UNIX, errno, "sigprocmask"); goto done; } diff --git a/lib/src/clixon_xml.c b/lib/src/clixon_xml.c index 750bbab2..a3c32725 100644 --- a/lib/src/clixon_xml.c +++ b/lib/src/clixon_xml.c @@ -581,10 +581,11 @@ xml_parent(cxobj *xn) return xn->x_up; } -/*! Set parent of xnode, parent is copied. +/*! Set parent of xml node. * @param[in] xn xml node * @param[in] parent pointer to new parent xml node * @retval 0 OK + * @see xml_child_rm remove child from parent */ int xml_parent_set(cxobj *xn, @@ -1986,8 +1987,6 @@ xml_copy(cxobj *x0, return retval; } - - /*! Create and return a copy of xml tree. * * @code 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..c9a8b0a0 100644 --- a/lib/src/clixon_yang.c +++ b/lib/src/clixon_yang.c @@ -2355,6 +2355,14 @@ ys_populate_unique(clicon_handle h, * RFC 7950 Sec 7.19: * If no "argument" statement is present, the keyword expects no argument when * it is used. + * Note there is some complexity in different yang modules with unknown-statements. + * y0) The location of the extension definition. E.g. extension autocli-op + * y1) The location of the unknown-statement (ys). This is for example: cl:autocli-op hide. + * Lookup of "cl" is lexically scoped in this context (to find (y0)). + * y2) The unknown statement may be used by uses/grouping of (y1). But "cl" is declared + * in y1 context. This is fixed by setting ys_mymodule to y1 which is then used in + * lookups such as in yang_extension_value(). + * @see yang_extension_value Called on expanded YANG, eg in context of (y2) */ static int ys_populate_unknown(clicon_handle h, @@ -2376,6 +2384,8 @@ ys_populate_unknown(clicon_handle h, clicon_err(OE_YANG, ENOENT, "Extension \"%s:%s\", module not found", prefix, id); goto done; } + /* To find right binding eg after grouping/uses */ + ys->ys_mymodule = ys_module(ys); if ((yext = yang_find(ymod, Y_EXTENSION, id)) == NULL){ clicon_err(OE_YANG, ENOENT, "Extension \"%s:%s\" not found", prefix, id); goto done; @@ -3255,7 +3265,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) @@ -3572,6 +3582,7 @@ yang_anydata_add(yang_stmt *yp, * // use extension value * } * @endcode + * @see ys_populate_unknown Called when parsing YANGo */ int yang_extension_value(yang_stmt *ys, diff --git a/lib/src/clixon_yang_internal.h b/lib/src/clixon_yang_internal.h index 06a73d4c..4fb3a489 100644 --- a/lib/src/clixon_yang_internal.h +++ b/lib/src/clixon_yang_internal.h @@ -71,9 +71,13 @@ struct yang_stmt{ char *ys_argument; /* String / argument depending on keyword */ uint16_t ys_flags; /* Flags according to YANG_FLAG_MARK and others */ - yang_stmt *ys_mymodule; /* Shortcut to "my" module. Augmented - nodes can belong to other - modules than the ancestor module */ + yang_stmt *ys_mymodule; /* Shortcut to "my" module. Used by: + 1) Augmented nodes "belong" to the module where the + augment is declared, which may be differnt from + the direct ancestor module + 2) Unknown nodes "belong" to where the extension is + declared + */ cg_var *ys_cv; /* cligen variable. See ys_populate() Following stmts have cv:s: leaf: for default value diff --git a/test/test_augment.sh b/test/test_augment.sh index 06ef088c..d910cbc6 100755 --- a/test/test_augment.sh +++ b/test/test_augment.sh @@ -185,6 +185,18 @@ module example-augment { type string; } } + /* augment a list */ + augment "/if:interfaces" { + list ports{ + key id; + leaf id { + type int32; + } + leaf str { + type string; + } + } + } } EOF @@ -291,6 +303,30 @@ expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/ietf-inte new "restconf GET augment multi-namespace cross level 2" expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces/interface=e1/example-augment:ospf/reference-bandwidth)" 0 "HTTP/$HVER 200" '{"example-augment:reference-bandwidth":23}' +new "delete interfaces" +expectpart "$(curl $CURLOPTS -X DELETE $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces)" 0 "HTTP/$HVER 204" + +# augmented lists +XML="22nisse44kalle" +new "netconf PUT augmented list" +expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLOmerge$XML]]>]]>" "^]]>]]>$" + +new "netconf commit" +expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO]]>]]>" "^]]>]]>$" + +new "netconf get config" +expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO]]>]]>" "$XML]]>]]>" + +JSON='{"ietf-interfaces:interfaces":{"example-augment:ports":[{"id":22,"str":"foo"},{"id":44,"str":"bar"}]}}' + +new "restconf PUT augmented list" +expectpart "$(curl $CURLOPTS -X PUT -H 'Content-Type: application/yang-data+json' $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces -d "$JSON")" 0 "HTTP/$HVER 204" + +# Escaped [] why? +JSON1='{"ietf-interfaces:interfaces":{"example-augment:ports":\[{"id":22,"str":"foo"},{"id":44,"str":"bar"}\]}}' +new "restconf GET augmented list" +expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+json' $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces)" 0 "HTTP/$HVER 200" "$JSON1" + if [ $RC -ne 0 ]; then new "Kill restconf daemon" stop_restconf diff --git a/test/test_cli_auto_extension.sh b/test/test_cli_auto_extension.sh index 15878398..1cccbbd3 100755 --- a/test/test_cli_auto_extension.sh +++ b/test/test_cli_auto_extension.sh @@ -136,7 +136,6 @@ wait_backend function testparam() { - # Try hidden parameter list new "query table parameter hidden" expectpart "$(echo "set table ?" | $clixon_cli -f $cfg 2>&1)" 0 "set table" "" --not-- "parameter" @@ -282,6 +281,60 @@ EOF new "Test hidden parameter in table/param/value augment" testvalue +# Example using imported module where clixon-lib is NOT declared in main module +# see discussion in ys_populate_unknown (y1 vs y2) and +# https://github.com/clicon/clixon/issues/282 +cat < $fyang +module example { + yang-version 1.1; + namespace "urn:example:clixon"; + prefix ex; + import example-augment{ + prefix aug; + } + + container table{ + list parameter{ + key name; + leaf name{ + type string; + } + uses aug:pg; + } + } +} +EOF + +# Use this as grouping (not annotate) +cat < $fyang2 +module example-augment { + namespace "urn:example:augment"; + prefix aug; + import clixon-lib{ + prefix cl; + } + grouping pg { + cl:autocli-op hide; /* This is the extension */ + leaf value{ + description "a value"; + type string; + } + list index{ + key i; + leaf i{ + type string; + } + leaf iv{ + type string; + } + } + } +} +EOF + +new "Test hidden parameter in imported module" +testparam + new "Kill backend" # Check if premature kill pid=$(pgrep -u root -f clixon_backend) diff --git a/test/test_cli_auto_genmodel.sh b/test/test_cli_auto_genmodel.sh index 566e2c04..6adb22f1 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 @@ -15,6 +16,7 @@ APPNAME=example cfg=$dir/conf_yang.xml fyang=$dir/$APPNAME.yang +fyang2=$dir/${APPNAME}2.yang fstate=$dir/state.xml clidir=$dir/cli if [ -d $clidir ]; then @@ -25,12 +27,19 @@ 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 + cat < $cfg $cfg /usr/local/share/clixon $dir_tmp - $fyang + $OPENCONFIG/ + $dir /usr/local/lib/$APPNAME/backend $clidir /usr/local/lib/$APPNAME/cli @@ -49,6 +58,9 @@ cat < $fyang module $APPNAME { namespace "urn:example:clixon"; prefix ex; + import openconfig-extensions { prefix oc-ext; } + /* Set openconfig version to "fake" an openconfig YANG */ + oc-ext:openconfig-version; container table{ list parameter{ key name; @@ -69,6 +81,85 @@ module $APPNAME { } } } + container interfaces { + 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 + +# For openconfig but NO openconfig extension +cat < $fyang2 +module ${APPNAME}2 { + namespace "urn:example:clixon2"; + prefix ex2; + import openconfig-extensions { prefix oc-ext; } + container interfaces2 { + 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 +218,9 @@ function testrun() elif [ $mode = HIDE ]; then table= name= + elif [ $mode = OC_COMPRESS ]; then + table= + name= else table=" table" name= @@ -159,7 +253,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 +284,9 @@ testrun HIDE new "keywords=ALL" testrun ALL +new "keywords=OC_COMPRESS" +testrun OC_COMPRESS + new "keywords=VARS" testrun VARS @@ -201,11 +298,20 @@ 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" +#---- openconfig path compression + +new "Openconfig: check no config path" +expectpart "$($clixon_cli -1 -f $cfg set interfaces interface e config enabled true 2>&1)" 255 "Unknown command" + +# negative test +new "Openconfig: check exist config path" +expectpart "$($clixon_cli -1 -f $cfg set interfaces2 interface e config enabled true 2>&1)" 0 "^$" + new "Kill backend" # Check if premature kill pid=$(pgrep -u root -f clixon_backend) 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{