diff --git a/apps/backend/backend_get.c b/apps/backend/backend_get.c index e50a8f9f..bd772eab 100644 --- a/apps/backend/backend_get.c +++ b/apps/backend/backend_get.c @@ -413,7 +413,6 @@ element2value(clicon_handle h, * @param[in] x XML node * @param[in] flag Flag to be used * @retval 0 OK - */ static int xml_flag_default_value(cxobj *x, @@ -464,11 +463,11 @@ xml_add_default_tag(cxobj *x, goto done; if (xml_value_set(xattr, "true") < 0) goto done; - if (xml_prefix_set(xattr, "wd") < 0) + if (xml_prefix_set(xattr, IETF_NETCONF_WITH_DEFAULTS_ATTR_PREFIX) < 0) goto done; } retval = 0; - done: + done: return retval; } @@ -478,7 +477,6 @@ xml_add_default_tag(cxobj *x, * @retval 0 OK * @retval -1 Error */ - static int with_defaults(cxobj *xe, cxobj *xret) @@ -506,7 +504,7 @@ with_defaults(cxobj *xe, goto done; goto ok; } - if (strcmp(mode, "trim") == 0) { + else if (strcmp(mode, "trim") == 0) { /* Remove default nodes from XML */ if (xml_tree_prune_flags(xret, XML_FLAG_DEFAULT, XML_FLAG_DEFAULT) < 0) goto done; @@ -521,8 +519,8 @@ with_defaults(cxobj *xe, goto done; goto ok; } - if (strcmp(mode, "report-all-tagged") == 0) { - if (xmlns_set(xret, "wd", "urn:ietf:params:xml:ns:netconf:default:1.0") < 0) + else if (strcmp(mode, "report-all-tagged") == 0) { + if (xmlns_set(xret, IETF_NETCONF_WITH_DEFAULTS_ATTR_PREFIX, IETF_NETCONF_WITH_DEFAULTS_ATTR_NAMESPACE) < 0) goto done; /* Mark nodes having default schema values */ if (xml_apply(xret, CX_ELMNT, (xml_applyfn_t*) xml_flag_default_value, (void*) XML_FLAG_MARK) < 0) @@ -532,7 +530,7 @@ with_defaults(cxobj *xe, goto done; goto ok; } - if (strcmp(mode, "report-all") == 0) { + else if (strcmp(mode, "report-all") == 0) { /* Accept mode, do nothing */ goto ok; } diff --git a/apps/cli/cli_auto.c b/apps/cli/cli_auto.c index db151e12..28fbbf44 100644 --- a/apps/cli/cli_auto.c +++ b/apps/cli/cli_auto.c @@ -347,8 +347,14 @@ cli_auto_top(clicon_handle h, * "text"|"xml"|"json"|"cli"|"netconf" (see format_enum) * true|false: pretty-print or not * true|false: pretty-print or not - * to print before cli syntax output + * Retrieval default mode: report-all, trim, explicit, report-all-tagged, + * report-all-tagged-default, report-all-tagged-strip + * CLI prefix: to print before cli syntax output * @see cli_show_auto + * @note default mods accorsing to RFC6243 + two extra modes based on report-all-tagged: + * report-all-tagged-default Strip "default" attribute (=report-all xxx) + * report-all-tagged-strip Strip "default" attribute and all nodes tagged with it (=trim) + * XXX Merge with cli_show_auto */ int cli_auto_show(clicon_handle h, @@ -376,9 +382,11 @@ cli_auto_show(clicon_handle h, char *prefix = NULL; int state; cg_var *boolcv = NULL; + char *defaultstr = NULL; /* with extended tagged modes */ + char *withdefaultstr = NULL; /* RFC 6243 modes */ - if (cvec_len(argv) != 5 && cvec_len(argv) != 6){ - clicon_err(OE_PLUGIN, EINVAL, "Usage: []."); + if (cvec_len(argv) < 5 || cvec_len(argv) > 7){ + clicon_err(OE_PLUGIN, EINVAL, "Usage: [ ]."); goto done; } /* First argv argument: treename */ @@ -407,10 +415,27 @@ cli_auto_show(clicon_handle h, goto done; } state = cv_bool_get(boolcv); - - /* Sixth: prefix */ - if (cvec_len(argv) == 6) { - prefix = cv_string_get(cvec_i(argv, 5)); + /* Sixth: default */ + if (cvec_len(argv) > 5) { + defaultstr = cv_string_get(cvec_i(argv, 5)); + /* From extended to RFC6243 withdefault modes */ + if (strcmp(defaultstr, "report-all-tagged-strip") == 0) + withdefaultstr = "report-all-tagged"; + else if (strcmp(defaultstr, "report-all-tagged-default") == 0) + withdefaultstr = "report-all-tagged"; + else if (strcmp(defaultstr, "report-all") != 0 && + strcmp(defaultstr, "trim") != 0 && + strcmp(defaultstr, "explicit") != 0 && + strcmp(defaultstr, "report-all-tagged") != 0){ + clicon_err(OE_YANG, EINVAL, "Unexpected with-default option: %s", defaultstr); + goto done; + } + else + withdefaultstr = defaultstr; + } + /* Seventh: cli prefix */ + if (cvec_len(argv) > 6) { + prefix = cv_string_get(cvec_i(argv, 6)); } if ((yspec = clicon_dbspec_yang(h)) == NULL){ clicon_err(OE_FATAL, 0, "No DB_SPEC"); @@ -428,22 +453,31 @@ cli_auto_show(clicon_handle h, if (api_path2xpath(api_path, yspec, &xpath, &nsc, NULL) < 0) goto done; skiproot = (xpath != NULL) && (strcmp(xpath,"/") != 0); - if (state == 0){ /* Get configuration-only from database */ - if (clicon_rpc_get_config(h, NULL, db, xpath, nsc, &xt) < 0) + if (state && strcmp(db, "running") != 0){ + clicon_err(OE_FATAL, 0, "Show state only for running database, not %s", db); + goto done; + } + if (state == 0){ /* Get configuration-only from a database */ + if (clicon_rpc_get_config(h, NULL, db, xpath, nsc, withdefaultstr, &xt) < 0) goto done; } - else { /* Get configuration and state from database */ - if (strcmp(db, "running") != 0){ - clicon_err(OE_FATAL, 0, "Show state only for running database, not %s", db); - goto done; - } - if (clicon_rpc_get(h, xpath, nsc, CONTENT_ALL, -1, NULL, &xt) < 0) + else { /* Get configuration and state from running */ + if (clicon_rpc_get(h, xpath, nsc, CONTENT_ALL, -1, withdefaultstr, &xt) < 0) goto done; } if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){ clixon_netconf_error(xerr, "Get configuration", NULL); goto done; } + /* Special tagged modes: strip wd:default=true attribute and (optionally) nodes associated with it */ + if (defaultstr && + (strcmp(defaultstr, "report-all-tagged-strip") == 0 || + strcmp(defaultstr, "report-all-tagged-default") == 0)){ + if (purge_tagged_nodes(xt, IETF_NETCONF_WITH_DEFAULTS_ATTR_NAMESPACE, "default", "true", + strcmp(defaultstr, "report-all-tagged-strip") + ) < 0) + goto done; + } if (xpath_vec(xt, nsc, "%s", &vec, &veclen, xpath) < 0) goto done; diff --git a/apps/cli/cli_common.c b/apps/cli/cli_common.c index 59967fd0..1fd41604 100644 --- a/apps/cli/cli_common.c +++ b/apps/cli/cli_common.c @@ -772,13 +772,13 @@ compare_dbs(clicon_handle h, format = FORMAT_TEXT; else format = FORMAT_XML; - if (clicon_rpc_get_config(h, NULL, "running", "/", NULL, &xc1) < 0) + if (clicon_rpc_get_config(h, NULL, "running", "/", NULL, NULL, &xc1) < 0) goto done; if ((xerr = xpath_first(xc1, NULL, "/rpc-error")) != NULL){ clixon_netconf_error(xerr, "Get configuration", NULL); goto done; } - if (clicon_rpc_get_config(h, NULL, "candidate", "/", NULL, &xc2) < 0) + if (clicon_rpc_get_config(h, NULL, "candidate", "/", NULL, NULL, &xc2) < 0) goto done; if ((xerr = xpath_first(xc2, NULL, "/rpc-error")) != NULL){ clixon_netconf_error(xerr, "Get configuration", NULL); @@ -1028,7 +1028,7 @@ save_config_file(clicon_handle h, goto done; } filename = cv_string_get(cv); - if (clicon_rpc_get_config(h, NULL, dbstr,"/", NULL, &xt) < 0) + if (clicon_rpc_get_config(h, NULL, dbstr,"/", NULL, NULL, &xt) < 0) goto done; if (xt == NULL){ clicon_err(OE_CFG, 0, "get config: empty tree"); /* Shouldnt happen */ @@ -1396,7 +1396,7 @@ cli_copy_config(clicon_handle h, if ((nsc = xml_nsctx_init(NULL, namespace)) == NULL) goto done; /* Get from object configuration and store in x1 */ - if (clicon_rpc_get_config(h, NULL, db, cbuf_get(cb), nsc, &x1) < 0) + if (clicon_rpc_get_config(h, NULL, db, cbuf_get(cb), nsc, NULL, &x1) < 0) goto done; if ((xerr = xpath_first(x1, NULL, "/rpc-error")) != NULL){ clixon_netconf_error(xerr, "Get configuration", NULL); diff --git a/apps/cli/cli_show.c b/apps/cli/cli_show.c index 9533a946..fcb8cad6 100644 --- a/apps/cli/cli_show.c +++ b/apps/cli/cli_show.c @@ -315,7 +315,7 @@ expand_dbvar(void *h, goto done; } /* Get configuration based on cbxpath */ - if (clicon_rpc_get_config(h, NULL, dbstr, cbuf_get(cbxpath), nsc, &xt) < 0) + if (clicon_rpc_get_config(h, NULL, dbstr, cbuf_get(cbxpath), nsc, NULL, &xt) < 0) goto done; if ((xe = xpath_first(xt, NULL, "/rpc-error")) != NULL){ clixon_netconf_error(xe, "Get configuration", NULL); @@ -476,7 +476,7 @@ cli_show_config1(clicon_handle h, prefix = cv_string_get(cvec_i(argv, 4)); } if (state == 0){ /* Get configuration-only from database */ - if (clicon_rpc_get_config(h, NULL, db, cbuf_get(cbxpath), nsc, &xt) < 0) + if (clicon_rpc_get_config(h, NULL, db, cbuf_get(cbxpath), nsc, NULL, &xt) < 0) goto done; } else { /* Get configuration and state from database */ @@ -637,7 +637,7 @@ show_conf_xpath(clicon_handle h, if (clicon_rpc_get(h, xpath, nsc, CONTENT_ALL, -1, &xt) < 0) goto done; #else - if (clicon_rpc_get_config(h, NULL, dbname, xpath, nsc, &xt) < 0) + if (clicon_rpc_get_config(h, NULL, dbname, xpath, nsc, NULL, &xt) < 0) goto done; #endif if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){ @@ -741,7 +741,7 @@ cli_show_auto1(clicon_handle h, xpath[strlen(xpath)-1] = '\0'; if (state == 0){ /* Get configuration-only from database */ - if (clicon_rpc_get_config(h, NULL, db, xpath, nsc, &xt) < 0) + if (clicon_rpc_get_config(h, NULL, db, xpath, nsc, NULL, &xt) < 0) goto done; } else{ /* Get configuration and state from database */ diff --git a/apps/restconf/restconf_main_fcgi.c b/apps/restconf/restconf_main_fcgi.c index 75cf08b3..ee8cf1be 100644 --- a/apps/restconf/restconf_main_fcgi.c +++ b/apps/restconf/restconf_main_fcgi.c @@ -181,7 +181,7 @@ restconf_main_config(clicon_handle h, clicon_err(OE_UNIX, errno, "getpwuid"); goto done; } - if (clicon_rpc_get_config(h, pw->pw_name, "running", "/restconf", nsc, &xconfig) < 0) + if (clicon_rpc_get_config(h, pw->pw_name, "running", "/restconf", nsc, NULL, &xconfig) < 0) goto done; if ((xerr = xpath_first(xconfig, NULL, "/rpc-error")) != NULL){ clixon_netconf_error(xerr, "Get backend restconf config", NULL); diff --git a/apps/restconf/restconf_main_native.c b/apps/restconf/restconf_main_native.c index 8638017b..be8e9264 100644 --- a/apps/restconf/restconf_main_native.c +++ b/apps/restconf/restconf_main_native.c @@ -670,7 +670,7 @@ restconf_clixon_backend(clicon_handle h, goto done; } /* XXX xconfig leaked */ - if (clicon_rpc_get_config(h, pw->pw_name, "running", "/restconf", nsc, &xconfig) < 0) + if (clicon_rpc_get_config(h, pw->pw_name, "running", "/restconf", nsc, NULL, &xconfig) < 0) goto done; if ((xerr = xpath_first(xconfig, NULL, "/rpc-error")) != NULL){ clixon_netconf_error(xerr, "Get backend restconf config", NULL); diff --git a/example/main/example_cli.c b/example/main/example_cli.c index d7dec97d..7cafb23d 100644 --- a/example/main/example_cli.c +++ b/example/main/example_cli.c @@ -71,7 +71,7 @@ mycallback(clicon_handle h, cvec *cvv, cvec *argv) /* Show eth0 interfaces config using XPATH */ if (clicon_rpc_get_config(h, NULL, "running", "/interfaces/interface[name='eth0']", - nsc, + nsc, NULL, &xret) < 0) goto done; if (clixon_xml2file(stdout, xret, 0, 1, cligen_output, 0, 1) < 0) diff --git a/example/main/example_cli.cli b/example/main/example_cli.cli index a4104c8d..551ed724 100644 --- a/example/main/example_cli.cli +++ b/example/main/example_cli.cli @@ -83,16 +83,35 @@ show("Show a particular state of the system"){ cli, cli_pagination("use xpath var", "es", "http://example.com/ns/example-social", "cli", "10"); text, cli_pagination("use xpath var", "es", "http://example.com/ns/example-social", "text", "10"); json, cli_pagination("use xpath var", "es", "http://example.com/ns/example-social", "json", "10"); - } + } configuration("Show configuration"), cli_auto_show("datamodel", "candidate", "text", true, false);{ - xml("Show configuration as XML"), cli_auto_show("datamodel", "candidate", "xml", 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);{ + default("With-default mode"){ + report-all, cli_auto_show("datamodel", "candidate", "xml", true, false, "report-all"); + trim, cli_auto_show("datamodel", "candidate", "xml", true, false, "trim"); + explicit, cli_auto_show("datamodel", "candidate", "xml", true, false, "explicit"); + report-all-tagged, cli_auto_show("datamodel", "candidate", "xml", true, false, "report-all-tagged"); + report-all-tagged-default, cli_auto_show("datamodel", "candidate", "xml", true, false, "report-all-tagged-default"); + report-all-tagged-strip, cli_auto_show("datamodel", "candidate", "xml", true, false, "report-all-tagged-strip"); + } + } + cli("Show configuration as CLI commands"), cli_auto_show("datamodel", "candidate", "cli", true, false, "explicit", "set "); netconf("Show configuration as netconf edit-config operation"), cli_auto_show("datamodel", "candidate", "netconf", true, false); text("Show configuration as text"), cli_auto_show("datamodel", "candidate", "text", true, false); json("Show configuration as JSON"), cli_auto_show("datamodel", "candidate", "json", true, false); + } state("Show configuration and state"), cli_auto_show("datamodel", "running", "text", true, true); { - xml("Show configuration and state as XML"), cli_auto_show("datamodel", "running", "xml", true, true); + xml("Show configuration and state as XML"), cli_auto_show("datamodel", "running", "xml", true, true);{ + default("With-default mode"){ + report-all, cli_auto_show("datamodel", "running", "xml", true, true, "report-all"); + trim, cli_auto_show("datamodel", "running", "xml", true, true, "trim"); + explicit, cli_auto_show("datamodel", "running", "xml", true, true, "explicit"); + report-all-tagged, cli_auto_show("datamodel", "running", "xml", true, true, "report-all-tagged"); + report-all-tagged-default, cli_auto_show("datamodel", "running", "xml", true, true, "report-all-tagged-default"); + report-all-tagged-strip, cli_auto_show("datamodel", "running", "xml", true, true, "report-all-tagged-strip"); + } + } } yang("Show yang specs"), show_yang(); { clixon-example("Show clixon-example yang spec"), show_yang("clixon-example"); diff --git a/lib/clixon/clixon_proto_client.h b/lib/clixon/clixon_proto_client.h index f6a43b0e..c021ff02 100644 --- a/lib/clixon/clixon_proto_client.h +++ b/lib/clixon/clixon_proto_client.h @@ -47,7 +47,7 @@ int clicon_rpc_msg(clicon_handle h, struct clicon_msg *msg, cxobj **xret0); int clicon_rpc_msg_persistent(clicon_handle h, struct clicon_msg *msg, cxobj **xret0, int *sock0); int clicon_rpc_netconf(clicon_handle h, char *xmlst, cxobj **xret, int *sp); int clicon_rpc_netconf_xml(clicon_handle h, cxobj *xml, cxobj **xret, int *sp); -int clicon_rpc_get_config(clicon_handle h, char *username, char *db, char *xpath, cvec *nsc, cxobj **xret); +int clicon_rpc_get_config(clicon_handle h, char *username, char *db, char *xpath, cvec *nsc, char *defaults, cxobj **xret); int clicon_rpc_edit_config(clicon_handle h, char *db, enum operation_type op, char *xml); int clicon_rpc_copy_config(clicon_handle h, char *db1, char *db2); diff --git a/lib/clixon/clixon_xml.h b/lib/clixon/clixon_xml.h index 09dcf776..1413fcea 100644 --- a/lib/clixon/clixon_xml.h +++ b/lib/clixon/clixon_xml.h @@ -65,6 +65,16 @@ */ #define IETF_PAGINATON_NC_NAMESPACE "urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc" +/* RFC 6243 With-defaults Capability for NETCONF + * ietf-netconf-with-defaults + * First in use in get requests + */ +#define IETF_NETCONF_WITH_DEFAULTS_YANG_NAMESPACE "urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults" + +/* Second in use in by replies for tagged attributes */ +#define IETF_NETCONF_WITH_DEFAULTS_ATTR_NAMESPACE "urn:ietf:params:xml:ns:netconf:default:1.0" +#define IETF_NETCONF_WITH_DEFAULTS_ATTR_PREFIX "wd" + /* Output symbol for netconf get/get-config * ietf-netconf.yang defines it as output: * output { anyxml data; diff --git a/lib/clixon/clixon_xml_map.h b/lib/clixon/clixon_xml_map.h index cd60bd55..400481bf 100644 --- a/lib/clixon/clixon_xml_map.h +++ b/lib/clixon/clixon_xml_map.h @@ -77,5 +77,6 @@ int xml_copy_marked(cxobj *x0, cxobj *x1); int yang_check_when_xpath(cxobj *xn, cxobj *xp, yang_stmt *yn, int *hit, int *nrp, char **xpathp); int xml_rpc_isaction(cxobj *xn); int xml_find_action(cxobj *xn, int top, cxobj **xap); +int purge_tagged_nodes(cxobj *xn, char *ns, char *name, char *value, int keepnode); #endif /* _CLIXON_XML_MAP_H_ */ diff --git a/lib/src/clixon_nacm.c b/lib/src/clixon_nacm.c index 3d97f05a..5f499f13 100644 --- a/lib/src/clixon_nacm.c +++ b/lib/src/clixon_nacm.c @@ -921,7 +921,7 @@ nacm_datanode_read_recurse(clicon_handle h, if (xml_flag(x, XML_FLAG_DEL)){ if (xml_purge(x) < 0) goto done; - x = xprev; + x = xprev; } } } diff --git a/lib/src/clixon_proto_client.c b/lib/src/clixon_proto_client.c index c7f29273..63ce9785 100644 --- a/lib/src/clixon_proto_client.c +++ b/lib/src/clixon_proto_client.c @@ -457,7 +457,8 @@ clicon_rpc_netconf_xml(clicon_handle h, * @param[in] username If NULL, use default * @param[in] db Name of database * @param[in] xpath XPath (or "") - * @param[in] nsc Namespace context for filter + * @param[in] nsc Namespace context for filter + * @param[in] defaults Value of the with-defaults mode, rfc6243, or NULL * @param[out] xt XML tree. Free with xml_free. * Either or . * @retval 0 OK @@ -468,7 +469,7 @@ clicon_rpc_netconf_xml(clicon_handle h, * * if ((nsc = xml_nsctx_init(NULL, "urn:example:hello")) == NULL) * err; - * if (clicon_rpc_get_config(h, NULL, "running", "/hello/world", nsc, &xt) < 0) + * if (clicon_rpc_get_config(h, NULL, "running", "/hello/world", nsc, "explicit", &xt) < 0) * err; * if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){ * clixon_netconf_error(xerr, "msg", "/hello/world"); @@ -489,6 +490,7 @@ clicon_rpc_get_config(clicon_handle h, char *db, char *xpath, cvec *nsc, + char *defaults, cxobj **xt) { int retval = -1; @@ -523,6 +525,10 @@ clicon_rpc_get_config(clicon_handle h, goto done; cprintf(cb, "/>"); } + if (defaults != NULL) + cprintf(cb, "%s", + IETF_NETCONF_WITH_DEFAULTS_YANG_NAMESPACE, + defaults); cprintf(cb, ""); if ((msg = clicon_msg_encode(session_id, "%s", cbuf_get(cb))) == NULL) goto done; @@ -910,7 +916,9 @@ clicon_rpc_get(clicon_handle h, cprintf(cb, "/>"); } if (defaults != NULL) - cprintf(cb, "%s", defaults); + cprintf(cb, "%s", + IETF_NETCONF_WITH_DEFAULTS_YANG_NAMESPACE, + defaults); cprintf(cb, ""); if ((msg = clicon_msg_encode(session_id, "%s", cbuf_get(cb))) == NULL) diff --git a/lib/src/clixon_xml.c b/lib/src/clixon_xml.c index 7fb7b087..e8dd1035 100644 --- a/lib/src/clixon_xml.c +++ b/lib/src/clixon_xml.c @@ -1367,7 +1367,7 @@ xml_wrap(cxobj *xc, * @param[in] xc xml child node (to be removed and freed) * @retval 0 OK * @retval -1 - * @note you cannot remove xchild in the loop (unless yoy keep track of xprev) + * @note you cannot remove xchild in the loop (unless you keep track of xprev) * @note Linear complexity - use xml_child_rm if possible * @see xml_free Free, dont remove from parent * @see xml_child_rm Remove if child order is known (does not free) @@ -1500,6 +1500,7 @@ xml_rm_children(cxobj *xp, return retval; } + /*! Remove top XML object and all children except a single child * Given a root xml node, and the i:th child, remove the child from its parent * and return it, remove the parent and all other children. (unwrap) diff --git a/lib/src/clixon_xml_map.c b/lib/src/clixon_xml_map.c index 81b35129..380f155f 100644 --- a/lib/src/clixon_xml_map.c +++ b/lib/src/clixon_xml_map.c @@ -2218,3 +2218,52 @@ xml_find_action(cxobj *xn, done: return retval; } + +/*! Utility function: recursive traverse an XML tree and remove nodes based on attribute value + * Conditionally remove attribute and node + * @param[in] xn XML node + * @param[in] ns Namespace of attribute + * @param[in] name Attribute name + * @param[in] value Attribute value + * @param[in] keepnode 0: remove node associated with attribute; 1: keep node but remove attr + */ +int +purge_tagged_nodes(cxobj *xn, + char *ns, + char *name, + char *value, + int keepnode) +{ + int retval = -1; + cxobj *x; + cxobj *xa; + cxobj *xprev; + char *prefix; + char *v; + int ret; + + x = NULL; + xprev = NULL; + while ((x = xml_child_each(xn, x, CX_ELMNT)) != NULL) { + if ((ret = xml2prefix(x, ns, &prefix)) < 0) + goto done; + if (ret == 0) + continue; + if ((xa = xml_find_type(x, prefix, "default", CX_ATTR)) != NULL){ + if (!keepnode && + (v = xml_value(xa)) != NULL && + strcmp(v, value) == 0){ + xml_purge(x); + x = xprev; + continue; + } + xml_purge(xa); /* remove attribute regardless */ + } + if (purge_tagged_nodes(x, ns, name, value, keepnode) < 0) + goto done; + xprev = x; + } + retval = 0; + done: + return retval; +} diff --git a/test/test_autocli_editmode.sh b/test/test_autocli_editmode.sh index 2b526033..2b3b6042 100755 --- a/test/test_autocli_editmode.sh +++ b/test/test_autocli_editmode.sh @@ -82,7 +82,7 @@ quit("Quit"), cli_quit(); show("Show a particular state of the system"){ configuration("Show configuration"), cli_auto_show("datamodel", "candidate", "text", true, false);{ xml("Show configuration as XML"), cli_auto_show("datamodel", "candidate", "xml", false, false); - cli("Show configuration as CLI commands"), cli_auto_show("datamodel", "candidate", "cli", false, false, "set "); + cli("Show configuration as CLI commands"), cli_auto_show("datamodel", "candidate", "cli", false, false, "report-all", "set "); netconf("Show configuration as netconf edit-config operation"), cli_auto_show("datamodel", "candidate", "netconf", false, false); text("Show configuration as text"), cli_auto_show("datamodel", "candidate", "text", false, false); json("Show configuration as JSON"), cli_auto_show("datamodel", "candidate", "json", false, false); diff --git a/test/test_autocli_spec.sh b/test/test_autocli_spec.sh index 63547c86..6284a562 100755 --- a/test/test_autocli_spec.sh +++ b/test/test_autocli_spec.sh @@ -81,7 +81,7 @@ quit("Quit"), cli_quit(); show("Show a particular state of the system"){ configuration("Show configuration"), cli_auto_show("datamodel", "candidate", "text", true, false);{ xml("Show configuration as XML"), cli_auto_show("datamodel", "candidate", "xml", false, false); - cli("Show configuration as CLI commands"), cli_auto_show("datamodel", "candidate", "cli", false, false, "set "); + cli("Show configuration as CLI commands"), cli_auto_show("datamodel", "candidate", "cli", false, false, "report-all", "set "); netconf("Show configuration as netconf edit-config operation"), cli_auto_show("datamodel", "candidate", "netconf", false, false); text("Show configuration as text"), cli_auto_show("datamodel", "candidate", "text", false, false); json("Show configuration as JSON"), cli_auto_show("datamodel", "candidate", "json", false, false); diff --git a/test/test_choice.sh b/test/test_choice.sh index f3e08a81..115260e2 100755 --- a/test/test_choice.sh +++ b/test/test_choice.sh @@ -201,7 +201,7 @@ discard("Discard edits (rollback 0)"), discard_changes(); show("Show a particular state of the system"){ 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 "); + cli("Show configuration as CLI commands"), cli_auto_show("datamodel", "candidate", "cli", true, false, "report-all", "set "); xml("Show configuration as XML"), cli_auto_show("datamodel", "candidate", "xml", true, false, NULL); } } diff --git a/test/test_cli.sh b/test/test_cli.sh index 4b7966f0..0b812f98 100755 --- a/test/test_cli.sh +++ b/test/test_cli.sh @@ -134,9 +134,9 @@ show("Show a particular state of the system"){ 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 "); + cli("Show configuration as CLI commands"), cli_auto_show("datamodel", "candidate", "cli", true, false, "report-all", "set "); + xml("Show configuration as XML"), cli_auto_show("datamodel", "candidate", "xml", true, false); + text("Show configuration as TEXT"), cli_auto_show("datamodel", "candidate", "text", true, false); } } save("Save candidate configuration to XML file") ("Filename (local filename)"), save_config_file("candidate","filename", "xml"){ diff --git a/test/test_cli_leafref.sh b/test/test_cli_leafref.sh index fef36f25..46a03171 100755 --- a/test/test_cli_leafref.sh +++ b/test/test_cli_leafref.sh @@ -167,7 +167,7 @@ delete("Delete a configuration item") { show("Show a particular state of the system"){ 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 "); + cli("Show configuration as CLI commands"), cli_auto_show("datamodel", "candidate", "cli", true, false, "report-all", "set "); } } validate("Validate changes"), cli_validate(); diff --git a/test/test_datastore_format.sh b/test/test_datastore_format.sh index 56ace059..73323006 100755 --- a/test/test_datastore_format.sh +++ b/test/test_datastore_format.sh @@ -108,7 +108,7 @@ show("Show a particular state of the system"){ 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 "); + cli("Show configuration as CLI commands"), cli_auto_show("datamodel", "candidate", "cli", true, false, "report-all", "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 "); } diff --git a/test/test_restconf_callhome.sh b/test/test_restconf_callhome.sh index 55866fec..e1ac9174 100755 --- a/test/test_restconf_callhome.sh +++ b/test/test_restconf_callhome.sh @@ -58,7 +58,6 @@ cat < $cfg ietf-netconf:startup ${YANG_INSTALLDIR} $fyang - /usr/local/lib/$APPNAME/clispec /usr/local/lib/$APPNAME/backend example_backend.so$ /usr/local/lib/$APPNAME/cli @@ -216,7 +215,7 @@ quit("Quit"), cli_quit(); show("Show a particular state of the system"){ configuration("Show configuration"), cli_auto_show("datamodel", "candidate", "text", true, false);{ xml("Show configuration as XML"), cli_auto_show("datamodel", "candidate", "xml", true, false); - cli("Show configuration as CLI commands"), cli_auto_show("datamodel", "candidate", "cli", false, false, "set "); + cli("Show configuration as CLI commands"), cli_auto_show("datamodel", "candidate", "cli", false, false, "report-all", "set "); netconf("Show configuration as netconf edit-config operation"), cli_auto_show("datamodel", "candidate", "netconf", false, false); text("Show configuration as text"), cli_auto_show("datamodel", "candidate", "text", false, false); json("Show configuration as JSON"), cli_auto_show("datamodel", "candidate", "json", false, false); diff --git a/test/test_yang_with_defaults.sh b/test/test_yang_with_defaults.sh index 47992970..5ba4ac74 100755 --- a/test/test_yang_with_defaults.sh +++ b/test/test_yang_with_defaults.sh @@ -1,6 +1,5 @@ #!/usr/bin/env bash - # Test of the IETF rfc6243: With-defaults Capability for NETCONF # # Test cases below follows the RFC. @@ -14,6 +13,7 @@ APPNAME=example cfg=$dir/conf_yang.xml fyang=$dir/example-default.yang fstate=$dir/state.xml +clispec=$dir/spec.cli RESTCONFIG=$(restconf_config none false) cat < $cfg @@ -23,7 +23,7 @@ cat < $cfg 42 ${YANG_INSTALLDIR} $fyang - /usr/local/lib/$APPNAME/clispec + $dir /usr/local/lib/$APPNAME/backend example_backend.so$ /usr/local/lib/$APPNAME/netconf @@ -116,6 +116,41 @@ module example { } EOF +# CLIspec for cli tests +cat < $clispec +CLICON_MODE="example"; +CLICON_PROMPT="%U@%H %W> "; +CLICON_PLUGIN="example_cli"; + +set @datamodel, cli_auto_set(); +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"){ + configuration("Show configuration") + xml("Show configuration and state as XML") + default("With-default mode"){ + report-all, cli_auto_show("datamodel", "candidate", "xml", false, false, "report-all"); + trim, cli_auto_show("datamodel", "candidate", "xml", false, false, "trim"); + explicit, cli_auto_show("datamodel", "candidate", "xml", false, false, "explicit"); + report-all-tagged, cli_auto_show("datamodel", "candidate", "xml", false, false, "report-all-tagged"); + report-all-tagged-default, cli_auto_show("datamodel", "candidate", "xml", false, false, "report-all-tagged-default"); + report-all-tagged-strip, cli_auto_show("datamodel", "candidate", "xml", false, false, "report-all-tagged-strip"); + } + state("Show configuration and state") + xml("Show configuration and state as XML") + default("With-default mode"){ + report-all, cli_auto_show("datamodel", "running", "xml", false, true, "report-all"); + trim, cli_auto_show("datamodel", "running", "xml", false, true, "trim"); + explicit, cli_auto_show("datamodel", "running", "xml", false, true, "explicit"); + report-all-tagged, cli_auto_show("datamodel", "running", "xml", false, true, "report-all-tagged"); + report-all-tagged-default, cli_auto_show("datamodel", "running", "xml", false, true, "report-all-tagged-default"); + report-all-tagged-strip, cli_auto_show("datamodel", "running", "xml", false, true, "report-all-tagged-strip"); + } +} +EOF + # A.2. Example Data Set EXAMPLENS="xmlns=\"http://example.com/ns/interfaces\"" @@ -527,6 +562,52 @@ expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+xml' $RCPR "Cache-Control: no-cache" \ 'eth11500ok' +# CLI tests +mode=explicit +new "cli with-default config $mode" +expectpart "$($clixon_cli -1 -f $cfg show config xml default $mode)" 0 "^eth08192eth1eth29000eth31500$" + +new "cli with-default state $mode" +expectpart "$($clixon_cli -1 -f $cfg show state xml default $mode)" 0 "^eth08192oketh1oketh29000not feeling so goodeth31500waking up$" + +mode=report-all +new "cli with-default config $mode" +expectpart "$($clixon_cli -1 -f $cfg show config xml default $mode)" 0 "^eth08192eth11500eth29000eth31500$" + +new "cli with-default state $mode" +expectpart "$($clixon_cli -1 -f $cfg show state xml default $mode)" 0 "^eth08192oketh11500oketh29000not feeling so goodeth31500waking up$" + +mode=report-all-tagged +new "cli with-default config $mode" +expectpart "$($clixon_cli -1 -f $cfg show config xml default $mode)" 0 "^eth08192eth11500eth29000eth31500$" + +new "cli with-default state $mode" +expectpart "$($clixon_cli -1 -f $cfg show state xml default $mode)" 0 "^eth08192oketh11500oketh29000not feeling so goodeth31500waking up$" + +mode=trim +new "cli with-default config $mode" +expectpart "$($clixon_cli -1 -f $cfg show config xml default $mode)" 0 "^eth08192eth1eth29000eth3$" + +new "cli with-default state $mode" +expectpart "$($clixon_cli -1 -f $cfg show state xml default $mode)" 0 "^eth08192eth1eth29000not feeling so goodeth3waking up$" + +mode=report-all-tagged-default +new "cli with-default config $mode" +expectpart "$($clixon_cli -1 -f $cfg show config xml default $mode)" 0 "^eth08192eth11500eth29000eth31500$" + +new "cli with-default state $mode" +expectpart "$($clixon_cli -1 -f $cfg show state xml default $mode)" 0 "^eth08192oketh11500oketh29000not feeling so goodeth31500waking up$" + +mode=report-all-tagged-strip +new "cli with-default config $mode" +expectpart "$($clixon_cli -1 -f $cfg show config xml default $mode)" 0 "^eth08192eth1eth29000eth3$" + +new "cli with-default state $mode" +expectpart "$($clixon_cli -1 -f $cfg show state xml default $mode)" 0 "^eth08192eth1eth29000not feeling so goodeth3waking up$" + +mode=negative-test +new "cli with-default config $mode" +expectpart "$($clixon_cli -1 -f $cfg -l o show config xml default $mode)" 255 "Unknown command" if [ $RC -ne 0 ]; then new "Kill restconf daemon"