* List-pagination: Adhere to ietf-draft: Removed list-pagination "presence"
* Remove default expansion in NETCONF client * C-API: Added `expanddefault` parameter to `xml_yang_validate_rpc()`
This commit is contained in:
parent
c2faf8b96c
commit
05cdbf5c4f
9 changed files with 125 additions and 72 deletions
|
|
@ -69,6 +69,7 @@ Developers may need to change their code
|
||||||
* [Code formatting: Change indentation style to space](https://github.com/clicon/clixon/issues/379)
|
* [Code formatting: Change indentation style to space](https://github.com/clicon/clixon/issues/379)
|
||||||
* Applies to all c/h/y/l/sh files and .editorconfig
|
* Applies to all c/h/y/l/sh files and .editorconfig
|
||||||
* C API changes
|
* C API changes
|
||||||
|
* Added `expanddefault` parameter to `xml_yang_validate_rpc()`
|
||||||
* Added `defaults` parameter to `clicon_rpc_get_pageable_list()`
|
* Added `defaults` parameter to `clicon_rpc_get_pageable_list()`
|
||||||
* `clicon_rpc_commit()` and `cli_commit`
|
* `clicon_rpc_commit()` and `cli_commit`
|
||||||
* Added `confirmed`, `cancel`, `timeout`, `persist-id`, and `persist-id-val` parameters to
|
* Added `confirmed`, `cancel`, `timeout`, `persist-id`, and `persist-id-val` parameters to
|
||||||
|
|
@ -79,6 +80,7 @@ Developers may need to change their code
|
||||||
|
|
||||||
### Minor features
|
### Minor features
|
||||||
|
|
||||||
|
* List-pagination: Adhere to ietf-draft: Removed list-pagination "presence"
|
||||||
* Main example: Removed dependency of external IETF RFCs
|
* Main example: Removed dependency of external IETF RFCs
|
||||||
* See [Can't initiate clixon_backend](https://github.com/clicon/clixon/issues/382)
|
* See [Can't initiate clixon_backend](https://github.com/clicon/clixon/issues/382)
|
||||||
* Added warning if modstate is not present in datastore if `CLICON_XMLDB_MODSTATE` is set.
|
* Added warning if modstate is not present in datastore if `CLICON_XMLDB_MODSTATE` is set.
|
||||||
|
|
|
||||||
|
|
@ -1388,7 +1388,7 @@ from_client_msg(clicon_handle h,
|
||||||
goto reply;
|
goto reply;
|
||||||
}
|
}
|
||||||
ce->ce_id = id;
|
ce->ce_id = id;
|
||||||
if ((ret = xml_yang_validate_rpc(h, x, &xret)) < 0)
|
if ((ret = xml_yang_validate_rpc(h, x, 1, &xret)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0){
|
if (ret == 0){
|
||||||
if (clixon_xml2cbuf(cbret, xret, 0, 0, -1, 0) < 0)
|
if (clixon_xml2cbuf(cbret, xret, 0, 0, -1, 0) < 0)
|
||||||
|
|
|
||||||
|
|
@ -385,11 +385,11 @@ get_nacm_and_reply(clicon_handle h,
|
||||||
* @param[in] h Clixon handle
|
* @param[in] h Clixon handle
|
||||||
* @param[in] name Name of attribute
|
* @param[in] name Name of attribute
|
||||||
* @param[in] defaultstr Default string which is accepted and sets value to 0
|
* @param[in] defaultstr Default string which is accepted and sets value to 0
|
||||||
* @param[in,out] cbret Output buffer for internal RPC message if invalid
|
* @param[in,out] cbret Output buffer for internal bad-element RPC message if invalid
|
||||||
* @param[out] value Value
|
* @param[out] value Value
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
* @retval 0 Invalid, cbret set
|
* @retval 0 Invalid, netconf bad-element error cbret set
|
||||||
* @retval 1 OK
|
* @retval 1 OK (or not found)
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
element2value(clicon_handle h,
|
element2value(clicon_handle h,
|
||||||
|
|
@ -545,6 +545,36 @@ with_defaults(cxobj *xe,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Extract offset and limit from get/list-pagination
|
||||||
|
*
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] xe Request: <rpc><xn></rpc>
|
||||||
|
* @param[out] offset Number of entries in the working result-set that should be skipped
|
||||||
|
* @param[out] limit Limits the number of entries returned from the working result-set
|
||||||
|
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
|
||||||
|
* @retval -1 Error
|
||||||
|
* @retval 0 Invalid, netconf bad-element error cbret set
|
||||||
|
* @retval 1 OK
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
list_pagination_hdr(clicon_handle h,
|
||||||
|
cxobj *xe,
|
||||||
|
uint32_t *offset,
|
||||||
|
uint32_t *limit,
|
||||||
|
cbuf *cbret)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
|
||||||
|
/* offset */
|
||||||
|
if ((retval = element2value(h, xe, "offset", "none", cbret, offset)) < 0)
|
||||||
|
goto done;
|
||||||
|
/* limit */
|
||||||
|
if (retval && (retval = element2value(h, xe, "limit", "unbounded", cbret, limit)) < 0)
|
||||||
|
goto done;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Specialized get for list-pagination
|
/*! Specialized get for list-pagination
|
||||||
*
|
*
|
||||||
* It is specialized enough to have its own function. Specifically, extra attributes as well
|
* It is specialized enough to have its own function. Specifically, extra attributes as well
|
||||||
|
|
@ -600,6 +630,10 @@ get_list_pagination(clicon_handle h,
|
||||||
char *where = NULL;
|
char *where = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (cbret == NULL){
|
||||||
|
clicon_err(OE_PLUGIN, EINVAL, "cbret is NULL");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
/* Check if list/leaf-list */
|
/* Check if list/leaf-list */
|
||||||
if (yang_path_arg(yspec, xpath?xpath:"/", &ylist) < 0)
|
if (yang_path_arg(yspec, xpath?xpath:"/", &ylist) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -635,11 +669,7 @@ get_list_pagination(clicon_handle h,
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* offset */
|
if ((ret = list_pagination_hdr(h, xe, &offset, &limit, cbret)) < 0)
|
||||||
if ((ret = element2value(h, xe, "offset", "none", cbret, &offset)) < 0)
|
|
||||||
goto done;
|
|
||||||
/* limit */
|
|
||||||
if (ret && (ret = element2value(h, xe, "limit", "unbounded", cbret, &limit)) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
#ifdef NOTYET
|
#ifdef NOTYET
|
||||||
/* direction */
|
/* direction */
|
||||||
|
|
@ -662,6 +692,8 @@ get_list_pagination(clicon_handle h,
|
||||||
if (ret && (x = xml_find_type(xe, NULL, "where", CX_ELMNT)) != NULL)
|
if (ret && (x = xml_find_type(xe, NULL, "where", CX_ELMNT)) != NULL)
|
||||||
where = xml_body(x);
|
where = xml_body(x);
|
||||||
#endif
|
#endif
|
||||||
|
if (ret == 0)
|
||||||
|
goto ok;
|
||||||
/* Read config */
|
/* Read config */
|
||||||
switch (content){
|
switch (content){
|
||||||
case CONTENT_CONFIG: /* config data only */
|
case CONTENT_CONFIG: /* config data only */
|
||||||
|
|
@ -860,6 +892,8 @@ get_common(clicon_handle h,
|
||||||
cxobj **xvec = NULL;
|
cxobj **xvec = NULL;
|
||||||
size_t xlen;
|
size_t xlen;
|
||||||
cxobj *xfind;
|
cxobj *xfind;
|
||||||
|
uint32_t offset = 0;
|
||||||
|
uint32_t limit = 0;
|
||||||
|
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
username = clicon_username_get(h);
|
username = clicon_username_get(h);
|
||||||
|
|
@ -900,8 +934,21 @@ get_common(clicon_handle h,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Check if list pagination */
|
/* Check if list pagination */
|
||||||
if ((xfind = xml_find_type(xe, NULL, "list-pagination", CX_ELMNT)) != NULL)
|
if ((xfind = xml_find_type(xe, NULL, "list-pagination", CX_ELMNT)) != NULL){
|
||||||
list_pagination = 1;
|
/* with non-presence list-pagination, use ad-hoc algorithm to determine
|
||||||
|
* whether list-pagination is enabled:
|
||||||
|
* offset!=0 && limit!=unbounded
|
||||||
|
*/
|
||||||
|
/* offset */
|
||||||
|
if ((ret = element2value(h, xfind, "offset", "none", cbret, &offset)) < 0)
|
||||||
|
goto done;
|
||||||
|
/* limit */
|
||||||
|
if (ret && (ret = element2value(h, xfind, "limit", "unbounded", cbret, &limit)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (ret == 0)
|
||||||
|
goto ok;
|
||||||
|
list_pagination = (offset != 0 || limit != 0);
|
||||||
|
}
|
||||||
/* Sanity check for list pagination: path must be a list/leaf-list, if it is,
|
/* Sanity check for list pagination: path must be a list/leaf-list, if it is,
|
||||||
* check config/state
|
* check config/state
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -223,7 +223,7 @@ netconf_rpc_message(clicon_handle h,
|
||||||
if ((ret = xml_bind_yang_rpc(xrpc, yspec, &xret)) < 0)
|
if ((ret = xml_bind_yang_rpc(xrpc, yspec, &xret)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret > 0 &&
|
if (ret > 0 &&
|
||||||
(ret = xml_yang_validate_rpc(h, xrpc, &xret)) < 0)
|
(ret = xml_yang_validate_rpc(h, xrpc, 0, &xret)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0){
|
if (ret == 0){
|
||||||
if (netconf_add_request_attr(xrpc, xret) < 0)
|
if (netconf_add_request_attr(xrpc, xret) < 0)
|
||||||
|
|
|
||||||
|
|
@ -806,7 +806,7 @@ api_operations_post(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
if ((ret = xml_yang_validate_rpc(h, xtop, &xerr)) < 0)
|
if ((ret = xml_yang_validate_rpc(h, xtop, 0, &xerr)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0){
|
if (ret == 0){
|
||||||
if (api_return_err0(h, req, xerr, pretty, media_out, 0) < 0)
|
if (api_return_err0(h, req, xerr, pretty, media_out, 0) < 0)
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@
|
||||||
/*
|
/*
|
||||||
* Prototypes
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
int xml_yang_validate_rpc(clicon_handle h, cxobj *xrpc, cxobj **xret);
|
int xml_yang_validate_rpc(clicon_handle h, cxobj *xrpc, int expanddefault, cxobj **xret);
|
||||||
int xml_yang_validate_rpc_reply(clicon_handle h, cxobj *xrpc, cxobj **xret);
|
int xml_yang_validate_rpc_reply(clicon_handle h, cxobj *xrpc, cxobj **xret);
|
||||||
int xml_yang_validate_add(clicon_handle h, cxobj *xt, cxobj **xret);
|
int xml_yang_validate_add(clicon_handle h, cxobj *xt, cxobj **xret);
|
||||||
int xml_yang_validate_list_key_only(cxobj *xt, cxobj **xret);
|
int xml_yang_validate_list_key_only(cxobj *xt, cxobj **xret);
|
||||||
|
|
|
||||||
|
|
@ -324,6 +324,7 @@ validate_identityref(cxobj *xt,
|
||||||
/*! Validate an RPC node
|
/*! Validate an RPC node
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] xrpc XML node to be validated
|
* @param[in] xrpc XML node to be validated
|
||||||
|
* @param[in] expanddefault
|
||||||
* @param[out] xret Error XML tree. Free with xml_free after use
|
* @param[out] xret Error XML tree. Free with xml_free after use
|
||||||
* @retval 1 Validation OK
|
* @retval 1 Validation OK
|
||||||
* @retval 0 Validation failed
|
* @retval 0 Validation failed
|
||||||
|
|
@ -366,6 +367,7 @@ validate_identityref(cxobj *xt,
|
||||||
int
|
int
|
||||||
xml_yang_validate_rpc(clicon_handle h,
|
xml_yang_validate_rpc(clicon_handle h,
|
||||||
cxobj *xrpc,
|
cxobj *xrpc,
|
||||||
|
int expanddefault,
|
||||||
cxobj **xret)
|
cxobj **xret)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
@ -403,7 +405,7 @@ xml_yang_validate_rpc(clicon_handle h,
|
||||||
goto done; /* error or validation fail */
|
goto done; /* error or validation fail */
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
if (xml_default_recurse(xn, 0) < 0)
|
if (expanddefault && xml_default_recurse(xn, 0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
// ok: /* pass validation */
|
// ok: /* pass validation */
|
||||||
|
|
|
||||||
|
|
@ -379,6 +379,9 @@ fi
|
||||||
new "wait restconf"
|
new "wait restconf"
|
||||||
wait_restconf
|
wait_restconf
|
||||||
|
|
||||||
|
new "Baseline: no pagination"
|
||||||
|
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get><filter type=\"xpath\" select=\"/es:members/es:member[es:member-id='alice']/es:favorites/es:uint8-numbers\" xmlns:es=\"http://example.com/ns/example-social\"/></get></rpc>" "<rpc-reply $DEFAULTNS><data><members xmlns=\"http://example.com/ns/example-social\"><member><member-id>alice</member-id><favorite"
|
||||||
|
|
||||||
new "A.3.1.1. limit=1"
|
new "A.3.1.1. limit=1"
|
||||||
testlimit 0 1 5 "17"
|
testlimit 0 1 5 "17"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,35 @@
|
||||||
module ietf-list-pagination-nc {
|
module ietf-list-pagination-nc {
|
||||||
yang-version 1.1;
|
yang-version 1.1;
|
||||||
namespace "urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc";
|
namespace "urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc";
|
||||||
prefix lpgnc;
|
prefix lpgnc;
|
||||||
|
|
||||||
import ietf-netconf {
|
import ietf-netconf {
|
||||||
prefix nc;
|
prefix nc;
|
||||||
reference
|
reference
|
||||||
"RFC 6241: Network Configuration Protocol (NETCONF)";
|
"RFC 6241: Network Configuration Protocol (NETCONF)";
|
||||||
}
|
}
|
||||||
|
|
||||||
import ietf-netconf-nmda {
|
import ietf-netconf-nmda {
|
||||||
prefix ncds;
|
prefix ncds;
|
||||||
reference
|
reference
|
||||||
"RFC 8526: NETCONF Extensions to Support the
|
"RFC 8526: NETCONF Extensions to Support the
|
||||||
Network Management Datastore Architecture";
|
Network Management Datastore Architecture";
|
||||||
}
|
}
|
||||||
|
|
||||||
import ietf-list-pagination {
|
import ietf-list-pagination {
|
||||||
prefix lp;
|
prefix lp;
|
||||||
reference
|
reference
|
||||||
"RFC XXXX: List Pagination for YANG-driven Protocols";
|
"RFC XXXX: List Pagination for YANG-driven Protocols";
|
||||||
}
|
}
|
||||||
|
|
||||||
organization
|
organization
|
||||||
"IETF NETCONF (Network Configuration) Working Group";
|
"IETF NETCONF (Network Configuration) Working Group";
|
||||||
|
|
||||||
contact
|
contact
|
||||||
"WG Web: https://datatracker.ietf.org/wg/netconf
|
"WG Web: https://datatracker.ietf.org/wg/netconf
|
||||||
WG List: NETCONF WG list <mailto:netconf@ietf.org>";
|
WG List: NETCONF WG list <mailto:netconf@ietf.org>";
|
||||||
description
|
description
|
||||||
"This module augments the <get>, <get-config>, and <get-data>
|
"This module augments the <get>, <get-config>, and <get-data>
|
||||||
'rpc' statements to support list pagination.
|
'rpc' statements to support list pagination.
|
||||||
|
|
||||||
Copyright (c) 2021 IETF Trust and the persons identified
|
Copyright (c) 2021 IETF Trust and the persons identified
|
||||||
|
|
@ -53,48 +53,47 @@ module ietf-list-pagination-nc {
|
||||||
(RFC 8174) when, and only when, they appear in all
|
(RFC 8174) when, and only when, they appear in all
|
||||||
capitals, as shown here.";
|
capitals, as shown here.";
|
||||||
|
|
||||||
revision 2022-07-24 {
|
revision 2022-07-24 {
|
||||||
description
|
description
|
||||||
"Initial revision.";
|
"Initial revision.";
|
||||||
reference
|
reference
|
||||||
"RFC XXXX: NETCONF Extensions to Support List Pagination";
|
"RFC XXXX: NETCONF Extensions to Support List Pagination";
|
||||||
}
|
}
|
||||||
|
|
||||||
grouping pagination-parameters {
|
grouping pagination-parameters {
|
||||||
description "A grouping for list pagination parameters.";
|
description "A grouping for list pagination parameters.";
|
||||||
container list-pagination {
|
container list-pagination {
|
||||||
description "List pagination parameters.";
|
description "List pagination parameters.";
|
||||||
presence "Flag that request contains pagination parameters";
|
uses lp:where-param-grouping;
|
||||||
uses lp:where-param-grouping;
|
uses lp:sort-by-param-grouping;
|
||||||
uses lp:sort-by-param-grouping;
|
uses lp:direction-param-grouping;
|
||||||
uses lp:direction-param-grouping;
|
uses lp:offset-param-grouping;
|
||||||
uses lp:offset-param-grouping;
|
uses lp:limit-param-grouping;
|
||||||
uses lp:limit-param-grouping;
|
uses lp:sublist-limit-param-grouping;
|
||||||
uses lp:sublist-limit-param-grouping;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
augment "/nc:get/nc:input" {
|
augment "/nc:get/nc:input" {
|
||||||
description
|
description
|
||||||
"Allow the 'get' operation to use content filter
|
"Allow the 'get' operation to use content filter
|
||||||
parameter for specifying the YANG list or leaf-list
|
parameter for specifying the YANG list or leaf-list
|
||||||
that is to be retrieved";
|
that is to be retrieved";
|
||||||
uses pagination-parameters;
|
uses pagination-parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
augment "/nc:get-config/nc:input" {
|
augment "/nc:get-config/nc:input" {
|
||||||
description
|
description
|
||||||
"Allow the 'get-config' operation to use content filter
|
"Allow the 'get-config' operation to use content filter
|
||||||
parameter for specifying the YANG list or leaf-list
|
parameter for specifying the YANG list or leaf-list
|
||||||
that is to be retrieved";
|
that is to be retrieved";
|
||||||
uses pagination-parameters;
|
uses pagination-parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
augment "/ncds:get-data/ncds:input" {
|
augment "/ncds:get-data/ncds:input" {
|
||||||
description
|
description
|
||||||
"Allow the 'get-data' operation to use content filter
|
"Allow the 'get-data' operation to use content filter
|
||||||
parameter for specifying the YANG list or leaf-list
|
parameter for specifying the YANG list or leaf-list
|
||||||
that is to be retrieved";
|
that is to be retrieved";
|
||||||
uses pagination-parameters;
|
uses pagination-parameters;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue