Fixes for multiple list keys

This commit is contained in:
Olof hagsand 2016-11-19 21:20:56 +01:00
parent 5c938febf4
commit f4e0b4bf20
5 changed files with 85 additions and 27 deletions

View file

@ -181,7 +181,7 @@ cli_expand_var_generate(clicon_handle h,
int retval = -1; int retval = -1;
char *xkfmt = NULL; char *xkfmt = NULL;
if (yang2xmlkeyfmt(ys, &xkfmt) < 0) if (yang2xmlkeyfmt(ys, 1, &xkfmt) < 0)
goto done; goto done;
cprintf(cb0, "|<%s:%s", ys->ys_argument, cprintf(cb0, "|<%s:%s", ys->ys_argument,
cv_type2str(cvtype)); cv_type2str(cvtype));
@ -190,8 +190,6 @@ cli_expand_var_generate(clicon_handle h,
cprintf(cb0, " %s(\"candidate %s\")>", cprintf(cb0, " %s(\"candidate %s\")>",
GENERATE_EXPAND_XMLDB, GENERATE_EXPAND_XMLDB,
xkfmt); xkfmt);
retval = 0; retval = 0;
done: done:
if (xkfmt) if (xkfmt)
@ -213,7 +211,7 @@ cli_callback_generate(clicon_handle h,
int retval = -1; int retval = -1;
char *xkfmt = NULL; char *xkfmt = NULL;
if (yang2xmlkeyfmt(ys, &xkfmt) < 0) if (yang2xmlkeyfmt(ys, 0, &xkfmt) < 0)
goto done; goto done;
cprintf(cb0, ",%s(\"%s\")", GENERATE_CALLBACK, xkfmt); cprintf(cb0, ",%s(\"%s\")", GENERATE_CALLBACK, xkfmt);
retval = 0; retval = 0;

View file

@ -94,12 +94,14 @@ expand_dbvar(void *h,
char *str; char *str;
char *dbstr; char *dbstr;
cxobj *xt = NULL; cxobj *xt = NULL;
char *xk = NULL; char *xkpath = NULL;
cxobj **xvec = NULL; cxobj **xvec = NULL;
size_t xlen = 0; size_t xlen = 0;
cxobj *x; cxobj *x;
char *bodystr; char *bodystr;
int i; int i;
int j;
int k;
int i0; int i0;
if (arg == NULL || (str = cv_string_get(arg)) == NULL){ if (arg == NULL || (str = cv_string_get(arg)) == NULL){
@ -122,10 +124,38 @@ expand_dbvar(void *h,
--> ^/interface/eth0/address/.*$ --> ^/interface/eth0/address/.*$
--> /interface/[name=eth0]/address --> /interface/[name=eth0]/address
*/ */
if (xmlkeyfmt2xpath(xkfmt, cvv, &xk) < 0) if (xmlkeyfmt2xpath(xkfmt, cvv, &xkpath) < 0)
goto done; goto done;
if (xmldb_get(h, dbstr, xk, 1, &xt, &xvec, &xlen) < 0) if (xmldb_get(h, dbstr, xkpath, 1, &xt, &xvec, &xlen) < 0)
goto done; goto done;
/* One round to detect duplicates
* XXX The code below would benefit from some cleanup
*/
j = 0;
for (i = 0; i < xlen; i++) {
char *str;
x = xvec[i];
if (xml_type(x) == CX_BODY)
bodystr = xml_value(x);
else
bodystr = xml_body(x);
if (bodystr == NULL){
clicon_err(OE_CFG, 0, "No xml body");
goto done;
}
/* detect duplicates */
for (k=0; k<j; k++){
if (xml_type(xvec[k]) == CX_BODY)
str = xml_value(xvec[k]);
else
str = xml_body(xvec[k]);
if (strcmp(str, bodystr)==0)
break;
}
if (k==j) /* not duplicate */
xvec[j++] = x;
}
xlen = j;
i0 = *nr; i0 = *nr;
*nr += xlen; *nr += xlen;
if ((*commands = realloc(*commands, sizeof(char *) * (*nr))) == NULL) { if ((*commands = realloc(*commands, sizeof(char *) * (*nr))) == NULL) {
@ -151,8 +181,8 @@ expand_dbvar(void *h,
free(xvec); free(xvec);
if (xt) if (xt)
xml_free(xt); xml_free(xt);
if (xk) if (xkpath)
free(xk); free(xkpath);
return retval; return retval;
} }

View file

@ -26,7 +26,7 @@
/* /*
* Prototypes * Prototypes
*/ */
int yang2xmlkeyfmt(yang_stmt *ys, char **xkfmt); int yang2xmlkeyfmt(yang_stmt *ys, int inclkey, char **xkfmt);
int xmlkeyfmt2key(char *xkfmt, cvec *cvv, char **xk); int xmlkeyfmt2key(char *xkfmt, cvec *cvv, char **xk);
int xmlkeyfmt2xpath(char *xkfmt, cvec *cvv, char **xk); int xmlkeyfmt2xpath(char *xkfmt, cvec *cvv, char **xk);
int xmldb_get(clicon_handle h, char *db, char *xpath, int vector, int xmldb_get(clicon_handle h, char *db, char *xpath, int vector,

View file

@ -419,11 +419,11 @@ clicon_rpc(int s,
case CLICON_MSG_ERR: case CLICON_MSG_ERR:
if (clicon_msg_err_decode(reply, &err, &suberr, &reason, label) < 0) if (clicon_msg_err_decode(reply, &err, &suberr, &reason, label) < 0)
goto done; goto done;
clicon_err(err, suberr, "%s", reason); clicon_err(err, suberr, "%s msgtype:%hu", reason, ntohs(msg->op_type));
goto done; goto done;
break; break;
default: default:
clicon_err(OE_PROTO, 0, "%s: unexpected reply: %d", clicon_err(OE_PROTO, 0, "%s: unexpected reply: %hu",
__FUNCTION__, type); __FUNCTION__, type);
goto done; goto done;
break; break;

View file

@ -96,9 +96,18 @@
* instead of /interfaces/interface/%s/ipv4/address/ip/%s * instead of /interfaces/interface/%s/ipv4/address/ip/%s
* you can have: /interfaces/interface[name=%s]/ipv4/address/[ip=%s] * you can have: /interfaces/interface[name=%s]/ipv4/address/[ip=%s]
*/ */
/*! Recursive help function */ /*! Construct an xml key format from yang statement using wildcards for keys
* Recursively construct it to the top.
* Example:
* yang: container a -> list b -> key c -> leaf d
* xpath: /a/b/%s/d
* @param[in] ys Yang statement
* @param[in] inclkey If !inclkey then dont include key leaf
* @param[out] cbuf keyfmt
*/
static int static int
yang2xmlkeyfmt_1(yang_stmt *ys, yang2xmlkeyfmt_1(yang_stmt *ys,
int inclkey,
cbuf *cb) cbuf *cb)
{ {
yang_node *yn; yang_node *yn;
@ -111,11 +120,23 @@ yang2xmlkeyfmt_1(yang_stmt *ys,
if (yn != NULL && if (yn != NULL &&
yn->yn_keyword != Y_MODULE && yn->yn_keyword != Y_MODULE &&
yn->yn_keyword != Y_SUBMODULE){ yn->yn_keyword != Y_SUBMODULE){
if (yang2xmlkeyfmt_1((yang_stmt *)yn, cb) < 0) if (yang2xmlkeyfmt_1((yang_stmt *)yn, 1, cb) < 0)
goto done; goto done;
} }
if (ys->ys_keyword != Y_CHOICE && ys->ys_keyword != Y_CASE) if (inclkey){
cprintf(cb, "/%s", ys->ys_argument); if (ys->ys_keyword != Y_CHOICE && ys->ys_keyword != Y_CASE)
cprintf(cb, "/%s", ys->ys_argument);
}
else{
if (ys->ys_keyword == Y_LEAF && yn && yn->yn_keyword == Y_LIST){
if (yang_key_match(yn, ys->ys_argument) == 0)
cprintf(cb, "/%s", ys->ys_argument); /* Not if leaf and key */
}
else
if (ys->ys_keyword != Y_CHOICE && ys->ys_keyword != Y_CASE)
cprintf(cb, "/%s", ys->ys_argument);
}
switch (ys->ys_keyword){ switch (ys->ys_keyword){
case Y_LIST: case Y_LIST:
if ((ykey = yang_find((yang_node*)ys, Y_KEY, NULL)) == NULL){ if ((ykey = yang_find((yang_node*)ys, Y_KEY, NULL)) == NULL){
@ -144,15 +165,17 @@ yang2xmlkeyfmt_1(yang_stmt *ys,
} }
/*! Construct an xml key format from yang statement using wildcards for keys /*! Construct an xml key format from yang statement using wildcards for keys
* Recursively contruct it to the top. * Recursively construct it to the top.
* Example: * Example:
* yang: container a -> list b -> key c -> leaf d * yang: container a -> list b -> key c -> leaf d
* xpath: /a/b/%s/d * xpath: /a/b/%s/d
* @param[in] ys Yang statement * @param[in] ys Yang statement
* @param[out] xpath String, needs to be freed after use * @param[in] inclkey If !inclkey then dont include key leaf
* @param[out] xkfmt XML key format. Needs to be freed after use.
*/ */
int int
yang2xmlkeyfmt(yang_stmt *ys, yang2xmlkeyfmt(yang_stmt *ys,
int inclkey,
char **xkfmt) char **xkfmt)
{ {
int retval = -1; int retval = -1;
@ -162,7 +185,7 @@ yang2xmlkeyfmt(yang_stmt *ys,
clicon_err(OE_UNIX, errno, "cbuf_new"); clicon_err(OE_UNIX, errno, "cbuf_new");
goto done; goto done;
} }
if (yang2xmlkeyfmt_1(ys, cb) < 0) if (yang2xmlkeyfmt_1(ys, inclkey, cb) < 0)
goto done; goto done;
if ((*xkfmt = strdup(cbuf_get(cb))) == NULL){ if ((*xkfmt = strdup(cbuf_get(cb))) == NULL){
clicon_err(OE_UNIX, errno, "strdup"); clicon_err(OE_UNIX, errno, "strdup");
@ -249,13 +272,17 @@ xmlkeyfmt2key(char *xkfmt,
return retval; return retval;
} }
/*! Transform an xml key format and a vector of values to an XML key /*! Transform an xml key format and a vector of values to an XML path
* Used to input xmldb_get() or xmldb_get_vec * Used to input xmldb_get() or xmldb_get_vec
* Add .* in last %s position. * Add .* in last %s position.
* Example: * Example:
* xmlkeyfmt: /interface/%s/address/%s * xmlkeyfmt: /interface/%s/address/%s
* cvv: name=eth0 * cvv: name=eth0
* xmlkey: /interface/[name=eth0]/address * xmlkey: /interface/[name=eth0]/address
* Example2:
* xmlkeyfmt: /ip/me/%s (if key)
* cvv: -
* xmlkey: /ipv4/me/a
* @param[in] xkfmt XML key format * @param[in] xkfmt XML key format
* @param[in] cvv cligen variable vector, one for every wildchar in xkfmt * @param[in] cvv cligen variable vector, one for every wildchar in xkfmt
* @param[out] xk XPATH * @param[out] xk XPATH
@ -301,9 +328,8 @@ xmlkeyfmt2xpath(char *xkfmt,
esc = 0; esc = 0;
if (c!='s') if (c!='s')
continue; continue;
if (j == cvec_len(cvv)){ /* last element */ if (j == cvec_len(cvv)) /* last element */
skip++; skip++;
}
else{ else{
/* XXX: remove preceding '/' : /* XXX: remove preceding '/' :
a/[x=y] -> a[x=y] */ a/[x=y] -> a[x=y] */
@ -481,10 +507,10 @@ append_listkeys(cbuf *ckey,
} }
/*! Help function to create xml key values /*! Help function to create xml key values
* @param[in] x Parent * @param[in,out] x Parent
* @param[in] xc0 * @param[in] ykey
* @param[in] y * @param[in] arg
* @param[in] keyname yang key name * @param[in] keyname yang key name
*/ */
static int static int
create_keyvalues(cxobj *x, create_keyvalues(cxobj *x,
@ -649,6 +675,10 @@ get(char *dbname,
cvi = NULL; cvi = NULL;
/* Iterate over individual yang keys */ /* Iterate over individual yang keys */
cprintf(cb, "%s", name); cprintf(cb, "%s", name);
if (cvec_len(cvk) > 1 && i+cvec_len(cvk) >= nvec-1){
retval = 0;
goto done;
}
while ((cvi = cvec_each(cvk, cvi)) != NULL){ while ((cvi = cvec_each(cvk, cvi)) != NULL){
i++; i++;
if (i>=nvec){ if (i>=nvec){