Fixes for multiple list keys
This commit is contained in:
parent
5c938febf4
commit
f4e0b4bf20
5 changed files with 85 additions and 27 deletions
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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 (inclkey){
|
||||||
if (ys->ys_keyword != Y_CHOICE && ys->ys_keyword != Y_CASE)
|
if (ys->ys_keyword != Y_CHOICE && ys->ys_keyword != Y_CASE)
|
||||||
cprintf(cb, "/%s", ys->ys_argument);
|
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,9 +507,9 @@ 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
|
||||||
|
|
@ -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){
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue