diff --git a/CHANGELOG.md b/CHANGELOG.md
index 66f6aaa9..c2ddb988 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -29,6 +29,19 @@
## 4.10.0
Expected: February 2021
+### C/CLI-API changes on existing features
+
+Developers may need to change their code
+
+* Added `cvv_i` output parameter to `api_path_fmt2api_path()` to see how many cvv entries were used.
+
+### API changes on existing protocol/config features
+
+Users may have to change how they access the system
+
+* CLIspec dbxml API: Ability to specify deletion of _any_ vs _specific_ entry.
+ * In a cli_del() call, the cvv arg list either exactly matches the api-format-path in which case _any_ deletion is specified, otherwise, if there is an extra element in the cvv list, that is used for a specific delete.
+
### Corrected Bugs
* [Presence container configs not displayed in 'show config set' #164 ](https://github.com/clicon/clixon/issues/164)
diff --git a/apps/cli/cli_auto.c b/apps/cli/cli_auto.c
index 4b679afa..30470181 100644
--- a/apps/cli/cli_auto.c
+++ b/apps/cli/cli_auto.c
@@ -172,7 +172,7 @@ cli_auto_edit(clicon_handle h,
goto done;
}
/* get api-path and xpath */
- if (api_path_fmt2api_path(api_path_fmt, cvv2, &api_path) < 0)
+ if (api_path_fmt2api_path(api_path_fmt, cvv2, &api_path, NULL) < 0)
goto done;
/* Store this as edit-mode */
if (clicon_data_set(h, "cli-edit-mode", api_path) < 0)
@@ -250,7 +250,7 @@ cli_auto_up(clicon_handle h,
cvec_append_var(cvv1, cv);
}
/* get api-path and xpath */
- if (api_path_fmt2api_path(api_path_fmt1, cvv1, &api_path) < 0)
+ if (api_path_fmt2api_path(api_path_fmt1, cvv1, &api_path, NULL) < 0)
goto done;
/* Store this as edit-mode */
clicon_data_set(h, "cli-edit-mode", api_path);
@@ -660,7 +660,7 @@ cli_auto_sub_enter(clicon_handle h,
if (cvec_append_var(cvv1, cvec_i(cvv, i)) < 0)
goto done;
}
- if (api_path_fmt2api_path(api_path_fmt, cvv1, &api_path) < 0)
+ if (api_path_fmt2api_path(api_path_fmt, cvv1, &api_path, NULL) < 0)
goto done;
/* Assign the variables */
if ((cvv2 = cvec_append(clicon_data_cvec_get(h, "cli-edit-cvv"), cvv1)) == NULL)
diff --git a/apps/cli/cli_common.c b/apps/cli/cli_common.c
index 40ea7d98..9ce400be 100644
--- a/apps/cli/cli_common.c
+++ b/apps/cli/cli_common.c
@@ -251,6 +251,7 @@ cli_dbxml(clicon_handle h,
cxobj *xerr = NULL;
int ret;
cg_var *cv;
+ int cvv_i = 0;
if (cvec_len(argv) != 1){
clicon_err(OE_PLUGIN, EINVAL, "Requires one element to be xml key format string");
@@ -262,7 +263,10 @@ cli_dbxml(clicon_handle h,
}
arg = cvec_i(argv, 0);
api_path_fmt = cv_string_get(arg);
- if (api_path_fmt2api_path(api_path_fmt, cvv, &api_path) < 0)
+ /* Transform template format string + cvv to actual api-path
+ * cvv_i indicates if all cvv entries were used
+ */
+ if (api_path_fmt2api_path(api_path_fmt, cvv, &api_path, &cvv_i) < 0)
goto done;
/* Create config top-of-tree */
if ((xtop = xml_new("config", NULL, CX_ELMNT)) == NULL)
@@ -292,9 +296,17 @@ cli_dbxml(clicon_handle h,
/* Add body last in case of leaf */
if (cvec_len(cvv) > 1 &&
(yang_keyword_get(y) == Y_LEAF)){
- /* Add the body last */
- if (dbxml_body(xbot, cvv) < 0)
- goto done;
+ /* Add the body last if there is remaining element that was not used in the
+ * earlier api-path transformation.
+ * This is to handle differences between:
+ * DELETE bar and DELETE
+ * i.e., (1) deletion of a specific leaf entry vs (2) deletion of any entry
+ * Discussion: one can claim (1) is "bad" usage but one could see cases where
+ * you would want to delete a value if it has a specific value but not otherwise
+ */
+ if (cvv_i != cvec_len(cvv))
+ if (dbxml_body(xbot, cvv) < 0)
+ goto done;
/* Loop over namespace context and add them to this leaf node */
cv = NULL;
while ((cv = cvec_each(nsctx, cv)) != NULL){
diff --git a/apps/cli/cli_show.c b/apps/cli/cli_show.c
index 0277677e..2eb736a6 100644
--- a/apps/cli/cli_show.c
+++ b/apps/cli/cli_show.c
@@ -121,6 +121,7 @@ expand_dbvar(void *h,
char *reason = NULL;
cvec *nsc = NULL;
int ret;
+ int cvvi = 0;
if (argv == NULL || cvec_len(argv) != 2){
clicon_err(OE_PLUGIN, EINVAL, "requires arguments: ");
@@ -150,7 +151,7 @@ expand_dbvar(void *h,
* api_path: --> /interface/eth0/address/.*
* xpath: --> /interface/[name="eth0"]/address
*/
- if (api_path_fmt2api_path(api_path_fmt, cvv, &api_path) < 0)
+ if (api_path_fmt2api_path(api_path_fmt, cvv, &api_path, &cvvi) < 0)
goto done;
if (api_path2xpath(api_path, yspec, &xpath, &nsc, NULL) < 0)
goto done;
@@ -711,6 +712,7 @@ cli_show_auto1(clicon_handle h,
char *prefix = NULL;
enum rfc_6020 ys_keyword;
int i = 0;
+ int cvvi = 0;
if (cvec_len(argv) < 3 || cvec_len(argv) > 4){
clicon_err(OE_PLUGIN, EINVAL, "Usage: * . (*) generated.");
@@ -734,7 +736,7 @@ cli_show_auto1(clicon_handle h,
clicon_err(OE_FATAL, 0, "No DB_SPEC");
goto done;
}
- if (api_path_fmt2api_path(api_path_fmt, cvv, &api_path) < 0)
+ if (api_path_fmt2api_path(api_path_fmt, cvv, &api_path, &cvvi) < 0)
goto done;
if (api_path2xpath(api_path, yspec, &xpath, &nsc, NULL) < 0)
goto done;
diff --git a/lib/clixon/clixon_path.h b/lib/clixon/clixon_path.h
index 906221ec..ce033347 100644
--- a/lib/clixon/clixon_path.h
+++ b/lib/clixon/clixon_path.h
@@ -77,7 +77,7 @@ typedef struct {
*/
int xml_yang_root(cxobj *x, cxobj **xr);
int yang2api_path_fmt(yang_stmt *ys, int inclkey, char **api_path_fmt);
-int api_path_fmt2api_path(const char *api_path_fmt, cvec *cvv, char **api_path);
+int api_path_fmt2api_path(const char *api_path_fmt, cvec *cvv, char **api_path, int *cvvi);
int api_path_fmt2xpath(char *api_path_fmt, cvec *cvv, char **xpath);
int api_path2xpath(char *api_path, yang_stmt *yspec, char **xpath, cvec **nsc, cxobj **xerr);
int api_path2xml(char *api_path, yang_stmt *yspec, cxobj *xtop,
diff --git a/lib/src/clixon_path.c b/lib/src/clixon_path.c
index 0c6cdcb1..d2413c0a 100644
--- a/lib/src/clixon_path.c
+++ b/lib/src/clixon_path.c
@@ -424,6 +424,8 @@ yang2api_path_fmt(yang_stmt *ys,
* @param[in] api_path_fmt XML key format, eg /aaa/%s/name
* @param[in] cvv cligen variable vector, one for every wildchar in api_path_fmt
* @param[out] api_path api_path, eg /aaa/17. Free after use
+ * @param[out] cvvi 1..cvv-len. Index into cvv of last cvv entry used, For example,
+ * if same as len of cvv, all were used, if < some entries were not
* @retval 0 OK
* @retval -1 Error
* @note first and last elements of cvv are not used,..
@@ -446,16 +448,17 @@ yang2api_path_fmt(yang_stmt *ys,
int
api_path_fmt2api_path(const char *api_path_fmt,
cvec *cvv,
- char **api_path)
+ char **api_path,
+ int *cvv_i)
{
- int retval = -1;
- char c;
- int esc=0;
- cbuf *cb = NULL;
- int i;
- int j;
- char *str;
- char *strenc=NULL;
+ int retval = -1;
+ char c;
+ int esc=0;
+ cbuf *cb = NULL;
+ int i;
+ int j;
+ char *str;
+ char *strenc=NULL;
cg_var *cv;
if ((cb = cbuf_new()) == NULL){
@@ -498,6 +501,8 @@ api_path_fmt2api_path(const char *api_path_fmt,
clicon_err(OE_UNIX, errno, "strdup");
goto done;
}
+ if (cvv_i) /* Last entry in cvv used */
+ *cvv_i = j;
retval = 0;
done:
if (cb)
diff --git a/test/test_upgrade_simple.sh b/test/test_upgrade_simple.sh
index ab0b21a1..fba067c1 100755
--- a/test/test_upgrade_simple.sh
+++ b/test/test_upgrade_simple.sh
@@ -59,7 +59,7 @@ if [ $BE -ne 0 ]; then
new "start backend -s init -f $cfg"
start_backend -s init -f $cfg
- new "waiting"
+ new "wait backend"
wait_backend
fi
@@ -69,6 +69,9 @@ expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" "^]]>]]>$"
+# race condition where backend is killed before flushed to disk
+sleep $DEMSLEEP
+
new "Kill backend"
# Check if premature kill
pid=$(pgrep -u root -f clixon_backend)