List pagination, uniform config/state handling with new attributes

New `clixon-lib@2024-04-01.yang` revision and list_pagination_partial_state extension
This commit is contained in:
Olof hagsand 2024-07-17 14:39:48 +02:00
parent 05c881dc39
commit 07a1fa164f
14 changed files with 357 additions and 135 deletions

View file

@ -17,6 +17,16 @@ Expected: October 2024
### Features ### Features
* List pagination: Added where, sort-by and direction parameter for configured data * List pagination: Added where, sort-by and direction parameter for configured data
* New `clixon-lib@2024-04-01.yang` revision
- Added: list_pagination_partial_state
### API changes on existing protocol/config features
Users may have to change how they access the system
* List pagination of large lists
* For backward-compatibility, mark the list with extension cl:list_pagination_partial_state extension
* New default is to use regular state read mechanism, which could have poorer performance but more functionality
### C/CLI-API changes on existing features ### C/CLI-API changes on existing features

View file

@ -495,6 +495,87 @@ list_pagination_hdr(clixon_handle h,
return retval; return retval;
} }
/*! Special handling of state data for partial reading
*
* Only if extension list-pagination-partial-state is enabled on the list
* @param[in] h Clixon handle
* @param[in] ce Client entry, for locking
* @param[in] yspec (Top-level) yang spec
* @param[in] xpath XPath point to object to get
* @param[in] offset Start of pagination interval
* @param[in] limit Number of elements (limit)
* @param[out] xret Returned xml state tree
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @retval 1 OK
* @retval 0 Fail, cbret contains error message
* @retval -1 Error
*/
static int
get_pagination_partial(clixon_handle h,
struct client_entry *ce,
yang_stmt *yspec,
char *xpath,
uint32_t offset,
uint32_t limit,
cxobj *xret,
cbuf *cbret)
{
int retval = -1;
int locked;
cbuf *cberr = NULL;
uint32_t iddb; /* DBs lock, if any */
cxobj *xerr = NULL;
int ret;
if ((iddb = xmldb_islocked(h, "running")) != 0 &&
iddb == ce->ce_id)
locked = 1;
else
locked = 0;
if ((ret = clixon_pagination_cb_call(h, xpath, locked,
offset, limit,
xret)) < 0)
goto done;
if (ret == 0){
if ((cberr = cbuf_new()) == NULL){
clixon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
/* error reason should be in clixon_err_reason */
cprintf(cberr, "Internal error, pagination state callback invalid return : %s",
clixon_err_reason());
if (netconf_operation_failed_xml(&xerr, "application", cbuf_get(cberr)) < 0)
goto done;
if (clixon_xml2cbuf(cbret, xerr, 0, 0, NULL, -1, 0) < 0)
goto done;
goto fail;
}
/* System makes the binding */
if ((ret = xml_bind_yang(h, xret, YB_MODULE, yspec, &xerr)) < 0)
goto done;
if (ret == 0){
clixon_debug_xml(CLIXON_DBG_BACKEND, xret, "Yang bind pagination state");
if (clixon_netconf_internal_error(xerr,
". Internal error, state callback returned invalid XML",
NULL) < 0)
goto done;
if (clixon_xml2cbuf(cbret, xerr, 0, 0, NULL, -1, 0) < 0)
goto done;
goto fail;
}
retval = 1;
done:
if (cberr)
cbuf_free(cberr);
if (xerr)
xml_free(xerr);
return retval;
fail:
retval = 0;
goto done;
}
/*! 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
@ -543,14 +624,11 @@ get_list_pagination(clixon_handle h,
uint32_t offset = 0; uint32_t offset = 0;
uint32_t limit = 0; uint32_t limit = 0;
uint32_t upper; uint32_t upper;
int list_config; int partial_pagination_cb = 0; /* use state partial reads callback */
yang_stmt *ylist; yang_stmt *ylist;
cxobj *xerr = NULL; cxobj *xerr = NULL;
cbuf *cbmsg = NULL; /* For error msg */ cbuf *cbmsg = NULL; /* For error msg */
cxobj *xret = NULL; cxobj *xret = NULL;
uint32_t iddb; /* DBs lock, if any */
int locked;
cbuf *cberr = NULL;
cxobj **xvec = NULL; cxobj **xvec = NULL;
size_t xlen; size_t xlen;
cxobj *x; cxobj *x;
@ -559,6 +637,7 @@ get_list_pagination(clixon_handle h,
char *sort_by = NULL; char *sort_by = NULL;
char *direction = NULL; char *direction = NULL;
char *where = NULL; char *where = NULL;
int extflag = 0;
int i; int i;
int j; int j;
int ret; int ret;
@ -588,7 +667,7 @@ get_list_pagination(clixon_handle h,
goto ok; goto ok;
} }
/* Sanity checks on state/config */ /* Sanity checks on state/config */
if ((list_config = yang_config_ancestor(ylist)) != 0){ /* config list */ if (yang_config_ancestor(ylist) != 0){ /* config list */
if (content == CONTENT_NONCONFIG){ if (content == CONTENT_NONCONFIG){
if (netconf_invalid_value(cbret, "application", "list-pagination targets a config list but content request is nonconfig") < 0) if (netconf_invalid_value(cbret, "application", "list-pagination targets a config list but content request is nonconfig") < 0)
goto done; goto done;
@ -601,7 +680,13 @@ get_list_pagination(clixon_handle h,
goto done; goto done;
goto ok; goto ok;
} }
if (yang_extension_value(ylist, "list-pagination-partial-state", CLIXON_LIB_NS, &extflag, NULL) < 0)
goto done;
if (extflag){ /* pagination_cb / partial state API */
partial_pagination_cb = 1;
}
} }
/* first processes the "where" parameter (see Section 3.1.1) */ /* first processes the "where" parameter (see Section 3.1.1) */
if ((x = xml_find_type(xe, NULL, "where", CX_ELMNT)) != NULL && if ((x = xml_find_type(xe, NULL, "where", CX_ELMNT)) != NULL &&
(where = xml_body(x)) != NULL){ (where = xml_body(x)) != NULL){
@ -664,7 +749,7 @@ get_list_pagination(clixon_handle h,
break; break;
case CONTENT_ALL: /* both config and state */ case CONTENT_ALL: /* both config and state */
case CONTENT_NONCONFIG: /* state data only */ case CONTENT_NONCONFIG: /* state data only */
if (list_config == 0) /* Special handling */ if (partial_pagination_cb) /* Partial reads, special handling */
break; break;
if ((ret = get_statedata(h, xpath?xpath:"/", nsc, &xret)) < 0) if ((ret = get_statedata(h, xpath?xpath:"/", nsc, &xret)) < 0)
goto done; goto done;
@ -681,7 +766,13 @@ get_list_pagination(clixon_handle h,
if (xml_default_recurse(xret, 1, 0) < 0) if (xml_default_recurse(xret, 1, 0) < 0)
goto done; goto done;
} }
if (list_config){ if (partial_pagination_cb) {
if ((ret = get_pagination_partial(h, ce, yspec, xpath, offset, limit, xret, cbret)) < 0)
goto done;
if (ret == 0)
goto ok;
}
else {
/* first processes the "where" parameter (see Section 3.1.1) */ /* first processes the "where" parameter (see Section 3.1.1) */
if (where){ if (where){
if (xpath_vec(xret, nsc, "%s[%s]", &xvec, &xlen, xpath?xpath:"/", where) < 0) if (xpath_vec(xret, nsc, "%s[%s]", &xvec, &xlen, xpath?xpath:"/", where) < 0)
@ -762,45 +853,6 @@ get_list_pagination(clixon_handle h,
} }
#endif #endif
} }
else {/* Check if running locked (by this session) */
if ((iddb = xmldb_islocked(h, "running")) != 0 &&
iddb == ce->ce_id)
locked = 1;
else
locked = 0;
if ((ret = clixon_pagination_cb_call(h, xpath, locked,
offset, limit,
xret)) < 0)
goto done;
if (ret == 0){
if ((cberr = cbuf_new()) == NULL){
clixon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
/* error reason should be in clixon_err_reason */
cprintf(cberr, "Internal error, pagination state callback invalid return : %s",
clixon_err_reason());
if (netconf_operation_failed_xml(&xerr, "application", cbuf_get(cberr)) < 0)
goto done;
if (clixon_xml2cbuf(cbret, xerr, 0, 0, NULL, -1, 0) < 0)
goto done;
goto ok;
}
/* System makes the binding */
if ((ret = xml_bind_yang(h, xret, YB_MODULE, yspec, &xerr)) < 0)
goto done;
if (ret == 0){
clixon_debug_xml(CLIXON_DBG_BACKEND, xret, "Yang bind pagination state");
if (clixon_netconf_internal_error(xerr,
". Internal error, state callback returned invalid XML",
NULL) < 0)
goto done;
if (clixon_xml2cbuf(cbret, xerr, 0, 0, NULL, -1, 0) < 0)
goto done;
goto ok;
}
}
if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
goto done; goto done;
/* Help function to filter out anything that is outside of xpath */ /* Help function to filter out anything that is outside of xpath */
@ -837,8 +889,6 @@ get_list_pagination(clixon_handle h,
cbuf_free(cbmsg); cbuf_free(cbmsg);
if (xerr) if (xerr)
xml_free(xerr); xml_free(xerr);
if (cberr)
cbuf_free(cberr);
if (xret) if (xret)
xml_free(xret); xml_free(xret);
return retval; return retval;

View file

@ -485,20 +485,25 @@ clixon_plugin_lockdb_all(clixon_handle h,
return retval; return retval;
} }
/*! Traverse state data callbacks /*! Traverse state data callbacks for partial pagination state callbacks
* *
* Only if list-pagination-partial-state extension is set
* @param[in] h Clixon handle * @param[in] h Clixon handle
* @param[in] xpath Registered XPath using canonical prefixes * @param[in] xpath Registered XPath using canonical prefixes
* @param[in] locked Running datastore is locked by this caller
* @param[in] offset Start of pagination interval
* @param[in] limit Number of elements (limit)
* @param[out] xstate Returned xml state tree
* @retval 1 OK * @retval 1 OK
* @retval -1 Error * @retval -1 Error
*/ */
int int
clixon_pagination_cb_call(clixon_handle h, clixon_pagination_cb_call(clixon_handle h,
char *xpath, char *xpath,
int locked, int locked,
uint32_t offset, uint32_t offset,
uint32_t limit, uint32_t limit,
cxobj *xstate) cxobj *xstate)
{ {
int retval = -1; int retval = -1;
pagination_data_t pd; pagination_data_t pd;

View file

@ -97,7 +97,7 @@ show("Show a particular state of the system"){
xml("Show comparison in xml"), compare_dbs("running", "candidate", "xml"); xml("Show comparison in xml"), compare_dbs("running", "candidate", "xml");
text("Show comparison in text"), compare_dbs("running", "candidate", "text"); text("Show comparison in text"), compare_dbs("running", "candidate", "text");
} }
pagination("Show list pagination") xpath("Show configuration") <xpath:string>("XPATH expression"), cli_pagination("use xpath var", "es", "http://example.com/ns/example-social", "default", "10"); pagination("Show list pagination") xpath("Show configuration") <xpath:string>("XPATH expression"), cli_pagination("use xpath var", "es", "https://example.com/ns/example-social", "default", "10");
configuration("Show configuration"), cli_show_auto_mode("candidate", "default", true, false, "explicit", "set ");{ configuration("Show configuration"), cli_show_auto_mode("candidate", "default", true, false, "explicit", "set ");{
@|example_pipe, cli_show_auto_mode("candidate", "xml", true, false, "explicit"); @|example_pipe, cli_show_auto_mode("candidate", "xml", true, false, "explicit");
default("With-default mode"){ default("With-default mode"){

View file

@ -101,7 +101,7 @@
* and thus an xpath on the form "../PARENT" may not be evaluated as they should. x0 is eventually * and thus an xpath on the form "../PARENT" may not be evaluated as they should. x0 is eventually
* added to its parent but then it is more difficult to check the when condition. * added to its parent but then it is more difficult to check the when condition.
* This fix add the parent x0p as a "candidate" so that the xpath-eval function can use it as * This fix add the parent x0p as a "candidate" so that the xpath-eval function can use it as
* an alernative if it exists. * an alternative if it exists.
* Note although this solves many usecases involving parents and absolute paths, it still does not * Note although this solves many usecases involving parents and absolute paths, it still does not
* solve all usecases, such as absolute usecases where the added node is looked for * solve all usecases, such as absolute usecases where the added node is looked for
*/ */

View file

@ -73,7 +73,7 @@ DATASTORE_TOP="config"
# clixon yang revisions occuring in tests (see eg yang/clixon/Makefile.in) # clixon yang revisions occuring in tests (see eg yang/clixon/Makefile.in)
CLIXON_AUTOCLI_REV="2023-09-01" CLIXON_AUTOCLI_REV="2023-09-01"
CLIXON_LIB_REV="2024-04-01" CLIXON_LIB_REV="2024-08-01"
CLIXON_CONFIG_REV="2024-04-01" CLIXON_CONFIG_REV="2024-04-01"
CLIXON_RESTCONF_REV="2022-08-01" CLIXON_RESTCONF_REV="2022-08-01"
CLIXON_EXAMPLE_REV="2022-11-01" CLIXON_EXAMPLE_REV="2022-11-01"

View file

@ -1,13 +1,13 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Example-social from draft-netconf-list-pagination-00.txt appendix A.1 # Example-social from draft-netconf-list-pagination-00.txt appendix A.1
# Assumes variable fexample is set to name of yang file # Assumes variable fexample is set to name of yang file
# Note audit-logs/audit-log/outcome is changed from mandatory to default
# Also: leaf-list member/state/numbers is added # Also: leaf-list member/state/numbers is added
# Mark deviation from original with "Clixon"
cat <<EOF > $fexample cat <<EOF > $fexample
module example-social { module example-social {
yang-version 1.1; yang-version 1.1;
namespace "http://example.com/ns/example-social"; namespace "https://example.com/ns/example-social";
prefix es; prefix es;
import ietf-yang-types { import ietf-yang-types {
@ -20,18 +20,21 @@ cat <<EOF > $fexample
reference reference
"RFC 6991: Common YANG Data Types"; "RFC 6991: Common YANG Data Types";
} }
import iana-crypt-hash { import iana-crypt-hash {
prefix ianach; prefix ianach;
reference reference
"RFC 7317: A YANG Data Model for System Management"; "RFC 7317: A YANG Data Model for System Management";
} }
import clixon-lib { // Clixon
prefix cl;
}
organization "Example, Inc."; organization "Example, Inc.";
contact "support@example.com"; contact "support@example.com";
description "Example Social Data Model."; description "Example Social Data Model.";
revision 2021-07-21 { /* clixon edit */
// revision YYYY-MM-DD {
revision 2021-07-21 { // Clixon
description description
"Initial version."; "Initial version.";
reference reference
@ -58,7 +61,8 @@ cat <<EOF > $fexample
} }
leaf email-address { leaf email-address {
type string; // type inet:email-address;
type string; // Clixon
mandatory true; mandatory true;
description description
"The member's email address."; "The member's email address.";
@ -119,7 +123,7 @@ cat <<EOF > $fexample
leaf-list following { leaf-list following {
type leafref { type leafref {
path "/members/member/member-id"; path "/members/member/member-id";
require-instance false; require-instance false; // Clixon
} }
description description
"Other members this members is following."; "Other members this members is following.";
@ -216,7 +220,7 @@ cat <<EOF > $fexample
config false; config false;
description description
"Operational state members values."; "Operational state members values.";
leaf-list numbers { leaf-list numbers { // Clixon
description "config false extension"; description "config false extension";
type int32; type int32;
} }
@ -261,6 +265,7 @@ cat <<EOF > $fexample
list audit-log { list audit-log {
description description
"List of audit logs."; "List of audit logs.";
cl:list_pagination_partial_state; // Clixon
leaf timestamp { leaf timestamp {
type yang:date-and-time; type yang:date-and-time;
mandatory true; mandatory true;
@ -287,7 +292,7 @@ cat <<EOF > $fexample
} }
leaf outcome { leaf outcome {
type boolean; type boolean;
default true; /* Note changed from mandatory in original */ mandatory true;
description description
"Indicate if request was permitted."; "Indicate if request was permitted.";
} }

View file

@ -30,7 +30,7 @@ fexample=$dir/example-social.yang
# Validate internal state xml # Validate internal state xml
: ${validatexml:=false} : ${validatexml:=false}
# Number of audit-log entries # Number of leaf-list entries
# Note mem.sh sets it # Note mem.sh sets it
: ${perfnr:=20000} : ${perfnr:=20000}
@ -60,7 +60,7 @@ EOF
# start file # start file
cat <<'EOF' > $dir/startup_db cat <<'EOF' > $dir/startup_db
<config> <config>
<members xmlns="http://example.com/ns/example-social"> <members xmlns="https://example.com/ns/example-social">
<member> <member>
<member-id>alice</member-id> <member-id>alice</member-id>
<email-address>alice@example.com</email-address> <email-address>alice@example.com</email-address>
@ -163,7 +163,7 @@ xpath="/es:members/es:member[es:member-id=\'bob\']/es:favorites/es:uint64-number
new "cli show pagination config using expect" new "cli show pagination config using expect"
sudo="sudo -g ${CLICON_GROUP}" ## cheat sudo="sudo -g ${CLICON_GROUP}" ## cheat
clixon_cli_="${clixon_cli##$sudo }" clixon_cli_="${clixon_cli##$sudo }"
clixon_cli="$clixon_cli_" $sudo --preserve-env=clixon_cli expect ./test_pagination_expect.exp "$cfg" "$xpath" "uint64-numbers 18" "uint64-numbers 19" clixon_cli="$clixon_cli_" $sudo --preserve-env=clixon_cli expect ./test_pagination_expect.exp "$cfg" "$xpath" "uint64-numbers 20" "uint64-numbers 21"
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
err1 "Failed: CLI show paginate config scroll using expect" err1 "Failed: CLI show paginate config scroll using expect"
fi fi

View file

@ -166,7 +166,7 @@ EOF
# See draft-wwlh-netconf-list-pagination-00 A.2 (only stats and audit-log) # See draft-wwlh-netconf-list-pagination-00 A.2 (only stats and audit-log)
cat<<EOF > $fstate cat<<EOF > $fstate
<members xmlns="http://example.com/ns/example-social"> <members xmlns="https://example.com/ns/example-social">
<member> <member>
<member-id>alice</member-id> <member-id>alice</member-id>
<stats> <stats>
@ -208,7 +208,7 @@ cat<<EOF > $fstate
</stats> </stats>
</member> </member>
</members> </members>
<audit-logs xmlns="http://example.com/ns/example-social"> <audit-logs xmlns="https://example.com/ns/example-social">
<audit-log> <audit-log>
<timestamp>": "2020-10-11T06:47:59Z",</timestamp> <timestamp>": "2020-10-11T06:47:59Z",</timestamp>
<member-id>alice</member-id> <member-id>alice</member-id>
@ -287,16 +287,16 @@ function testlimit()
# if [ $limit == 0 ]; then # if [ $limit == 0 ]; then
if true; then if true; then
el="<uint8-numbers>$li</uint8-numbers>" el="<uint8-numbers>$li</uint8-numbers>"
el2="<uint8-numbers xmlns=\"http://example.com/ns/example-social\">$li</uint8-numbers>" el2="<uint8-numbers xmlns=\"https://example.com/ns/example-social\">$li</uint8-numbers>"
else else
el="<uint8-numbers lp:remaining=\"$remaining\" xmlns:lp=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination\">$li</uint8-numbers>" el="<uint8-numbers lp:remaining=\"$remaining\" xmlns:lp=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination\">$li</uint8-numbers>"
el2="<uint8-numbers lp:remaining=\"$remaining\" xmlns:lp=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination\" xmlns=\"http://example.com/ns/example-social\">$li</uint8-numbers>" el2="<uint8-numbers lp:remaining=\"$remaining\" xmlns:lp=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination\" xmlns=\"https://example.com/ns/example-social\">$li</uint8-numbers>"
jsonmeta=",\"@example-social:uint8-numbers\":\[{\"ietf-list-pagination:remaining\":$remaining}\]" jsonmeta=",\"@example-social:uint8-numbers\":\[{\"ietf-list-pagination:remaining\":$remaining}\]"
fi fi
jsonlist="$li" jsonlist="$li"
else else
el="<uint8-numbers>$li</uint8-numbers>" el="<uint8-numbers>$li</uint8-numbers>"
el2="<uint8-numbers xmlns=\"http://example.com/ns/example-social\">$li</uint8-numbers>" jsonlist="$jsonlist,$li" el2="<uint8-numbers xmlns=\"https://example.com/ns/example-social\">$li</uint8-numbers>" jsonlist="$jsonlist,$li"
fi fi
xmllist="$xmllist$el" xmllist="$xmllist$el"
xmllist2="$xmllist2$el2" xmllist2="$xmllist2$el2"
@ -324,18 +324,18 @@ function testlimit()
if [ -z "$list" ]; then if [ -z "$list" ]; then
reply="<rpc-reply $DEFAULTNS><data/></rpc-reply>" reply="<rpc-reply $DEFAULTNS><data/></rpc-reply>"
else else
reply="<rpc-reply $DEFAULTNS><data><members xmlns=\"http://example.com/ns/example-social\"><member><member-id>alice</member-id><favorites>$xmllist</favorites></member></members></data></rpc-reply>" reply="<rpc-reply $DEFAULTNS><data><members xmlns=\"https://example.com/ns/example-social\"><member><member-id>alice</member-id><favorites>$xmllist</favorites></member></members></data></rpc-reply>"
fi fi
new "limit=$limit offset=$offset NETCONF get-config" new "limit=$limit offset=$offset NETCONF get-config"
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get-config><source><running/></source><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\"/><list-pagination xmlns=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc\">$limitxmlstr$offsetxmlstr</list-pagination></get-config></rpc>" "" "$reply" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get-config><source><running/></source><filter type=\"xpath\" select=\"/es:members/es:member[es:member-id='alice']/es:favorites/es:uint8-numbers\" xmlns:es=\"https://example.com/ns/example-social\"/><list-pagination xmlns=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc\">$limitxmlstr$offsetxmlstr</list-pagination></get-config></rpc>" "" "$reply"
if [ -z "$list" ]; then if [ -z "$list" ]; then
reply="<rpc-reply $DEFAULTNS><data/></rpc-reply>" reply="<rpc-reply $DEFAULTNS><data/></rpc-reply>"
else else
reply="<rpc-reply $DEFAULTNS><data><members xmlns=\"http://example.com/ns/example-social\"><member><member-id>alice</member-id><favorites>$xmllist</favorites></member></members></data></rpc-reply>" reply="<rpc-reply $DEFAULTNS><data><members xmlns=\"https://example.com/ns/example-social\"><member><member-id>alice</member-id><favorites>$xmllist</favorites></member></members></data></rpc-reply>"
fi fi
new "limit=$limit offset=$offset NETCONF get" new "limit=$limit offset=$offset NETCONF get"
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\"/><list-pagination xmlns=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc\">$limitxmlstr$offsetxmlstr</list-pagination></get></rpc>" "" "$reply" 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=\"https://example.com/ns/example-social\"/><list-pagination xmlns=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc\">$limitxmlstr$offsetxmlstr</list-pagination></get></rpc>" "" "$reply"
if [ -z "$list" ]; then if [ -z "$list" ]; then
reply="<xml-list xmlns=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination\"/>" reply="<xml-list xmlns=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination\"/>"
@ -383,7 +383,7 @@ new "wait restconf"
wait_restconf wait_restconf
new "Baseline: no pagination" 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" 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=\"https://example.com/ns/example-social\"/></get></rpc>" "<rpc-reply $DEFAULTNS><data><members xmlns=\"https://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"

View file

@ -1,4 +1,5 @@
#!/usr/bin/env expect -f #!/usr/bin/env expect -f
# Use of expect to emulate a terminal with given size, difficult in shell-based test-scripts
# Tests of paginated state scrolling using expect. Simply that --More-- is shown and # Tests of paginated state scrolling using expect. Simply that --More-- is shown and
# that first two pages scroll OK. More tests could be done. # that first two pages scroll OK. More tests could be done.
# Arguments: # Arguments:
@ -10,7 +11,7 @@
set timeout 1 set timeout 1
#log_user 0 #log_user 0
set stty_init "rows 20 cols 128" set stty_init "rows 22 cols 128"
send_user "\nTest State paginate cli scrolling\n" send_user "\nTest State paginate cli scrolling\n"

View file

@ -157,7 +157,7 @@ EOF
# See draft-wwlh-netconf-list-pagination-00 A.2 (only stats and audit-log) # See draft-wwlh-netconf-list-pagination-00 A.2 (only stats and audit-log)
cat<<EOF > $fstate cat<<EOF > $fstate
<members xmlns="http://example.com/ns/example-social"> <members xmlns="https://example.com/ns/example-social">
<member> <member>
<member-id>bob</member-id> <member-id>bob</member-id>
<stats> <stats>
@ -221,38 +221,38 @@ wait_backend
new "A.3.4.1. direction=forwards" new "A.3.4.1. direction=forwards"
# 17, 13, 11, 7, 5, 3] # 17, 13, 11, 7, 5, 3]
# Confusing: forwards means dont change order # Confusing: forwards means dont change order
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\"/><list-pagination xmlns=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc\"><direction>forwards</direction></list-pagination></get></rpc>" "<rpc-reply $DEFAULTNS><data><members xmlns=\"http://example.com/ns/example-social\"><member><member-id>alice</member-id><favorites><uint8-numbers>17</uint8-numbers><uint8-numbers>13</uint8-numbers><uint8-numbers>11</uint8-numbers><uint8-numbers>7</uint8-numbers><uint8-numbers>5</uint8-numbers><uint8-numbers>3</uint8-numbers></favorites></member></members></data></rpc-reply>" 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=\"https://example.com/ns/example-social\"/><list-pagination xmlns=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc\"><direction>forwards</direction></list-pagination></get></rpc>" "<rpc-reply $DEFAULTNS><data><members xmlns=\"https://example.com/ns/example-social\"><member><member-id>alice</member-id><favorites><uint8-numbers>17</uint8-numbers><uint8-numbers>13</uint8-numbers><uint8-numbers>11</uint8-numbers><uint8-numbers>7</uint8-numbers><uint8-numbers>5</uint8-numbers><uint8-numbers>3</uint8-numbers></favorites></member></members></data></rpc-reply>"
new "A.3.4.2. direction=backwards" new "A.3.4.2. direction=backwards"
# 3, 5, 7, 11, 13, 17] # 3, 5, 7, 11, 13, 17]
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\"/><list-pagination xmlns=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc\"><direction>backwards</direction></list-pagination></get></rpc>" "<rpc-reply $DEFAULTNS><data><members xmlns=\"http://example.com/ns/example-social\"><member><member-id>alice</member-id><favorites><uint8-numbers>3</uint8-numbers><uint8-numbers>5</uint8-numbers><uint8-numbers>7</uint8-numbers><uint8-numbers>11</uint8-numbers><uint8-numbers>13</uint8-numbers><uint8-numbers>17</uint8-numbers></favorites></member></members></data></rpc-reply>" 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=\"https://example.com/ns/example-social\"/><list-pagination xmlns=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc\"><direction>backwards</direction></list-pagination></get></rpc>" "<rpc-reply $DEFAULTNS><data><members xmlns=\"https://example.com/ns/example-social\"><member><member-id>alice</member-id><favorites><uint8-numbers>3</uint8-numbers><uint8-numbers>5</uint8-numbers><uint8-numbers>7</uint8-numbers><uint8-numbers>11</uint8-numbers><uint8-numbers>13</uint8-numbers><uint8-numbers>17</uint8-numbers></favorites></member></members></data></rpc-reply>"
new "A.3.5.1.1. sort-by type is a leaf-list" new "A.3.5.1.1. sort-by type is a leaf-list"
# 3,5,7,11,13,17 # 3,5,7,11,13,17
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\"/><list-pagination xmlns=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc\"><sort-by>.</sort-by></list-pagination></get></rpc>" "<rpc-reply $DEFAULTNS><data><members xmlns=\"http://example.com/ns/example-social\"><member><member-id>alice</member-id><favorites><uint8-numbers>3</uint8-numbers><uint8-numbers>5</uint8-numbers><uint8-numbers>7</uint8-numbers><uint8-numbers>11</uint8-numbers><uint8-numbers>13</uint8-numbers><uint8-numbers>17</uint8-numbers></favorites></member></members></data></rpc-reply>" 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=\"https://example.com/ns/example-social\"/><list-pagination xmlns=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc\"><sort-by>.</sort-by></list-pagination></get></rpc>" "<rpc-reply $DEFAULTNS><data><members xmlns=\"https://example.com/ns/example-social\"><member><member-id>alice</member-id><favorites><uint8-numbers>3</uint8-numbers><uint8-numbers>5</uint8-numbers><uint8-numbers>7</uint8-numbers><uint8-numbers>11</uint8-numbers><uint8-numbers>13</uint8-numbers><uint8-numbers>17</uint8-numbers></favorites></member></members></data></rpc-reply>"
new "A.3.5.1.2. sort-by type is a list and sort-by node is a direct descendent" new "A.3.5.1.2. sort-by type is a list and sort-by node is a direct descendent"
# alice, bob, eric, joe, lin # alice, bob, eric, joe, lin
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get><filter type=\"xpath\" select=\"/es:members/es:member\" xmlns:es=\"http://example.com/ns/example-social\"/><list-pagination xmlns=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc\"><sort-by>member-id</sort-by></list-pagination></get></rpc>" "<rpc-reply $DEFAULTNS><data><members xmlns=\"http://example.com/ns/example-social\"><member><member-id>alice</member-id>.*<member-id>bob</member-id>.*<member-id>eric</member-id>.*<member-id>joe</member-id>.*<member-id>lin</member-id>" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get><filter type=\"xpath\" select=\"/es:members/es:member\" xmlns:es=\"https://example.com/ns/example-social\"/><list-pagination xmlns=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc\"><sort-by>member-id</sort-by></list-pagination></get></rpc>" "<rpc-reply $DEFAULTNS><data><members xmlns=\"https://example.com/ns/example-social\"><member><member-id>alice</member-id>.*<member-id>bob</member-id>.*<member-id>eric</member-id>.*<member-id>joe</member-id>.*<member-id>lin</member-id>"
new "A.3.5.1.3. sort-by type is a list and sort-by node is an indirect descendent" new "A.3.5.1.3. sort-by type is a list and sort-by node is an indirect descendent"
# alice, lin, bob, eric, joe # alice, lin, bob, eric, joe
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get><filter type=\"xpath\" select=\"/es:members/es:member\" xmlns:es=\"http://example.com/ns/example-social\"/><list-pagination xmlns=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc\"><sort-by>stats/joined</sort-by></list-pagination></get></rpc>" "<rpc-reply $DEFAULTNS><data><members xmlns=\"http://example.com/ns/example-social\"><member><member-id>alice</member-id>.*<member-id>lin</member-id>.*<member-id>bob</member-id>.*<member-id>eric</member-id>.*<member-id>joe</member-id>" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get><filter type=\"xpath\" select=\"/es:members/es:member\" xmlns:es=\"https://example.com/ns/example-social\"/><list-pagination xmlns=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc\"><sort-by>stats/joined</sort-by></list-pagination></get></rpc>" "<rpc-reply $DEFAULTNS><data><members xmlns=\"https://example.com/ns/example-social\"><member><member-id>alice</member-id>.*<member-id>lin</member-id>.*<member-id>bob</member-id>.*<member-id>eric</member-id>.*<member-id>joe</member-id>"
new "A.3.6.2. where, match on descendent string containing a substring" new "A.3.6.2. where, match on descendent string containing a substring"
# bob, eric, alice, lin, joe # bob, eric, alice, lin, joe
# Confusing: all match # Confusing: all match
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get><filter type=\"xpath\" select=\"/es:members/es:member\" xmlns:es=\"http://example.com/ns/example-social\"/><list-pagination xmlns=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc\"><where>.[contains (email-address,'@example.com')]</where></list-pagination></get></rpc>" "<rpc-reply $DEFAULTNS><data><members xmlns=\"http://example.com/ns/example-social\"><member><member-id>bob</member-id>.*<member-id>eric</member-id>.*<member-id>alice</member-id>.*<member-id>lin</member-id>.*<member-id>joe</member-id>" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get><filter type=\"xpath\" select=\"/es:members/es:member\" xmlns:es=\"https://example.com/ns/example-social\"/><list-pagination xmlns=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc\"><where>.[contains (email-address,'@example.com')]</where></list-pagination></get></rpc>" "<rpc-reply $DEFAULTNS><data><members xmlns=\"https://example.com/ns/example-social\"><member><member-id>bob</member-id>.*<member-id>eric</member-id>.*<member-id>alice</member-id>.*<member-id>lin</member-id>.*<member-id>joe</member-id>"
new "A.3.6.3. where, match on decendent timestamp starting with a substring" new "A.3.6.3. where, match on decendent timestamp starting with a substring"
# bob, eric, alice, joe, # bob, eric, alice, joe,
# starts-with NYI, replaced with contains # starts-with NYI, replaced with contains
# posts//post[starts-with(timestamp,'2020')] # posts//post[starts-with(timestamp,'2020')]
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get><filter type=\"xpath\" select=\"/es:members/es:member\" xmlns:es=\"http://example.com/ns/example-social\"/><list-pagination xmlns=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc\"><where>posts/post[contains(timestamp,'2020')]</where></list-pagination></get></rpc>" "<rpc-reply $DEFAULTNS><data><members xmlns=\"http://example.com/ns/example-social\"><member><member-id>bob</member-id>.*<member-id>eric</member-id>.*<member-id>alice</member-id>.*<member-id>joe</member-id>" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get><filter type=\"xpath\" select=\"/es:members/es:member\" xmlns:es=\"https://example.com/ns/example-social\"/><list-pagination xmlns=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc\"><where>posts/post[contains(timestamp,'2020')]</where></list-pagination></get></rpc>" "<rpc-reply $DEFAULTNS><data><members xmlns=\"https://example.com/ns/example-social\"><member><member-id>bob</member-id>.*<member-id>eric</member-id>.*<member-id>alice</member-id>.*<member-id>joe</member-id>"
new "A.3.9.1. All six parameters at once" new "A.3.9.1. All six parameters at once"
# eric, bob # eric, bob
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get><filter type=\"xpath\" select=\"/es:members/es:member\" xmlns:es=\"http://example.com/ns/example-social\"/><list-pagination xmlns=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc\"><where>//post[contains(timestamp,'2020')]</where><sort-by>member-id</sort-by><direction>backwards</direction><offset>2</offset><limit>2</limit></list-pagination></get></rpc>" "<rpc-reply $DEFAULTNS><data><members xmlns=\"http://example.com/ns/example-social\"><member><member-id>eric</member-id>.*<member-id>bob</member-id>" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get><filter type=\"xpath\" select=\"/es:members/es:member\" xmlns:es=\"https://example.com/ns/example-social\"/><list-pagination xmlns=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc\"><where>//post[contains(timestamp,'2020')]</where><sort-by>member-id</sort-by><direction>backwards</direction><offset>2</offset><limit>2</limit></list-pagination></get></rpc>" "<rpc-reply $DEFAULTNS><data><members xmlns=\"https://example.com/ns/example-social\"><member><member-id>eric</member-id>.*<member-id>bob</member-id>"
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "Kill backend" new "Kill backend"

View file

@ -7,6 +7,7 @@
# 3. CLI get audit logs (only interactive) # 3. CLI get audit logs (only interactive)
# This tests contains a large state list: audit-logs from the example # This tests contains a large state list: audit-logs from the example
# Only CLI is used # Only CLI is used
# Test also of list_pagination_partial_state extension
# Magic line must be first in script (see README.md) # Magic line must be first in script (see README.md)
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
@ -53,7 +54,7 @@ EOF
# See draft-wwlh-netconf-list-pagination-00 A.2 (only stats and audit-log) # See draft-wwlh-netconf-list-pagination-00 A.2 (only stats and audit-log)
cat<<EOF > $fstate cat<<EOF > $fstate
<members xmlns="http://example.com/ns/example-social"> <members xmlns="https://example.com/ns/example-social">
<member> <member>
<member-id>alice</member-id> <member-id>alice</member-id>
<stats> <stats>
@ -83,13 +84,14 @@ EOF
# Generation of random timestamps (not used) # Generation of random timestamps (not used)
# and succesive bob$i member-ids # and succesive bob$i member-ids
new "generate state with $perfnr list entries" new "generate state with $perfnr list entries"
echo "<audit-logs xmlns=\"http://example.com/ns/example-social\">" >> $fstate echo "<audit-logs xmlns=\"https://example.com/ns/example-social\">" >> $fstate
for (( i=0; i<$perfnr; i++ )); do for (( i=0; i<$perfnr; i++ )); do
echo " <audit-log>" >> $fstate echo " <audit-log>" >> $fstate
echo " <timestamp>2021-09-05T018:48:11Z</timestamp>" >> $fstate echo " <timestamp>2021-09-05T018:48:11Z</timestamp>" >> $fstate
echo " <member-id>bob$i</member-id>" >> $fstate echo " <member-id>bob$i</member-id>" >> $fstate
echo " <source-ip>192.168.1.32</source-ip>" >> $fstate echo " <source-ip>192.168.1.32</source-ip>" >> $fstate
echo " <request>POST</request>" >> $fstate echo " <request>POST</request>" >> $fstate
echo " <outcome>true</outcome>" >> $fstate
echo " </audit-log>" >> $fstate echo " </audit-log>" >> $fstate
done done
@ -136,15 +138,15 @@ xpath="$xpath0/es:numbers"
testrun_start $xpath testrun_start $xpath
new "NETCONF get leaf-list member/numbers 0-10 alice" new "NETCONF get leaf-list member/numbers 0-10 alice"
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get content=\"nonconfig\"><filter type=\"xpath\" select=\"$xpath\" xmlns:es=\"http://example.com/ns/example-social\"/><list-pagination xmlns=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc\"><offset>0</offset><limit>10</limit></list-pagination></get></rpc>" "" "<rpc-reply $DEFAULTNS><data><members xmlns=\"http://example.com/ns/example-social\"><member><member-id>alice</member-id><stats><numbers>3</numbers><numbers>4</numbers><numbers>5</numbers><numbers>6</numbers><numbers>7</numbers><numbers>8</numbers></stats></member></members></data></rpc-reply>" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get content=\"nonconfig\"><filter type=\"xpath\" select=\"$xpath\" xmlns:es=\"https://example.com/ns/example-social\"/><list-pagination xmlns=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc\"><offset>0</offset><limit>10</limit></list-pagination></get></rpc>" "" "<rpc-reply $DEFAULTNS><data><members xmlns=\"https://example.com/ns/example-social\"><member><member-id>alice</member-id><stats><numbers>3</numbers><numbers>4</numbers><numbers>5</numbers><numbers>6</numbers><numbers>7</numbers><numbers>8</numbers></stats></member></members></data></rpc-reply>"
# negative # negative
new "NETCONF get container, expect fail" new "NETCONF get container, expect fail"
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get content=\"nonconfig\"><filter type=\"xpath\" select=\"$xpath0\" xmlns:es=\"http://example.com/ns/example-social\"/><list-pagination xmlns=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc\"><offset>0</offset><limit>10</limit></list-pagination></get></rpc>" "" "<rpc-reply $DEFAULTNS><rpc-error><error-type>application</error-type><error-tag>invalid-value</error-tag><error-severity>error</error-severity><error-message>list-pagination is enabled but target is not list or leaf-list</error-message></rpc-error></rpc-reply>" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get content=\"nonconfig\"><filter type=\"xpath\" select=\"$xpath0\" xmlns:es=\"https://example.com/ns/example-social\"/><list-pagination xmlns=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc\"><offset>0</offset><limit>10</limit></list-pagination></get></rpc>" "" "<rpc-reply $DEFAULTNS><rpc-error><error-type>application</error-type><error-tag>invalid-value</error-tag><error-severity>error</error-severity><error-message>list-pagination is enabled but target is not list or leaf-list</error-message></rpc-error></rpc-reply>"
xpath="/es:members/es:member[es:member-id='bob']/es:stats/es:numbers" xpath="/es:members/es:member[es:member-id='bob']/es:stats/es:numbers"
new "NETCONF get leaf-list member/numbers 0-10 bob" new "NETCONF get leaf-list member/numbers 0-10 bob"
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get content=\"nonconfig\"><filter type=\"xpath\" select=\"$xpath\" xmlns:es=\"http://example.com/ns/example-social\"/><list-pagination xmlns=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc\"><offset>0</offset><limit>10</limit></list-pagination></get></rpc>" "" "<rpc-reply $DEFAULTNS><data><members xmlns=\"http://example.com/ns/example-social\"><member><member-id>bob</member-id><stats><numbers>13</numbers><numbers>14</numbers><numbers>15</numbers><numbers>16</numbers><numbers>17</numbers><numbers>18</numbers></stats></member></members></data></rpc-reply>" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get content=\"nonconfig\"><filter type=\"xpath\" select=\"$xpath\" xmlns:es=\"https://example.com/ns/example-social\"/><list-pagination xmlns=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc\"><offset>0</offset><limit>10</limit></list-pagination></get></rpc>" "" "<rpc-reply $DEFAULTNS><data><members xmlns=\"https://example.com/ns/example-social\"><member><member-id>bob</member-id><stats><numbers>13</numbers><numbers>14</numbers><numbers>15</numbers><numbers>16</numbers><numbers>17</numbers><numbers>18</numbers></stats></member></members></data></rpc-reply>"
testrun_stop testrun_stop
@ -153,7 +155,7 @@ xpath="/es:members/es:member/es:stats/es:numbers"
testrun_start $xpath testrun_start $xpath
new "NETCONF get leaf-list member/numbers all" new "NETCONF get leaf-list member/numbers all"
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get content=\"nonconfig\"><filter type=\"xpath\" select=\"$xpath\" xmlns:es=\"http://example.com/ns/example-social\"/><list-pagination xmlns=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc\"><offset>0</offset><limit>10</limit></list-pagination></get></rpc>" "" "<rpc-reply $DEFAULTNS><data><members xmlns=\"http://example.com/ns/example-social\"><member><member-id>alice</member-id><stats><numbers>3</numbers><numbers>4</numbers><numbers>5</numbers><numbers>6</numbers><numbers>7</numbers><numbers>8</numbers></stats></member><member><member-id>bob</member-id><stats><numbers>13</numbers><numbers>14</numbers><numbers>15</numbers><numbers>16</numbers></stats></member></members></data></rpc-reply>" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get content=\"nonconfig\"><filter type=\"xpath\" select=\"$xpath\" xmlns:es=\"https://example.com/ns/example-social\"/><list-pagination xmlns=\"urn:ietf:params:xml:ns:yang:ietf-list-pagination-nc\"><offset>0</offset><limit>10</limit></list-pagination></get></rpc>" "" "<rpc-reply $DEFAULTNS><data><members xmlns=\"https://example.com/ns/example-social\"><member><member-id>alice</member-id><stats><numbers>3</numbers><numbers>4</numbers><numbers>5</numbers><numbers>6</numbers><numbers>7</numbers><numbers>8</numbers></stats></member><member><member-id>bob</member-id><stats><numbers>13</numbers><numbers>14</numbers><numbers>15</numbers><numbers>16</numbers></stats></member></members></data></rpc-reply>"
testrun_stop testrun_stop
@ -165,8 +167,10 @@ if [ -n "$(type expect 2> /dev/null)" ]; then
testrun_start "/es:audit-logs/es:audit-log" testrun_start "/es:audit-logs/es:audit-log"
new "CLI scroll test using expect" new "CLI scroll test using expect"
xpath="/es:audit-logs/es:audit-log"
sudo="sudo -g ${CLICON_GROUP}" ## cheat sudo="sudo -g ${CLICON_GROUP}" ## cheat
clixon_cli_="${clixon_cli##$sudo }" clixon_cli_="${clixon_cli##$sudo }"
# echo "$sudo --preserve-env=clixon_cli expect ./test_pagination_expect.exp $cfg $xpath bob3 bob4"
clixon_cli="$clixon_cli_" $sudo --preserve-env=clixon_cli expect ./test_pagination_expect.exp "$cfg" "$xpath" bob3 bob4 clixon_cli="$clixon_cli_" $sudo --preserve-env=clixon_cli expect ./test_pagination_expect.exp "$cfg" "$xpath" bob3 bob4
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
err1 "Failed: CLI show paginate state scroll using expect" err1 "Failed: CLI show paginate state scroll using expect"

View file

@ -43,7 +43,7 @@ YANG_INSTALLDIR = @YANG_INSTALLDIR@
# Note: mirror these to test/config.sh.in # Note: mirror these to test/config.sh.in
YANGSPECS = clixon-config@2024-04-01.yang # 7.1 YANGSPECS = clixon-config@2024-04-01.yang # 7.1
YANGSPECS += clixon-lib@2024-04-01.yang # 7.1 YANGSPECS += clixon-lib@2024-08-01.yang # 7.2
YANGSPECS += clixon-rfc5277@2008-07-01.yang YANGSPECS += clixon-rfc5277@2008-07-01.yang
YANGSPECS += clixon-xml-changelog@2019-03-21.yang YANGSPECS += clixon-xml-changelog@2019-03-21.yang
YANGSPECS += clixon-restconf@2022-08-01.yang # 5.9 YANGSPECS += clixon-restconf@2022-08-01.yang # 5.9

View file

@ -66,8 +66,21 @@ module clixon-lib {
- source-host (see RFC6022) - source-host (see RFC6022)
- objectcreate - objectcreate
- objectexisted - objectexisted
- link # For split multiple XML files
"; ";
revision 2024-08-01 {
description
"Added: list-pagination-partial-state
Released in Clixon 7.2";
}
revision 2024-04-01 {
description
"Added: debug bits type
Added: xmldb-split extension
Added: Default format
Released in Clixon 7.1";
}
revision 2024-01-01 { revision 2024-01-01 {
description description
"Removed container creators from 6.5 "Removed container creators from 6.5
@ -175,6 +188,116 @@ module clixon-lib {
enum cli{ enum cli{
description "CLI format"; description "CLI format";
} }
enum default{
description "Default format";
}
}
}
typedef clixon_debug_t {
description
"Debug flags.
Flags are seperated into subject areas and detail
Can also be given directly as -D <flag> to clixon commands
Note there are also constants in the code that need to be in sync with these values";
type bits {
/* Subjects: */
bit default {
description "Default logs";
position 0;
}
bit msg {
description "In/out messages";
position 1;
}
bit init {
description "Initialization";
position 2;
}
bit xml {
description "XML processing";
position 3;
}
bit xpath {
description "XPath processing";
position 4;
}
bit yang {
description "YANG processing";
position 5;
}
bit backend {
description "Backend-specific";
position 6;
}
bit cli {
description "CLI frontend";
position 7;
}
bit netconf {
description "NETCONF frontend";
position 8;
}
bit restconf {
description "RESTCONF frontend";
position 9;
}
bit snmp {
description "SNMP frontend";
position 10;
}
bit nacm {
description "NACM processing";
position 11;
}
bit proc {
description "Process handling";
position 12;
}
bit datastore {
description "Datastore xmldb management";
position 13;
}
bit event {
description "Event processing";
position 14;
}
bit rpc {
description "RPC handling";
position 15;
}
bit stream {
description "Notification streams";
position 16;
}
bit parse {
description "Parser: XML,YANG, etc";
position 17;
}
bit app {
description "External applications";
position 20;
}
bit app2 {
description "External application";
position 21;
}
bit app3 {
description "External application 2";
position 22;
}
/* Detail level: */
bit detail {
description "Details: traces, parse trees, etc";
position 24;
}
bit detail2 {
description "Extra details";
position 25;
}
bit detail3 {
description "Probably more detail than you want";
position 26;
}
} }
} }
identity snmp { identity snmp {
@ -199,12 +322,34 @@ module clixon-lib {
"A CLI session"; "A CLI session";
base ncm:transport; base ncm:transport;
} }
extension list-pagination-partial-state {
description
"List should be partially read according to the clixon_pagination_cb_register API.
This is a performance enhancement of pagination state data.
This means that a special callback is used for retreiving list state which is aware of
offset/limit attributes.
In this way the non-config data can be partially read by the server, instead of reading
the whole state on every pagination request.
It affects only the server/backend-side
It only handles the offset and limit attributes, all other attributes,
such as where, sort-by, direction, etc, are ignored";
}
extension ignore-compare { extension ignore-compare {
description description
"The object should be ignored when comparing device configs for equality. "The object should be ignored when comparing device configs for equality.
The object should never be added, modified, or deleted on target. The object should never be added, modified, or deleted on target.
Essentially a read-only object Essentially a read-only object
One example is auto-created objects by the , such as uid."; One example is auto-created objects by the controller, such as uid.";
}
extension xmldb-split {
description
"When split configuration stores are used, ie CLICON_XMLDB_MULTI is set,
This extension marks where in the configuration tree, one file terminates
and a new sub-file is written.
A designer adds the 'xmldb-split' extension to a YANG node which should be split.
For example, a split could be made at mountpoints.
See also the 'link 'attribute.
";
} }
md:annotation creator { md:annotation creator {
type string; type string;
@ -217,7 +362,9 @@ module clixon-lib {
A sub-object will not be noted"; A sub-object will not be noted";
} }
rpc debug { rpc debug {
description "Set debug level of backend."; description
"Set debug flags of backend.
Note only numerical values";
input { input {
leaf level { leaf level {
type uint32; type uint32;
@ -256,44 +403,27 @@ module clixon-lib {
} }
} }
container datastores{ container datastores{
list datastore{ list datastore{
description "Per datastore statistics for cxobj"; description "Per datastore statistics for cxobj";
key "name"; key "name";
leaf name{ leaf name{
description "Name of datastore (eg running)."; description "Name of datastore (eg running).";
type string; type string;
} }
leaf nr{ leaf nr{
description "Number of XML objects. That is number of residing xml/json objects description "Number of XML objects. That is number of residing xml/json objects
in the internal 'cxobj' representation."; in the internal 'cxobj' representation.";
type uint64; type uint64;
}
leaf size{
description "Size in bytes of internal datastore cache of datastore tree.";
type uint64;
}
} }
leaf size{
description "Size in bytes of internal datastore cache of datastore tree.";
type uint64;
}
}
} }
container module-sets{ container module-sets{
list module-set{ list module-set{
description "Statistics per group of module, eg top-level and mount-points"; description "Statistics per group of module, eg top-level and mount-points";
key "name";
leaf name{
description "Name of YANG module.";
type string;
}
leaf nr{
description
"Total number of YANG objects in set";
type uint64;
}
leaf size{
description
"Total size in bytes of internal YANG object representation for module set";
type uint64;
}
list module{
description "Statistics per module (if modules set in input)";
key "name"; key "name";
leaf name{ leaf name{
description "Name of YANG module."; description "Name of YANG module.";
@ -301,16 +431,33 @@ module clixon-lib {
} }
leaf nr{ leaf nr{
description description
"Number of YANG objects. That is number of residing YANG objects"; "Total number of YANG objects in set";
type uint64; type uint64;
} }
leaf size{ leaf size{
description description
"Size in bytes of internal YANG object representation."; "Total size in bytes of internal YANG object representation for module set";
type uint64; type uint64;
} }
list module{
description "Statistics per module (if modules set in input)";
key "name";
leaf name{
description "Name of YANG module.";
type string;
}
leaf nr{
description
"Number of YANG objects. That is number of residing YANG objects";
type uint64;
}
leaf size{
description
"Size in bytes of internal YANG object representation.";
type uint64;
}
}
} }
}
} }
} }
} }